aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-07-07 01:01:31 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-07-07 01:01:31 +0000
commit4795ba337f7dba15ceb94f8884a1b15ad903b746 (patch)
tree9de2e37332c9056aacfebc24339302109cf2c64a
parentc8df0ff0cbe131029d794ad3b5a9d8d0cd0de645 (diff)
parent763d76ecdc285e49c0535f256b0df4a932e1f145 (diff)
downloadbumble-4795ba337f7dba15ceb94f8884a1b15ad903b746.tar.gz
Snap for 10447354 from 763d76ecdc285e49c0535f256b0df4a932e1f145 to mainline-cellbroadcast-releaseaml_cbr_340914000
Change-Id: I0e4f56b50202635e074235bc417718406219e673
-rw-r--r--.git-blame-ignore-revs2
-rw-r--r--.github/workflows/code-check.yml35
-rw-r--r--.github/workflows/python-build-test.yml25
-rw-r--r--.github/workflows/python-publish.yml37
-rw-r--r--.gitignore8
-rw-r--r--.vscode/settings.json80
-rw-r--r--Android.bp37
-rw-r--r--LICENSE21
-rw-r--r--OWNERS2
-rw-r--r--README.md37
-rw-r--r--apps/README.md2
-rw-r--r--apps/bench.py1209
-rw-r--r--apps/console.py995
-rw-r--r--apps/controller_info.py173
-rw-r--r--apps/controllers.py16
-rw-r--r--apps/gatt_dump.py25
-rw-r--r--apps/gg_bridge.py327
-rw-r--r--apps/hci_bridge.py42
-rw-r--r--apps/l2cap_bridge.py350
-rw-r--r--apps/link_relay/link_relay.py59
-rw-r--r--apps/pair.py299
-rw-r--r--apps/pandora_server.py30
-rw-r--r--apps/scan.py126
-rw-r--r--apps/show.py52
-rw-r--r--apps/unbond.py2
-rw-r--r--apps/usb_probe.py278
-rw-r--r--bumble/__init__.py4
-rw-r--r--bumble/a2dp.py477
-rw-r--r--bumble/att.py458
-rw-r--r--bumble/avdtp.py648
-rw-r--r--bumble/bridge.py14
-rw-r--r--bumble/colors.py103
-rw-r--r--bumble/company_ids.py55
-rw-r--r--bumble/controller.py856
-rw-r--r--bumble/core.py364
-rw-r--r--bumble/crypto.py138
-rw-r--r--bumble/decoder.py416
-rw-r--r--bumble/device.py2746
-rw-r--r--bumble/gap.py20
-rw-r--r--bumble/gatt.py367
-rw-r--r--bumble/gatt_client.py639
-rw-r--r--bumble/gatt_server.py677
-rw-r--r--bumble/hci.py4711
-rw-r--r--bumble/helpers.py90
-rw-r--r--bumble/hfp.py27
-rw-r--r--bumble/host.py628
-rw-r--r--bumble/keys.py159
-rw-r--r--bumble/l2cap.py1591
-rw-r--r--bumble/link.py274
-rw-r--r--bumble/pairing.py188
-rw-r--r--bumble/pandora/__init__.py105
-rw-r--r--bumble/pandora/config.py48
-rw-r--r--bumble/pandora/device.py157
-rw-r--r--bumble/pandora/host.py856
-rw-r--r--bumble/pandora/py.typed0
-rw-r--r--bumble/pandora/security.py529
-rw-r--r--bumble/pandora/utils.py112
-rw-r--r--bumble/profiles/asha_service.py188
-rw-r--r--bumble/profiles/battery_service.py15
-rw-r--r--bumble/profiles/device_information_service.py75
-rw-r--r--bumble/profiles/heart_rate_service.py237
-rw-r--r--bumble/profiles/py.typed0
-rw-r--r--bumble/py.typed0
-rw-r--r--bumble/rfcomm.py575
-rw-r--r--bumble/sdp.py516
-rw-r--r--bumble/smp.py1303
-rw-r--r--bumble/snoop.py170
-rw-r--r--bumble/transport/__init__.py139
-rw-r--r--bumble/transport/android_emulator.py23
-rw-r--r--bumble/transport/android_netsim.py410
-rw-r--r--bumble/transport/common.py142
-rw-r--r--bumble/transport/emulated_bluetooth_pb2.py53
-rw-r--r--bumble/transport/file.py12
-rw-r--r--bumble/transport/grpc_protobuf/__init__.py0
-rw-r--r--bumble/transport/grpc_protobuf/common_pb2.py25
-rw-r--r--bumble/transport/grpc_protobuf/common_pb2.pyi12
-rw-r--r--bumble/transport/grpc_protobuf/common_pb2_grpc.py4
-rw-r--r--bumble/transport/grpc_protobuf/emulated_bluetooth_device_pb2.py64
-rw-r--r--bumble/transport/grpc_protobuf/emulated_bluetooth_device_pb2.pyi158
-rw-r--r--bumble/transport/grpc_protobuf/emulated_bluetooth_device_pb2_grpc.py193
-rw-r--r--bumble/transport/grpc_protobuf/emulated_bluetooth_packets_pb2.py (renamed from bumble/transport/emulated_bluetooth_packets_pb2.py)30
-rw-r--r--bumble/transport/grpc_protobuf/emulated_bluetooth_packets_pb2.pyi22
-rw-r--r--bumble/transport/grpc_protobuf/emulated_bluetooth_packets_pb2_grpc.py4
-rw-r--r--bumble/transport/grpc_protobuf/emulated_bluetooth_pb2.py32
-rw-r--r--bumble/transport/grpc_protobuf/emulated_bluetooth_pb2.pyi19
-rw-r--r--bumble/transport/grpc_protobuf/emulated_bluetooth_pb2_grpc.py (renamed from bumble/transport/emulated_bluetooth_pb2_grpc.py)58
-rw-r--r--bumble/transport/grpc_protobuf/emulated_bluetooth_vhci_pb2.py (renamed from bumble/transport/emulated_bluetooth_vhci_pb2.py)24
-rw-r--r--bumble/transport/grpc_protobuf/emulated_bluetooth_vhci_pb2.pyi5
-rw-r--r--bumble/transport/grpc_protobuf/emulated_bluetooth_vhci_pb2_grpc.py (renamed from bumble/transport/emulated_bluetooth_vhci_pb2_grpc.py)14
-rw-r--r--bumble/transport/grpc_protobuf/grpc_endpoint_description_pb2.py30
-rw-r--r--bumble/transport/grpc_protobuf/grpc_endpoint_description_pb2.pyi34
-rw-r--r--bumble/transport/grpc_protobuf/grpc_endpoint_description_pb2_grpc.py4
-rw-r--r--bumble/transport/grpc_protobuf/hci_packet_pb2.py28
-rw-r--r--bumble/transport/grpc_protobuf/hci_packet_pb2.pyi22
-rw-r--r--bumble/transport/grpc_protobuf/hci_packet_pb2_grpc.py4
-rw-r--r--bumble/transport/grpc_protobuf/packet_streamer_pb2.py31
-rw-r--r--bumble/transport/grpc_protobuf/packet_streamer_pb2.pyi27
-rw-r--r--bumble/transport/grpc_protobuf/packet_streamer_pb2_grpc.py109
-rw-r--r--bumble/transport/grpc_protobuf/startup_pb2.py32
-rw-r--r--bumble/transport/grpc_protobuf/startup_pb2.pyi46
-rw-r--r--bumble/transport/grpc_protobuf/startup_pb2_grpc.py4
-rw-r--r--bumble/transport/hci_socket.py64
-rw-r--r--bumble/transport/pty.py6
-rw-r--r--bumble/transport/py.typed0
-rw-r--r--bumble/transport/pyusb.py103
-rw-r--r--bumble/transport/serial.py5
-rw-r--r--bumble/transport/tcp_client.py8
-rw-r--r--bumble/transport/tcp_server.py8
-rw-r--r--bumble/transport/udp.py9
-rw-r--r--bumble/transport/usb.py381
-rw-r--r--bumble/transport/vhci.py3
-rw-r--r--bumble/transport/ws_client.py2
-rw-r--r--bumble/transport/ws_server.py22
-rw-r--r--bumble/utils.py172
-rw-r--r--docs/README.md6
-rw-r--r--docs/images/logo.vectornator/Artboard0.json2
-rw-r--r--docs/images/logo.vectornator/Document.json2
-rw-r--r--docs/images/logo.vectornator/Manifest.json2
-rw-r--r--docs/images/logo.vectornator/UndoHistory.json2
-rw-r--r--docs/images/logo_framed.vectornator/Artboard0.json2
-rw-r--r--docs/images/logo_framed.vectornator/Document.json2
-rw-r--r--docs/images/logo_framed.vectornator/Manifest.json2
-rw-r--r--docs/images/logo_framed.vectornator/UndoHistory.json2
-rw-r--r--docs/mkdocs/mkdocs.yml11
-rw-r--r--docs/mkdocs/requirements.txt10
-rw-r--r--docs/mkdocs/src/api/examples.md2
-rw-r--r--docs/mkdocs/src/api/guide.md2
-rw-r--r--docs/mkdocs/src/api/reference.md1
-rw-r--r--docs/mkdocs/src/apps_and_tools/bench.md158
-rw-r--r--docs/mkdocs/src/apps_and_tools/console.md6
-rw-r--r--docs/mkdocs/src/apps_and_tools/gg_bridge.md2
-rw-r--r--docs/mkdocs/src/apps_and_tools/hci_bridge.md2
-rw-r--r--docs/mkdocs/src/apps_and_tools/index.md2
-rw-r--r--docs/mkdocs/src/apps_and_tools/link_relay.md1
-rw-r--r--docs/mkdocs/src/apps_and_tools/usb_probe.md50
-rw-r--r--docs/mkdocs/src/components/controller.md2
-rw-r--r--docs/mkdocs/src/components/gatt.md2
-rw-r--r--docs/mkdocs/src/components/host.md2
-rw-r--r--docs/mkdocs/src/components/security_manager.md2
-rw-r--r--docs/mkdocs/src/development/code_style.md43
-rw-r--r--docs/mkdocs/src/development/contributing.md11
-rw-r--r--docs/mkdocs/src/development/python_environments.md10
-rw-r--r--docs/mkdocs/src/examples/index.md2
-rw-r--r--docs/mkdocs/src/getting_started.md20
-rw-r--r--docs/mkdocs/src/hardware/index.md12
-rw-r--r--docs/mkdocs/src/images/bumble_layers.svg2
-rw-r--r--docs/mkdocs/src/index.md4
-rw-r--r--docs/mkdocs/src/platforms/android.md98
-rw-r--r--docs/mkdocs/src/platforms/linux.md166
-rw-r--r--docs/mkdocs/src/platforms/macos.md1
-rw-r--r--docs/mkdocs/src/platforms/windows.md2
-rw-r--r--docs/mkdocs/src/transports/android_emulator.md40
-rw-r--r--docs/mkdocs/src/transports/file.md4
-rw-r--r--docs/mkdocs/src/transports/hci_socket.md4
-rw-r--r--docs/mkdocs/src/transports/index.md3
-rw-r--r--docs/mkdocs/src/transports/pty.md2
-rw-r--r--docs/mkdocs/src/transports/serial.md2
-rw-r--r--docs/mkdocs/src/transports/tcp_client.md4
-rw-r--r--docs/mkdocs/src/transports/tcp_server.md6
-rw-r--r--docs/mkdocs/src/transports/udp.md2
-rw-r--r--docs/mkdocs/src/transports/usb.md68
-rw-r--r--docs/mkdocs/src/transports/vhci.md4
-rw-r--r--docs/mkdocs/src/transports/ws_client.md2
-rw-r--r--docs/mkdocs/src/transports/ws_server.md2
-rw-r--r--docs/mkdocs/src/use_cases/use_case_1.md2
-rw-r--r--docs/mkdocs/src/use_cases/use_case_2.md2
-rw-r--r--docs/mkdocs/src/use_cases/use_case_3.md2
-rw-r--r--docs/mkdocs/src/use_cases/use_case_4.md4
-rw-r--r--docs/mkdocs/src/use_cases/use_case_5.md2
-rw-r--r--docs/mkdocs/src/use_cases/use_case_6.md4
-rw-r--r--examples/a2dp_sink1.json1
-rw-r--r--examples/asha_sink1.json5
-rw-r--r--examples/asha_sink2.json5
-rw-r--r--examples/async_runner.py3
-rw-r--r--examples/battery_client.py42
-rw-r--r--examples/battery_server.py26
-rw-r--r--examples/device_information_client.py60
-rw-r--r--examples/device_information_server.py28
-rw-r--r--examples/heart_rate_client.py74
-rw-r--r--examples/heart_rate_server.py115
-rw-r--r--examples/hfp_handsfree.html2
-rw-r--r--examples/hfp_handsfree.json4
-rw-r--r--examples/keyboard.html2
-rw-r--r--examples/keyboard.py365
-rw-r--r--examples/run_a2dp_info.py56
-rw-r--r--examples/run_a2dp_sink.py59
-rw-r--r--examples/run_a2dp_source.py73
-rw-r--r--examples/run_advertiser.py34
-rw-r--r--examples/run_asha_sink.py202
-rw-r--r--examples/run_classic_connect.py54
-rw-r--r--examples/run_classic_discoverable.py65
-rw-r--r--examples/run_classic_discovery.py30
-rw-r--r--examples/run_connect_and_encrypt.py12
-rw-r--r--examples/run_controller.py53
-rw-r--r--examples/run_controller_with_scanner.py27
-rw-r--r--examples/run_device_with_snooper.py51
-rw-r--r--examples/run_gatt_client.py11
-rw-r--r--examples/run_gatt_client_and_server.py31
-rw-r--r--examples/run_gatt_server.py53
-rw-r--r--examples/run_hfp_gateway.py102
-rw-r--r--examples/run_hfp_handsfree.py69
-rw-r--r--examples/run_notifier.py42
-rw-r--r--examples/run_rfcomm_client.py98
-rw-r--r--examples/run_rfcomm_server.py52
-rw-r--r--examples/run_scanner.py27
-rw-r--r--pyproject.toml82
-rw-r--r--scripts/process_android_emulator_protos.sh16
-rw-r--r--scripts/process_android_netsim_protos.sh14
-rw-r--r--setup.cfg40
-rw-r--r--setup.py1
-rw-r--r--tasks.py154
-rw-r--r--tests/a2dp_test.py172
-rw-r--r--tests/avdtp_test.py24
-rw-r--r--tests/core_test.py54
-rw-r--r--tests/decoder_test.py47
-rw-r--r--tests/device_test.py267
-rw-r--r--tests/g722_sample.g7221
-rw-r--r--tests/gatt_test.py799
-rw-r--r--tests/hci_test.py336
-rw-r--r--tests/import_test.py64
-rw-r--r--tests/l2cap_test.py279
-rw-r--r--tests/pytest.ini2
-rw-r--r--tests/rfcomm_test.py4
-rw-r--r--tests/sdp_test.py39
-rw-r--r--tests/self_test.py306
-rw-r--r--tests/smp_test.py172
-rw-r--r--tests/transport_test.py15
-rw-r--r--web/index.html2
-rw-r--r--web/scanner.py10
229 files changed, 25784 insertions, 7258 deletions
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
new file mode 100644
index 0000000..be480be
--- /dev/null
+++ b/.git-blame-ignore-revs
@@ -0,0 +1,2 @@
+# Migrate code style to Black
+135df0dcc01ab765f432e19b1a5202d29bd55545
diff --git a/.github/workflows/code-check.yml b/.github/workflows/code-check.yml
new file mode 100644
index 0000000..b6cf8fd
--- /dev/null
+++ b/.github/workflows/code-check.yml
@@ -0,0 +1,35 @@
+# Check the code against the formatter and linter
+name: Code format and lint check
+
+on:
+ push:
+ branches: [ main ]
+ pull_request:
+ branches: [ main ]
+
+permissions:
+ contents: read
+
+jobs:
+ check:
+ name: Check Code
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Check out from Git
+ uses: actions/checkout@v3
+ - name: Get history and tags for SCM versioning to work
+ run: |
+ git fetch --prune --unshallow
+ git fetch --depth=1 origin +refs/tags/*:refs/tags/*
+ - name: Set up Python
+ uses: actions/setup-python@v3
+ with:
+ python-version: '3.10'
+ - name: Install dependencies
+ run: |
+ python -m pip install --upgrade pip
+ python -m pip install ".[build,test,development]"
+ - name: Check
+ run: |
+ invoke project.pre-commit
diff --git a/.github/workflows/python-build-test.yml b/.github/workflows/python-build-test.yml
index 062f153..72c7b43 100644
--- a/.github/workflows/python-build-test.yml
+++ b/.github/workflows/python-build-test.yml
@@ -14,21 +14,30 @@ jobs:
build:
runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ python-version: ["3.8", "3.9", "3.10"]
+ fail-fast: false
steps:
- - uses: actions/checkout@v3
- - name: Set up Python 3.10
- uses: actions/setup-python@v3
+ - name: Check out from Git
+ uses: actions/checkout@v3
+ - name: Get history and tags for SCM versioning to work
+ run: |
+ git fetch --prune --unshallow
+ git fetch --depth=1 origin +refs/tags/*:refs/tags/*
+ - name: Set up Python ${{ matrix.python-version }}
+ uses: actions/setup-python@v4
with:
- python-version: "3.10"
+ python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
- python -m pip install ".[test,development,documentation]"
- - name: Test with pytest
+ python -m pip install ".[build,test,development,documentation]"
+ - name: Test
run: |
- pytest
+ invoke test
- name: Build
run: |
inv build
- inv mkdocs
+ inv build.mkdocs
diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml
new file mode 100644
index 0000000..7d9bc19
--- /dev/null
+++ b/.github/workflows/python-publish.yml
@@ -0,0 +1,37 @@
+name: Upload Python Package
+
+on:
+ release:
+ types: [published]
+
+permissions:
+ contents: read
+
+jobs:
+ deploy:
+ name: Build and publish Python ðŸ distributions 📦 to PyPI and TestPyPI
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Check out from Git
+ uses: actions/checkout@v3
+ - name: Get history and tags for SCM versioning to work
+ run: |
+ git fetch --prune --unshallow
+ git fetch --depth=1 origin +refs/tags/*:refs/tags/*
+ - name: Set up Python
+ uses: actions/setup-python@v3
+ with:
+ python-version: '3.10'
+ - name: Install dependencies
+ run: |
+ python -m pip install --upgrade pip
+ python -m pip install build
+ - name: Build package
+ run: python -m build
+ - name: Publish package to PyPI
+ if: github.event_name == 'release' && startsWith(github.ref, 'refs/tags')
+ uses: pypa/gh-action-pypi-publish@release/v1
+ with:
+ user: __token__
+ password: ${{ secrets.PYPI_API_TOKEN }}
diff --git a/.gitignore b/.gitignore
index 5cb29bb..43b6410 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,9 +3,9 @@ build/
dist/
*.egg-info/
*~
-bumble/__pycache__
docs/mkdocs/site
-tests/__pycache__
test-results.xml
-bumble/transport/__pycache__
-bumble/profiles/__pycache__
+__pycache__
+# generated by setuptools_scm
+bumble/_version.py
+.vscode/launch.json
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..864fe69
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,80 @@
+{
+ "cSpell.words": [
+ "Abortable",
+ "altsetting",
+ "ansiblue",
+ "ansicyan",
+ "ansigreen",
+ "ansimagenta",
+ "ansired",
+ "ansiyellow",
+ "appendleft",
+ "ASHA",
+ "asyncio",
+ "ATRAC",
+ "avdtp",
+ "bitpool",
+ "bitstruct",
+ "BSCP",
+ "BTPROTO",
+ "CCCD",
+ "cccds",
+ "cmac",
+ "CONNECTIONLESS",
+ "csrcs",
+ "datagram",
+ "DATALINK",
+ "delayreport",
+ "deregisters",
+ "deregistration",
+ "dhkey",
+ "diversifier",
+ "Fitbit",
+ "GATTLINK",
+ "HANDSFREE",
+ "keydown",
+ "keyup",
+ "levelname",
+ "libc",
+ "libusb",
+ "MITM",
+ "NDIS",
+ "NONBLOCK",
+ "NONCONN",
+ "OXIMETER",
+ "popleft",
+ "psms",
+ "pyee",
+ "pyusb",
+ "rfcomm",
+ "ROHC",
+ "rssi",
+ "SEID",
+ "seids",
+ "SERV",
+ "ssrc",
+ "strerror",
+ "subband",
+ "subbands",
+ "subevent",
+ "Subrating",
+ "substates",
+ "tobytes",
+ "tsep",
+ "usbmodem",
+ "vhci",
+ "websockets",
+ "xcursor",
+ "ycursor"
+ ],
+ "[python]": {
+ "editor.rulers": [88]
+ },
+ "python.formatting.provider": "black",
+ "pylint.importStrategy": "useBundled",
+ "python.testing.pytestArgs": [
+ "."
+ ],
+ "python.testing.unittestEnabled": false,
+ "python.testing.pytestEnabled": true
+}
diff --git a/Android.bp b/Android.bp
index 7d26b07..640bded 100644
--- a/Android.bp
+++ b/Android.bp
@@ -23,6 +23,41 @@ python_library_host {
"bumble/transport/*.py",
],
libs: [
- "py-cryptography",
+ "pyee",
+ ]
+}
+
+python_library_host {
+ name: "bumble-pandora",
+ srcs: [
+ "bumble/pandora/*.py",
+ ],
+ libs: [
+ "bumble",
+ "pandora-python",
+ "libprotobuf-python",
+ ],
+ data: [
+ "bumble/pandora/py.typed"
+ ]
+}
+
+python_test_host {
+ name: "bumble_pandora_server",
+ main: "apps/pandora_server.py",
+ srcs: [
+ "apps/pandora_server.py",
],
+ libs: [
+ "bumble-pandora",
+ "pandora-python",
+ ],
+
+ test_options: {
+ unit_test: false,
+ },
+
+ test_suites: [
+ "general-tests"
+ ]
}
diff --git a/LICENSE b/LICENSE
index 7a4a3ea..0cb8949 100644
--- a/LICENSE
+++ b/LICENSE
@@ -199,4 +199,23 @@
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
- limitations under the License. \ No newline at end of file
+ limitations under the License.
+
+
+---
+
+
+Files: bumble/colors.py
+Copyright (c) 2012 Giorgos Verigakis <verigak@gmail.com>
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/OWNERS b/OWNERS
index b008db5..610a689 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,3 +1,5 @@
boccongibod@google.com
+charliebout@google.com
girardier@google.com
licorne@google.com
+uael@google.com
diff --git a/README.md b/README.md
index 3370baf..59a15bb 100644
--- a/README.md
+++ b/README.md
@@ -9,18 +9,49 @@
Bluetooth Stack for Apps, Emulation, Test and Experimentation
=============================================================
-<img src="docs/mkdocs/src/images/logo_framed.png" alt="drawing" width="200" height="200"/>
+<img src="docs/mkdocs/src/images/logo_framed.png" alt="Logo" width="200" height="200"/>
Bumble is a full-featured Bluetooth stack written entirely in Python. It supports most of the common Bluetooth Low Energy (BLE) and Bluetooth Classic (BR/EDR) protocols and profiles, including GAP, L2CAP, ATT, GATT, SMP, SDP, RFCOMM, HFP, HID and A2DP. The stack can be used with physical radios via HCI over USB, UART, or the Linux VHCI, as well as virtual radios, including the virtual Bluetooth support of the Android emulator.
## Documentation
-Browse the pre-built [Online Documentation](https://google.github.io/bumble/),
+Browse the pre-built [Online Documentation](https://google.github.io/bumble/),
or see the documentation source under `docs/mkdocs/src`, or build the static HTML site from the markdown text with:
```
-mkdocs build -f docs/mkdocs/mkdocs.yml
+mkdocs build -f docs/mkdocs/mkdocs.yml
```
+## Usage
+
+### Getting Started
+
+For a quick start to using Bumble, see the [Getting Started](docs/mkdocs/src/getting_started.md) guide.
+
+### Dependencies
+
+To install package dependencies needed to run the bumble examples, execute the following commands:
+
+```
+python -m pip install --upgrade pip
+python -m pip install ".[test,development,documentation]"
+```
+
+### Examples
+
+Refer to the [Examples Documentation](examples/README.md) for details on the included example scripts and how to run them.
+
+The complete [list of Examples](/docs/mkdocs/src/examples/index.md), and what they are designed to do is here.
+
+There are also a set of [Apps and Tools](docs/mkdocs/src/apps_and_tools/index.md) that show the utility of Bumble.
+
+### Using Bumble With a USB Dongle
+
+Bumble is easiest to use with a dedicated USB dongle.
+This is because internal Bluetooth interfaces tend to be locked down by the operating system.
+You can use the [usb_probe](/docs/mkdocs/src/apps_and_tools/usb_probe.md) tool (all platforms) or `lsusb` (Linux or macOS) to list the available USB devices on your system.
+
+See the [USB Transport](/docs/mkdocs/src/transports/usb.md) page for details on how to refer to USB devices. Also, if your are on a mac, see [these instructions](docs/mkdocs/src/platforms/macos.md).
+
## License
Licensed under the [Apache 2.0](LICENSE) License.
diff --git a/apps/README.md b/apps/README.md
index 0abcf09..814d23d 100644
--- a/apps/README.md
+++ b/apps/README.md
@@ -47,5 +47,3 @@ NOTE: this assumes you're running a Link Relay on port `10723`.
## `console.py`
A simple text-based-ui interactive Bluetooth device with GATT client capabilities.
-
-
diff --git a/apps/bench.py b/apps/bench.py
new file mode 100644
index 0000000..4708403
--- /dev/null
+++ b/apps/bench.py
@@ -0,0 +1,1209 @@
+# Copyright 2021-2023 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# -----------------------------------------------------------------------------
+# Imports
+# -----------------------------------------------------------------------------
+import asyncio
+import enum
+import logging
+import os
+import struct
+import time
+
+import click
+
+from bumble.core import (
+ BT_BR_EDR_TRANSPORT,
+ BT_LE_TRANSPORT,
+ BT_L2CAP_PROTOCOL_ID,
+ BT_RFCOMM_PROTOCOL_ID,
+ UUID,
+ CommandTimeoutError,
+)
+from bumble.colors import color
+from bumble.device import Connection, ConnectionParametersPreferences, Device, Peer
+from bumble.gatt import Characteristic, CharacteristicValue, Service
+from bumble.hci import (
+ HCI_LE_1M_PHY,
+ HCI_LE_2M_PHY,
+ HCI_LE_CODED_PHY,
+ HCI_Constant,
+ HCI_Error,
+ HCI_StatusError,
+)
+from bumble.sdp import (
+ SDP_BROWSE_GROUP_LIST_ATTRIBUTE_ID,
+ SDP_PROTOCOL_DESCRIPTOR_LIST_ATTRIBUTE_ID,
+ SDP_PUBLIC_BROWSE_ROOT,
+ SDP_SERVICE_CLASS_ID_LIST_ATTRIBUTE_ID,
+ SDP_SERVICE_RECORD_HANDLE_ATTRIBUTE_ID,
+ DataElement,
+ ServiceAttribute,
+)
+from bumble.transport import open_transport_or_link
+import bumble.rfcomm
+import bumble.core
+from bumble.utils import AsyncRunner
+
+
+# -----------------------------------------------------------------------------
+# Logging
+# -----------------------------------------------------------------------------
+logger = logging.getLogger(__name__)
+
+
+# -----------------------------------------------------------------------------
+# Constants
+# -----------------------------------------------------------------------------
+DEFAULT_CENTRAL_ADDRESS = 'F0:F0:F0:F0:F0:F0'
+DEFAULT_CENTRAL_NAME = 'Speed Central'
+DEFAULT_PERIPHERAL_ADDRESS = 'F1:F1:F1:F1:F1:F1'
+DEFAULT_PERIPHERAL_NAME = 'Speed Peripheral'
+
+SPEED_SERVICE_UUID = '50DB505C-8AC4-4738-8448-3B1D9CC09CC5'
+SPEED_TX_UUID = 'E789C754-41A1-45F4-A948-A0A1A90DBA53'
+SPEED_RX_UUID = '016A2CC7-E14B-4819-935F-1F56EAE4098D'
+
+DEFAULT_L2CAP_PSM = 1234
+DEFAULT_L2CAP_MAX_CREDITS = 128
+DEFAULT_L2CAP_MTU = 1022
+DEFAULT_L2CAP_MPS = 1024
+
+DEFAULT_LINGER_TIME = 1.0
+
+DEFAULT_RFCOMM_CHANNEL = 8
+
+# -----------------------------------------------------------------------------
+# Utils
+# -----------------------------------------------------------------------------
+def parse_packet(packet):
+ if len(packet) < 1:
+ print(
+ color(f'!!! Packet too short (got {len(packet)} bytes, need >= 1)', 'red')
+ )
+ raise ValueError('packet too short')
+
+ try:
+ packet_type = PacketType(packet[0])
+ except ValueError:
+ print(color(f'!!! Invalid packet type 0x{packet[0]:02X}', 'red'))
+ raise
+
+ return (packet_type, packet[1:])
+
+
+def parse_packet_sequence(packet_data):
+ if len(packet_data) < 5:
+ print(
+ color(
+ f'!!!Packet too short (got {len(packet_data)} bytes, need >= 5)',
+ 'red',
+ )
+ )
+ raise ValueError('packet too short')
+ return struct.unpack_from('>bI', packet_data, 0)
+
+
+def le_phy_name(phy_id):
+ return {HCI_LE_1M_PHY: '1M', HCI_LE_2M_PHY: '2M', HCI_LE_CODED_PHY: 'CODED'}.get(
+ phy_id, HCI_Constant.le_phy_name(phy_id)
+ )
+
+
+def print_connection(connection):
+ if connection.transport == BT_LE_TRANSPORT:
+ phy_state = (
+ 'PHY='
+ f'RX:{le_phy_name(connection.phy.rx_phy)}/'
+ f'TX:{le_phy_name(connection.phy.tx_phy)}'
+ )
+
+ data_length = f'DL={connection.data_length}'
+ connection_parameters = (
+ 'Parameters='
+ f'{connection.parameters.connection_interval * 1.25:.2f}/'
+ f'{connection.parameters.peripheral_latency}/'
+ f'{connection.parameters.supervision_timeout * 10} '
+ )
+
+ else:
+ phy_state = ''
+ data_length = ''
+ connection_parameters = ''
+
+ mtu = connection.att_mtu
+
+ print(
+ f'{color("@@@ Connection:", "yellow")} '
+ f'{connection_parameters} '
+ f'{data_length} '
+ f'{phy_state} '
+ f'MTU={mtu}'
+ )
+
+
+def make_sdp_records(channel):
+ return {
+ 0x00010001: [
+ ServiceAttribute(
+ SDP_SERVICE_RECORD_HANDLE_ATTRIBUTE_ID,
+ DataElement.unsigned_integer_32(0x00010001),
+ ),
+ ServiceAttribute(
+ SDP_BROWSE_GROUP_LIST_ATTRIBUTE_ID,
+ DataElement.sequence([DataElement.uuid(SDP_PUBLIC_BROWSE_ROOT)]),
+ ),
+ ServiceAttribute(
+ SDP_SERVICE_CLASS_ID_LIST_ATTRIBUTE_ID,
+ DataElement.sequence(
+ [DataElement.uuid(UUID('E6D55659-C8B4-4B85-96BB-B1143AF6D3AE'))]
+ ),
+ ),
+ ServiceAttribute(
+ SDP_PROTOCOL_DESCRIPTOR_LIST_ATTRIBUTE_ID,
+ DataElement.sequence(
+ [
+ DataElement.sequence([DataElement.uuid(BT_L2CAP_PROTOCOL_ID)]),
+ DataElement.sequence(
+ [
+ DataElement.uuid(BT_RFCOMM_PROTOCOL_ID),
+ DataElement.unsigned_integer_8(channel),
+ ]
+ ),
+ ]
+ ),
+ ),
+ ]
+ }
+
+
+class PacketType(enum.IntEnum):
+ RESET = 0
+ SEQUENCE = 1
+ ACK = 2
+
+
+PACKET_FLAG_LAST = 1
+
+# -----------------------------------------------------------------------------
+# Sender
+# -----------------------------------------------------------------------------
+class Sender:
+ def __init__(self, packet_io, start_delay, packet_size, packet_count):
+ self.tx_start_delay = start_delay
+ self.tx_packet_size = packet_size
+ self.tx_packet_count = packet_count
+ self.packet_io = packet_io
+ self.packet_io.packet_listener = self
+ self.start_time = 0
+ self.bytes_sent = 0
+ self.done = asyncio.Event()
+
+ def reset(self):
+ pass
+
+ async def run(self):
+ print(color('--- Waiting for I/O to be ready...', 'blue'))
+ await self.packet_io.ready.wait()
+ print(color('--- Go!', 'blue'))
+
+ if self.tx_start_delay:
+ print(color(f'*** Startup delay: {self.tx_start_delay}', 'blue'))
+ await asyncio.sleep(self.tx_start_delay) # FIXME
+
+ print(color('=== Sending RESET', 'magenta'))
+ await self.packet_io.send_packet(bytes([PacketType.RESET]))
+ self.start_time = time.time()
+ for tx_i in range(self.tx_packet_count):
+ packet_flags = PACKET_FLAG_LAST if tx_i == self.tx_packet_count - 1 else 0
+ packet = struct.pack(
+ '>bbI',
+ PacketType.SEQUENCE,
+ packet_flags,
+ tx_i,
+ ) + bytes(self.tx_packet_size - 6)
+ print(color(f'Sending packet {tx_i}: {len(packet)} bytes', 'yellow'))
+ self.bytes_sent += len(packet)
+ await self.packet_io.send_packet(packet)
+
+ await self.done.wait()
+ print(color('=== Done!', 'magenta'))
+
+ def on_packet_received(self, packet):
+ try:
+ packet_type, _ = parse_packet(packet)
+ except ValueError:
+ return
+
+ if packet_type == PacketType.ACK:
+ elapsed = time.time() - self.start_time
+ average_tx_speed = self.bytes_sent / elapsed
+ print(
+ color(
+ f'@@@ Received ACK. Speed: average={average_tx_speed:.4f}'
+ f' ({self.bytes_sent} bytes in {elapsed:.2f} seconds)',
+ 'green',
+ )
+ )
+ self.done.set()
+
+
+# -----------------------------------------------------------------------------
+# Receiver
+# -----------------------------------------------------------------------------
+class Receiver:
+ def __init__(self, packet_io):
+ self.reset()
+ self.packet_io = packet_io
+ self.packet_io.packet_listener = self
+ self.done = asyncio.Event()
+
+ def reset(self):
+ self.expected_packet_index = 0
+ self.start_timestamp = 0.0
+ self.last_timestamp = 0.0
+ self.bytes_received = 0
+
+ def on_packet_received(self, packet):
+ try:
+ packet_type, packet_data = parse_packet(packet)
+ except ValueError:
+ return
+
+ now = time.time()
+
+ if packet_type == PacketType.RESET:
+ print(color('=== Received RESET', 'magenta'))
+ self.reset()
+ self.start_timestamp = now
+ return
+
+ try:
+ packet_flags, packet_index = parse_packet_sequence(packet_data)
+ except ValueError:
+ return
+ print(
+ f'<<< Received packet {packet_index}: '
+ f'flags=0x{packet_flags:02X}, {len(packet)} bytes'
+ )
+
+ if packet_index != self.expected_packet_index:
+ print(
+ color(
+ f'!!! Unexpected packet, expected {self.expected_packet_index} '
+ f'but received {packet_index}'
+ )
+ )
+
+ elapsed_since_start = now - self.start_timestamp
+ elapsed_since_last = now - self.last_timestamp
+ self.bytes_received += len(packet)
+ instant_rx_speed = len(packet) / elapsed_since_last
+ average_rx_speed = self.bytes_received / elapsed_since_start
+ print(
+ color(
+ f'Speed: instant={instant_rx_speed:.4f}, average={average_rx_speed:.4f}',
+ 'yellow',
+ )
+ )
+
+ self.last_timestamp = now
+ self.expected_packet_index = packet_index + 1
+
+ if packet_flags & PACKET_FLAG_LAST:
+ AsyncRunner.spawn(
+ self.packet_io.send_packet(
+ struct.pack('>bbI', PacketType.ACK, packet_flags, packet_index)
+ )
+ )
+ print(color('@@@ Received last packet', 'green'))
+ self.done.set()
+
+ async def run(self):
+ await self.done.wait()
+ print(color('=== Done!', 'magenta'))
+
+
+# -----------------------------------------------------------------------------
+# Ping
+# -----------------------------------------------------------------------------
+class Ping:
+ def __init__(self, packet_io, start_delay, packet_size, packet_count):
+ self.tx_start_delay = start_delay
+ self.tx_packet_size = packet_size
+ self.tx_packet_count = packet_count
+ self.packet_io = packet_io
+ self.packet_io.packet_listener = self
+ self.done = asyncio.Event()
+ self.current_packet_index = 0
+ self.ping_sent_time = 0.0
+ self.latencies = []
+
+ def reset(self):
+ pass
+
+ async def run(self):
+ print(color('--- Waiting for I/O to be ready...', 'blue'))
+ await self.packet_io.ready.wait()
+ print(color('--- Go!', 'blue'))
+
+ if self.tx_start_delay:
+ print(color(f'*** Startup delay: {self.tx_start_delay}', 'blue'))
+ await asyncio.sleep(self.tx_start_delay) # FIXME
+
+ print(color('=== Sending RESET', 'magenta'))
+ await self.packet_io.send_packet(bytes([PacketType.RESET]))
+
+ await self.send_next_ping()
+
+ await self.done.wait()
+ average_latency = sum(self.latencies) / len(self.latencies)
+ print(color(f'@@@ Average latency: {average_latency:.2f}'))
+ print(color('=== Done!', 'magenta'))
+
+ async def send_next_ping(self):
+ packet = struct.pack(
+ '>bbI',
+ PacketType.SEQUENCE,
+ PACKET_FLAG_LAST
+ if self.current_packet_index == self.tx_packet_count - 1
+ else 0,
+ self.current_packet_index,
+ ) + bytes(self.tx_packet_size - 6)
+ print(color(f'Sending packet {self.current_packet_index}', 'yellow'))
+ self.ping_sent_time = time.time()
+ await self.packet_io.send_packet(packet)
+
+ def on_packet_received(self, packet):
+ elapsed = time.time() - self.ping_sent_time
+
+ try:
+ packet_type, packet_data = parse_packet(packet)
+ except ValueError:
+ return
+
+ try:
+ packet_flags, packet_index = parse_packet_sequence(packet_data)
+ except ValueError:
+ return
+
+ if packet_type == PacketType.ACK:
+ latency = elapsed * 1000
+ self.latencies.append(latency)
+ print(
+ color(
+ f'<<< Received ACK [{packet_index}], latency={latency:.2f}ms',
+ 'green',
+ )
+ )
+
+ if packet_index == self.current_packet_index:
+ self.current_packet_index += 1
+ else:
+ print(
+ color(
+ f'!!! Unexpected packet, expected {self.current_packet_index} '
+ f'but received {packet_index}'
+ )
+ )
+
+ if packet_flags & PACKET_FLAG_LAST:
+ self.done.set()
+ return
+
+ AsyncRunner.spawn(self.send_next_ping())
+
+
+# -----------------------------------------------------------------------------
+# Pong
+# -----------------------------------------------------------------------------
+class Pong:
+ def __init__(self, packet_io):
+ self.reset()
+ self.packet_io = packet_io
+ self.packet_io.packet_listener = self
+ self.done = asyncio.Event()
+
+ def reset(self):
+ self.expected_packet_index = 0
+
+ def on_packet_received(self, packet):
+ try:
+ packet_type, packet_data = parse_packet(packet)
+ except ValueError:
+ return
+
+ if packet_type == PacketType.RESET:
+ print(color('=== Received RESET', 'magenta'))
+ self.reset()
+ return
+
+ try:
+ packet_flags, packet_index = parse_packet_sequence(packet_data)
+ except ValueError:
+ return
+ print(
+ color(
+ f'<<< Received packet {packet_index}: '
+ f'flags=0x{packet_flags:02X}, {len(packet)} bytes',
+ 'green',
+ )
+ )
+
+ if packet_index != self.expected_packet_index:
+ print(
+ color(
+ f'!!! Unexpected packet, expected {self.expected_packet_index} '
+ f'but received {packet_index}'
+ )
+ )
+
+ self.expected_packet_index = packet_index + 1
+
+ AsyncRunner.spawn(
+ self.packet_io.send_packet(
+ struct.pack('>bbI', PacketType.ACK, packet_flags, packet_index)
+ )
+ )
+
+ if packet_flags & PACKET_FLAG_LAST:
+ self.done.set()
+
+ async def run(self):
+ await self.done.wait()
+ print(color('=== Done!', 'magenta'))
+
+
+# -----------------------------------------------------------------------------
+# GattClient
+# -----------------------------------------------------------------------------
+class GattClient:
+ def __init__(self, _device, att_mtu=None):
+ self.att_mtu = att_mtu
+ self.speed_rx = None
+ self.speed_tx = None
+ self.packet_listener = None
+ self.ready = asyncio.Event()
+
+ async def on_connection(self, connection):
+ peer = Peer(connection)
+
+ if self.att_mtu:
+ print(color(f'*** Requesting MTU update: {self.att_mtu}', 'blue'))
+ await peer.request_mtu(self.att_mtu)
+
+ print(color('*** Discovering services...', 'blue'))
+ await peer.discover_services()
+
+ speed_services = peer.get_services_by_uuid(SPEED_SERVICE_UUID)
+ if not speed_services:
+ print(color('!!! Speed Service not found', 'red'))
+ return
+ speed_service = speed_services[0]
+ print(color('*** Discovering characteristics...', 'blue'))
+ await speed_service.discover_characteristics()
+
+ speed_txs = speed_service.get_characteristics_by_uuid(SPEED_TX_UUID)
+ if not speed_txs:
+ print(color('!!! Speed TX not found', 'red'))
+ return
+ self.speed_tx = speed_txs[0]
+
+ speed_rxs = speed_service.get_characteristics_by_uuid(SPEED_RX_UUID)
+ if not speed_rxs:
+ print(color('!!! Speed RX not found', 'red'))
+ return
+ self.speed_rx = speed_rxs[0]
+
+ print(color('*** Subscribing to RX', 'blue'))
+ await self.speed_rx.subscribe(self.on_packet_received)
+
+ print(color('*** Discovery complete', 'blue'))
+
+ connection.on('disconnection', self.on_disconnection)
+ self.ready.set()
+
+ def on_disconnection(self, _):
+ self.ready.clear()
+
+ def on_packet_received(self, packet):
+ if self.packet_listener:
+ self.packet_listener.on_packet_received(packet)
+
+ async def send_packet(self, packet):
+ await self.speed_tx.write_value(packet)
+
+
+# -----------------------------------------------------------------------------
+# GattServer
+# -----------------------------------------------------------------------------
+class GattServer:
+ def __init__(self, device):
+ self.device = device
+ self.packet_listener = None
+ self.ready = asyncio.Event()
+
+ # Setup the GATT service
+ self.speed_tx = Characteristic(
+ SPEED_TX_UUID,
+ Characteristic.Properties.WRITE,
+ Characteristic.WRITEABLE,
+ CharacteristicValue(write=self.on_tx_write),
+ )
+ self.speed_rx = Characteristic(
+ SPEED_RX_UUID, Characteristic.Properties.NOTIFY, 0
+ )
+
+ speed_service = Service(
+ SPEED_SERVICE_UUID,
+ [self.speed_tx, self.speed_rx],
+ )
+ device.add_services([speed_service])
+
+ self.speed_rx.on('subscription', self.on_rx_subscription)
+
+ async def on_connection(self, connection):
+ connection.on('disconnection', self.on_disconnection)
+
+ def on_disconnection(self, _):
+ self.ready.clear()
+
+ def on_rx_subscription(self, _connection, notify_enabled, _indicate_enabled):
+ if notify_enabled:
+ print(color('*** RX subscription', 'blue'))
+ self.ready.set()
+ else:
+ print(color('*** RX un-subscription', 'blue'))
+ self.ready.clear()
+
+ def on_tx_write(self, _, value):
+ if self.packet_listener:
+ self.packet_listener.on_packet_received(value)
+
+ async def send_packet(self, packet):
+ await self.device.notify_subscribers(self.speed_rx, packet)
+
+
+# -----------------------------------------------------------------------------
+# StreamedPacketIO
+# -----------------------------------------------------------------------------
+class StreamedPacketIO:
+ def __init__(self):
+ self.packet_listener = None
+ self.io_sink = None
+ self.rx_packet = b''
+ self.rx_packet_header = b''
+ self.rx_packet_need = 0
+
+ def on_packet(self, packet):
+ while packet:
+ if self.rx_packet_need:
+ chunk = packet[: self.rx_packet_need]
+ self.rx_packet += chunk
+ packet = packet[len(chunk) :]
+ self.rx_packet_need -= len(chunk)
+ if not self.rx_packet_need:
+ # Packet completed
+ if self.packet_listener:
+ self.packet_listener.on_packet_received(self.rx_packet)
+
+ self.rx_packet = b''
+ self.rx_packet_header = b''
+ else:
+ # Expect the next packet
+ header_bytes_needed = 2 - len(self.rx_packet_header)
+ header_bytes = packet[:header_bytes_needed]
+ self.rx_packet_header += header_bytes
+ if len(self.rx_packet_header) != 2:
+ return
+ packet = packet[len(header_bytes) :]
+ self.rx_packet_need = struct.unpack('>H', self.rx_packet_header)[0]
+
+ async def send_packet(self, packet):
+ if not self.io_sink:
+ print(color('!!! No sink, dropping packet', 'red'))
+ return
+
+ # pylint: disable-next=not-callable
+ self.io_sink(struct.pack('>H', len(packet)) + packet)
+
+
+# -----------------------------------------------------------------------------
+# L2capClient
+# -----------------------------------------------------------------------------
+class L2capClient(StreamedPacketIO):
+ def __init__(
+ self,
+ _device,
+ psm=DEFAULT_L2CAP_PSM,
+ max_credits=DEFAULT_L2CAP_MAX_CREDITS,
+ mtu=DEFAULT_L2CAP_MTU,
+ mps=DEFAULT_L2CAP_MPS,
+ ):
+ super().__init__()
+ self.psm = psm
+ self.max_credits = max_credits
+ self.mtu = mtu
+ self.mps = mps
+ self.ready = asyncio.Event()
+
+ async def on_connection(self, connection):
+ connection.on('disconnection', self.on_disconnection)
+
+ # Connect a new L2CAP channel
+ print(color(f'>>> Opening L2CAP channel on PSM = {self.psm}', 'yellow'))
+ try:
+ l2cap_channel = await connection.open_l2cap_channel(
+ psm=self.psm,
+ max_credits=self.max_credits,
+ mtu=self.mtu,
+ mps=self.mps,
+ )
+ print(color('*** L2CAP channel:', 'cyan'), l2cap_channel)
+ except Exception as error:
+ print(color(f'!!! Connection failed: {error}', 'red'))
+ return
+
+ l2cap_channel.sink = self.on_packet
+ l2cap_channel.on('close', self.on_l2cap_close)
+ self.io_sink = l2cap_channel.write
+
+ self.ready.set()
+
+ def on_disconnection(self, _):
+ pass
+
+ def on_l2cap_close(self):
+ print(color('*** L2CAP channel closed', 'red'))
+
+
+# -----------------------------------------------------------------------------
+# L2capServer
+# -----------------------------------------------------------------------------
+class L2capServer(StreamedPacketIO):
+ def __init__(
+ self,
+ device,
+ psm=DEFAULT_L2CAP_PSM,
+ max_credits=DEFAULT_L2CAP_MAX_CREDITS,
+ mtu=DEFAULT_L2CAP_MTU,
+ mps=DEFAULT_L2CAP_MPS,
+ ):
+ super().__init__()
+ self.l2cap_channel = None
+ self.ready = asyncio.Event()
+
+ # Listen for incoming L2CAP CoC connections
+ device.register_l2cap_channel_server(
+ psm=psm,
+ server=self.on_l2cap_channel,
+ max_credits=max_credits,
+ mtu=mtu,
+ mps=mps,
+ )
+ print(color(f'### Listening for CoC connection on PSM {psm}', 'yellow'))
+
+ async def on_connection(self, connection):
+ connection.on('disconnection', self.on_disconnection)
+
+ def on_disconnection(self, _):
+ pass
+
+ def on_l2cap_channel(self, l2cap_channel):
+ print(color('*** L2CAP channel:', 'cyan'), l2cap_channel)
+
+ self.io_sink = l2cap_channel.write
+ l2cap_channel.on('close', self.on_l2cap_close)
+ l2cap_channel.sink = self.on_packet
+
+ self.ready.set()
+
+ def on_l2cap_close(self):
+ print(color('*** L2CAP channel closed', 'red'))
+ self.l2cap_channel = None
+
+
+# -----------------------------------------------------------------------------
+# RfcommClient
+# -----------------------------------------------------------------------------
+class RfcommClient(StreamedPacketIO):
+ def __init__(self, device):
+ super().__init__()
+ self.device = device
+ self.ready = asyncio.Event()
+
+ async def on_connection(self, connection):
+ connection.on('disconnection', self.on_disconnection)
+
+ # Create a client and start it
+ print(color('*** Starting RFCOMM client...', 'blue'))
+ rfcomm_client = bumble.rfcomm.Client(self.device, connection)
+ rfcomm_mux = await rfcomm_client.start()
+ print(color('*** Started', 'blue'))
+
+ channel = DEFAULT_RFCOMM_CHANNEL
+ print(color(f'### Opening session for channel {channel}...', 'yellow'))
+ try:
+ rfcomm_session = await rfcomm_mux.open_dlc(channel)
+ print(color('### Session open', 'yellow'), rfcomm_session)
+ except bumble.core.ConnectionError as error:
+ print(color(f'!!! Session open failed: {error}', 'red'))
+ await rfcomm_mux.disconnect()
+ return
+
+ rfcomm_session.sink = self.on_packet
+ self.io_sink = rfcomm_session.write
+
+ self.ready.set()
+
+ def on_disconnection(self, _):
+ pass
+
+
+# -----------------------------------------------------------------------------
+# RfcommServer
+# -----------------------------------------------------------------------------
+class RfcommServer(StreamedPacketIO):
+ def __init__(self, device):
+ super().__init__()
+ self.ready = asyncio.Event()
+
+ # Create and register a server
+ rfcomm_server = bumble.rfcomm.Server(device)
+
+ # Listen for incoming DLC connections
+ channel_number = rfcomm_server.listen(self.on_dlc, DEFAULT_RFCOMM_CHANNEL)
+
+ # Setup the SDP to advertise this channel
+ device.sdp_service_records = make_sdp_records(channel_number)
+
+ print(
+ color(
+ f'### Listening for RFComm connection on channel {channel_number}',
+ 'yellow',
+ )
+ )
+
+ async def on_connection(self, connection):
+ connection.on('disconnection', self.on_disconnection)
+
+ def on_disconnection(self, _):
+ pass
+
+ def on_dlc(self, dlc):
+ print(color('*** DLC connected:', 'blue'), dlc)
+ dlc.sink = self.on_packet
+ self.io_sink = dlc.write
+
+
+# -----------------------------------------------------------------------------
+# Central
+# -----------------------------------------------------------------------------
+class Central(Connection.Listener):
+ def __init__(
+ self,
+ transport,
+ peripheral_address,
+ classic,
+ role_factory,
+ mode_factory,
+ connection_interval,
+ phy,
+ ):
+ super().__init__()
+ self.transport = transport
+ self.peripheral_address = peripheral_address
+ self.classic = classic
+ self.role_factory = role_factory
+ self.mode_factory = mode_factory
+ self.device = None
+ self.connection = None
+
+ if phy:
+ self.phy = {
+ '1m': HCI_LE_1M_PHY,
+ '2m': HCI_LE_2M_PHY,
+ 'coded': HCI_LE_CODED_PHY,
+ }[phy]
+ else:
+ self.phy = None
+
+ if connection_interval:
+ connection_parameter_preferences = ConnectionParametersPreferences()
+ connection_parameter_preferences.connection_interval_min = (
+ connection_interval
+ )
+ connection_parameter_preferences.connection_interval_max = (
+ connection_interval
+ )
+
+ # Preferences for the 1M PHY are always set.
+ self.connection_parameter_preferences = {
+ HCI_LE_1M_PHY: connection_parameter_preferences,
+ }
+
+ if self.phy not in (None, HCI_LE_1M_PHY):
+ # Add an connections parameters entry for this PHY.
+ self.connection_parameter_preferences[
+ self.phy
+ ] = connection_parameter_preferences
+ else:
+ self.connection_parameter_preferences = None
+
+ async def run(self):
+ print(color('>>> Connecting to HCI...', 'green'))
+ async with await open_transport_or_link(self.transport) as (
+ hci_source,
+ hci_sink,
+ ):
+ print(color('>>> Connected', 'green'))
+
+ central_address = DEFAULT_CENTRAL_ADDRESS
+ self.device = Device.with_hci(
+ DEFAULT_CENTRAL_NAME, central_address, hci_source, hci_sink
+ )
+ mode = self.mode_factory(self.device)
+ role = self.role_factory(mode)
+ self.device.classic_enabled = self.classic
+
+ await self.device.power_on()
+
+ print(color(f'### Connecting to {self.peripheral_address}...', 'cyan'))
+ try:
+ self.connection = await self.device.connect(
+ self.peripheral_address,
+ connection_parameters_preferences=self.connection_parameter_preferences,
+ transport=BT_BR_EDR_TRANSPORT if self.classic else BT_LE_TRANSPORT,
+ )
+ except CommandTimeoutError:
+ print(color('!!! Connection timed out', 'red'))
+ return
+ except bumble.core.ConnectionError as error:
+ print(color(f'!!! Connection error: {error}', 'red'))
+ return
+ except HCI_StatusError as error:
+ print(color(f'!!! Connection failed: {error.error_name}'))
+ return
+ print(color('### Connected', 'cyan'))
+ self.connection.listener = self
+ print_connection(self.connection)
+
+ await mode.on_connection(self.connection)
+
+ # Set the PHY if requested
+ if self.phy is not None:
+ try:
+ await self.connection.set_phy(
+ tx_phys=[self.phy], rx_phys=[self.phy]
+ )
+ except HCI_Error as error:
+ print(
+ color(
+ f'!!! Unable to set the PHY: {error.error_name}', 'yellow'
+ )
+ )
+
+ await role.run()
+ await asyncio.sleep(DEFAULT_LINGER_TIME)
+
+ def on_disconnection(self, reason):
+ print(color(f'!!! Disconnection: reason={reason}', 'red'))
+ self.connection = None
+
+ def on_connection_parameters_update(self):
+ print_connection(self.connection)
+
+ def on_connection_phy_update(self):
+ print_connection(self.connection)
+
+ def on_connection_att_mtu_update(self):
+ print_connection(self.connection)
+
+ def on_connection_data_length_change(self):
+ print_connection(self.connection)
+
+
+# -----------------------------------------------------------------------------
+# Peripheral
+# -----------------------------------------------------------------------------
+class Peripheral(Device.Listener, Connection.Listener):
+ def __init__(self, transport, classic, role_factory, mode_factory):
+ self.transport = transport
+ self.classic = classic
+ self.role_factory = role_factory
+ self.role = None
+ self.mode_factory = mode_factory
+ self.mode = None
+ self.device = None
+ self.connection = None
+ self.connected = asyncio.Event()
+
+ async def run(self):
+ print(color('>>> Connecting to HCI...', 'green'))
+ async with await open_transport_or_link(self.transport) as (
+ hci_source,
+ hci_sink,
+ ):
+ print(color('>>> Connected', 'green'))
+
+ peripheral_address = DEFAULT_PERIPHERAL_ADDRESS
+ self.device = Device.with_hci(
+ DEFAULT_PERIPHERAL_NAME, peripheral_address, hci_source, hci_sink
+ )
+ self.device.listener = self
+ self.mode = self.mode_factory(self.device)
+ self.role = self.role_factory(self.mode)
+ self.device.classic_enabled = self.classic
+
+ await self.device.power_on()
+
+ if self.classic:
+ await self.device.set_discoverable(True)
+ await self.device.set_connectable(True)
+ else:
+ await self.device.start_advertising(auto_restart=True)
+
+ if self.classic:
+ print(
+ color(
+ '### Waiting for connection on'
+ f' {self.device.public_address}...',
+ 'cyan',
+ )
+ )
+ else:
+ print(
+ color(
+ f'### Waiting for connection on {peripheral_address}...',
+ 'cyan',
+ )
+ )
+ await self.connected.wait()
+ print(color('### Connected', 'cyan'))
+
+ await self.mode.on_connection(self.connection)
+ await self.role.run()
+ await asyncio.sleep(DEFAULT_LINGER_TIME)
+
+ def on_connection(self, connection):
+ connection.listener = self
+ self.connection = connection
+ self.connected.set()
+
+ def on_disconnection(self, reason):
+ print(color(f'!!! Disconnection: reason={reason}', 'red'))
+ self.connection = None
+ self.role.reset()
+
+ def on_connection_parameters_update(self):
+ print_connection(self.connection)
+
+ def on_connection_phy_update(self):
+ print_connection(self.connection)
+
+ def on_connection_att_mtu_update(self):
+ print_connection(self.connection)
+
+ def on_connection_data_length_change(self):
+ print_connection(self.connection)
+
+
+# -----------------------------------------------------------------------------
+def create_mode_factory(ctx, default_mode):
+ mode = ctx.obj['mode']
+ if mode is None:
+ mode = default_mode
+
+ def create_mode(device):
+ if mode == 'gatt-client':
+ return GattClient(device, att_mtu=ctx.obj['att_mtu'])
+
+ if mode == 'gatt-server':
+ return GattServer(device)
+
+ if mode == 'l2cap-client':
+ return L2capClient(device)
+
+ if mode == 'l2cap-server':
+ return L2capServer(device)
+
+ if mode == 'rfcomm-client':
+ return RfcommClient(device)
+
+ if mode == 'rfcomm-server':
+ return RfcommServer(device)
+
+ raise ValueError('invalid mode')
+
+ return create_mode
+
+
+# -----------------------------------------------------------------------------
+def create_role_factory(ctx, default_role):
+ role = ctx.obj['role']
+ if role is None:
+ role = default_role
+
+ def create_role(packet_io):
+ if role == 'sender':
+ return Sender(
+ packet_io,
+ start_delay=ctx.obj['start_delay'],
+ packet_size=ctx.obj['packet_size'],
+ packet_count=ctx.obj['packet_count'],
+ )
+
+ if role == 'receiver':
+ return Receiver(packet_io)
+
+ if role == 'ping':
+ return Ping(
+ packet_io,
+ start_delay=ctx.obj['start_delay'],
+ packet_size=ctx.obj['packet_size'],
+ packet_count=ctx.obj['packet_count'],
+ )
+
+ if role == 'pong':
+ return Pong(packet_io)
+
+ raise ValueError('invalid role')
+
+ return create_role
+
+
+# -----------------------------------------------------------------------------
+# Main
+# -----------------------------------------------------------------------------
+@click.group()
+@click.option('--device-config', metavar='FILENAME', help='Device configuration file')
+@click.option('--role', type=click.Choice(['sender', 'receiver', 'ping', 'pong']))
+@click.option(
+ '--mode',
+ type=click.Choice(
+ [
+ 'gatt-client',
+ 'gatt-server',
+ 'l2cap-client',
+ 'l2cap-server',
+ 'rfcomm-client',
+ 'rfcomm-server',
+ ]
+ ),
+)
+@click.option(
+ '--att-mtu',
+ metavar='MTU',
+ type=click.IntRange(23, 517),
+ help='GATT MTU (gatt-client mode)',
+)
+@click.option(
+ '--packet-size',
+ '-s',
+ metavar='SIZE',
+ type=click.IntRange(8, 4096),
+ default=500,
+ help='Packet size (server role)',
+)
+@click.option(
+ '--packet-count',
+ '-c',
+ metavar='COUNT',
+ type=int,
+ default=10,
+ help='Packet count (server role)',
+)
+@click.option(
+ '--start-delay',
+ '-sd',
+ metavar='SECONDS',
+ type=int,
+ default=1,
+ help='Start delay (server role)',
+)
+@click.pass_context
+def bench(
+ ctx, device_config, role, mode, att_mtu, packet_size, packet_count, start_delay
+):
+ ctx.ensure_object(dict)
+ ctx.obj['device_config'] = device_config
+ ctx.obj['role'] = role
+ ctx.obj['mode'] = mode
+ ctx.obj['att_mtu'] = att_mtu
+ ctx.obj['packet_size'] = packet_size
+ ctx.obj['packet_count'] = packet_count
+ ctx.obj['start_delay'] = start_delay
+
+ ctx.obj['classic'] = mode in ('rfcomm-client', 'rfcomm-server')
+
+
+@bench.command()
+@click.argument('transport')
+@click.option(
+ '--peripheral',
+ 'peripheral_address',
+ metavar='ADDRESS_OR_NAME',
+ default=DEFAULT_PERIPHERAL_ADDRESS,
+ help='Address or name to connect to',
+)
+@click.option(
+ '--connection-interval',
+ '--ci',
+ metavar='CONNECTION_INTERVAL',
+ type=int,
+ help='Connection interval (in ms)',
+)
+@click.option('--phy', type=click.Choice(['1m', '2m', 'coded']), help='PHY to use')
+@click.pass_context
+def central(ctx, transport, peripheral_address, connection_interval, phy):
+ """Run as a central (initiates the connection)"""
+ role_factory = create_role_factory(ctx, 'sender')
+ mode_factory = create_mode_factory(ctx, 'gatt-client')
+ classic = ctx.obj['classic']
+
+ asyncio.run(
+ Central(
+ transport,
+ peripheral_address,
+ classic,
+ role_factory,
+ mode_factory,
+ connection_interval,
+ phy,
+ ).run()
+ )
+
+
+@bench.command()
+@click.argument('transport')
+@click.pass_context
+def peripheral(ctx, transport):
+ """Run as a peripheral (waits for a connection)"""
+ role_factory = create_role_factory(ctx, 'receiver')
+ mode_factory = create_mode_factory(ctx, 'gatt-server')
+
+ asyncio.run(
+ Peripheral(transport, ctx.obj['classic'], role_factory, mode_factory).run()
+ )
+
+
+def main():
+ logging.basicConfig(level=os.environ.get('BUMBLE_LOGLEVEL', 'INFO').upper())
+ bench()
+
+
+# -----------------------------------------------------------------------------
+if __name__ == "__main__":
+ main() # pylint: disable=no-value-for-parameter
diff --git a/apps/console.py b/apps/console.py
index 3ac4957..0ea9e5b 100644
--- a/apps/console.py
+++ b/apps/console.py
@@ -20,18 +20,16 @@
# Imports
# -----------------------------------------------------------------------------
import asyncio
-from bumble.hci import HCI_Constant
-import os
-import os.path
import logging
-import click
+import os
+import random
+import re
+import humanize
+from typing import Optional, Union
from collections import OrderedDict
-import colors
-from bumble.core import UUID, AdvertisingData
-from bumble.device import Device, Connection, Peer
-from bumble.utils import AsyncRunner
-from bumble.transport import open_transport_or_link
+import click
+from prettytable import PrettyTable
from prompt_toolkit import Application
from prompt_toolkit.history import FileHistory
@@ -42,6 +40,7 @@ from prompt_toolkit.styles import Style
from prompt_toolkit.filters import Condition
from prompt_toolkit.widgets import TextArea, Frame
from prompt_toolkit.widgets.toolbars import FormattedTextToolbar
+from prompt_toolkit.data_structures import Point
from prompt_toolkit.layout import (
Layout,
HSplit,
@@ -50,41 +49,100 @@ from prompt_toolkit.layout import (
Float,
FormattedTextControl,
FloatContainer,
- ConditionalContainer
+ ConditionalContainer,
+ Dimension,
+)
+
+from bumble import __version__
+import bumble.core
+from bumble import colors
+from bumble.core import UUID, AdvertisingData, BT_LE_TRANSPORT
+from bumble.device import ConnectionParametersPreferences, Device, Connection, Peer
+from bumble.utils import AsyncRunner
+from bumble.transport import open_transport_or_link
+from bumble.gatt import Characteristic, Service, CharacteristicDeclaration, Descriptor
+from bumble.gatt_client import CharacteristicProxy
+from bumble.hci import (
+ HCI_Constant,
+ HCI_LE_1M_PHY,
+ HCI_LE_2M_PHY,
+ HCI_LE_CODED_PHY,
)
+
# -----------------------------------------------------------------------------
# Constants
# -----------------------------------------------------------------------------
-BUMBLE_USER_DIR = os.path.expanduser('~/.bumble')
-DEFAULT_PROMPT_HEIGHT = 20
+BUMBLE_USER_DIR = os.path.expanduser('~/.bumble')
DEFAULT_RSSI_BAR_WIDTH = 20
-DISPLAY_MIN_RSSI = -100
-DISPLAY_MAX_RSSI = -30
+DEFAULT_CONNECTION_TIMEOUT = 30.0
+DISPLAY_MIN_RSSI = -100
+DISPLAY_MAX_RSSI = -30
+RSSI_MONITOR_INTERVAL = 5.0 # Seconds
+
# -----------------------------------------------------------------------------
-# Globals
+# Utils
# -----------------------------------------------------------------------------
-App = None
+
+
+def le_phy_name(phy_id):
+ return {HCI_LE_1M_PHY: '1M', HCI_LE_2M_PHY: '2M', HCI_LE_CODED_PHY: 'CODED'}.get(
+ phy_id, HCI_Constant.le_phy_name(phy_id)
+ )
+
+
+def rssi_bar(rssi):
+ blocks = ['', 'â–', 'â–Ž', 'â–', 'â–Œ', 'â–‹', 'â–Š', 'â–‰']
+ bar_width = (rssi - DISPLAY_MIN_RSSI) / (DISPLAY_MAX_RSSI - DISPLAY_MIN_RSSI)
+ bar_width = min(max(bar_width, 0), 1)
+ bar_ticks = int(bar_width * DEFAULT_RSSI_BAR_WIDTH * 8)
+ bar_blocks = ('â–ˆ' * int(bar_ticks / 8)) + blocks[bar_ticks % 8]
+ return f'{rssi:4} {bar_blocks}'
+
+
+def parse_phys(phys):
+ if phys.lower() == '*':
+ return None
+
+ phy_list = []
+ elements = phys.lower().split(',')
+ for element in elements:
+ if element == '1m':
+ phy_list.append(HCI_LE_1M_PHY)
+ elif element == '2m':
+ phy_list.append(HCI_LE_2M_PHY)
+ elif element == 'coded':
+ phy_list.append(HCI_LE_CODED_PHY)
+ else:
+ raise ValueError('invalid PHY name')
+ return phy_list
# -----------------------------------------------------------------------------
# Console App
# -----------------------------------------------------------------------------
class ConsoleApp:
+ connected_peer: Optional[Peer]
+
def __init__(self):
self.known_addresses = set()
- self.known_attributes = []
+ self.known_remote_attributes = []
+ self.known_local_attributes = []
self.device = None
self.connected_peer = None
- self.top_tab = 'scan'
-
- style = Style.from_dict({
- 'output-field': 'bg:#000044 #ffffff',
- 'input-field': 'bg:#000000 #ffffff',
- 'line': '#004400',
- 'error': 'fg:ansired'
- })
+ self.top_tab = 'device'
+ self.monitor_rssi = False
+ self.connection_rssi = None
+
+ style = Style.from_dict(
+ {
+ 'output-field': 'bg:#000044 #ffffff',
+ 'input-field': 'bg:#000000 #ffffff',
+ 'line': '#004400',
+ 'error': 'fg:ansired',
+ }
+ )
class LiveCompleter(Completer):
def __init__(self, words):
@@ -96,34 +154,40 @@ class ConsoleApp:
yield Completion(word, start_position=-len(prefix))
def make_completer():
- return NestedCompleter.from_nested_dict({
- 'scan': {
- 'on': None,
- 'off': None
- },
- 'advertise': {
- 'on': None,
- 'off': None
- },
- 'show': {
- 'scan': None,
- 'services': None,
- 'attributes': None,
- 'log': None
- },
- 'connect': LiveCompleter(self.known_addresses),
- 'update-parameters': None,
- 'encrypt': None,
- 'disconnect': None,
- 'discover': {
- 'services': None,
- 'attributes': None
- },
- 'read': LiveCompleter(self.known_attributes),
- 'write': LiveCompleter(self.known_attributes),
- 'quit': None,
- 'exit': None
- })
+ return NestedCompleter.from_nested_dict(
+ {
+ 'scan': {'on': None, 'off': None, 'clear': None},
+ 'advertise': {'on': None, 'off': None},
+ 'rssi': {'on': None, 'off': None},
+ 'show': {
+ 'scan': None,
+ 'log': None,
+ 'device': None,
+ 'local-services': None,
+ 'remote-services': None,
+ 'local-values': None,
+ 'remote-values': None,
+ },
+ 'filter': {
+ 'address': None,
+ },
+ 'connect': LiveCompleter(self.known_addresses),
+ 'update-parameters': None,
+ 'encrypt': None,
+ 'disconnect': None,
+ 'discover': {'services': None, 'attributes': None},
+ 'request-mtu': None,
+ 'read': LiveCompleter(self.known_remote_attributes),
+ 'write': LiveCompleter(self.known_remote_attributes),
+ 'local-write': LiveCompleter(self.known_local_attributes),
+ 'subscribe': LiveCompleter(self.known_remote_attributes),
+ 'unsubscribe': LiveCompleter(self.known_remote_attributes),
+ 'set-phy': {'1m': None, '2m': None, 'coded': None},
+ 'set-default-phy': None,
+ 'quit': None,
+ 'exit': None,
+ }
+ )
self.input_field = TextArea(
height=1,
@@ -131,43 +195,65 @@ class ConsoleApp:
multiline=False,
wrap_lines=False,
completer=make_completer(),
- history=FileHistory(os.path.join(BUMBLE_USER_DIR, 'history'))
+ history=FileHistory(os.path.join(BUMBLE_USER_DIR, 'history')),
)
self.input_field.accept_handler = self.accept_input
- self.output_height = 7
+ self.output_height = Dimension(min=7, max=7, weight=1)
self.output_lines = []
- self.output = FormattedTextControl()
+ self.output = FormattedTextControl(
+ get_cursor_position=lambda: Point(0, max(0, len(self.output_lines) - 1))
+ )
+ self.output_max_lines = 20
self.scan_results_text = FormattedTextControl()
- self.services_text = FormattedTextControl()
- self.attributes_text = FormattedTextControl()
- self.log_text = FormattedTextControl()
- self.log_height = 20
+ self.local_services_text = FormattedTextControl()
+ self.remote_services_text = FormattedTextControl()
+ self.device_text = FormattedTextControl()
+ self.log_text = FormattedTextControl(
+ get_cursor_position=lambda: Point(0, max(0, len(self.log_lines) - 1))
+ )
+ self.local_values_text = FormattedTextControl()
+ self.remote_values_text = FormattedTextControl()
+ self.log_height = Dimension(min=7, weight=4)
+ self.log_max_lines = 100
self.log_lines = []
- container = HSplit([
- ConditionalContainer(
- Frame(Window(self.scan_results_text), title='Scan Results'),
- filter=Condition(lambda: self.top_tab == 'scan')
- ),
- ConditionalContainer(
- Frame(Window(self.services_text), title='Services'),
- filter=Condition(lambda: self.top_tab == 'services')
- ),
- ConditionalContainer(
- Frame(Window(self.attributes_text), title='Attributes'),
- filter=Condition(lambda: self.top_tab == 'attributes')
- ),
- ConditionalContainer(
- Frame(Window(self.log_text), title='Log'),
- filter=Condition(lambda: self.top_tab == 'log')
- ),
- Frame(Window(self.output), height=self.output_height),
- # HorizontalLine(),
- FormattedTextToolbar(text=self.get_status_bar_text, style='reverse'),
- self.input_field
- ])
+ container = HSplit(
+ [
+ ConditionalContainer(
+ Frame(Window(self.scan_results_text), title='Scan Results'),
+ filter=Condition(lambda: self.top_tab == 'scan'),
+ ),
+ ConditionalContainer(
+ Frame(Window(self.local_services_text), title='Local Services'),
+ filter=Condition(lambda: self.top_tab == 'local-services'),
+ ),
+ ConditionalContainer(
+ Frame(Window(self.local_values_text), title='Local Values'),
+ filter=Condition(lambda: self.top_tab == 'local-values'),
+ ),
+ ConditionalContainer(
+ Frame(Window(self.remote_services_text), title='Remote Services'),
+ filter=Condition(lambda: self.top_tab == 'remote-services'),
+ ),
+ ConditionalContainer(
+ Frame(Window(self.remote_values_text), title='Remote Values'),
+ filter=Condition(lambda: self.top_tab == 'remote-values'),
+ ),
+ ConditionalContainer(
+ Frame(Window(self.log_text, height=self.log_height), title='Log'),
+ filter=Condition(lambda: self.top_tab == 'log'),
+ ),
+ ConditionalContainer(
+ Frame(Window(self.device_text), title='Device'),
+ filter=Condition(lambda: self.top_tab == 'device'),
+ ),
+ Frame(Window(self.output, height=self.output_height)),
+ FormattedTextToolbar(text=self.get_status_bar_text, style='reverse'),
+ self.input_field,
+ ]
+ )
container = FloatContainer(
container,
@@ -182,35 +268,50 @@ class ConsoleApp:
layout = Layout(container, focused_element=self.input_field)
- kb = KeyBindings()
- @kb.add("c-c")
- @kb.add("c-q")
+ key_bindings = KeyBindings()
+
+ @key_bindings.add("c-c")
+ @key_bindings.add("c-q")
def _(event):
event.app.exit()
+ # pylint: disable=invalid-name
self.ui = Application(
- layout=layout,
- style=style,
- key_bindings=kb,
- full_screen=True
+ layout=layout, style=style, key_bindings=key_bindings, full_screen=True
)
async def run_async(self, device_config, transport):
+ rssi_monitoring_task = asyncio.create_task(self.rssi_monitor_loop())
+
async with await open_transport_or_link(transport) as (hci_source, hci_sink):
if device_config:
- self.device = Device.from_config_file_with_hci(device_config, hci_source, hci_sink)
+ self.device = Device.from_config_file_with_hci(
+ device_config, hci_source, hci_sink
+ )
else:
- self.device = Device.with_hci('Bumble', 'F0:F1:F2:F3:F4:F5', hci_source, hci_sink)
+ random_address = (
+ f"{random.randint(192,255):02X}" # address is static random
+ )
+ for random_byte in random.sample(range(255), 5):
+ random_address += f":{random_byte:02X}"
+ self.append_to_log(f"Setting random address: {random_address}")
+ self.device = Device.with_hci(
+ 'Bumble', random_address, hci_source, hci_sink
+ )
self.device.listener = DeviceListener(self)
await self.device.power_on()
+ self.show_device(self.device)
+ self.show_local_services(self.device.gatt_server.attributes)
# Run the UI
await self.ui.run_async()
+ rssi_monitoring_task.cancel()
+
def add_known_address(self, address):
self.known_addresses.add(address)
- def accept_input(self, buff):
+ def accept_input(self, _):
if len(self.input_field.text) == 0:
return
self.append_to_output([('', '* '), ('ansicyan', self.input_field.text)], False)
@@ -221,25 +322,50 @@ class ConsoleApp:
connection_state = 'NONE'
encryption_state = ''
+ att_mtu = ''
+ rssi = '' if self.connection_rssi is None else rssi_bar(self.connection_rssi)
if self.device:
- if self.device.is_connecting:
+ if self.device.is_le_connecting:
connection_state = 'CONNECTING'
elif self.connected_peer:
connection = self.connected_peer.connection
- connection_parameters = f'{connection.parameters.connection_interval}/{connection.parameters.connection_latency}/{connection.parameters.supervision_timeout}'
- connection_state = f'{connection.peer_address} {connection_parameters} {connection.data_length}'
- encryption_state = 'ENCRYPTED' if connection.is_encrypted else 'NOT ENCRYPTED'
+ connection_parameters = (
+ f'{connection.parameters.connection_interval}/'
+ f'{connection.parameters.peripheral_latency}/'
+ f'{connection.parameters.supervision_timeout}'
+ )
+ if connection.transport == BT_LE_TRANSPORT:
+ phy_state = (
+ f' RX={le_phy_name(connection.phy.rx_phy)}/'
+ f'TX={le_phy_name(connection.phy.tx_phy)}'
+ )
+ else:
+ phy_state = ''
+ connection_state = (
+ f'{connection.peer_address} '
+ f'{connection_parameters} '
+ f'{connection.data_length}'
+ f'{phy_state}'
+ )
+ encryption_state = (
+ 'ENCRYPTED' if connection.is_encrypted else 'NOT ENCRYPTED'
+ )
+ att_mtu = f'ATT_MTU: {connection.att_mtu}'
return [
('ansigreen', f' SCAN: {scanning} '),
('', ' '),
('ansiblue', f' CONNECTION: {connection_state} '),
('', ' '),
- ('ansimagenta', f' {encryption_state} ')
+ ('ansimagenta', f' {encryption_state} '),
+ ('', ' '),
+ ('ansicyan', f' {att_mtu} '),
+ ('', ' '),
+ ('ansiyellow', f' {rssi} '),
]
- def show_error(self, title, details = None):
+ def show_error(self, title, details=None):
appended = [('class:error', title)]
if details:
appended.append(('', f' {details}'))
@@ -254,36 +380,108 @@ class ConsoleApp:
self.scan_results_text.text = ANSI('\n'.join(lines))
self.ui.invalidate()
- def show_services(self, services):
+ def show_remote_services(self, services):
lines = []
- del self.known_attributes[:]
+ del self.known_remote_attributes[:]
for service in services:
- lines.append(('ansicyan', str(service) + '\n'))
+ lines.append(("ansicyan", f"{service}\n"))
for characteristic in service.characteristics:
- lines.append(('ansimagenta', ' ' + str(characteristic) + '\n'))
- self.known_attributes.append(f'{service.uuid.to_hex_str()}.{characteristic.uuid.to_hex_str()}')
- self.known_attributes.append(f'*.{characteristic.uuid.to_hex_str()}')
- self.known_attributes.append(f'#{characteristic.handle:X}')
+ lines.append(('ansimagenta', f' {characteristic} + \n'))
+ self.known_remote_attributes.append(
+ f'{service.uuid.to_hex_str()}.{characteristic.uuid.to_hex_str()}'
+ )
+ self.known_remote_attributes.append(
+ f'*.{characteristic.uuid.to_hex_str()}'
+ )
+ self.known_remote_attributes.append(f'#{characteristic.handle:X}')
for descriptor in characteristic.descriptors:
- lines.append(('ansigreen', ' ' + str(descriptor) + '\n'))
+ lines.append(("ansigreen", f" {descriptor}\n"))
- self.services_text.text = lines
+ self.remote_services_text.text = lines
self.ui.invalidate()
- async def show_attributes(self, attributes):
+ def show_local_services(self, attributes):
lines = []
-
+ del self.known_local_attributes[:]
for attribute in attributes:
- lines.append(('ansicyan', f'{attribute}\n'))
+ if isinstance(attribute, Service):
+ # Save the most recent service for use later
+ service = attribute
+ lines.append(("ansicyan", f"{attribute}\n"))
+ elif isinstance(attribute, Characteristic):
+ # CharacteristicDeclaration includes all info from Characteristic
+ # no need to print it twice
+ continue
+ elif isinstance(attribute, CharacteristicDeclaration):
+ # Save the most recent characteristic declaration for use later
+ characteristic_declaration = attribute
+ self.known_local_attributes.append(
+ f'{service.uuid.to_hex_str()}.{attribute.characteristic.uuid.to_hex_str()}'
+ )
+ self.known_local_attributes.append(
+ f'#{attribute.characteristic.handle:X}'
+ )
+ lines.append(("ansimagenta", f" {attribute}\n"))
+ elif isinstance(attribute, Descriptor):
+ self.known_local_attributes.append(
+ f'{service.uuid.to_hex_str()}.{characteristic_declaration.characteristic.uuid.to_hex_str()}.{attribute.type.to_hex_str()}'
+ )
+ self.known_local_attributes.append(f'#{attribute.handle:X}')
+ lines.append(("ansigreen", f" {attribute}\n"))
+ else:
+ lines.append(("ansiyellow", f"{attribute}\n"))
- self.attributes_text.text = lines
+ self.local_services_text.text = lines
+ self.ui.invalidate()
+
+ def show_device(self, device):
+ lines = []
+
+ lines.append(('ansicyan', 'Bumble Version: '))
+ lines.append(('', f'{__version__}\n'))
+ lines.append(('ansicyan', 'Name: '))
+ lines.append(('', f'{device.name}\n'))
+ lines.append(('ansicyan', 'Public Address: '))
+ lines.append(('', f'{device.public_address}\n'))
+ lines.append(('ansicyan', 'Random Address: '))
+ lines.append(('', f'{device.random_address}\n'))
+ lines.append(('ansicyan', 'LE Enabled: '))
+ lines.append(('', f'{device.le_enabled}\n'))
+ lines.append(('ansicyan', 'Classic Enabled: '))
+ lines.append(('', f'{device.classic_enabled}\n'))
+ lines.append(('ansicyan', 'Classic SC Enabled: '))
+ lines.append(('', f'{device.classic_sc_enabled}\n'))
+ lines.append(('ansicyan', 'Classic SSP Enabled: '))
+ lines.append(('', f'{device.classic_ssp_enabled}\n'))
+ lines.append(('ansicyan', 'Classic Class: '))
+ lines.append(('', f'{device.class_of_device}\n'))
+ lines.append(('ansicyan', 'Discoverable: '))
+ lines.append(('', f'{device.discoverable}\n'))
+ lines.append(('ansicyan', 'Connectable: '))
+ lines.append(('', f'{device.connectable}\n'))
+ lines.append(('ansicyan', 'Advertising Data: '))
+ lines.append(('', f'{device.advertising_data}\n'))
+ lines.append(('ansicyan', 'Scan Response Data: '))
+ lines.append(('', f'{device.scan_response_data}\n'))
+ advertising_interval = (
+ device.advertising_interval_min
+ if device.advertising_interval_min == device.advertising_interval_max
+ else (
+ f'{device.advertising_interval_min} to '
+ f'{device.advertising_interval_max}'
+ )
+ )
+ lines.append(('ansicyan', 'Advertising Interval: '))
+ lines.append(('', f'{advertising_interval}\n'))
+
+ self.device_text.text = lines
self.ui.invalidate()
def append_to_output(self, line, invalidate=True):
- if type(line) is str:
+ if isinstance(line, str):
line = [('', line)]
- self.output_lines = self.output_lines[-(self.output_height - 3):]
+ self.output_lines = self.output_lines[-self.output_max_lines :]
self.output_lines.append(line)
formatted_text = []
for line in self.output_lines:
@@ -295,7 +493,7 @@ class ConsoleApp:
def append_to_log(self, lines, invalidate=True):
self.log_lines.extend(lines.split('\n'))
- self.log_lines = self.log_lines[-(self.log_height - 3):]
+ self.log_lines = self.log_lines[-self.log_max_lines :]
self.log_text.text = ANSI('\n'.join(self.log_lines))
if invalidate:
self.ui.invalidate()
@@ -308,7 +506,10 @@ class ConsoleApp:
# Discover all services, characteristics and descriptors
self.append_to_output('discovering services...')
await self.connected_peer.discover_services()
- self.append_to_output(f'found {len(self.connected_peer.services)} services, discovering charateristics...')
+ self.append_to_output(
+ f'found {len(self.connected_peer.services)} services,'
+ ' discovering characteristics...'
+ )
await self.connected_peer.discover_characteristics()
self.append_to_output('found characteristics, discovering descriptors...')
for service in self.connected_peer.services:
@@ -316,7 +517,7 @@ class ConsoleApp:
await self.connected_peer.discover_descriptors(characteristic)
self.append_to_output('discovery completed')
- self.show_services(self.connected_peer.services)
+ self.show_remote_services(self.connected_peer.services)
async def discover_attributes(self):
if not self.connected_peer:
@@ -328,11 +529,71 @@ class ConsoleApp:
attributes = await self.connected_peer.discover_attributes()
self.append_to_output(f'discovered {len(attributes)} attributes...')
- await self.show_attributes(attributes)
+ self.show_attributes(attributes)
+
+ def find_remote_characteristic(self, param) -> Optional[CharacteristicProxy]:
+ if not self.connected_peer:
+ return None
+ parts = param.split('.')
+ if len(parts) == 2:
+ service_uuid = UUID(parts[0]) if parts[0] != '*' else None
+ characteristic_uuid = UUID(parts[1])
+ for service in self.connected_peer.services:
+ if service_uuid is None or service.uuid == service_uuid:
+ for characteristic in service.characteristics:
+ if characteristic.uuid == characteristic_uuid:
+ return characteristic
+ elif len(parts) == 1:
+ if parts[0].startswith('#'):
+ attribute_handle = int(f'{parts[0][1:]}', 16)
+ for service in self.connected_peer.services:
+ for characteristic in service.characteristics:
+ if characteristic.handle == attribute_handle:
+ return characteristic
+
+ return None
+
+ def find_local_attribute(
+ self, param
+ ) -> Optional[Union[Characteristic, Descriptor]]:
+ parts = param.split('.')
+ if len(parts) == 3:
+ service_uuid = UUID(parts[0])
+ characteristic_uuid = UUID(parts[1])
+ descriptor_uuid = UUID(parts[2])
+ return self.device.gatt_server.get_descriptor_attribute(
+ service_uuid, characteristic_uuid, descriptor_uuid
+ )
+ if len(parts) == 2:
+ service_uuid = UUID(parts[0])
+ characteristic_uuid = UUID(parts[1])
+ characteristic_attributes = (
+ self.device.gatt_server.get_characteristic_attributes(
+ service_uuid, characteristic_uuid
+ )
+ )
+ if characteristic_attributes:
+ return characteristic_attributes[1]
+ return None
+ elif len(parts) == 1:
+ if parts[0].startswith('#'):
+ attribute_handle = int(f'{parts[0][1:]}', 16)
+ attribute = self.device.gatt_server.get_attribute(attribute_handle)
+ if isinstance(attribute, (Characteristic, Descriptor)):
+ return attribute
+ return None
+
+ return None
+
+ async def rssi_monitor_loop(self):
+ while True:
+ if self.monitor_rssi and self.connected_peer:
+ self.connection_rssi = await self.connected_peer.connection.get_rssi()
+ await asyncio.sleep(RSSI_MONITOR_INTERVAL)
async def command(self, command):
try:
- (keyword, *params) = command.strip().split(' ', 1)
+ (keyword, *params) = command.strip().split(' ')
keyword = keyword.replace('-', '_').lower()
handler = getattr(self, f'do_{keyword}', None)
if handler:
@@ -351,50 +612,109 @@ class ConsoleApp:
else:
await self.device.start_scanning()
elif params[0] == 'on':
+ if len(params) == 2:
+ if not params[1].startswith("filter="):
+ self.show_error(
+ 'invalid syntax',
+ 'expected address filter=key1:value1,key2:value,... '
+ 'available filters: address',
+ )
+ # regex: (word):(any char except ,)
+ matches = re.findall(r"(\w+):([^,]+)", params[1])
+ for match in matches:
+ if match[0] == "address":
+ self.device.listener.address_filter = match[1]
+
await self.device.start_scanning()
self.top_tab = 'scan'
elif params[0] == 'off':
await self.device.stop_scanning()
+ elif params[0] == 'clear':
+ self.device.listener.scan_results.clear()
+ self.known_addresses.clear()
+ self.show_scan_results(self.device.listener.scan_results)
else:
self.show_error('unsupported arguments for scan command')
+ async def do_rssi(self, params):
+ if len(params) == 0:
+ # Toggle monitoring
+ self.monitor_rssi = not self.monitor_rssi
+ elif params[0] == 'on':
+ self.monitor_rssi = True
+ elif params[0] == 'off':
+ self.monitor_rssi = False
+ else:
+ self.show_error('unsupported arguments for rssi command')
+
async def do_connect(self, params):
- if len(params) != 1:
- self.show_error('invalid syntax', 'expected connect <address>')
+ if len(params) != 1 and len(params) != 2:
+ self.show_error('invalid syntax', 'expected connect <address> [phys]')
return
+ if len(params) == 1:
+ phys = None
+ else:
+ phys = parse_phys(params[1])
+ if phys is None:
+ connection_parameters_preferences = None
+ else:
+ connection_parameters_preferences = {
+ phy: ConnectionParametersPreferences() for phy in phys
+ }
+
+ if self.device.is_scanning:
+ await self.device.stop_scanning()
+
self.append_to_output('connecting...')
- await self.device.connect(params[0])
- self.top_tab = 'services'
- async def do_disconnect(self, params):
- if not self.connected_peer:
- self.show_error('not connected')
- return
+ try:
+ await self.device.connect(
+ params[0],
+ connection_parameters_preferences=connection_parameters_preferences,
+ timeout=DEFAULT_CONNECTION_TIMEOUT,
+ )
+ self.top_tab = 'services'
+ except bumble.core.TimeoutError:
+ self.show_error('connection timed out')
+
+ async def do_disconnect(self, _):
+ if self.device.is_le_connecting:
+ await self.device.cancel_connection()
+ else:
+ if not self.connected_peer:
+ self.show_error('not connected')
+ return
- await self.connected_peer.connection.disconnect()
+ await self.connected_peer.connection.disconnect()
async def do_update_parameters(self, params):
if len(params) != 1 or len(params[0].split('/')) != 3:
- self.show_error('invalid syntax', 'expected update-parameters <interval-min>-<interval-max>/<latency>/<supervision>')
+ self.show_error(
+ 'invalid syntax',
+ 'expected update-parameters <interval-min>-<interval-max>'
+ '/<max-latency>/<supervision>',
+ )
return
if not self.connected_peer:
self.show_error('not connected')
return
- connection_intervals, connection_latency, supervision_timeout = params[0].split('/')
- connection_interval_min, connection_interval_max = [int(x) for x in connection_intervals.split('-')]
- connection_latency = int(connection_latency)
+ connection_intervals, max_latency, supervision_timeout = params[0].split('/')
+ connection_interval_min, connection_interval_max = [
+ int(x) for x in connection_intervals.split('-')
+ ]
+ max_latency = int(max_latency)
supervision_timeout = int(supervision_timeout)
await self.connected_peer.connection.update_parameters(
connection_interval_min,
connection_interval_max,
- connection_latency,
- supervision_timeout
+ max_latency,
+ supervision_timeout,
)
- async def do_encrypt(self, params):
+ async def do_encrypt(self, _):
if not self.connected_peer:
self.show_error('not connected')
return
@@ -417,10 +737,137 @@ class ConsoleApp:
async def do_show(self, params):
if params:
- if params[0] in {'scan', 'services', 'attributes', 'log'}:
+ if params[0] in {
+ 'scan',
+ 'log',
+ 'device',
+ 'local-services',
+ 'remote-services',
+ 'local-values',
+ 'remote-values',
+ }:
self.top_tab = params[0]
self.ui.invalidate()
+ while self.top_tab == 'local-values':
+ await self.do_show_local_values()
+ await asyncio.sleep(1)
+
+ while self.top_tab == 'remote-values':
+ await self.do_show_remote_values()
+ await asyncio.sleep(1)
+
+ async def do_show_local_values(self):
+ prettytable = PrettyTable()
+ field_names = ["Service", "Characteristic", "Descriptor"]
+
+ # if there's no connections, add a column just for value
+ if not self.device.connections:
+ field_names.append("Value")
+
+ # if there are connections, add a column for each connection's value
+ for connection in self.device.connections.values():
+ field_names.append(f"Connection {connection.handle}")
+
+ for attribute in self.device.gatt_server.attributes:
+ if isinstance(attribute, Characteristic):
+ service = self.device.gatt_server.get_attribute_group(
+ attribute.handle, Service
+ )
+ if not service:
+ continue
+ values = [
+ attribute.read_value(connection)
+ for connection in self.device.connections.values()
+ ]
+ if not values:
+ values = [attribute.read_value(None)]
+ prettytable.add_row([f"{service.uuid}", attribute.uuid, ""] + values)
+
+ elif isinstance(attribute, Descriptor):
+ service = self.device.gatt_server.get_attribute_group(
+ attribute.handle, Service
+ )
+ if not service:
+ continue
+ characteristic = self.device.gatt_server.get_attribute_group(
+ attribute.handle, Characteristic
+ )
+ if not characteristic:
+ continue
+ values = [
+ attribute.read_value(connection)
+ for connection in self.device.connections.values()
+ ]
+ if not values:
+ values = [attribute.read_value(None)]
+
+ # TODO: future optimization: convert CCCD value to human readable string
+
+ prettytable.add_row(
+ [service.uuid, characteristic.uuid, attribute.type] + values
+ )
+
+ prettytable.field_names = field_names
+ self.local_values_text.text = prettytable.get_string()
+ self.ui.invalidate()
+
+ async def do_show_remote_values(self):
+ prettytable = PrettyTable(
+ field_names=[
+ "Connection",
+ "Service",
+ "Characteristic",
+ "Descriptor",
+ "Time",
+ "Value",
+ ]
+ )
+ for connection in self.device.connections.values():
+ for handle, (time, value) in connection.gatt_client.cached_values.items():
+ row = [connection.handle]
+ attribute = connection.gatt_client.get_attributes(handle)
+ if not attribute:
+ continue
+ if len(attribute) == 3:
+ row.extend(
+ [attribute[0].uuid, attribute[1].uuid, attribute[2].type]
+ )
+ elif len(attribute) == 2:
+ row.extend([attribute[0].uuid, attribute[1].uuid, ""])
+ elif len(attribute) == 1:
+ row.extend([attribute[0].uuid, "", ""])
+ else:
+ continue
+
+ row.extend([humanize.naturaltime(time), value])
+ prettytable.add_row(row)
+
+ self.remote_values_text.text = prettytable.get_string()
+ self.ui.invalidate()
+
+ async def do_get_phy(self, _):
+ if not self.connected_peer:
+ self.show_error('not connected')
+ return
+
+ phy = await self.connected_peer.connection.get_phy()
+ self.append_to_output(
+ f'PHY: RX={HCI_Constant.le_phy_name(phy[0])}, '
+ f'TX={HCI_Constant.le_phy_name(phy[1])}'
+ )
+
+ async def do_request_mtu(self, params):
+ if len(params) != 1:
+ self.show_error('invalid syntax', 'expected request-mtu <mtu>')
+ return
+
+ if not self.connected_peer:
+ self.show_error('not connected')
+ return
+
+ await self.connected_peer.request_mtu(int(params[0]))
+
async def do_discover(self, params):
if not params:
self.show_error('invalid syntax', 'expected discover services|attributes')
@@ -433,41 +880,164 @@ class ConsoleApp:
await self.discover_attributes()
async def do_read(self, params):
+ if len(params) != 1:
+ self.show_error('invalid syntax', 'expected read <attribute>')
+ return
+
if not self.connected_peer:
self.show_error('not connected')
return
- if len(params) != 1:
- self.show_error('invalid syntax', 'expected read <attribute>')
+ characteristic = self.find_remote_characteristic(params[0])
+ if characteristic is None:
+ self.show_error('no such characteristic')
return
- parts = params[0].split('.')
- if len(parts) == 2:
- service_uuid = UUID(parts[0]) if parts[0] != '*' else None
- characteristic_uuid = UUID(parts[1])
- for service in self.connected_peer.services:
- if service_uuid is None or service.uuid == service_uuid:
- for characteristic in service.characteristics:
- if characteristic.uuid == characteristic_uuid:
- value = await self.connected_peer.read_value(characteristic)
- self.append_to_output(f'VALUE: {value}')
- return
+ value = await characteristic.read_value()
+ self.append_to_output(f'VALUE: 0x{value.hex()}')
+
+ async def do_write(self, params):
+ if not self.connected_peer:
+ self.show_error('not connected')
+ return
+
+ if len(params) != 2:
+ self.show_error('invalid syntax', 'expected write <attribute> <value>')
+ return
+
+ if params[1].upper().startswith("0X"):
+ value = bytes.fromhex(params[1][2:]) # parse as hex string
+ else:
+ try:
+ value = int(params[1]) # try as integer
+ except ValueError:
+ value = str.encode(params[1]) # must be a string
+
+ characteristic = self.find_remote_characteristic(params[0])
+ if characteristic is None:
self.show_error('no such characteristic')
- elif len(parts) == 1:
- if parts[0].startswith('#'):
- attribute_handle = int(f'{parts[0][1:]}', 16)
- value = await self.connected_peer.read_value(attribute_handle)
- self.append_to_output(f'VALUE: {value}')
- return
+ return
+
+ # use write with response if supported
+ with_response = characteristic.properties & Characteristic.Properties.WRITE
+ await characteristic.write_value(value, with_response=with_response)
+
+ async def do_local_write(self, params):
+ if len(params) != 2:
+ self.show_error(
+ 'invalid syntax', 'expected local-write <attribute> <value>'
+ )
+ return
+
+ if params[1].upper().startswith("0X"):
+ value = bytes.fromhex(params[1][2:]) # parse as hex string
else:
+ try:
+ value = int(params[1]).to_bytes(2, "little") # try as 2 byte integer
+ except ValueError:
+ value = str.encode(params[1]) # must be a string
+
+ attribute = self.find_local_attribute(params[0])
+ if not attribute:
+ self.show_error('invalid syntax', 'unable to find attribute')
+ return
+
+ # send data to any subscribers
+ if isinstance(attribute, Characteristic):
+ attribute.write_value(None, value)
+ if attribute.has_properties(Characteristic.NOTIFY):
+ await self.device.gatt_server.notify_subscribers(attribute)
+ if attribute.has_properties(Characteristic.INDICATE):
+ await self.device.gatt_server.indicate_subscribers(attribute)
+
+ async def do_subscribe(self, params):
+ if not self.connected_peer:
+ self.show_error('not connected')
+ return
+
+ if len(params) != 1:
+ self.show_error('invalid syntax', 'expected subscribe <attribute>')
+ return
+
+ characteristic = self.find_remote_characteristic(params[0])
+ if characteristic is None:
self.show_error('no such characteristic')
+ return
- async def do_exit(self, params):
+ await characteristic.subscribe(
+ lambda value: self.append_to_output(
+ f"{characteristic} VALUE: 0x{value.hex()}"
+ ),
+ )
+
+ async def do_unsubscribe(self, params):
+ if not self.connected_peer:
+ self.show_error('not connected')
+ return
+
+ if len(params) != 1:
+ self.show_error('invalid syntax', 'expected subscribe <attribute>')
+ return
+
+ characteristic = self.find_remote_characteristic(params[0])
+ if characteristic is None:
+ self.show_error('no such characteristic')
+ return
+
+ await characteristic.unsubscribe()
+
+ async def do_set_phy(self, params):
+ if len(params) != 1:
+ self.show_error(
+ 'invalid syntax', 'expected set-phy <tx_rx_phys>|<tx_phys>/<rx_phys>'
+ )
+ return
+
+ if not self.connected_peer:
+ self.show_error('not connected')
+ return
+
+ if '/' in params[0]:
+ tx_phys, rx_phys = params[0].split('/')
+ else:
+ tx_phys = params[0]
+ rx_phys = tx_phys
+
+ await self.connected_peer.connection.set_phy(
+ tx_phys=parse_phys(tx_phys), rx_phys=parse_phys(rx_phys)
+ )
+
+ async def do_set_default_phy(self, params):
+ if len(params) != 1:
+ self.show_error(
+ 'invalid syntax',
+ 'expected set-default-phy <tx_rx_phys>|<tx_phys>/<rx_phys>',
+ )
+ return
+
+ if '/' in params[0]:
+ tx_phys, rx_phys = params[0].split('/')
+ else:
+ tx_phys = params[0]
+ rx_phys = tx_phys
+
+ await self.device.set_default_phy(
+ tx_phys=parse_phys(tx_phys), rx_phys=parse_phys(rx_phys)
+ )
+
+ async def do_exit(self, _):
self.ui.exit()
- async def do_quit(self, params):
+ async def do_quit(self, _):
self.ui.exit()
+ async def do_filter(self, params):
+ if params[0] == "address":
+ if len(params) != 2:
+ self.show_error('invalid syntax', 'expected filter address <pattern>')
+ return
+ self.device.listener.address_filter = params[1]
+
# -----------------------------------------------------------------------------
# Device and Connection Listener
@@ -476,42 +1046,96 @@ class DeviceListener(Device.Listener, Connection.Listener):
def __init__(self, app):
self.app = app
self.scan_results = OrderedDict()
+ self.address_filter = None
+
+ @property
+ def address_filter(self):
+ return self._address_filter
+
+ @address_filter.setter
+ def address_filter(self, filter_addr):
+ if filter_addr is None:
+ self._address_filter = re.compile(r".*")
+ else:
+ self._address_filter = re.compile(filter_addr)
+ self.scan_results = OrderedDict(
+ filter(self.filter_address_match, self.scan_results)
+ )
+ self.app.show_scan_results(self.scan_results)
+
+ def filter_address_match(self, address):
+ """
+ Returns true if an address matches the filter
+ """
+ return bool(self.address_filter.match(address))
@AsyncRunner.run_in_task()
+ # pylint: disable=invalid-overridden-method
async def on_connection(self, connection):
self.app.connected_peer = Peer(connection)
+ self.app.connection_rssi = None
self.app.append_to_output(f'connected to {self.app.connected_peer}')
connection.listener = self
def on_disconnection(self, reason):
- self.app.append_to_output(f'disconnected from {self.app.connected_peer}, reason: {HCI_Constant.error_name(reason)}')
+ self.app.append_to_output(
+ f'disconnected from {self.app.connected_peer}, '
+ f'reason: {HCI_Constant.error_name(reason)}'
+ )
self.app.connected_peer = None
+ self.app.connection_rssi = None
def on_connection_parameters_update(self):
- self.app.append_to_output(f'connection parameters update: {self.app.connected_peer.connection.parameters}')
+ self.app.append_to_output(
+ f'connection parameters update: '
+ f'{self.app.connected_peer.connection.parameters}'
+ )
def on_connection_phy_update(self):
- self.app.append_to_output(f'connection phy update: {self.app.connected_peer.connection.phy}')
+ self.app.append_to_output(
+ f'connection phy update: {self.app.connected_peer.connection.phy}'
+ )
def on_connection_att_mtu_update(self):
- self.app.append_to_output(f'connection att mtu update: {self.app.connected_peer.connection.att_mtu}')
+ self.app.append_to_output(
+ f'connection att mtu update: {self.app.connected_peer.connection.att_mtu}'
+ )
def on_connection_encryption_change(self):
- self.app.append_to_output(f'connection encryption change: {"encrypted" if self.app.connected_peer.connection.is_encrypted else "not encrypted"}')
+ encryption_state = (
+ 'encrypted'
+ if self.app.connected_peer.connection.is_encrypted
+ else 'not encrypted'
+ )
+ self.app.append_to_output(
+ 'connection encryption change: ' f'{encryption_state}'
+ )
def on_connection_data_length_change(self):
- self.app.append_to_output(f'connection data length change: {self.app.connected_peer.connection.data_length}')
+ self.app.append_to_output(
+ 'connection data length change: '
+ f'{self.app.connected_peer.connection.data_length}'
+ )
+
+ def on_advertisement(self, advertisement):
+ if not self.filter_address_match(str(advertisement.address)):
+ return
- def on_advertisement(self, address, ad_data, rssi, connectable):
- entry_key = f'{address}/{address.address_type}'
+ entry_key = f'{advertisement.address}/{advertisement.address.address_type}'
entry = self.scan_results.get(entry_key)
if entry:
- entry.ad_data = ad_data
- entry.rssi = rssi
- entry.connectable = connectable
+ entry.ad_data = advertisement.data
+ entry.rssi = advertisement.rssi
+ entry.connectable = advertisement.is_connectable
else:
- self.app.add_known_address(str(address))
- self.scan_results[entry_key] = ScanResult(address, address.address_type, ad_data, rssi, connectable)
+ self.app.add_known_address(str(advertisement.address))
+ self.scan_results[entry_key] = ScanResult(
+ advertisement.address,
+ advertisement.address.address_type,
+ advertisement.data,
+ advertisement.rssi,
+ advertisement.is_connectable,
+ )
self.app.show_scan_results(self.scan_results)
@@ -521,11 +1145,11 @@ class DeviceListener(Device.Listener, Connection.Listener):
# -----------------------------------------------------------------------------
class ScanResult:
def __init__(self, address, address_type, ad_data, rssi, connectable):
- self.address = address
+ self.address = address
self.address_type = address_type
- self.ad_data = ad_data
- self.rssi = rssi
- self.connectable = connectable
+ self.ad_data = ad_data
+ self.rssi = rssi
+ self.connectable = connectable
def to_display_string(self):
address_type_string = ('P', 'R', 'PI', 'RI')[self.address_type]
@@ -535,9 +1159,9 @@ class ScanResult:
else:
type_color = colors.cyan
- name = self.ad_data.get(AdvertisingData.COMPLETE_LOCAL_NAME)
+ name = self.ad_data.get(AdvertisingData.COMPLETE_LOCAL_NAME, raw=True)
if name is None:
- name = self.ad_data.get(AdvertisingData.SHORTENED_LOCAL_NAME)
+ name = self.ad_data.get(AdvertisingData.SHORTENED_LOCAL_NAME, raw=True)
if name:
# Convert to string
try:
@@ -547,15 +1171,16 @@ class ScanResult:
else:
name = ''
+ # Remove any '/P' qualifier suffix from the address string
+ address_str = str(self.address).replace('/P', '')
+
# RSSI bar
- blocks = ['', 'â–', 'â–Ž', 'â–', 'â–Œ', 'â–‹', 'â–Š', 'â–‰']
- bar_width = (self.rssi - DISPLAY_MIN_RSSI) / (DISPLAY_MAX_RSSI - DISPLAY_MIN_RSSI)
- bar_width = min(max(bar_width, 0), 1)
- bar_ticks = int(bar_width * DEFAULT_RSSI_BAR_WIDTH * 8)
- bar_blocks = ('â–ˆ' * int(bar_ticks / 8)) + blocks[bar_ticks % 8]
- bar_string = f'{self.rssi} {bar_blocks}'
+ bar_string = rssi_bar(self.rssi)
bar_padding = ' ' * (DEFAULT_RSSI_BAR_WIDTH + 5 - len(bar_string))
- return f'{address_color(str(self.address))} [{type_color(address_type_string)}] {bar_string} {bar_padding} {name}'
+ return (
+ f'{address_color(address_str)} [{type_color(address_type_string)}] '
+ f'{bar_string} {bar_padding} {name}'
+ )
# -----------------------------------------------------------------------------
@@ -565,6 +1190,7 @@ class LogHandler(logging.Handler):
def __init__(self, app):
super().__init__()
self.app = app
+ self.setFormatter(logging.Formatter('[%(asctime)s][%(levelname)s] %(message)s'))
def emit(self, record):
message = self.format(record)
@@ -582,13 +1208,14 @@ def main(device_config, transport):
if not os.path.isdir(BUMBLE_USER_DIR):
os.mkdir(BUMBLE_USER_DIR)
- # Create an instane of the app
+ # Create an instance of the app
app = ConsoleApp()
# Setup logging
# logging.basicConfig(level = 'FATAL')
# logging.basicConfig(level = 'DEBUG')
root_logger = logging.getLogger()
+
root_logger.addHandler(LogHandler(app))
root_logger.setLevel(logging.DEBUG)
@@ -598,4 +1225,4 @@ def main(device_config, transport):
# -----------------------------------------------------------------------------
if __name__ == "__main__":
- main()
+ main() # pylint: disable=no-value-for-parameter
diff --git a/apps/controller_info.py b/apps/controller_info.py
new file mode 100644
index 0000000..4707983
--- /dev/null
+++ b/apps/controller_info.py
@@ -0,0 +1,173 @@
+# Copyright 2021-2022 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# -----------------------------------------------------------------------------
+# Imports
+# -----------------------------------------------------------------------------
+import asyncio
+import os
+import logging
+import click
+from bumble.company_ids import COMPANY_IDENTIFIERS
+
+from bumble.colors import color
+from bumble.core import name_or_number
+from bumble.hci import (
+ map_null_terminated_utf8_string,
+ HCI_SUCCESS,
+ HCI_LE_SUPPORTED_FEATURES_NAMES,
+ HCI_VERSION_NAMES,
+ LMP_VERSION_NAMES,
+ HCI_Command,
+ HCI_Command_Complete_Event,
+ HCI_Command_Status_Event,
+ HCI_READ_BD_ADDR_COMMAND,
+ HCI_Read_BD_ADDR_Command,
+ HCI_READ_LOCAL_NAME_COMMAND,
+ HCI_Read_Local_Name_Command,
+ HCI_LE_READ_MAXIMUM_DATA_LENGTH_COMMAND,
+ HCI_LE_Read_Maximum_Data_Length_Command,
+ HCI_LE_READ_NUMBER_OF_SUPPORTED_ADVERTISING_SETS_COMMAND,
+ HCI_LE_Read_Number_Of_Supported_Advertising_Sets_Command,
+ HCI_LE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH_COMMAND,
+ HCI_LE_Read_Maximum_Advertising_Data_Length_Command,
+)
+from bumble.host import Host
+from bumble.transport import open_transport_or_link
+
+
+# -----------------------------------------------------------------------------
+def command_succeeded(response):
+ if isinstance(response, HCI_Command_Status_Event):
+ return response.status == HCI_SUCCESS
+ if isinstance(response, HCI_Command_Complete_Event):
+ return response.return_parameters.status == HCI_SUCCESS
+ return False
+
+
+# -----------------------------------------------------------------------------
+async def get_classic_info(host):
+ if host.supports_command(HCI_READ_BD_ADDR_COMMAND):
+ response = await host.send_command(HCI_Read_BD_ADDR_Command())
+ if command_succeeded(response):
+ print()
+ print(
+ color('Classic Address:', 'yellow'), response.return_parameters.bd_addr
+ )
+
+ if host.supports_command(HCI_READ_LOCAL_NAME_COMMAND):
+ response = await host.send_command(HCI_Read_Local_Name_Command())
+ if command_succeeded(response):
+ print()
+ print(
+ color('Local Name:', 'yellow'),
+ map_null_terminated_utf8_string(response.return_parameters.local_name),
+ )
+
+
+# -----------------------------------------------------------------------------
+async def get_le_info(host):
+ print()
+
+ if host.supports_command(HCI_LE_READ_NUMBER_OF_SUPPORTED_ADVERTISING_SETS_COMMAND):
+ response = await host.send_command(
+ HCI_LE_Read_Number_Of_Supported_Advertising_Sets_Command()
+ )
+ if command_succeeded(response):
+ print(
+ color('LE Number Of Supported Advertising Sets:', 'yellow'),
+ response.return_parameters.num_supported_advertising_sets,
+ '\n',
+ )
+
+ if host.supports_command(HCI_LE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH_COMMAND):
+ response = await host.send_command(
+ HCI_LE_Read_Maximum_Advertising_Data_Length_Command()
+ )
+ if command_succeeded(response):
+ print(
+ color('LE Maximum Advertising Data Length:', 'yellow'),
+ response.return_parameters.max_advertising_data_length,
+ '\n',
+ )
+
+ if host.supports_command(HCI_LE_READ_MAXIMUM_DATA_LENGTH_COMMAND):
+ response = await host.send_command(HCI_LE_Read_Maximum_Data_Length_Command())
+ if command_succeeded(response):
+ print(
+ color('Maximum Data Length:', 'yellow'),
+ (
+ f'tx:{response.return_parameters.supported_max_tx_octets}/'
+ f'{response.return_parameters.supported_max_tx_time}, '
+ f'rx:{response.return_parameters.supported_max_rx_octets}/'
+ f'{response.return_parameters.supported_max_rx_time}'
+ ),
+ '\n',
+ )
+
+ print(color('LE Features:', 'yellow'))
+ for feature in host.supported_le_features:
+ print(' ', name_or_number(HCI_LE_SUPPORTED_FEATURES_NAMES, feature))
+
+
+# -----------------------------------------------------------------------------
+async def async_main(transport):
+ print('<<< connecting to HCI...')
+ async with await open_transport_or_link(transport) as (hci_source, hci_sink):
+ print('<<< connected')
+
+ host = Host(hci_source, hci_sink)
+ await host.reset()
+
+ # Print version
+ print(color('Version:', 'yellow'))
+ print(
+ color(' Manufacturer: ', 'green'),
+ name_or_number(COMPANY_IDENTIFIERS, host.local_version.company_identifier),
+ )
+ print(
+ color(' HCI Version: ', 'green'),
+ name_or_number(HCI_VERSION_NAMES, host.local_version.hci_version),
+ )
+ print(color(' HCI Subversion:', 'green'), host.local_version.hci_subversion)
+ print(
+ color(' LMP Version: ', 'green'),
+ name_or_number(LMP_VERSION_NAMES, host.local_version.lmp_version),
+ )
+ print(color(' LMP Subversion:', 'green'), host.local_version.lmp_subversion)
+
+ # Get the Classic info
+ await get_classic_info(host)
+
+ # Get the LE info
+ await get_le_info(host)
+
+ # Print the list of commands supported by the controller
+ print()
+ print(color('Supported Commands:', 'yellow'))
+ for command in host.supported_commands:
+ print(' ', HCI_Command.command_name(command))
+
+
+# -----------------------------------------------------------------------------
+@click.command()
+@click.argument('transport')
+def main(transport):
+ logging.basicConfig(level=os.environ.get('BUMBLE_LOGLEVEL', 'WARNING').upper())
+ asyncio.run(async_main(transport))
+
+
+# -----------------------------------------------------------------------------
+if __name__ == '__main__':
+ main()
diff --git a/apps/controllers.py b/apps/controllers.py
index 8e5f70e..ac6477e 100644
--- a/apps/controllers.py
+++ b/apps/controllers.py
@@ -28,11 +28,14 @@ from bumble.transport import open_transport_or_link
# -----------------------------------------------------------------------------
async def async_main():
if len(sys.argv) != 3:
- print('Usage: controllers.py <hci-transport-1> <hci-transport-2> [<hci-transport-3> ...]')
+ print(
+ 'Usage: controllers.py <hci-transport-1> <hci-transport-2> '
+ '[<hci-transport-3> ...]'
+ )
print('example: python controllers.py pty:ble1 pty:ble2')
return
- # Create a loccal link to attach the controllers to
+ # Create a local link to attach the controllers to
link = LocalLink()
# Create a transport and controller for all requested names
@@ -41,7 +44,12 @@ async def async_main():
for index, transport_name in enumerate(sys.argv[1:]):
transport = await open_transport_or_link(transport_name)
transports.append(transport)
- controller = Controller(f'C{index}', host_source = transport.source, host_sink = transport.sink, link = link)
+ controller = Controller(
+ f'C{index}',
+ host_source=transport.source,
+ host_sink=transport.sink,
+ link=link,
+ )
controllers.append(controller)
# Wait until the user interrupts
@@ -54,7 +62,7 @@ async def async_main():
# -----------------------------------------------------------------------------
def main():
- logging.basicConfig(level = os.environ.get('BUMBLE_LOGLEVEL', 'INFO').upper())
+ logging.basicConfig(level=os.environ.get('BUMBLE_LOGLEVEL', 'INFO').upper())
asyncio.run(async_main())
diff --git a/apps/gatt_dump.py b/apps/gatt_dump.py
index 02c3641..a3205c0 100644
--- a/apps/gatt_dump.py
+++ b/apps/gatt_dump.py
@@ -19,9 +19,9 @@ import asyncio
import os
import logging
import click
-from colors import color
-from bumble.core import ProtocolError, TimeoutError
+import bumble.core
+from bumble.colors import color
from bumble.device import Device, Peer
from bumble.gatt import show_services
from bumble.transport import open_transport_or_link
@@ -49,9 +49,9 @@ async def dump_gatt_db(peer, done):
try:
value = await attribute.read_value()
print(color(f'{value.hex()}', 'green'))
- except ProtocolError as error:
+ except bumble.core.ProtocolError as error:
print(color(error, 'red'))
- except TimeoutError:
+ except bumble.core.TimeoutError:
print(color('read timeout', 'red'))
if done is not None:
@@ -64,9 +64,13 @@ async def async_main(device_config, encrypt, transport, address_or_name):
# Create a device
if device_config:
- device = Device.from_config_file_with_hci(device_config, hci_source, hci_sink)
+ device = Device.from_config_file_with_hci(
+ device_config, hci_source, hci_sink
+ )
else:
- device = Device.with_hci('Bumble', 'F0:F1:F2:F3:F4:F5', hci_source, hci_sink)
+ device = Device.with_hci(
+ 'Bumble', 'F0:F1:F2:F3:F4:F5', hci_source, hci_sink
+ )
await device.power_on()
if address_or_name:
@@ -81,7 +85,12 @@ async def async_main(device_config, encrypt, transport, address_or_name):
else:
# Wait for a connection
done = asyncio.get_running_loop().create_future()
- device.on('connection', lambda connection: asyncio.create_task(dump_gatt_db(Peer(connection), done)))
+ device.on(
+ 'connection',
+ lambda connection: asyncio.create_task(
+ dump_gatt_db(Peer(connection), done)
+ ),
+ )
await device.start_advertising(auto_restart=True)
print(color('### Waiting for connection...', 'blue'))
@@ -99,7 +108,7 @@ def main(device_config, encrypt, transport, address_or_name):
Dump the GATT database on a remote device. If ADDRESS_OR_NAME is not specified,
wait for an incoming connection.
"""
- logging.basicConfig(level = os.environ.get('BUMBLE_LOGLEVEL', 'INFO').upper())
+ logging.basicConfig(level=os.environ.get('BUMBLE_LOGLEVEL', 'INFO').upper())
asyncio.run(async_main(device_config, encrypt, transport, address_or_name))
diff --git a/apps/gg_bridge.py b/apps/gg_bridge.py
index d524913..88ebdc5 100644
--- a/apps/gg_bridge.py
+++ b/apps/gg_bridge.py
@@ -17,13 +17,14 @@
# -----------------------------------------------------------------------------
import asyncio
import os
+import struct
import logging
import click
-from colors import color
+from bumble.colors import color
from bumble.device import Device, Peer
from bumble.core import AdvertisingData
-from bumble.gatt import Service, Characteristic
+from bumble.gatt import Service, Characteristic, CharacteristicValue
from bumble.utils import AsyncRunner
from bumble.transport import open_transport_or_link
from bumble.hci import HCI_Constant
@@ -32,24 +33,73 @@ from bumble.hci import HCI_Constant
# -----------------------------------------------------------------------------
# Constants
# -----------------------------------------------------------------------------
-GG_GATTLINK_SERVICE_UUID = 'ABBAFF00-E56A-484C-B832-8B17CF6CBFE8'
-GG_GATTLINK_RX_CHARACTERISTIC_UUID = 'ABBAFF01-E56A-484C-B832-8B17CF6CBFE8'
-GG_GATTLINK_TX_CHARACTERISTIC_UUID = 'ABBAFF02-E56A-484C-B832-8B17CF6CBFE8'
-GG_GATTLINK_L2CAP_CHANNEL_PSM_CHARACTERISTIC_UUID = 'ABBAFF03-E56A-484C-B832-8B17CF6CBFE8'
+GG_GATTLINK_SERVICE_UUID = 'ABBAFF00-E56A-484C-B832-8B17CF6CBFE8'
+GG_GATTLINK_RX_CHARACTERISTIC_UUID = 'ABBAFF01-E56A-484C-B832-8B17CF6CBFE8'
+GG_GATTLINK_TX_CHARACTERISTIC_UUID = 'ABBAFF02-E56A-484C-B832-8B17CF6CBFE8'
+GG_GATTLINK_L2CAP_CHANNEL_PSM_CHARACTERISTIC_UUID = (
+ 'ABBAFF03-E56A-484C-B832-8B17CF6CBFE8'
+)
GG_PREFERRED_MTU = 256
# -----------------------------------------------------------------------------
-class GattlinkHubBridge(Device.Listener):
+class GattlinkL2capEndpoint:
def __init__(self):
- self.peer = None
- self.rx_socket = None
- self.tx_socket = None
+ self.l2cap_channel = None
+ self.l2cap_packet = b''
+ self.l2cap_packet_size = 0
+
+ # Called when an L2CAP SDU has been received
+ def on_coc_sdu(self, sdu):
+ print(color(f'<<< [L2CAP SDU]: {len(sdu)} bytes', 'cyan'))
+ while len(sdu):
+ if self.l2cap_packet_size == 0:
+ # Expect a new packet
+ self.l2cap_packet_size = sdu[0] + 1
+ sdu = sdu[1:]
+ else:
+ bytes_needed = self.l2cap_packet_size - len(self.l2cap_packet)
+ chunk = min(bytes_needed, len(sdu))
+ self.l2cap_packet += sdu[:chunk]
+ sdu = sdu[chunk:]
+ if len(self.l2cap_packet) == self.l2cap_packet_size:
+ self.on_l2cap_packet(self.l2cap_packet)
+ self.l2cap_packet = b''
+ self.l2cap_packet_size = 0
+
+
+# -----------------------------------------------------------------------------
+class GattlinkHubBridge(GattlinkL2capEndpoint, Device.Listener):
+ def __init__(self, device, peer_address):
+ super().__init__()
+ self.device = device
+ self.peer_address = peer_address
+ self.peer = None
+ self.tx_socket = None
self.rx_characteristic = None
self.tx_characteristic = None
+ self.l2cap_psm_characteristic = None
+
+ device.listener = self
+
+ async def start(self):
+ # Connect to the peer
+ print(f'=== Connecting to {self.peer_address}...')
+ await self.device.connect(self.peer_address)
+
+ async def connect_l2cap(self, psm):
+ print(color(f'### Connecting with L2CAP on PSM = {psm}', 'yellow'))
+ try:
+ self.l2cap_channel = await self.peer.connection.open_l2cap_channel(psm)
+ print(color('*** Connected', 'yellow'), self.l2cap_channel)
+ self.l2cap_channel.sink = self.on_coc_sdu
+
+ except Exception as error:
+ print(color(f'!!! Connection failed: {error}', 'red'))
@AsyncRunner.run_in_task()
+ # pylint: disable=invalid-overridden-method
async def on_connection(self, connection):
print(f'=== Connected to {connection}')
self.peer = Peer(connection)
@@ -80,115 +130,221 @@ class GattlinkHubBridge(Device.Listener):
self.rx_characteristic = characteristic
elif characteristic.uuid == GG_GATTLINK_TX_CHARACTERISTIC_UUID:
self.tx_characteristic = characteristic
+ elif (
+ characteristic.uuid == GG_GATTLINK_L2CAP_CHANNEL_PSM_CHARACTERISTIC_UUID
+ ):
+ self.l2cap_psm_characteristic = characteristic
print('RX:', self.rx_characteristic)
print('TX:', self.tx_characteristic)
-
- # Subscribe to TX
- if self.tx_characteristic:
+ print('PSM:', self.l2cap_psm_characteristic)
+
+ if self.l2cap_psm_characteristic:
+ # Subscribe to and then read the PSM value
+ await self.peer.subscribe(
+ self.l2cap_psm_characteristic, self.on_l2cap_psm_received
+ )
+ psm_bytes = await self.peer.read_value(self.l2cap_psm_characteristic)
+ psm = struct.unpack('<H', psm_bytes)[0]
+ await self.connect_l2cap(psm)
+ elif self.tx_characteristic:
+ # Subscribe to TX
await self.peer.subscribe(self.tx_characteristic, self.on_tx_received)
print(color('=== Subscribed to Gattlink TX', 'yellow'))
else:
- print(color('!!! Gattlink TX not found', 'red'))
+ print(color('!!! No Gattlink TX or PSM found', 'red'))
def on_connection_failure(self, error):
print(color(f'!!! Connection failed: {error}'))
def on_disconnection(self, reason):
- print(color(f'!!! Disconnected from {self.peer}, reason={HCI_Constant.error_name(reason)}', 'red'))
+ print(
+ color(
+ f'!!! Disconnected from {self.peer}, '
+ f'reason={HCI_Constant.error_name(reason)}',
+ 'red',
+ )
+ )
self.tx_characteristic = None
self.rx_characteristic = None
self.peer = None
+ # Called when an L2CAP packet has been received
+ def on_l2cap_packet(self, packet):
+ print(color(f'<<< [L2CAP PACKET]: {len(packet)} bytes', 'cyan'))
+ print(color('>>> [UDP]', 'magenta'))
+ self.tx_socket.sendto(packet)
+
# Called by the GATT client when a notification is received
def on_tx_received(self, value):
- print(color('>>> TX:', 'magenta'), value.hex())
+ print(color(f'<<< [GATT TX]: {len(value)} bytes', 'cyan'))
if self.tx_socket:
+ print(color('>>> [UDP]', 'magenta'))
self.tx_socket.sendto(value)
# Called by asyncio when the UDP socket is created
+ def on_l2cap_psm_received(self, value):
+ psm = struct.unpack('<H', value)[0]
+ asyncio.create_task(self.connect_l2cap(psm))
+
+ # Called by asyncio when the UDP socket is created
def connection_made(self, transport):
pass
# Called by asyncio when a UDP datagram is received
- def datagram_received(self, data, address):
- print(color('<<< RX:', 'magenta'), data.hex())
-
- # TODO: use a queue instead of creating a task everytime
- if self.peer and self.rx_characteristic:
+ def datagram_received(self, data, _address):
+ print(color(f'<<< [UDP]: {len(data)} bytes', 'green'))
+
+ if self.l2cap_channel:
+ print(color('>>> [L2CAP]', 'yellow'))
+ self.l2cap_channel.write(bytes([len(data) - 1]) + data)
+ elif self.peer and self.rx_characteristic:
+ print(color('>>> [GATT RX]', 'yellow'))
asyncio.create_task(self.peer.write_value(self.rx_characteristic, data))
# -----------------------------------------------------------------------------
-class GattlinkNodeBridge(Device.Listener):
- def __init__(self):
- self.peer = None
- self.rx_socket = None
+class GattlinkNodeBridge(GattlinkL2capEndpoint, Device.Listener):
+ def __init__(self, device):
+ super().__init__()
+ self.device = device
+ self.peer = None
self.tx_socket = None
+ self.tx_subscriber = None
+ self.rx_characteristic = None
+ self.transport = None
+
+ # Register as a listener
+ device.listener = self
+
+ # Listen for incoming L2CAP CoC connections
+ psm = 0xFB
+ device.register_l2cap_channel_server(0xFB, self.on_coc)
+ print(f'### Listening for CoC connection on PSM {psm}')
+
+ # Setup the Gattlink service
+ self.rx_characteristic = Characteristic(
+ GG_GATTLINK_RX_CHARACTERISTIC_UUID,
+ Characteristic.WRITE_WITHOUT_RESPONSE,
+ Characteristic.WRITEABLE,
+ CharacteristicValue(write=self.on_rx_write),
+ )
+ self.tx_characteristic = Characteristic(
+ GG_GATTLINK_TX_CHARACTERISTIC_UUID,
+ Characteristic.Properties.NOTIFY,
+ Characteristic.READABLE,
+ )
+ self.tx_characteristic.on('subscription', self.on_tx_subscription)
+ self.psm_characteristic = Characteristic(
+ GG_GATTLINK_L2CAP_CHANNEL_PSM_CHARACTERISTIC_UUID,
+ Characteristic.Properties.READ | Characteristic.Properties.NOTIFY,
+ Characteristic.READABLE,
+ bytes([psm, 0]),
+ )
+ gattlink_service = Service(
+ GG_GATTLINK_SERVICE_UUID,
+ [self.rx_characteristic, self.tx_characteristic, self.psm_characteristic],
+ )
+ device.add_services([gattlink_service])
+ device.advertising_data = bytes(
+ AdvertisingData(
+ [
+ (AdvertisingData.COMPLETE_LOCAL_NAME, bytes('Bumble GG', 'utf-8')),
+ (
+ AdvertisingData.INCOMPLETE_LIST_OF_128_BIT_SERVICE_CLASS_UUIDS,
+ bytes(
+ reversed(bytes.fromhex('ABBAFF00E56A484CB8328B17CF6CBFE8'))
+ ),
+ ),
+ ]
+ )
+ )
+
+ async def start(self):
+ await self.device.start_advertising()
# Called by asyncio when the UDP socket is created
def connection_made(self, transport):
- pass
+ self.transport = transport
# Called by asyncio when a UDP datagram is received
- def datagram_received(self, data, address):
- print(color('<<< RX:', 'magenta'), data.hex())
+ def datagram_received(self, data, _address):
+ print(color(f'<<< [UDP]: {len(data)} bytes', 'green'))
+
+ if self.l2cap_channel:
+ print(color('>>> [L2CAP]', 'yellow'))
+ self.l2cap_channel.write(bytes([len(data) - 1]) + data)
+ elif self.tx_subscriber:
+ print(color('>>> [GATT TX]', 'yellow'))
+ self.tx_characteristic.value = data
+ asyncio.create_task(self.device.notify_subscribers(self.tx_characteristic))
+
+ # Called when a write to the RX characteristic has been received
+ def on_rx_write(self, _connection, data):
+ print(color(f'<<< [GATT RX]: {len(data)} bytes', 'cyan'))
+ print(color('>>> [UDP]', 'magenta'))
+ self.tx_socket.sendto(data)
+
+ # Called when the subscription to the TX characteristic has changed
+ def on_tx_subscription(self, peer, enabled):
+ print(
+ f'### [GATT TX] subscription from {peer}: '
+ f'{"enabled" if enabled else "disabled"}'
+ )
+ if enabled:
+ self.tx_subscriber = peer
+ else:
+ self.tx_subscriber = None
- # TODO: use a queue instead of creating a task everytime
- if self.peer and self.rx_characteristic:
- asyncio.create_task(self.peer.write_value(self.rx_characteristic, data))
+ # Called when an L2CAP packet is received
+ def on_l2cap_packet(self, packet):
+ print(color(f'<<< [L2CAP PACKET]: {len(packet)} bytes', 'cyan'))
+ print(color('>>> [UDP]', 'magenta'))
+ self.tx_socket.sendto(packet)
+
+ # Called when a new connection is established
+ def on_coc(self, channel):
+ print('*** CoC Connection', channel)
+ self.l2cap_channel = channel
+ channel.sink = self.on_coc_sdu
# -----------------------------------------------------------------------------
-async def run(hci_transport, device_address, send_host, send_port, receive_host, receive_port):
+async def run(
+ hci_transport,
+ device_address,
+ role_or_peer_address,
+ send_host,
+ send_port,
+ receive_host,
+ receive_port,
+):
print('<<< connecting to HCI...')
async with await open_transport_or_link(hci_transport) as (hci_source, hci_sink):
print('<<< connected')
# Instantiate a bridge object
- bridge = GattlinkNodeBridge()
+ device = Device.with_hci('Bumble GG', device_address, hci_source, hci_sink)
+
+ # Instantiate a bridge object
+ if role_or_peer_address == 'node':
+ bridge = GattlinkNodeBridge(device)
+ else:
+ bridge = GattlinkHubBridge(device, role_or_peer_address)
# Create a UDP to RX bridge (receive from UDP, send to RX)
loop = asyncio.get_running_loop()
await loop.create_datagram_endpoint(
- lambda: bridge,
- local_addr=(receive_host, receive_port)
+ lambda: bridge, local_addr=(receive_host, receive_port)
)
# Create a UDP to TX bridge (receive from TX, send to UDP)
bridge.tx_socket, _ = await loop.create_datagram_endpoint(
- lambda: asyncio.DatagramProtocol(),
- remote_addr=(send_host, send_port)
+ asyncio.DatagramProtocol,
+ remote_addr=(send_host, send_port),
)
- # Create a device to manage the host, with a custom listener
- device = Device.with_hci('Bumble', 'F0:F1:F2:F3:F4:F5', hci_source, hci_sink)
- device.listener = bridge
await device.power_on()
-
- # Connect to the peer
- # print(f'=== Connecting to {device_address}...')
- # await device.connect(device_address)
-
- # TODO move to class
- gattlink_service = Service(
- GG_GATTLINK_SERVICE_UUID,
- [
- Characteristic(
- GG_GATTLINK_L2CAP_CHANNEL_PSM_CHARACTERISTIC_UUID,
- Characteristic.READ,
- Characteristic.READABLE,
- bytes([193, 0])
- )
- ]
- )
- device.add_services([gattlink_service])
- device.advertising_data = bytes(
- AdvertisingData([
- (AdvertisingData.COMPLETE_LOCAL_NAME, bytes('Bumble GG', 'utf-8')),
- (AdvertisingData.INCOMPLETE_LIST_OF_128_BIT_SERVICE_CLASS_UUIDS, bytes(reversed(bytes.fromhex('ABBAFF00E56A484CB8328B17CF6CBFE8'))))
- ])
- )
- await device.start_advertising()
+ await bridge.start()
# Wait until the source terminates
await hci_source.wait_for_termination()
@@ -197,15 +353,44 @@ async def run(hci_transport, device_address, send_host, send_port, receive_host,
@click.command()
@click.argument('hci_transport')
@click.argument('device_address')
-@click.option('-sh', '--send-host', type=str, default='127.0.0.1', help='UDP host to send to')
+@click.argument('role_or_peer_address')
+@click.option(
+ '-sh', '--send-host', type=str, default='127.0.0.1', help='UDP host to send to'
+)
@click.option('-sp', '--send-port', type=int, default=9001, help='UDP port to send to')
-@click.option('-rh', '--receive-host', type=str, default='127.0.0.1', help='UDP host to receive on')
-@click.option('-rp', '--receive-port', type=int, default=9000, help='UDP port to receive on')
-def main(hci_transport, device_address, send_host, send_port, receive_host, receive_port):
- logging.basicConfig(level = os.environ.get('BUMBLE_LOGLEVEL', 'INFO').upper())
- asyncio.run(run(hci_transport, device_address, send_host, send_port, receive_host, receive_port))
+@click.option(
+ '-rh',
+ '--receive-host',
+ type=str,
+ default='127.0.0.1',
+ help='UDP host to receive on',
+)
+@click.option(
+ '-rp', '--receive-port', type=int, default=9000, help='UDP port to receive on'
+)
+def main(
+ hci_transport,
+ device_address,
+ role_or_peer_address,
+ send_host,
+ send_port,
+ receive_host,
+ receive_port,
+):
+ asyncio.run(
+ run(
+ hci_transport,
+ device_address,
+ role_or_peer_address,
+ send_host,
+ send_port,
+ receive_host,
+ receive_port,
+ )
+ )
# -----------------------------------------------------------------------------
+logging.basicConfig(level=os.environ.get('BUMBLE_LOGLEVEL', 'WARNING').upper())
if __name__ == '__main__':
main()
diff --git a/apps/hci_bridge.py b/apps/hci_bridge.py
index 0680f52..1d1f9a1 100644
--- a/apps/hci_bridge.py
+++ b/apps/hci_bridge.py
@@ -34,16 +34,29 @@ logger = logging.getLogger(__name__)
# -----------------------------------------------------------------------------
async def async_main():
if len(sys.argv) < 3:
- print('Usage: hci_bridge.py <host-transport-spec> <controller-transport-spec> [command-short-circuit-list]')
- print('example: python hci_bridge.py udp:0.0.0.0:9000,127.0.0.1:9001 serial:/dev/tty.usbmodem0006839912171,1000000 0x3f:0x0070,0x3f:0x0074,0x3f:0x0077,0x3f:0x0078')
+ print(
+ 'Usage: hci_bridge.py <host-transport-spec> <controller-transport-spec> '
+ '[command-short-circuit-list]'
+ )
+ print(
+ 'example: python hci_bridge.py udp:0.0.0.0:9000,127.0.0.1:9001 '
+ 'serial:/dev/tty.usbmodem0006839912171,1000000 '
+ '0x3f:0x0070,0x3f:0x0074,0x3f:0x0077,0x3f:0x0078'
+ )
return
print('>>> connecting to HCI...')
- async with await transport.open_transport_or_link(sys.argv[1]) as (hci_host_source, hci_host_sink):
+ async with await transport.open_transport_or_link(sys.argv[1]) as (
+ hci_host_source,
+ hci_host_sink,
+ ):
print('>>> connected')
print('>>> connecting to HCI...')
- async with await transport.open_transport_or_link(sys.argv[2]) as (hci_controller_source, hci_controller_sink):
+ async with await transport.open_transport_or_link(sys.argv[2]) as (
+ hci_controller_source,
+ hci_controller_sink,
+ ):
print('>>> connected')
command_short_circuits = []
@@ -51,36 +64,43 @@ async def async_main():
for op_code_str in sys.argv[3].split(','):
if ':' in op_code_str:
ogf, ocf = op_code_str.split(':')
- command_short_circuits.append(hci.hci_command_op_code(int(ogf, 16), int(ocf, 16)))
+ command_short_circuits.append(
+ hci.hci_command_op_code(int(ogf, 16), int(ocf, 16))
+ )
else:
command_short_circuits.append(int(op_code_str, 16))
def host_to_controller_filter(hci_packet):
- if hci_packet.hci_packet_type == hci.HCI_COMMAND_PACKET and hci_packet.op_code in command_short_circuits:
+ if (
+ hci_packet.hci_packet_type == hci.HCI_COMMAND_PACKET
+ and hci_packet.op_code in command_short_circuits
+ ):
# Respond with a success response
logger.debug('short-circuiting packet')
response = hci.HCI_Command_Complete_Event(
- num_hci_command_packets = 1,
- command_opcode = hci_packet.op_code,
- return_parameters = bytes([hci.HCI_SUCCESS])
+ num_hci_command_packets=1,
+ command_opcode=hci_packet.op_code,
+ return_parameters=bytes([hci.HCI_SUCCESS]),
)
# Return a packet with 'respond to sender' set to True
return (response.to_bytes(), True)
+ return None
+
_ = HCI_Bridge(
hci_host_source,
hci_host_sink,
hci_controller_source,
hci_controller_sink,
host_to_controller_filter,
- None
+ None,
)
await asyncio.get_running_loop().create_future()
# -----------------------------------------------------------------------------
def main():
- logging.basicConfig(level = os.environ.get('BUMBLE_LOGLEVEL', 'INFO').upper())
+ logging.basicConfig(level=os.environ.get('BUMBLE_LOGLEVEL', 'INFO').upper())
asyncio.run(async_main())
diff --git a/apps/l2cap_bridge.py b/apps/l2cap_bridge.py
new file mode 100644
index 0000000..17623e4
--- /dev/null
+++ b/apps/l2cap_bridge.py
@@ -0,0 +1,350 @@
+# Copyright 2021-2022 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# -----------------------------------------------------------------------------
+# Imports
+# -----------------------------------------------------------------------------
+import asyncio
+import logging
+import os
+import click
+
+from bumble.colors import color
+from bumble.transport import open_transport_or_link
+from bumble.device import Device
+from bumble.utils import FlowControlAsyncPipe
+from bumble.hci import HCI_Constant
+
+
+# -----------------------------------------------------------------------------
+class ServerBridge:
+ """
+ L2CAP CoC server bridge: waits for a peer to connect an L2CAP CoC channel
+ on a specified PSM. When the connection is made, the bridge connects a TCP
+ socket to a remote host and bridges the data in both directions, with flow
+ control.
+ When the L2CAP CoC channel is closed, the bridge disconnects the TCP socket
+ and waits for a new L2CAP CoC channel to be connected.
+ When the TCP connection is closed by the TCP server, XXXX
+ """
+
+ def __init__(self, psm, max_credits, mtu, mps, tcp_host, tcp_port):
+ self.psm = psm
+ self.max_credits = max_credits
+ self.mtu = mtu
+ self.mps = mps
+ self.tcp_host = tcp_host
+ self.tcp_port = tcp_port
+
+ async def start(self, device):
+ # Listen for incoming L2CAP CoC connections
+ device.register_l2cap_channel_server(
+ psm=self.psm,
+ server=self.on_coc,
+ max_credits=self.max_credits,
+ mtu=self.mtu,
+ mps=self.mps,
+ )
+ print(color(f'### Listening for CoC connection on PSM {self.psm}', 'yellow'))
+
+ def on_ble_connection(connection):
+ def on_ble_disconnection(reason):
+ print(
+ color('@@@ Bluetooth disconnection:', 'red'),
+ HCI_Constant.error_name(reason),
+ )
+
+ print(color('@@@ Bluetooth connection:', 'green'), connection)
+ connection.on('disconnection', on_ble_disconnection)
+
+ device.on('connection', on_ble_connection)
+
+ await device.start_advertising(auto_restart=True)
+
+ # Called when a new L2CAP connection is established
+ def on_coc(self, l2cap_channel):
+ print(color('*** L2CAP channel:', 'cyan'), l2cap_channel)
+
+ class Pipe:
+ def __init__(self, bridge, l2cap_channel):
+ self.bridge = bridge
+ self.tcp_transport = None
+ self.l2cap_channel = l2cap_channel
+
+ l2cap_channel.on('close', self.on_l2cap_close)
+ l2cap_channel.sink = self.on_coc_sdu
+
+ async def connect_to_tcp(self):
+ # Connect to the TCP server
+ print(
+ color(
+ f'### Connecting to TCP {self.bridge.tcp_host}:'
+ f'{self.bridge.tcp_port}...',
+ 'yellow',
+ )
+ )
+
+ class TcpClientProtocol(asyncio.Protocol):
+ def __init__(self, pipe):
+ self.pipe = pipe
+
+ def connection_lost(self, exc):
+ print(color(f'!!! TCP connection lost: {exc}', 'red'))
+ if self.pipe.l2cap_channel is not None:
+ asyncio.create_task(self.pipe.l2cap_channel.disconnect())
+
+ def data_received(self, data):
+ print(f'<<< Received on TCP: {len(data)}')
+ self.pipe.l2cap_channel.write(data)
+
+ try:
+ (
+ self.tcp_transport,
+ _,
+ ) = await asyncio.get_running_loop().create_connection(
+ lambda: TcpClientProtocol(self),
+ host=self.bridge.tcp_host,
+ port=self.bridge.tcp_port,
+ )
+ print(color('### Connected', 'green'))
+ except Exception as error:
+ print(color(f'!!! Connection failed: {error}', 'red'))
+ await self.l2cap_channel.disconnect()
+
+ def on_l2cap_close(self):
+ self.l2cap_channel = None
+ if self.tcp_transport is not None:
+ self.tcp_transport.close()
+
+ def on_coc_sdu(self, sdu):
+ print(color(f'<<< [L2CAP SDU]: {len(sdu)} bytes', 'cyan'))
+ if self.tcp_transport is None:
+ print(color('!!! TCP socket not open, dropping', 'red'))
+ return
+ self.tcp_transport.write(sdu)
+
+ pipe = Pipe(self, l2cap_channel)
+
+ asyncio.create_task(pipe.connect_to_tcp())
+
+
+# -----------------------------------------------------------------------------
+class ClientBridge:
+ """
+ L2CAP CoC client bridge: connects to a BLE device, then waits for an inbound
+ TCP connection on a specified port number. When a TCP client connects, an
+ L2CAP CoC channel connection to the BLE device is established, and the data
+ is bridged in both directions, with flow control.
+ When the TCP connection is closed by the client, the L2CAP CoC channel is
+ disconnected, but the connection to the BLE device remains, ready for a new
+ TCP client to connect.
+ When the L2CAP CoC channel is closed, XXXX
+ """
+
+ READ_CHUNK_SIZE = 4096
+
+ def __init__(self, psm, max_credits, mtu, mps, address, tcp_host, tcp_port):
+ self.psm = psm
+ self.max_credits = max_credits
+ self.mtu = mtu
+ self.mps = mps
+ self.address = address
+ self.tcp_host = tcp_host
+ self.tcp_port = tcp_port
+
+ async def start(self, device):
+ print(color(f'### Connecting to {self.address}...', 'yellow'))
+ connection = await device.connect(self.address)
+ print(color('### Connected', 'green'))
+
+ # Called when the BLE connection is disconnected
+ def on_ble_disconnection(reason):
+ print(
+ color('@@@ Bluetooth disconnection:', 'red'),
+ HCI_Constant.error_name(reason),
+ )
+
+ connection.on('disconnection', on_ble_disconnection)
+
+ # Called when a TCP connection is established
+ async def on_tcp_connection(reader, writer):
+ peer_name = writer.get_extra_info('peer_name')
+ print(color(f'<<< TCP connection from {peer_name}', 'magenta'))
+
+ def on_coc_sdu(sdu):
+ print(color(f'<<< [L2CAP SDU]: {len(sdu)} bytes', 'cyan'))
+ l2cap_to_tcp_pipe.write(sdu)
+
+ def on_l2cap_close():
+ print(color('*** L2CAP channel closed', 'red'))
+ l2cap_to_tcp_pipe.stop()
+ writer.close()
+
+ # Connect a new L2CAP channel
+ print(color(f'>>> Opening L2CAP channel on PSM = {self.psm}', 'yellow'))
+ try:
+ l2cap_channel = await connection.open_l2cap_channel(
+ psm=self.psm,
+ max_credits=self.max_credits,
+ mtu=self.mtu,
+ mps=self.mps,
+ )
+ print(color('*** L2CAP channel:', 'cyan'), l2cap_channel)
+ except Exception as error:
+ print(color(f'!!! Connection failed: {error}', 'red'))
+ writer.close()
+ return
+
+ l2cap_channel.sink = on_coc_sdu
+ l2cap_channel.on('close', on_l2cap_close)
+
+ # Start a flow control pipe from L2CAP to TCP
+ l2cap_to_tcp_pipe = FlowControlAsyncPipe(
+ l2cap_channel.pause_reading,
+ l2cap_channel.resume_reading,
+ writer.write,
+ writer.drain,
+ )
+ l2cap_to_tcp_pipe.start()
+
+ # Pipe data from TCP to L2CAP
+ while True:
+ try:
+ data = await reader.read(self.READ_CHUNK_SIZE)
+
+ if len(data) == 0:
+ print(color('!!! End of stream', 'red'))
+ await l2cap_channel.disconnect()
+ return
+
+ print(color(f'<<< [TCP DATA]: {len(data)} bytes', 'blue'))
+ l2cap_channel.write(data)
+ await l2cap_channel.drain()
+ except Exception as error:
+ print(f'!!! Exception: {error}')
+ break
+
+ writer.close()
+ print(color('~~~ Bye bye', 'magenta'))
+
+ await asyncio.start_server(
+ on_tcp_connection,
+ host=self.tcp_host if self.tcp_host != '_' else None,
+ port=self.tcp_port,
+ )
+ print(
+ color(
+ f'### Listening for TCP connections on port {self.tcp_port}', 'magenta'
+ )
+ )
+
+
+# -----------------------------------------------------------------------------
+async def run(device_config, hci_transport, bridge):
+ print('<<< connecting to HCI...')
+ async with await open_transport_or_link(hci_transport) as (hci_source, hci_sink):
+ print('<<< connected')
+
+ device = Device.from_config_file_with_hci(device_config, hci_source, hci_sink)
+
+ # Let's go
+ await device.power_on()
+ await bridge.start(device)
+
+ # Wait until the transport terminates
+ await hci_source.wait_for_termination()
+
+
+# -----------------------------------------------------------------------------
+@click.group()
+@click.pass_context
+@click.option('--device-config', help='Device configuration file', required=True)
+@click.option('--hci-transport', help='HCI transport', required=True)
+@click.option('--psm', help='PSM for L2CAP CoC', type=int, default=1234)
+@click.option(
+ '--l2cap-coc-max-credits',
+ help='Maximum L2CAP CoC Credits',
+ type=click.IntRange(1, 65535),
+ default=128,
+)
+@click.option(
+ '--l2cap-coc-mtu',
+ help='L2CAP CoC MTU',
+ type=click.IntRange(23, 65535),
+ default=1022,
+)
+@click.option(
+ '--l2cap-coc-mps',
+ help='L2CAP CoC MPS',
+ type=click.IntRange(23, 65533),
+ default=1024,
+)
+def cli(
+ context,
+ device_config,
+ hci_transport,
+ psm,
+ l2cap_coc_max_credits,
+ l2cap_coc_mtu,
+ l2cap_coc_mps,
+):
+ context.ensure_object(dict)
+ context.obj['device_config'] = device_config
+ context.obj['hci_transport'] = hci_transport
+ context.obj['psm'] = psm
+ context.obj['max_credits'] = l2cap_coc_max_credits
+ context.obj['mtu'] = l2cap_coc_mtu
+ context.obj['mps'] = l2cap_coc_mps
+
+
+# -----------------------------------------------------------------------------
+@cli.command()
+@click.pass_context
+@click.option('--tcp-host', help='TCP host', default='localhost')
+@click.option('--tcp-port', help='TCP port', default=9544)
+def server(context, tcp_host, tcp_port):
+ bridge = ServerBridge(
+ context.obj['psm'],
+ context.obj['max_credits'],
+ context.obj['mtu'],
+ context.obj['mps'],
+ tcp_host,
+ tcp_port,
+ )
+ asyncio.run(run(context.obj['device_config'], context.obj['hci_transport'], bridge))
+
+
+# -----------------------------------------------------------------------------
+@cli.command()
+@click.pass_context
+@click.argument('bluetooth-address')
+@click.option('--tcp-host', help='TCP host', default='_')
+@click.option('--tcp-port', help='TCP port', default=9543)
+def client(context, bluetooth_address, tcp_host, tcp_port):
+ bridge = ClientBridge(
+ context.obj['psm'],
+ context.obj['max_credits'],
+ context.obj['mtu'],
+ context.obj['mps'],
+ bluetooth_address,
+ tcp_host,
+ tcp_port,
+ )
+ asyncio.run(run(context.obj['device_config'], context.obj['hci_transport'], bridge))
+
+
+# -----------------------------------------------------------------------------
+logging.basicConfig(level=os.environ.get('BUMBLE_LOGLEVEL', 'WARNING').upper())
+if __name__ == '__main__':
+ cli(obj={}) # pylint: disable=no-value-for-parameter
diff --git a/apps/link_relay/link_relay.py b/apps/link_relay/link_relay.py
index c979ea6..6036fa0 100644
--- a/apps/link_relay/link_relay.py
+++ b/apps/link_relay/link_relay.py
@@ -16,7 +16,6 @@
# Imports
# ----------------------------------------------------------------------------
import sys
-import websockets
import logging
import json
import asyncio
@@ -24,7 +23,9 @@ import argparse
import uuid
import os
from urllib.parse import urlparse
-from colors import color
+import websockets
+
+from bumble.colors import color
# -----------------------------------------------------------------------------
# Logging
@@ -65,9 +66,9 @@ class Connection:
"""
def __init__(self, room, websocket):
- self.room = room
+ self.room = room
self.websocket = websocket
- self.address = str(uuid.uuid4())
+ self.address = str(uuid.uuid4())
async def send_message(self, message):
try:
@@ -98,7 +99,11 @@ class Connection:
self.address = address
def __str__(self):
- return f'Connection(address="{self.address}", client={self.websocket.remote_address[0]}:{self.websocket.remote_address[1]})'
+ return (
+ f'Connection(address="{self.address}", '
+ f'client={self.websocket.remote_address[0]}:'
+ f'{self.websocket.remote_address[1]})'
+ )
# ----------------------------------------------------------------------------
@@ -110,9 +115,9 @@ class Room:
"""
def __init__(self, relay, name):
- self.relay = relay
- self.name = name
- self.observers = []
+ self.relay = relay
+ self.name = name
+ self.observers = []
self.connections = []
async def add_connection(self, connection):
@@ -139,13 +144,15 @@ class Room:
# Parse the message to decide how to handle it
if message.startswith('@'):
- # This is a targetted message
- await self.on_targetted_message(connection, message)
+ # This is a targeted message
+ await self.on_targeted_message(connection, message)
elif message.startswith('/'):
# This is an RPC request
await self.on_rpc_request(connection, message)
else:
- await connection.send_message(f'result:{error_to_json("error: invalid message")}')
+ await connection.send_message(
+ f'result:{error_to_json("error: invalid message")}'
+ )
async def broadcast_message(self, sender, message):
'''
@@ -155,7 +162,9 @@ class Room:
async def on_rpc_request(self, connection, message):
command, *params = message.split(' ', 1)
- if handler := getattr(self, f'on_{command[1:].lower().replace("-","_")}_command', None):
+ if handler := getattr(
+ self, f'on_{command[1:].lower().replace("-","_")}_command', None
+ ):
try:
result = await handler(connection, params)
except Exception as error:
@@ -165,7 +174,7 @@ class Room:
await connection.send_message(result or 'result:{}')
- async def on_targetted_message(self, connection, message):
+ async def on_targeted_message(self, connection, message):
target, *payload = message.split(' ', 1)
if not payload:
return error_to_json('missing arguments')
@@ -174,7 +183,8 @@ class Room:
# Determine what targets to send to
if target == '*':
- # Send to all connections in the room except the connection from which the message was received
+ # Send to all connections in the room except the connection from which the
+ # message was received
connections = [c for c in self.connections if c != connection]
else:
connections = self.find_connections_by_address(target)
@@ -192,7 +202,9 @@ class Room:
current_address = connection.address
new_address = params[0]
connection.set_address(new_address)
- await self.broadcast_message(connection, f'address-changed:from={current_address},to={new_address}')
+ await self.broadcast_message(
+ connection, f'address-changed:from={current_address},to={new_address}'
+ )
# ----------------------------------------------------------------------------
@@ -210,9 +222,10 @@ class Relay:
def start(self):
logger.info(f'Starting Relay on port {self.port}')
+ # pylint: disable-next=no-member
return websockets.serve(self.serve, '0.0.0.0', self.port, ping_interval=None)
- async def serve_as_controller(connection):
+ async def serve_as_controller(self, connection):
pass
async def serve(self, websocket, path):
@@ -246,24 +259,24 @@ def main():
print('ERROR: Python 3.6.1 or higher is required')
sys.exit(1)
- logging.basicConfig(level = os.environ.get('BUMBLE_LOGLEVEL', 'INFO').upper())
+ logging.basicConfig(level=os.environ.get('BUMBLE_LOGLEVEL', 'INFO').upper())
# Parse arguments
arg_parser = argparse.ArgumentParser(description='Bumble Link Relay')
arg_parser.add_argument('--log-level', default='INFO', help='logger level')
arg_parser.add_argument('--log-config', help='logger config file (YAML)')
- arg_parser.add_argument('--port',
- type = int,
- default = DEFAULT_RELAY_PORT,
- help = 'Port to listen on')
+ arg_parser.add_argument(
+ '--port', type=int, default=DEFAULT_RELAY_PORT, help='Port to listen on'
+ )
args = arg_parser.parse_args()
# Setup logger
if args.log_config:
- from logging import config
+ from logging import config # pylint: disable=import-outside-toplevel
+
config.fileConfig(args.log_config)
else:
- logging.basicConfig(level = getattr(logging, args.log_level.upper()))
+ logging.basicConfig(level=getattr(logging, args.log_level.upper()))
# Start a relay
relay = Relay(args.port)
diff --git a/apps/pair.py b/apps/pair.py
index 7f89629..a7844fe 100644
--- a/apps/pair.py
+++ b/apps/pair.py
@@ -19,12 +19,12 @@ import asyncio
import os
import logging
import click
-import aioconsole
-from colors import color
+from prompt_toolkit.shortcuts import PromptSession
+from bumble.colors import color
from bumble.device import Device, Peer
from bumble.transport import open_transport_or_link
-from bumble.smp import PairingDelegate, PairingConfig
+from bumble.pairing import PairingDelegate, PairingConfig
from bumble.smp import error_name as smp_error_name
from bumble.keys import JsonKeyStore
from bumble.core import ProtocolError
@@ -33,30 +33,57 @@ from bumble.gatt import (
GATT_GENERIC_ACCESS_SERVICE,
Service,
Characteristic,
- CharacteristicValue
+ CharacteristicValue,
)
from bumble.att import (
ATT_Error,
ATT_INSUFFICIENT_AUTHENTICATION_ERROR,
- ATT_INSUFFICIENT_ENCRYPTION_ERROR
+ ATT_INSUFFICIENT_ENCRYPTION_ERROR,
)
# -----------------------------------------------------------------------------
+class Waiter:
+ instance = None
+
+ def __init__(self):
+ self.done = asyncio.get_running_loop().create_future()
+
+ def terminate(self):
+ self.done.set_result(None)
+
+ async def wait_until_terminated(self):
+ return await self.done
+
+
+# -----------------------------------------------------------------------------
class Delegate(PairingDelegate):
- def __init__(self, mode, connection, capability_string, prompt):
- super().__init__({
- 'keyboard': PairingDelegate.KEYBOARD_INPUT_ONLY,
- 'display': PairingDelegate.DISPLAY_OUTPUT_ONLY,
- 'display+keyboard': PairingDelegate.DISPLAY_OUTPUT_AND_KEYBOARD_INPUT,
- 'display+yes/no': PairingDelegate.DISPLAY_OUTPUT_AND_YES_NO_INPUT,
- 'none': PairingDelegate.NO_OUTPUT_NO_INPUT
- }[capability_string.lower()])
-
- self.mode = mode
- self.peer = Peer(connection)
+ def __init__(self, mode, connection, capability_string, do_prompt):
+ super().__init__(
+ {
+ 'keyboard': PairingDelegate.KEYBOARD_INPUT_ONLY,
+ 'display': PairingDelegate.DISPLAY_OUTPUT_ONLY,
+ 'display+keyboard': PairingDelegate.DISPLAY_OUTPUT_AND_KEYBOARD_INPUT,
+ 'display+yes/no': PairingDelegate.DISPLAY_OUTPUT_AND_YES_NO_INPUT,
+ 'none': PairingDelegate.NO_OUTPUT_NO_INPUT,
+ }[capability_string.lower()]
+ )
+
+ self.mode = mode
+ self.peer = Peer(connection)
self.peer_name = None
- self.prompt = prompt
+ self.do_prompt = do_prompt
+
+ def print(self, message):
+ print(color(message, 'yellow'))
+
+ async def prompt(self, message):
+ # Wait a bit to allow some of the log lines to print before we prompt
+ await asyncio.sleep(1)
+
+ session = PromptSession(message)
+ response = await session.prompt_async()
+ return response.lower().strip()
async def update_peer_name(self):
if self.peer_name is not None:
@@ -71,87 +98,83 @@ class Delegate(PairingDelegate):
self.peer_name = '[?]'
async def accept(self):
- if self.prompt:
+ if self.do_prompt:
await self.update_peer_name()
- # Wait a bit to allow some of the log lines to print before we prompt
- await asyncio.sleep(1)
-
# Prompt for acceptance
- print(color('###-----------------------------------', 'yellow'))
- print(color(f'### Pairing request from {self.peer_name}', 'yellow'))
- print(color('###-----------------------------------', 'yellow'))
+ self.print('###-----------------------------------')
+ self.print(f'### Pairing request from {self.peer_name}')
+ self.print('###-----------------------------------')
while True:
- response = await aioconsole.ainput(color('>>> Accept? ', 'yellow'))
- response = response.lower().strip()
+ response = await self.prompt('>>> Accept? ')
+
if response == 'yes':
return True
- elif response == 'no':
+
+ if response == 'no':
return False
- else:
- # Accept silently
- return True
+
+ # Accept silently
+ return True
async def compare_numbers(self, number, digits):
await self.update_peer_name()
- # Wait a bit to allow some of the log lines to print before we prompt
- await asyncio.sleep(1)
-
# Prompt for a numeric comparison
- print(color('###-----------------------------------', 'yellow'))
- print(color(f'### Pairing with {self.peer_name}', 'yellow'))
- print(color('###-----------------------------------', 'yellow'))
+ self.print('###-----------------------------------')
+ self.print(f'### Pairing with {self.peer_name}')
+ self.print('###-----------------------------------')
while True:
- response = await aioconsole.ainput(color(f'>>> Does the other device display {number:0{digits}}? ', 'yellow'))
- response = response.lower().strip()
+ response = await self.prompt(
+ f'>>> Does the other device display {number:0{digits}}? '
+ )
+
if response == 'yes':
return True
- elif response == 'no':
+
+ if response == 'no':
return False
async def get_number(self):
await self.update_peer_name()
- # Wait a bit to allow some of the log lines to print before we prompt
- await asyncio.sleep(1)
-
# Prompt for a PIN
while True:
try:
- print(color('###-----------------------------------', 'yellow'))
- print(color(f'### Pairing with {self.peer_name}', 'yellow'))
- print(color('###-----------------------------------', 'yellow'))
- return int(await aioconsole.ainput(color('>>> Enter PIN: ', 'yellow')))
+ self.print('###-----------------------------------')
+ self.print(f'### Pairing with {self.peer_name}')
+ self.print('###-----------------------------------')
+ return int(await self.prompt('>>> Enter PIN: '))
except ValueError:
pass
async def display_number(self, number, digits):
await self.update_peer_name()
- # Wait a bit to allow some of the log lines to print before we prompt
- await asyncio.sleep(1)
-
# Display a PIN code
- print(color('###-----------------------------------', 'yellow'))
- print(color(f'### Pairing with {self.peer_name}', 'yellow'))
- print(color(f'### PIN: {number:0{digits}}', 'yellow'))
- print(color('###-----------------------------------', 'yellow'))
+ self.print('###-----------------------------------')
+ self.print(f'### Pairing with {self.peer_name}')
+ self.print(f'### PIN: {number:0{digits}}')
+ self.print('###-----------------------------------')
# -----------------------------------------------------------------------------
async def get_peer_name(peer, mode):
if mode == 'classic':
return await peer.request_name()
- else:
- # Try to get the peer name from GATT
- services = await peer.discover_service(GATT_GENERIC_ACCESS_SERVICE)
- if not services:
- return None
- values = await peer.read_characteristics_by_uuid(GATT_DEVICE_NAME_CHARACTERISTIC, services[0])
- if values:
- return values[0].decode('utf-8')
+ # Try to get the peer name from GATT
+ services = await peer.discover_service(GATT_GENERIC_ACCESS_SERVICE)
+ if not services:
+ return None
+
+ values = await peer.read_characteristics_by_uuid(
+ GATT_DEVICE_NAME_CHARACTERISTIC, services[0]
+ )
+ if values:
+ return values[0].decode('utf-8')
+
+ return None
# -----------------------------------------------------------------------------
@@ -164,12 +187,12 @@ def read_with_error(connection):
if AUTHENTICATION_ERROR_RETURNED[0]:
return bytes([1])
- else:
- AUTHENTICATION_ERROR_RETURNED[0] = True
- raise ATT_Error(ATT_INSUFFICIENT_AUTHENTICATION_ERROR)
+
+ AUTHENTICATION_ERROR_RETURNED[0] = True
+ raise ATT_Error(ATT_INSUFFICIENT_AUTHENTICATION_ERROR)
-def write_with_error(connection, value):
+def write_with_error(connection, _value):
if not connection.is_encrypted:
raise ATT_Error(ATT_INSUFFICIENT_ENCRYPTION_ERROR)
@@ -183,14 +206,14 @@ def on_connection(connection, request):
print(color(f'<<< Connection: {connection}', 'green'))
# Listen for pairing events
- connection.on('pairing_start', on_pairing_start)
- connection.on('pairing', on_pairing)
+ connection.on('pairing_start', on_pairing_start)
+ connection.on('pairing', on_pairing)
connection.on('pairing_failure', on_pairing_failure)
# Listen for encryption changes
connection.on(
'connection_encryption_change',
- lambda: on_connection_encryption_change(connection)
+ lambda: on_connection_encryption_change(connection),
)
# Request pairing if needed
@@ -202,7 +225,12 @@ def on_connection(connection, request):
# -----------------------------------------------------------------------------
def on_connection_encryption_change(connection):
print(color('@@@-----------------------------------', 'blue'))
- print(color(f'@@@ Connection is {"" if connection.is_encrypted else "not"}encrypted', 'blue'))
+ print(
+ color(
+ f'@@@ Connection is {"" if connection.is_encrypted else "not"}encrypted',
+ 'blue',
+ )
+ )
print(color('@@@-----------------------------------', 'blue'))
@@ -219,6 +247,7 @@ def on_pairing(keys):
print(color('*** Paired!', 'cyan'))
keys.print(prefix=color('*** ', 'cyan'))
print(color('***-----------------------------------', 'cyan'))
+ Waiter.instance.terminate()
# -----------------------------------------------------------------------------
@@ -226,6 +255,7 @@ def on_pairing_failure(reason):
print(color('***-----------------------------------', 'red'))
print(color(f'*** Pairing failed: {smp_error_name(reason)}', 'red'))
print(color('***-----------------------------------', 'red'))
+ Waiter.instance.terminate()
# -----------------------------------------------------------------------------
@@ -234,6 +264,7 @@ async def pair(
sc,
mitm,
bond,
+ ctkd,
io,
prompt,
request,
@@ -241,8 +272,10 @@ async def pair(
keystore_file,
device_config,
hci_transport,
- address_or_name
+ address_or_name,
):
+ Waiter.instance = Waiter()
+
print('<<< connecting to HCI...')
async with await open_transport_or_link(hci_transport) as (hci_source, hci_sink):
print('<<< connected')
@@ -270,11 +303,14 @@ async def pair(
[
Characteristic(
'552957FB-CF1F-4A31-9535-E78847E1A714',
- Characteristic.READ | Characteristic.WRITE,
+ Characteristic.Properties.READ
+ | Characteristic.Properties.WRITE,
Characteristic.READABLE | Characteristic.WRITEABLE,
- CharacteristicValue(read=read_with_error, write=write_with_error)
+ CharacteristicValue(
+ read=read_with_error, write=write_with_error
+ ),
)
- ]
+ ],
)
)
@@ -282,16 +318,14 @@ async def pair(
if mode == 'classic':
device.classic_enabled = True
device.le_enabled = False
+ device.classic_smp_enabled = ctkd
# Get things going
await device.power_on()
# Set up a pairing config factory
device.pairing_config_factory = lambda connection: PairingConfig(
- sc,
- mitm,
- bond,
- Delegate(mode, connection, io, prompt)
+ sc, mitm, bond, Delegate(mode, connection, io, prompt)
)
# Connect to a peer or wait for a connection
@@ -311,29 +345,114 @@ async def pair(
print(color(f'Pairing failed: {error}', 'red'))
return
else:
- # Advertise so that peers can find us and connect
- await device.start_advertising(auto_restart=True)
+ if mode == 'le':
+ # Advertise so that peers can find us and connect
+ await device.start_advertising(auto_restart=True)
+ else:
+ # Become discoverable and connectable
+ await device.set_discoverable(True)
+ await device.set_connectable(True)
+
+ # Run until the user asks to exit
+ await Waiter.instance.wait_until_terminated()
+
+
+# -----------------------------------------------------------------------------
+class LogHandler(logging.Handler):
+ def __init__(self):
+ super().__init__()
+ self.setFormatter(logging.Formatter('%(levelname)s:%(name)s:%(message)s'))
- await hci_source.wait_for_termination()
+ def emit(self, record):
+ message = self.format(record)
+ print(message)
# -----------------------------------------------------------------------------
@click.command()
-@click.option('--mode', type=click.Choice(['le', 'classic']), default='le', show_default=True)
-@click.option('--sc', type=bool, default=True, help='Use the Secure Connections protocol', show_default=True)
-@click.option('--mitm', type=bool, default=True, help='Request MITM protection', show_default=True)
-@click.option('--bond', type=bool, default=True, help='Enable bonding', show_default=True)
-@click.option('--io', type=click.Choice(['keyboard', 'display', 'display+keyboard', 'display+yes/no', 'none']), default='display+keyboard', show_default=True)
+@click.option(
+ '--mode', type=click.Choice(['le', 'classic']), default='le', show_default=True
+)
+@click.option(
+ '--sc',
+ type=bool,
+ default=True,
+ help='Use the Secure Connections protocol',
+ show_default=True,
+)
+@click.option(
+ '--mitm', type=bool, default=True, help='Request MITM protection', show_default=True
+)
+@click.option(
+ '--bond', type=bool, default=True, help='Enable bonding', show_default=True
+)
+@click.option(
+ '--ctkd',
+ type=bool,
+ default=True,
+ help='Enable CTKD',
+ show_default=True,
+)
+@click.option(
+ '--io',
+ type=click.Choice(
+ ['keyboard', 'display', 'display+keyboard', 'display+yes/no', 'none']
+ ),
+ default='display+keyboard',
+ show_default=True,
+)
@click.option('--prompt', is_flag=True, help='Prompt to accept/reject pairing request')
-@click.option('--request', is_flag=True, help='Request that the connecting peer initiate pairing')
+@click.option(
+ '--request', is_flag=True, help='Request that the connecting peer initiate pairing'
+)
@click.option('--print-keys', is_flag=True, help='Print the bond keys before pairing')
-@click.option('--keystore-file', help='File in which to store the pairing keys')
+@click.option(
+ '--keystore-file',
+ metavar='<filename>',
+ help='File in which to store the pairing keys',
+)
@click.argument('device-config')
@click.argument('hci_transport')
@click.argument('address-or-name', required=False)
-def main(mode, sc, mitm, bond, io, prompt, request, print_keys, keystore_file, device_config, hci_transport, address_or_name):
- logging.basicConfig(level = os.environ.get('BUMBLE_LOGLEVEL', 'INFO').upper())
- asyncio.run(pair(mode, sc, mitm, bond, io, prompt, request, print_keys, keystore_file, device_config, hci_transport, address_or_name))
+def main(
+ mode,
+ sc,
+ mitm,
+ bond,
+ ctkd,
+ io,
+ prompt,
+ request,
+ print_keys,
+ keystore_file,
+ device_config,
+ hci_transport,
+ address_or_name,
+):
+ # Setup logging
+ log_handler = LogHandler()
+ root_logger = logging.getLogger()
+ root_logger.addHandler(log_handler)
+ root_logger.setLevel(os.environ.get('BUMBLE_LOGLEVEL', 'INFO').upper())
+
+ # Pair
+ asyncio.run(
+ pair(
+ mode,
+ sc,
+ mitm,
+ bond,
+ ctkd,
+ io,
+ prompt,
+ request,
+ print_keys,
+ keystore_file,
+ device_config,
+ hci_transport,
+ address_or_name,
+ )
+ )
# -----------------------------------------------------------------------------
diff --git a/apps/pandora_server.py b/apps/pandora_server.py
new file mode 100644
index 0000000..5f92309
--- /dev/null
+++ b/apps/pandora_server.py
@@ -0,0 +1,30 @@
+import asyncio
+import click
+import logging
+
+from bumble.pandora import PandoraDevice, serve
+
+BUMBLE_SERVER_GRPC_PORT = 7999
+ROOTCANAL_PORT_CUTTLEFISH = 7300
+
+
+@click.command()
+@click.option('--grpc-port', help='gRPC port to serve', default=BUMBLE_SERVER_GRPC_PORT)
+@click.option(
+ '--rootcanal-port', help='Rootcanal TCP port', default=ROOTCANAL_PORT_CUTTLEFISH
+)
+@click.option(
+ '--transport',
+ help='HCI transport',
+ default=f'tcp-client:127.0.0.1:<rootcanal-port>',
+)
+def main(grpc_port: int, rootcanal_port: int, transport: str) -> None:
+ if '<rootcanal-port>' in transport:
+ transport = transport.replace('<rootcanal-port>', str(rootcanal_port))
+ device = PandoraDevice({'transport': transport})
+ logging.basicConfig(level=logging.DEBUG)
+ asyncio.run(serve(device, port=grpc_port))
+
+
+if __name__ == '__main__':
+ main() # pylint: disable=no-value-for-parameter
diff --git a/apps/scan.py b/apps/scan.py
index 045cb57..dac7a2c 100644
--- a/apps/scan.py
+++ b/apps/scan.py
@@ -19,20 +19,20 @@ import asyncio
import os
import logging
import click
-from colors import color
+from bumble.colors import color
from bumble.device import Device
from bumble.transport import open_transport_or_link
from bumble.keys import JsonKeyStore
from bumble.smp import AddressResolver
-from bumble.hci import HCI_LE_Advertising_Report_Event
-from bumble.core import AdvertisingData
+from bumble.device import Advertisement
+from bumble.hci import HCI_Constant, HCI_LE_1M_PHY, HCI_LE_CODED_PHY
# -----------------------------------------------------------------------------
def make_rssi_bar(rssi):
- DISPLAY_MIN_RSSI = -105
- DISPLAY_MAX_RSSI = -30
+ DISPLAY_MIN_RSSI = -105
+ DISPLAY_MAX_RSSI = -30
DEFAULT_RSSI_BAR_WIDTH = 30
blocks = ['', 'â–', 'â–Ž', 'â–', 'â–Œ', 'â–‹', 'â–Š', 'â–‰']
@@ -48,19 +48,24 @@ class AdvertisementPrinter:
self.min_rssi = min_rssi
self.resolver = resolver
- def print_advertisement(self, address, address_color, ad_data, rssi):
- if self.min_rssi is not None and rssi < self.min_rssi:
+ def print_advertisement(self, advertisement):
+ address = advertisement.address
+ address_color = 'yellow' if advertisement.is_connectable else 'red'
+
+ if self.min_rssi is not None and advertisement.rssi < self.min_rssi:
return
address_qualifier = ''
resolution_qualifier = ''
- if self.resolver and address.is_resolvable:
- resolved = self.resolver.resolve(address)
+ if self.resolver and advertisement.address.is_resolvable:
+ resolved = self.resolver.resolve(advertisement.address)
if resolved is not None:
- resolution_qualifier = f'(resolved from {address})'
+ resolution_qualifier = f'(resolved from {advertisement.address})'
address = resolved
- address_type_string = ('PUBLIC', 'RANDOM', 'PUBLIC_ID', 'RANDOM_ID')[address.address_type]
+ address_type_string = ('PUBLIC', 'RANDOM', 'PUBLIC_ID', 'RANDOM_ID')[
+ address.address_type
+ ]
if address.is_public:
type_color = 'cyan'
else:
@@ -74,18 +79,32 @@ class AdvertisementPrinter:
type_color = 'blue'
address_qualifier = '(non-resolvable)'
- rssi_bar = make_rssi_bar(rssi)
separator = '\n '
- print(f'>>> {color(address, address_color)} [{color(address_type_string, type_color)}]{address_qualifier}{resolution_qualifier}:{separator}RSSI:{rssi:4} {rssi_bar}{separator}{ad_data.to_string(separator)}\n')
+ rssi_bar = make_rssi_bar(advertisement.rssi)
+ if not advertisement.is_legacy:
+ phy_info = (
+ f'PHY: {HCI_Constant.le_phy_name(advertisement.primary_phy)}/'
+ f'{HCI_Constant.le_phy_name(advertisement.secondary_phy)} '
+ f'{separator}'
+ )
+ else:
+ phy_info = ''
+
+ print(
+ f'>>> {color(address, address_color)} '
+ f'[{color(address_type_string, type_color)}]{address_qualifier}'
+ f'{resolution_qualifier}:{separator}'
+ f'{phy_info}'
+ f'RSSI:{advertisement.rssi:4} {rssi_bar}{separator}'
+ f'{advertisement.data.to_string(separator)}\n'
+ )
- def on_advertisement(self, address, ad_data, rssi, connectable):
- address_color = 'yellow' if connectable else 'red'
- self.print_advertisement(address, address_color, ad_data, rssi)
+ def on_advertisement(self, advertisement):
+ self.print_advertisement(advertisement)
- def on_advertising_report(self, address, ad_data, rssi, event_type):
- print(f'{color("EVENT", "green")}: {HCI_LE_Advertising_Report_Event.event_type_name(event_type)}')
- ad_data = AdvertisingData.from_bytes(ad_data)
- self.print_advertisement(address, 'yellow', ad_data, rssi)
+ def on_advertising_report(self, report):
+ print(f'{color("EVENT", "green")}: {report.event_type_string()}')
+ self.print_advertisement(Advertisement.from_advertising_report(report))
# -----------------------------------------------------------------------------
@@ -94,20 +113,25 @@ async def scan(
passive,
scan_interval,
scan_window,
+ phy,
filter_duplicates,
raw,
keystore_file,
device_config,
- transport
+ transport,
):
print('<<< connecting to HCI...')
async with await open_transport_or_link(transport) as (hci_source, hci_sink):
print('<<< connected')
if device_config:
- device = Device.from_config_file_with_hci(device_config, hci_source, hci_sink)
+ device = Device.from_config_file_with_hci(
+ device_config, hci_source, hci_sink
+ )
else:
- device = Device.with_hci('Bumble', 'F0:F1:F2:F3:F4:F5', hci_source, hci_sink)
+ device = Device.with_hci(
+ 'Bumble', 'F0:F1:F2:F3:F4:F5', hci_source, hci_sink
+ )
if keystore_file:
keystore = JsonKeyStore(namespace=None, filename=keystore_file)
@@ -126,11 +150,18 @@ async def scan(
device.on('advertisement', printer.on_advertisement)
await device.power_on()
+
+ if phy is None:
+ scanning_phys = [HCI_LE_1M_PHY, HCI_LE_CODED_PHY]
+ else:
+ scanning_phys = [{'1m': HCI_LE_1M_PHY, 'coded': HCI_LE_CODED_PHY}[phy]]
+
await device.start_scanning(
active=(not passive),
scan_interval=scan_interval,
scan_window=scan_window,
- filter_duplicates=filter_duplicates
+ filter_duplicates=filter_duplicates,
+ scanning_phys=scanning_phys,
)
await hci_source.wait_for_termination()
@@ -142,14 +173,51 @@ async def scan(
@click.option('--passive', is_flag=True, default=False, help='Perform passive scanning')
@click.option('--scan-interval', type=int, default=60, help='Scan interval')
@click.option('--scan-window', type=int, default=60, help='Scan window')
-@click.option('--filter-duplicates', type=bool, default=True, help='Filter duplicates at the controller level')
-@click.option('--raw', is_flag=True, default=False, help='Listen for raw advertising reports instead of processed ones')
+@click.option(
+ '--phy', type=click.Choice(['1m', 'coded']), help='Only scan on the specified PHY'
+)
+@click.option(
+ '--filter-duplicates',
+ type=bool,
+ default=True,
+ help='Filter duplicates at the controller level',
+)
+@click.option(
+ '--raw',
+ is_flag=True,
+ default=False,
+ help='Listen for raw advertising reports instead of processed ones',
+)
@click.option('--keystore-file', help='Keystore file to use when resolving addresses')
@click.option('--device-config', help='Device config file for the scanning device')
@click.argument('transport')
-def main(min_rssi, passive, scan_interval, scan_window, filter_duplicates, raw, keystore_file, device_config, transport):
- logging.basicConfig(level = os.environ.get('BUMBLE_LOGLEVEL', 'WARNING').upper())
- asyncio.run(scan(min_rssi, passive, scan_interval, scan_window, filter_duplicates, raw, keystore_file, device_config, transport))
+def main(
+ min_rssi,
+ passive,
+ scan_interval,
+ scan_window,
+ phy,
+ filter_duplicates,
+ raw,
+ keystore_file,
+ device_config,
+ transport,
+):
+ logging.basicConfig(level=os.environ.get('BUMBLE_LOGLEVEL', 'WARNING').upper())
+ asyncio.run(
+ scan(
+ min_rssi,
+ passive,
+ scan_interval,
+ scan_window,
+ phy,
+ filter_duplicates,
+ raw,
+ keystore_file,
+ device_config,
+ transport,
+ )
+ )
# -----------------------------------------------------------------------------
diff --git a/apps/show.py b/apps/show.py
index bba6c66..bf01ead 100644
--- a/apps/show.py
+++ b/apps/show.py
@@ -17,8 +17,8 @@
# -----------------------------------------------------------------------------
import struct
import click
-from colors import color
+from bumble.colors import color
from bumble import hci
from bumble.transport.common import PacketReader
from bumble.helpers import PacketTracer
@@ -27,13 +27,14 @@ from bumble.helpers import PacketTracer
# -----------------------------------------------------------------------------
class SnoopPacketReader:
'''
- Reader that reads HCI packets from a "snoop" file (based on RFC 1761, but not exactly the same...)
+ Reader that reads HCI packets from a "snoop" file (based on RFC 1761, but not
+ exactly the same...)
'''
- DATALINK_H1 = 1001
- DATALINK_H4 = 1002
+ DATALINK_H1 = 1001
+ DATALINK_H4 = 1002
DATALINK_BSCP = 1003
- DATALINK_H5 = 1004
+ DATALINK_H5 = 1004
def __init__(self, source):
self.source = source
@@ -41,9 +42,13 @@ class SnoopPacketReader:
# Read the header
identification_pattern = source.read(8)
if identification_pattern.hex().lower() != '6274736e6f6f7000':
- raise ValueError('not a valid snoop file, unexpected identification pattern')
- (self.version_number, self.data_link_type) = struct.unpack('>II', source.read(8))
- if self.data_link_type != self.DATALINK_H4 and self.data_link_type != self.DATALINK_H1:
+ raise ValueError(
+ 'not a valid snoop file, unexpected identification pattern'
+ )
+ (self.version_number, self.data_link_type) = struct.unpack(
+ '>II', source.read(8)
+ )
+ if self.data_link_type not in (self.DATALINK_H4, self.DATALINK_H1):
raise ValueError(f'datalink type {self.data_link_type} not supported')
def next_packet(self):
@@ -55,9 +60,9 @@ class SnoopPacketReader:
original_length,
included_length,
packet_flags,
- cumulative_drops,
- timestamp_seconds,
- timestamp_microsecond
+ _cumulative_drops,
+ _timestamp_seconds,
+ _timestamp_microsecond,
) = struct.unpack('>IIIIII', header)
# Abort on truncated packets
@@ -79,24 +84,34 @@ class SnoopPacketReader:
else:
packet_type = hci.HCI_ACL_DATA_PACKET
- return (packet_flags & 1, bytes([packet_type]) + self.source.read(included_length))
- else:
- return (packet_flags & 1, self.source.read(included_length))
+ return (
+ packet_flags & 1,
+ bytes([packet_type]) + self.source.read(included_length),
+ )
+
+ return (packet_flags & 1, self.source.read(included_length))
# -----------------------------------------------------------------------------
# Main
# -----------------------------------------------------------------------------
@click.command()
-@click.option('--format', type=click.Choice(['h4', 'snoop']), default='h4', help='Format of the input file')
+@click.option(
+ '--format',
+ type=click.Choice(['h4', 'snoop']),
+ default='h4',
+ help='Format of the input file',
+)
@click.argument('filename')
-def show(format, filename):
+# pylint: disable=redefined-builtin
+def main(format, filename):
input = open(filename, 'rb')
if format == 'h4':
packet_reader = PacketReader(input)
def read_next_packet():
- (0, packet_reader.next_packet())
+ return (0, packet_reader.next_packet())
+
else:
packet_reader = SnoopPacketReader(input)
read_next_packet = packet_reader.next_packet
@@ -112,9 +127,8 @@ def show(format, filename):
except Exception as error:
print(color(f'!!! {error}', 'red'))
- pass
# -----------------------------------------------------------------------------
if __name__ == '__main__':
- show()
+ main() # pylint: disable=no-value-for-parameter
diff --git a/apps/unbond.py b/apps/unbond.py
index cf1877c..105d9a4 100644
--- a/apps/unbond.py
+++ b/apps/unbond.py
@@ -54,7 +54,7 @@ async def unbond(keystore_file, device_config, address):
@click.argument('device-config')
@click.argument('address', required=False)
def main(keystore_file, device_config, address):
- logging.basicConfig(level = os.environ.get('BUMBLE_LOGLEVEL', 'INFO').upper())
+ logging.basicConfig(level=os.environ.get('BUMBLE_LOGLEVEL', 'INFO').upper())
asyncio.run(unbond(keystore_file, device_config, address))
diff --git a/apps/usb_probe.py b/apps/usb_probe.py
new file mode 100644
index 0000000..785b0dd
--- /dev/null
+++ b/apps/usb_probe.py
@@ -0,0 +1,278 @@
+# Copyright 2021-2022 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# -----------------------------------------------------------------------------
+# This tool lists all the USB devices, with details about each device.
+# For each device, the different possible Bumble transport strings that can
+# refer to it are listed. If the device is known to be a Bluetooth HCI device,
+# its identifier is printed in reverse colors, and the transport names in cyan color.
+# For other devices, regardless of their type, the transport names are printed
+# in red. Whether that device is actually a Bluetooth device or not depends on
+# whether it is a Bluetooth device that uses a non-standard Class, or some other
+# type of device (there's no way to tell).
+# -----------------------------------------------------------------------------
+
+# -----------------------------------------------------------------------------
+# Imports
+# -----------------------------------------------------------------------------
+import os
+import logging
+import click
+import usb1
+
+from bumble.colors import color
+from bumble.transport.usb import load_libusb
+
+
+# -----------------------------------------------------------------------------
+# Constants
+# -----------------------------------------------------------------------------
+USB_DEVICE_CLASS_DEVICE = 0x00
+USB_DEVICE_CLASS_WIRELESS_CONTROLLER = 0xE0
+USB_DEVICE_SUBCLASS_RF_CONTROLLER = 0x01
+USB_DEVICE_PROTOCOL_BLUETOOTH_PRIMARY_CONTROLLER = 0x01
+
+USB_DEVICE_CLASSES = {
+ 0x00: 'Device',
+ 0x01: 'Audio',
+ 0x02: 'Communications and CDC Control',
+ 0x03: 'Human Interface Device',
+ 0x05: 'Physical',
+ 0x06: 'Still Imaging',
+ 0x07: 'Printer',
+ 0x08: 'Mass Storage',
+ 0x09: 'Hub',
+ 0x0A: 'CDC Data',
+ 0x0B: 'Smart Card',
+ 0x0D: 'Content Security',
+ 0x0E: 'Video',
+ 0x0F: 'Personal Healthcare',
+ 0x10: 'Audio/Video',
+ 0x11: 'Billboard',
+ 0x12: 'USB Type-C Bridge',
+ 0x3C: 'I3C',
+ 0xDC: 'Diagnostic',
+ USB_DEVICE_CLASS_WIRELESS_CONTROLLER: (
+ 'Wireless Controller',
+ {
+ 0x01: {
+ 0x01: 'Bluetooth',
+ 0x02: 'UWB',
+ 0x03: 'Remote NDIS',
+ 0x04: 'Bluetooth AMP',
+ }
+ },
+ ),
+ 0xEF: 'Miscellaneous',
+ 0xFE: 'Application Specific',
+ 0xFF: 'Vendor Specific',
+}
+
+USB_ENDPOINT_IN = 0x80
+USB_ENDPOINT_TYPES = ['CONTROL', 'ISOCHRONOUS', 'BULK', 'INTERRUPT']
+
+USB_BT_HCI_CLASS_TUPLE = (
+ USB_DEVICE_CLASS_WIRELESS_CONTROLLER,
+ USB_DEVICE_SUBCLASS_RF_CONTROLLER,
+ USB_DEVICE_PROTOCOL_BLUETOOTH_PRIMARY_CONTROLLER,
+)
+
+
+# -----------------------------------------------------------------------------
+def show_device_details(device):
+ for configuration in device:
+ print(f' Configuration {configuration.getConfigurationValue()}')
+ for interface in configuration:
+ for setting in interface:
+ alternate_setting = setting.getAlternateSetting()
+ suffix = (
+ f'/{alternate_setting}' if interface.getNumSettings() > 1 else ''
+ )
+ (class_string, subclass_string) = get_class_info(
+ setting.getClass(), setting.getSubClass(), setting.getProtocol()
+ )
+ details = f'({class_string}, {subclass_string})'
+ print(f' Interface: {setting.getNumber()}{suffix} {details}')
+ for endpoint in setting:
+ endpoint_type = USB_ENDPOINT_TYPES[endpoint.getAttributes() & 3]
+ endpoint_direction = (
+ 'OUT'
+ if (endpoint.getAddress() & USB_ENDPOINT_IN == 0)
+ else 'IN'
+ )
+ print(
+ f' Endpoint 0x{endpoint.getAddress():02X}: '
+ f'{endpoint_type} {endpoint_direction}'
+ )
+
+
+# -----------------------------------------------------------------------------
+def get_class_info(cls, subclass, protocol):
+ class_info = USB_DEVICE_CLASSES.get(cls)
+ protocol_string = ''
+ if class_info is None:
+ class_string = f'0x{cls:02X}'
+ else:
+ if isinstance(class_info, tuple):
+ class_string = class_info[0]
+ subclass_info = class_info[1].get(subclass)
+ if subclass_info:
+ protocol_string = subclass_info.get(protocol)
+ if protocol_string is not None:
+ protocol_string = f' [{protocol_string}]'
+
+ else:
+ class_string = class_info
+
+ subclass_string = f'{subclass}/{protocol}{protocol_string}'
+
+ return (class_string, subclass_string)
+
+
+# -----------------------------------------------------------------------------
+def is_bluetooth_hci(device):
+ # Check if the device class indicates a match
+ if (
+ device.getDeviceClass(),
+ device.getDeviceSubClass(),
+ device.getDeviceProtocol(),
+ ) == USB_BT_HCI_CLASS_TUPLE:
+ return True
+
+ # If the device class is 'Device', look for a matching interface
+ if device.getDeviceClass() == USB_DEVICE_CLASS_DEVICE:
+ for configuration in device:
+ for interface in configuration:
+ for setting in interface:
+ if (
+ setting.getClass(),
+ setting.getSubClass(),
+ setting.getProtocol(),
+ ) == USB_BT_HCI_CLASS_TUPLE:
+ return True
+
+ return False
+
+
+# -----------------------------------------------------------------------------
+@click.command()
+@click.option('--verbose', is_flag=True, default=False, help='Print more details')
+def main(verbose):
+ logging.basicConfig(level=os.environ.get('BUMBLE_LOGLEVEL', 'WARNING').upper())
+
+ load_libusb()
+ with usb1.USBContext() as context:
+ bluetooth_device_count = 0
+ devices = {}
+
+ for device in context.getDeviceIterator(skip_on_error=True):
+ device_class = device.getDeviceClass()
+ device_subclass = device.getDeviceSubClass()
+ device_protocol = device.getDeviceProtocol()
+
+ device_id = (device.getVendorID(), device.getProductID())
+
+ (device_class_string, device_subclass_string) = get_class_info(
+ device_class, device_subclass, device_protocol
+ )
+
+ try:
+ device_serial_number = device.getSerialNumber()
+ except usb1.USBError:
+ device_serial_number = None
+
+ try:
+ device_manufacturer = device.getManufacturer()
+ except usb1.USBError:
+ device_manufacturer = None
+
+ try:
+ device_product = device.getProduct()
+ except usb1.USBError:
+ device_product = None
+
+ device_is_bluetooth_hci = is_bluetooth_hci(device)
+ if device_is_bluetooth_hci:
+ bluetooth_device_count += 1
+ fg_color = 'black'
+ bg_color = 'yellow'
+ else:
+ fg_color = 'yellow'
+ bg_color = 'black'
+
+ # Compute the different ways this can be referenced as a Bumble transport
+ bumble_transport_names = []
+ basic_transport_name = (
+ f'usb:{device.getVendorID():04X}:{device.getProductID():04X}'
+ )
+
+ if device_is_bluetooth_hci:
+ bumble_transport_names.append(f'usb:{bluetooth_device_count - 1}')
+
+ if device_id not in devices:
+ bumble_transport_names.append(basic_transport_name)
+ else:
+ bumble_transport_names.append(
+ f'{basic_transport_name}#{len(devices[device_id])}'
+ )
+
+ if device_serial_number is not None:
+ if (
+ device_id not in devices
+ or device_serial_number not in devices[device_id]
+ ):
+ bumble_transport_names.append(
+ f'{basic_transport_name}/{device_serial_number}'
+ )
+
+ # Print the results
+ print(
+ color(
+ f'ID {device.getVendorID():04X}:{device.getProductID():04X}',
+ fg=fg_color,
+ bg=bg_color,
+ )
+ )
+ if bumble_transport_names:
+ print(
+ color(' Bumble Transport Names:', 'blue'),
+ ' or '.join(
+ color(x, 'cyan' if device_is_bluetooth_hci else 'red')
+ for x in bumble_transport_names
+ ),
+ )
+ print(
+ color(' Bus/Device: ', 'green'),
+ f'{device.getBusNumber():03}/{device.getDeviceAddress():03}',
+ )
+ print(color(' Class: ', 'green'), device_class_string)
+ print(color(' Subclass/Protocol: ', 'green'), device_subclass_string)
+ if device_serial_number is not None:
+ print(color(' Serial: ', 'green'), device_serial_number)
+ if device_manufacturer is not None:
+ print(color(' Manufacturer: ', 'green'), device_manufacturer)
+ if device_product is not None:
+ print(color(' Product: ', 'green'), device_product)
+
+ if verbose:
+ show_device_details(device)
+
+ print()
+
+ devices.setdefault(device_id, []).append(device_serial_number)
+
+
+# -----------------------------------------------------------------------------
+if __name__ == '__main__':
+ main() # pylint: disable=no-value-for-parameter
diff --git a/bumble/__init__.py b/bumble/__init__.py
index e69de29..8a067ca 100644
--- a/bumble/__init__.py
+++ b/bumble/__init__.py
@@ -0,0 +1,4 @@
+try:
+ from ._version import version as __version__
+except ImportError:
+ __version__ = "unknown version"
diff --git a/bumble/a2dp.py b/bumble/a2dp.py
index 03c3fd2..772846a 100644
--- a/bumble/a2dp.py
+++ b/bumble/a2dp.py
@@ -16,10 +16,8 @@
# Imports
# -----------------------------------------------------------------------------
import struct
-import bitstruct
import logging
from collections import namedtuple
-from colors import color
from .company_ids import COMPANY_IDENTIFIERS
from .sdp import (
@@ -30,7 +28,7 @@ from .sdp import (
SDP_SERVICE_RECORD_HANDLE_ATTRIBUTE_ID,
SDP_SERVICE_CLASS_ID_LIST_ATTRIBUTE_ID,
SDP_PROTOCOL_DESCRIPTOR_LIST_ATTRIBUTE_ID,
- SDP_BLUETOOTH_PROFILE_DESCRIPTOR_LIST_ATTRIBUTE_ID
+ SDP_BLUETOOTH_PROFILE_DESCRIPTOR_LIST_ATTRIBUTE_ID,
)
from .core import (
BT_L2CAP_PROTOCOL_ID,
@@ -38,7 +36,7 @@ from .core import (
BT_AUDIO_SINK_SERVICE,
BT_AVDTP_PROTOCOL_ID,
BT_ADVANCED_AUDIO_DISTRIBUTION_SERVICE,
- name_or_number
+ name_or_number,
)
@@ -51,6 +49,7 @@ logger = logging.getLogger(__name__)
# -----------------------------------------------------------------------------
# Constants
# -----------------------------------------------------------------------------
+# fmt: off
A2DP_SBC_CODEC_TYPE = 0x00
A2DP_MPEG_1_2_AUDIO_CODEC_TYPE = 0x01
@@ -127,71 +126,115 @@ MPEG_2_4_OBJECT_TYPE_NAMES = {
MPEG_4_AAC_SCALABLE_OBJECT_TYPE: 'MPEG_4_AAC_SCALABLE_OBJECT_TYPE'
}
+# fmt: on
+
# -----------------------------------------------------------------------------
def flags_to_list(flags, values):
result = []
- for i in range(len(values)):
+ for i, value in enumerate(values):
if flags & (1 << (len(values) - i - 1)):
- result.append(values[i])
+ result.append(value)
return result
# -----------------------------------------------------------------------------
def make_audio_source_service_sdp_records(service_record_handle, version=(1, 3)):
+ # pylint: disable=import-outside-toplevel
from .avdtp import AVDTP_PSM
+
version_int = version[0] << 8 | version[1]
return [
- ServiceAttribute(SDP_SERVICE_RECORD_HANDLE_ATTRIBUTE_ID, DataElement.unsigned_integer_32(service_record_handle)),
- ServiceAttribute(SDP_BROWSE_GROUP_LIST_ATTRIBUTE_ID, DataElement.sequence([
- DataElement.uuid(SDP_PUBLIC_BROWSE_ROOT)
- ])),
- ServiceAttribute(SDP_SERVICE_CLASS_ID_LIST_ATTRIBUTE_ID, DataElement.sequence([
- DataElement.uuid(BT_AUDIO_SOURCE_SERVICE)
- ])),
- ServiceAttribute(SDP_PROTOCOL_DESCRIPTOR_LIST_ATTRIBUTE_ID, DataElement.sequence([
- DataElement.sequence([
- DataElement.uuid(BT_L2CAP_PROTOCOL_ID),
- DataElement.unsigned_integer_16(AVDTP_PSM)
- ]),
- DataElement.sequence([
- DataElement.uuid(BT_AVDTP_PROTOCOL_ID),
- DataElement.unsigned_integer_16(version_int)
- ])
- ])),
- ServiceAttribute(SDP_BLUETOOTH_PROFILE_DESCRIPTOR_LIST_ATTRIBUTE_ID, DataElement.sequence([
- DataElement.uuid(BT_ADVANCED_AUDIO_DISTRIBUTION_SERVICE),
- DataElement.unsigned_integer_16(version_int)
- ])),
+ ServiceAttribute(
+ SDP_SERVICE_RECORD_HANDLE_ATTRIBUTE_ID,
+ DataElement.unsigned_integer_32(service_record_handle),
+ ),
+ ServiceAttribute(
+ SDP_BROWSE_GROUP_LIST_ATTRIBUTE_ID,
+ DataElement.sequence([DataElement.uuid(SDP_PUBLIC_BROWSE_ROOT)]),
+ ),
+ ServiceAttribute(
+ SDP_SERVICE_CLASS_ID_LIST_ATTRIBUTE_ID,
+ DataElement.sequence([DataElement.uuid(BT_AUDIO_SOURCE_SERVICE)]),
+ ),
+ ServiceAttribute(
+ SDP_PROTOCOL_DESCRIPTOR_LIST_ATTRIBUTE_ID,
+ DataElement.sequence(
+ [
+ DataElement.sequence(
+ [
+ DataElement.uuid(BT_L2CAP_PROTOCOL_ID),
+ DataElement.unsigned_integer_16(AVDTP_PSM),
+ ]
+ ),
+ DataElement.sequence(
+ [
+ DataElement.uuid(BT_AVDTP_PROTOCOL_ID),
+ DataElement.unsigned_integer_16(version_int),
+ ]
+ ),
+ ]
+ ),
+ ),
+ ServiceAttribute(
+ SDP_BLUETOOTH_PROFILE_DESCRIPTOR_LIST_ATTRIBUTE_ID,
+ DataElement.sequence(
+ [
+ DataElement.uuid(BT_ADVANCED_AUDIO_DISTRIBUTION_SERVICE),
+ DataElement.unsigned_integer_16(version_int),
+ ]
+ ),
+ ),
]
# -----------------------------------------------------------------------------
def make_audio_sink_service_sdp_records(service_record_handle, version=(1, 3)):
+ # pylint: disable=import-outside-toplevel
from .avdtp import AVDTP_PSM
+
version_int = version[0] << 8 | version[1]
return [
- ServiceAttribute(SDP_SERVICE_RECORD_HANDLE_ATTRIBUTE_ID, DataElement.unsigned_integer_32(service_record_handle)),
- ServiceAttribute(SDP_BROWSE_GROUP_LIST_ATTRIBUTE_ID, DataElement.sequence([
- DataElement.uuid(SDP_PUBLIC_BROWSE_ROOT)
- ])),
- ServiceAttribute(SDP_SERVICE_CLASS_ID_LIST_ATTRIBUTE_ID, DataElement.sequence([
- DataElement.uuid(BT_AUDIO_SINK_SERVICE)
- ])),
- ServiceAttribute(SDP_PROTOCOL_DESCRIPTOR_LIST_ATTRIBUTE_ID, DataElement.sequence([
- DataElement.sequence([
- DataElement.uuid(BT_L2CAP_PROTOCOL_ID),
- DataElement.unsigned_integer_16(AVDTP_PSM)
- ]),
- DataElement.sequence([
- DataElement.uuid(BT_AVDTP_PROTOCOL_ID),
- DataElement.unsigned_integer_16(version_int)
- ])
- ])),
- ServiceAttribute(SDP_BLUETOOTH_PROFILE_DESCRIPTOR_LIST_ATTRIBUTE_ID, DataElement.sequence([
- DataElement.uuid(BT_ADVANCED_AUDIO_DISTRIBUTION_SERVICE),
- DataElement.unsigned_integer_16(version_int)
- ])),
+ ServiceAttribute(
+ SDP_SERVICE_RECORD_HANDLE_ATTRIBUTE_ID,
+ DataElement.unsigned_integer_32(service_record_handle),
+ ),
+ ServiceAttribute(
+ SDP_BROWSE_GROUP_LIST_ATTRIBUTE_ID,
+ DataElement.sequence([DataElement.uuid(SDP_PUBLIC_BROWSE_ROOT)]),
+ ),
+ ServiceAttribute(
+ SDP_SERVICE_CLASS_ID_LIST_ATTRIBUTE_ID,
+ DataElement.sequence([DataElement.uuid(BT_AUDIO_SINK_SERVICE)]),
+ ),
+ ServiceAttribute(
+ SDP_PROTOCOL_DESCRIPTOR_LIST_ATTRIBUTE_ID,
+ DataElement.sequence(
+ [
+ DataElement.sequence(
+ [
+ DataElement.uuid(BT_L2CAP_PROTOCOL_ID),
+ DataElement.unsigned_integer_16(AVDTP_PSM),
+ ]
+ ),
+ DataElement.sequence(
+ [
+ DataElement.uuid(BT_AVDTP_PROTOCOL_ID),
+ DataElement.unsigned_integer_16(version_int),
+ ]
+ ),
+ ]
+ ),
+ ),
+ ServiceAttribute(
+ SDP_BLUETOOTH_PROFILE_DESCRIPTOR_LIST_ATTRIBUTE_ID,
+ DataElement.sequence(
+ [
+ DataElement.uuid(BT_ADVANCED_AUDIO_DISTRIBUTION_SERVICE),
+ DataElement.unsigned_integer_16(version_int),
+ ]
+ ),
+ ),
]
@@ -206,45 +249,46 @@ class SbcMediaCodecInformation(
'subbands',
'allocation_method',
'minimum_bitpool_value',
- 'maximum_bitpool_value'
- ]
+ 'maximum_bitpool_value',
+ ],
)
):
'''
A2DP spec - 4.3.2 Codec Specific Information Elements
'''
- BIT_FIELDS = 'u4u4u4u2u2u8u8'
- SAMPLING_FREQUENCY_BITS = {
- 16000: 1 << 3,
- 32000: 1 << 2,
- 44100: 1 << 1,
- 48000: 1
- }
+ SAMPLING_FREQUENCY_BITS = {16000: 1 << 3, 32000: 1 << 2, 44100: 1 << 1, 48000: 1}
CHANNEL_MODE_BITS = {
- SBC_MONO_CHANNEL_MODE: 1 << 3,
- SBC_DUAL_CHANNEL_MODE: 1 << 2,
- SBC_STEREO_CHANNEL_MODE: 1 << 1,
- SBC_JOINT_STEREO_CHANNEL_MODE: 1
- }
- BLOCK_LENGTH_BITS = {
- 4: 1 << 3,
- 8: 1 << 2,
- 12: 1 << 1,
- 16: 1
- }
- SUBBANDS_BITS = {
- 4: 1 << 1,
- 8: 1
+ SBC_MONO_CHANNEL_MODE: 1 << 3,
+ SBC_DUAL_CHANNEL_MODE: 1 << 2,
+ SBC_STEREO_CHANNEL_MODE: 1 << 1,
+ SBC_JOINT_STEREO_CHANNEL_MODE: 1,
}
+ BLOCK_LENGTH_BITS = {4: 1 << 3, 8: 1 << 2, 12: 1 << 1, 16: 1}
+ SUBBANDS_BITS = {4: 1 << 1, 8: 1}
ALLOCATION_METHOD_BITS = {
- SBC_SNR_ALLOCATION_METHOD: 1 << 1,
- SBC_LOUDNESS_ALLOCATION_METHOD: 1
+ SBC_SNR_ALLOCATION_METHOD: 1 << 1,
+ SBC_LOUDNESS_ALLOCATION_METHOD: 1,
}
@staticmethod
- def from_bytes(data):
- return SbcMediaCodecInformation(*bitstruct.unpack(SbcMediaCodecInformation.BIT_FIELDS, data))
+ def from_bytes(data: bytes) -> 'SbcMediaCodecInformation':
+ sampling_frequency = (data[0] >> 4) & 0x0F
+ channel_mode = (data[0] >> 0) & 0x0F
+ block_length = (data[1] >> 4) & 0x0F
+ subbands = (data[1] >> 2) & 0x03
+ allocation_method = (data[1] >> 0) & 0x03
+ minimum_bitpool_value = (data[2] >> 0) & 0xFF
+ maximum_bitpool_value = (data[3] >> 0) & 0xFF
+ return SbcMediaCodecInformation(
+ sampling_frequency,
+ channel_mode,
+ block_length,
+ subbands,
+ allocation_method,
+ minimum_bitpool_value,
+ maximum_bitpool_value,
+ )
@classmethod
def from_discrete_values(
@@ -255,16 +299,16 @@ class SbcMediaCodecInformation(
subbands,
allocation_method,
minimum_bitpool_value,
- maximum_bitpool_value
+ maximum_bitpool_value,
):
return SbcMediaCodecInformation(
- sampling_frequency = cls.SAMPLING_FREQUENCY_BITS[sampling_frequency],
- channel_mode = cls.CHANNEL_MODE_BITS[channel_mode],
- block_length = cls.BLOCK_LENGTH_BITS[block_length],
- subbands = cls.SUBBANDS_BITS[subbands],
- allocation_method = cls.ALLOCATION_METHOD_BITS[allocation_method],
- minimum_bitpool_value = minimum_bitpool_value,
- maximum_bitpool_value = maximum_bitpool_value
+ sampling_frequency=cls.SAMPLING_FREQUENCY_BITS[sampling_frequency],
+ channel_mode=cls.CHANNEL_MODE_BITS[channel_mode],
+ block_length=cls.BLOCK_LENGTH_BITS[block_length],
+ subbands=cls.SUBBANDS_BITS[subbands],
+ allocation_method=cls.ALLOCATION_METHOD_BITS[allocation_method],
+ minimum_bitpool_value=minimum_bitpool_value,
+ maximum_bitpool_value=maximum_bitpool_value,
)
@classmethod
@@ -276,63 +320,71 @@ class SbcMediaCodecInformation(
subbands,
allocation_methods,
minimum_bitpool_value,
- maximum_bitpool_value
+ maximum_bitpool_value,
):
return SbcMediaCodecInformation(
- sampling_frequency = sum(cls.SAMPLING_FREQUENCY_BITS[x] for x in sampling_frequencies),
- channel_mode = sum(cls.CHANNEL_MODE_BITS[x] for x in channel_modes),
- block_length = sum(cls.BLOCK_LENGTH_BITS[x] for x in block_lengths),
- subbands = sum(cls.SUBBANDS_BITS[x] for x in subbands),
- allocation_method = sum(cls.ALLOCATION_METHOD_BITS[x] for x in allocation_methods),
- minimum_bitpool_value = minimum_bitpool_value,
- maximum_bitpool_value = maximum_bitpool_value
+ sampling_frequency=sum(
+ cls.SAMPLING_FREQUENCY_BITS[x] for x in sampling_frequencies
+ ),
+ channel_mode=sum(cls.CHANNEL_MODE_BITS[x] for x in channel_modes),
+ block_length=sum(cls.BLOCK_LENGTH_BITS[x] for x in block_lengths),
+ subbands=sum(cls.SUBBANDS_BITS[x] for x in subbands),
+ allocation_method=sum(
+ cls.ALLOCATION_METHOD_BITS[x] for x in allocation_methods
+ ),
+ minimum_bitpool_value=minimum_bitpool_value,
+ maximum_bitpool_value=maximum_bitpool_value,
)
- def __bytes__(self):
- return bitstruct.pack(self.BIT_FIELDS, *self)
+ def __bytes__(self) -> bytes:
+ return bytes(
+ [
+ (self.sampling_frequency << 4) | self.channel_mode,
+ (self.block_length << 4)
+ | (self.subbands << 2)
+ | self.allocation_method,
+ self.minimum_bitpool_value,
+ self.maximum_bitpool_value,
+ ]
+ )
def __str__(self):
channel_modes = ['MONO', 'DUAL_CHANNEL', 'STEREO', 'JOINT_STEREO']
allocation_methods = ['SNR', 'Loudness']
- return '\n'.join([
- 'SbcMediaCodecInformation(',
- f' sampling_frequency: {",".join([str(x) for x in flags_to_list(self.sampling_frequency, SBC_SAMPLING_FREQUENCIES)])}',
- f' channel_mode: {",".join([str(x) for x in flags_to_list(self.channel_mode, channel_modes)])}',
- f' block_length: {",".join([str(x) for x in flags_to_list(self.block_length, SBC_BLOCK_LENGTHS)])}',
- f' subbands: {",".join([str(x) for x in flags_to_list(self.subbands, SBC_SUBBANDS)])}',
- f' allocation_method: {",".join([str(x) for x in flags_to_list(self.allocation_method, allocation_methods)])}',
- f' minimum_bitpool_value: {self.minimum_bitpool_value}',
- f' maximum_bitpool_value: {self.maximum_bitpool_value}'
- ')'
- ])
+ return '\n'.join(
+ # pylint: disable=line-too-long
+ [
+ 'SbcMediaCodecInformation(',
+ f' sampling_frequency: {",".join([str(x) for x in flags_to_list(self.sampling_frequency, SBC_SAMPLING_FREQUENCIES)])}',
+ f' channel_mode: {",".join([str(x) for x in flags_to_list(self.channel_mode, channel_modes)])}',
+ f' block_length: {",".join([str(x) for x in flags_to_list(self.block_length, SBC_BLOCK_LENGTHS)])}',
+ f' subbands: {",".join([str(x) for x in flags_to_list(self.subbands, SBC_SUBBANDS)])}',
+ f' allocation_method: {",".join([str(x) for x in flags_to_list(self.allocation_method, allocation_methods)])}',
+ f' minimum_bitpool_value: {self.minimum_bitpool_value}',
+ f' maximum_bitpool_value: {self.maximum_bitpool_value}' ')',
+ ]
+ )
# -----------------------------------------------------------------------------
class AacMediaCodecInformation(
namedtuple(
'AacMediaCodecInformation',
- [
- 'object_type',
- 'sampling_frequency',
- 'channels',
- 'vbr',
- 'bitrate'
- ]
+ ['object_type', 'sampling_frequency', 'channels', 'rfa', 'vbr', 'bitrate'],
)
):
'''
A2DP spec - 4.5.2 Codec Specific Information Elements
'''
- BIT_FIELDS = 'u8u12u2p2u1u23'
OBJECT_TYPE_BITS = {
- MPEG_2_AAC_LC_OBJECT_TYPE: 1 << 7,
- MPEG_4_AAC_LC_OBJECT_TYPE: 1 << 6,
- MPEG_4_AAC_LTP_OBJECT_TYPE: 1 << 5,
- MPEG_4_AAC_SCALABLE_OBJECT_TYPE: 1 << 4
+ MPEG_2_AAC_LC_OBJECT_TYPE: 1 << 7,
+ MPEG_4_AAC_LC_OBJECT_TYPE: 1 << 6,
+ MPEG_4_AAC_LTP_OBJECT_TYPE: 1 << 5,
+ MPEG_4_AAC_SCALABLE_OBJECT_TYPE: 1 << 4,
}
SAMPLING_FREQUENCY_BITS = {
- 8000: 1 << 11,
+ 8000: 1 << 11,
11025: 1 << 10,
12000: 1 << 9,
16000: 1 << 8,
@@ -343,66 +395,82 @@ class AacMediaCodecInformation(
48000: 1 << 3,
64000: 1 << 2,
88200: 1 << 1,
- 96000: 1
- }
- CHANNELS_BITS = {
- 1: 1 << 1,
- 2: 1
+ 96000: 1,
}
+ CHANNELS_BITS = {1: 1 << 1, 2: 1}
@staticmethod
- def from_bytes(data):
- return AacMediaCodecInformation(*bitstruct.unpack(AacMediaCodecInformation.BIT_FIELDS, data))
+ def from_bytes(data: bytes) -> 'AacMediaCodecInformation':
+ object_type = data[0]
+ sampling_frequency = (data[1] << 4) | ((data[2] >> 4) & 0x0F)
+ channels = (data[2] >> 2) & 0x03
+ rfa = 0
+ vbr = (data[3] >> 7) & 0x01
+ bitrate = ((data[3] & 0x7F) << 16) | (data[4] << 8) | data[5]
+ return AacMediaCodecInformation(
+ object_type, sampling_frequency, channels, rfa, vbr, bitrate
+ )
@classmethod
def from_discrete_values(
- cls,
- object_type,
- sampling_frequency,
- channels,
- vbr,
- bitrate
+ cls, object_type, sampling_frequency, channels, vbr, bitrate
):
return AacMediaCodecInformation(
- object_type = cls.OBJECT_TYPE_BITS[object_type],
- sampling_frequency = cls.SAMPLING_FREQUENCY_BITS[sampling_frequency],
- channels = cls.CHANNELS_BITS[channels],
- vbr = vbr,
- bitrate = bitrate
+ object_type=cls.OBJECT_TYPE_BITS[object_type],
+ sampling_frequency=cls.SAMPLING_FREQUENCY_BITS[sampling_frequency],
+ channels=cls.CHANNELS_BITS[channels],
+ rfa=0,
+ vbr=vbr,
+ bitrate=bitrate,
)
@classmethod
- def from_lists(
- cls,
- object_types,
- sampling_frequencies,
- channels,
- vbr,
- bitrate
- ):
+ def from_lists(cls, object_types, sampling_frequencies, channels, vbr, bitrate):
return AacMediaCodecInformation(
- object_type = sum(cls.OBJECT_TYPE_BITS[x] for x in object_types),
- sampling_frequency = sum(cls.SAMPLING_FREQUENCY_BITS[x] for x in sampling_frequencies),
- channels = sum(cls.CHANNELS_BITS[x] for x in channels),
- vbr = vbr,
- bitrate = bitrate
+ object_type=sum(cls.OBJECT_TYPE_BITS[x] for x in object_types),
+ sampling_frequency=sum(
+ cls.SAMPLING_FREQUENCY_BITS[x] for x in sampling_frequencies
+ ),
+ channels=sum(cls.CHANNELS_BITS[x] for x in channels),
+ vbr=vbr,
+ bitrate=bitrate,
)
- def __bytes__(self):
- return bitstruct.pack(self.BIT_FIELDS, *self)
+ def __bytes__(self) -> bytes:
+ return bytes(
+ [
+ self.object_type & 0xFF,
+ (self.sampling_frequency >> 4) & 0xFF,
+ (((self.sampling_frequency & 0x0F) << 4) | (self.channels << 2)) & 0xFF,
+ ((self.vbr << 7) | ((self.bitrate >> 16) & 0x7F)) & 0xFF,
+ ((self.bitrate >> 8) & 0xFF) & 0xFF,
+ self.bitrate & 0xFF,
+ ]
+ )
def __str__(self):
- object_types = ['MPEG_2_AAC_LC', 'MPEG_4_AAC_LC', 'MPEG_4_AAC_LTP', 'MPEG_4_AAC_SCALABLE', '[4]', '[5]', '[6]', '[7]']
+ object_types = [
+ 'MPEG_2_AAC_LC',
+ 'MPEG_4_AAC_LC',
+ 'MPEG_4_AAC_LTP',
+ 'MPEG_4_AAC_SCALABLE',
+ '[4]',
+ '[5]',
+ '[6]',
+ '[7]',
+ ]
channels = [1, 2]
- return '\n'.join([
- 'AacMediaCodecInformation(',
- f' object_type: {",".join([str(x) for x in flags_to_list(self.object_type, object_types)])}',
- f' sampling_frequency: {",".join([str(x) for x in flags_to_list(self.sampling_frequency, MPEG_2_4_AAC_SAMPLING_FREQUENCIES)])}',
- f' channels: {",".join([str(x) for x in flags_to_list(self.channels, channels)])}',
- f' vbr: {self.vbr}',
- f' bitrate: {self.bitrate}'
- ')'
- ])
+ # pylint: disable=line-too-long
+ return '\n'.join(
+ [
+ 'AacMediaCodecInformation(',
+ f' object_type: {",".join([str(x) for x in flags_to_list(self.object_type, object_types)])}',
+ f' sampling_frequency: {",".join([str(x) for x in flags_to_list(self.sampling_frequency, MPEG_2_4_AAC_SAMPLING_FREQUENCIES)])}',
+ f' channels: {",".join([str(x) for x in flags_to_list(self.channels, channels)])}',
+ f' vbr: {self.vbr}',
+ f' bitrate: {self.bitrate}' ')',
+ ]
+ )
# -----------------------------------------------------------------------------
@@ -418,37 +486,34 @@ class VendorSpecificMediaCodecInformation:
def __init__(self, vendor_id, codec_id, value):
self.vendor_id = vendor_id
- self.codec_id = codec_id
- self.value = value
+ self.codec_id = codec_id
+ self.value = value
def __bytes__(self):
return struct.pack('<IH', self.vendor_id, self.codec_id, self.value)
def __str__(self):
- return '\n'.join([
- 'VendorSpecificMediaCodecInformation(',
- f' vendor_id: {self.vendor_id:08X} ({name_or_number(COMPANY_IDENTIFIERS, self.vendor_id & 0xFFFF)})',
- f' codec_id: {self.codec_id:04X}',
- f' value: {self.value.hex()}'
- ')'
- ])
+ # pylint: disable=line-too-long
+ return '\n'.join(
+ [
+ 'VendorSpecificMediaCodecInformation(',
+ f' vendor_id: {self.vendor_id:08X} ({name_or_number(COMPANY_IDENTIFIERS, self.vendor_id & 0xFFFF)})',
+ f' codec_id: {self.codec_id:04X}',
+ f' value: {self.value.hex()}' ')',
+ ]
+ )
# -----------------------------------------------------------------------------
class SbcFrame:
def __init__(
- self,
- sampling_frequency,
- block_count,
- channel_mode,
- subband_count,
- payload
+ self, sampling_frequency, block_count, channel_mode, subband_count, payload
):
self.sampling_frequency = sampling_frequency
- self.block_count = block_count
- self.channel_mode = channel_mode
- self.subband_count = subband_count
- self.payload = payload
+ self.block_count = block_count
+ self.channel_mode = channel_mode
+ self.subband_count = subband_count
+ self.payload = payload
@property
def sample_count(self):
@@ -463,7 +528,13 @@ class SbcFrame:
return self.sample_count / self.sampling_frequency
def __str__(self):
- return f'SBC(sf={self.sampling_frequency},cm={self.channel_mode},br={self.bitrate},sc={self.sample_count},size={len(self.payload)})'
+ return (
+ f'SBC(sf={self.sampling_frequency},'
+ f'cm={self.channel_mode},'
+ f'br={self.bitrate},'
+ f'sc={self.sample_count},'
+ f'size={len(self.payload)})'
+ )
# -----------------------------------------------------------------------------
@@ -487,24 +558,30 @@ class SbcParser:
# Extract some of the header fields
sampling_frequency = SBC_SAMPLING_FREQUENCIES[(header[1] >> 6) & 3]
- blocks = 4 * (1 + ((header[1] >> 4) & 3))
- channel_mode = (header[1] >> 2) & 3
- channels = 1 if channel_mode == SBC_MONO_CHANNEL_MODE else 2
- subbands = 8 if ((header[1]) & 1) else 4
- bitpool = header[2]
+ blocks = 4 * (1 + ((header[1] >> 4) & 3))
+ channel_mode = (header[1] >> 2) & 3
+ channels = 1 if channel_mode == SBC_MONO_CHANNEL_MODE else 2
+ subbands = 8 if ((header[1]) & 1) else 4
+ bitpool = header[2]
# Compute the frame length
frame_length = 4 + (4 * subbands * channels) // 8
if channel_mode in (SBC_MONO_CHANNEL_MODE, SBC_DUAL_CHANNEL_MODE):
frame_length += (blocks * channels * bitpool) // 8
else:
- frame_length += ((1 if channel_mode == SBC_JOINT_STEREO_CHANNEL_MODE else 0) * subbands + blocks * bitpool) // 8
+ frame_length += (
+ (1 if channel_mode == SBC_JOINT_STEREO_CHANNEL_MODE else 0)
+ * subbands
+ + blocks * bitpool
+ ) // 8
# Read the rest of the frame
payload = header + await self.read(frame_length - 4)
# Emit the next frame
- yield SbcFrame(sampling_frequency, blocks, channel_mode, subbands, payload)
+ yield SbcFrame(
+ sampling_frequency, blocks, channel_mode, subbands, payload
+ )
return generate_frames()
@@ -512,19 +589,20 @@ class SbcParser:
# -----------------------------------------------------------------------------
class SbcPacketSource:
def __init__(self, read, mtu, codec_capabilities):
- self.read = read
- self.mtu = mtu
+ self.read = read
+ self.mtu = mtu
self.codec_capabilities = codec_capabilities
@property
def packets(self):
async def generate_packets():
+ # pylint: disable=import-outside-toplevel
from .avdtp import MediaPacket # Import here to avoid a circular reference
sequence_number = 0
- timestamp = 0
- frames = []
- frames_size = 0
+ timestamp = 0
+ frames = []
+ frames_size = 0
max_rtp_payload = self.mtu - 12 - 1
# NOTE: this doesn't support frame fragments
@@ -532,18 +610,25 @@ class SbcPacketSource:
async for frame in sbc_parser.frames:
print(frame)
- if frames_size + len(frame.payload) > max_rtp_payload or len(frames) == 16:
+ if (
+ frames_size + len(frame.payload) > max_rtp_payload
+ or len(frames) == 16
+ ):
# Need to flush what has been accumulated so far
# Emit a packet
- sbc_payload = bytes([len(frames)]) + b''.join([frame.payload for frame in frames])
- packet = MediaPacket(2, 0, 0, 0, sequence_number, timestamp, 0, [], 96, sbc_payload)
+ sbc_payload = bytes([len(frames)]) + b''.join(
+ [frame.payload for frame in frames]
+ )
+ packet = MediaPacket(
+ 2, 0, 0, 0, sequence_number, timestamp, 0, [], 96, sbc_payload
+ )
packet.timestamp_seconds = timestamp / frame.sampling_frequency
yield packet
# Prepare for next packets
sequence_number += 1
- timestamp += sum([frame.sample_count for frame in frames])
+ timestamp += sum((frame.sample_count for frame in frames))
frames = [frame]
frames_size = len(frame.payload)
else:
diff --git a/bumble/att.py b/bumble/att.py
index 22b683e..55ae8a5 100644
--- a/bumble/att.py
+++ b/bumble/att.py
@@ -22,15 +22,25 @@
# -----------------------------------------------------------------------------
# Imports
# -----------------------------------------------------------------------------
-from colors import color
+from __future__ import annotations
+import functools
+import struct
from pyee import EventEmitter
+from typing import Dict, Type, TYPE_CHECKING
-from .core import *
-from .hci import *
+from bumble.core import UUID, name_or_number, get_dict_key_by_value, ProtocolError
+from bumble.hci import HCI_Object, key_with_value, HCI_Constant
+from bumble.colors import color
+
+if TYPE_CHECKING:
+ from bumble.device import Connection
# -----------------------------------------------------------------------------
# Constants
# -----------------------------------------------------------------------------
+# fmt: off
+# pylint: disable=line-too-long
+
ATT_CID = 0x04
ATT_ERROR_RESPONSE = 0x01
@@ -163,30 +173,30 @@ ATT_ERROR_NAMES = {
ATT_DEFAULT_MTU = 23
HANDLE_FIELD_SPEC = {'size': 2, 'mapper': lambda x: f'0x{x:04X}'}
-UUID_2_16_FIELD_SPEC = lambda x, y: UUID.parse_uuid(x, y) # noqa: E731
+# pylint: disable-next=unnecessary-lambda-assignment,unnecessary-lambda
+UUID_2_16_FIELD_SPEC = lambda x, y: UUID.parse_uuid(x, y)
+# pylint: disable-next=unnecessary-lambda-assignment,unnecessary-lambda
UUID_2_FIELD_SPEC = lambda x, y: UUID.parse_uuid_2(x, y) # noqa: E731
-
-# -----------------------------------------------------------------------------
-# Utils
-# -----------------------------------------------------------------------------
-def key_with_value(dictionary, target_value):
- for key, value in dictionary.items():
- if value == target_value:
- return key
- return None
-
+# fmt: on
+# pylint: enable=line-too-long
+# pylint: disable=invalid-name
# -----------------------------------------------------------------------------
# Exceptions
# -----------------------------------------------------------------------------
-class ATT_Error(Exception):
- def __init__(self, error_code, att_handle=0x0000):
- self.error_code = error_code
+class ATT_Error(ProtocolError):
+ def __init__(self, error_code, att_handle=0x0000, message=''):
+ super().__init__(
+ error_code,
+ error_namespace='att',
+ error_name=ATT_PDU.error_name(error_code),
+ )
self.att_handle = att_handle
+ self.message = message
def __str__(self):
- return f'ATT_Error({ATT_PDU.error_name(self.error_code)})'
+ return f'ATT_Error(error={self.error_name}, handle={self.att_handle:04X}): {self.message}'
# -----------------------------------------------------------------------------
@@ -196,8 +206,10 @@ class ATT_PDU:
'''
See Bluetooth spec @ Vol 3, Part F - 3.3 ATTRIBUTE PDU
'''
- pdu_classes = {}
+
+ pdu_classes: Dict[int, Type[ATT_PDU]] = {}
op_code = 0
+ name = None
@staticmethod
def from_bytes(pdu):
@@ -274,11 +286,13 @@ class ATT_PDU:
# -----------------------------------------------------------------------------
-@ATT_PDU.subclass([
- ('request_opcode_in_error', {'size': 1, 'mapper': ATT_PDU.pdu_name}),
- ('attribute_handle_in_error', HANDLE_FIELD_SPEC),
- ('error_code', {'size': 1, 'mapper': ATT_PDU.error_name})
-])
+@ATT_PDU.subclass(
+ [
+ ('request_opcode_in_error', {'size': 1, 'mapper': ATT_PDU.pdu_name}),
+ ('attribute_handle_in_error', HANDLE_FIELD_SPEC),
+ ('error_code', {'size': 1, 'mapper': ATT_PDU.error_name}),
+ ]
+)
class ATT_Error_Response(ATT_PDU):
'''
See Bluetooth spec @ Vol 3, Part F - 3.4.1.1 Error Response
@@ -286,9 +300,7 @@ class ATT_Error_Response(ATT_PDU):
# -----------------------------------------------------------------------------
-@ATT_PDU.subclass([
- ('client_rx_mtu', 2)
-])
+@ATT_PDU.subclass([('client_rx_mtu', 2)])
class ATT_Exchange_MTU_Request(ATT_PDU):
'''
See Bluetooth spec @ Vol 3, Part F - 3.4.2.1 Exchange MTU Request
@@ -296,9 +308,7 @@ class ATT_Exchange_MTU_Request(ATT_PDU):
# -----------------------------------------------------------------------------
-@ATT_PDU.subclass([
- ('server_rx_mtu', 2)
-])
+@ATT_PDU.subclass([('server_rx_mtu', 2)])
class ATT_Exchange_MTU_Response(ATT_PDU):
'''
See Bluetooth spec @ Vol 3, Part F - 3.4.2.2 Exchange MTU Response
@@ -306,10 +316,9 @@ class ATT_Exchange_MTU_Response(ATT_PDU):
# -----------------------------------------------------------------------------
-@ATT_PDU.subclass([
- ('starting_handle', HANDLE_FIELD_SPEC),
- ('ending_handle', HANDLE_FIELD_SPEC)
-])
+@ATT_PDU.subclass(
+ [('starting_handle', HANDLE_FIELD_SPEC), ('ending_handle', HANDLE_FIELD_SPEC)]
+)
class ATT_Find_Information_Request(ATT_PDU):
'''
See Bluetooth spec @ Vol 3, Part F - 3.4.3.1 Find Information Request
@@ -317,10 +326,7 @@ class ATT_Find_Information_Request(ATT_PDU):
# -----------------------------------------------------------------------------
-@ATT_PDU.subclass([
- ('format', 1),
- ('information_data', '*')
-])
+@ATT_PDU.subclass([('format', 1), ('information_data', '*')])
class ATT_Find_Information_Response(ATT_PDU):
'''
See Bluetooth spec @ Vol 3, Part F - 3.4.3.2 Find Information Response
@@ -332,7 +338,7 @@ class ATT_Find_Information_Response(ATT_PDU):
uuid_size = 2 if self.format == 1 else 16
while offset + uuid_size <= len(self.information_data):
handle = struct.unpack_from('<H', self.information_data, offset)[0]
- uuid = self.information_data[2 + offset:2 + offset + uuid_size]
+ uuid = self.information_data[2 + offset : 2 + offset + uuid_size]
self.information.append((handle, uuid))
offset += 2 + uuid_size
@@ -346,20 +352,33 @@ class ATT_Find_Information_Response(ATT_PDU):
def __str__(self):
result = color(self.name, 'yellow')
- result += ':\n' + HCI_Object.format_fields(self.__dict__, [
- ('format', 1),
- ('information', {'mapper': lambda x: ', '.join([f'0x{handle:04X}:{uuid.hex()}' for handle, uuid in x])})
- ], ' ')
+ result += ':\n' + HCI_Object.format_fields(
+ self.__dict__,
+ [
+ ('format', 1),
+ (
+ 'information',
+ {
+ 'mapper': lambda x: ', '.join(
+ [f'0x{handle:04X}:{uuid.hex()}' for handle, uuid in x]
+ )
+ },
+ ),
+ ],
+ ' ',
+ )
return result
# -----------------------------------------------------------------------------
-@ATT_PDU.subclass([
- ('starting_handle', HANDLE_FIELD_SPEC),
- ('ending_handle', HANDLE_FIELD_SPEC),
- ('attribute_type', UUID_2_FIELD_SPEC),
- ('attribute_value', '*')
-])
+@ATT_PDU.subclass(
+ [
+ ('starting_handle', HANDLE_FIELD_SPEC),
+ ('ending_handle', HANDLE_FIELD_SPEC),
+ ('attribute_type', UUID_2_FIELD_SPEC),
+ ('attribute_value', '*'),
+ ]
+)
class ATT_Find_By_Type_Value_Request(ATT_PDU):
'''
See Bluetooth spec @ Vol 3, Part F - 3.4.3.3 Find By Type Value Request
@@ -367,9 +386,7 @@ class ATT_Find_By_Type_Value_Request(ATT_PDU):
# -----------------------------------------------------------------------------
-@ATT_PDU.subclass([
- ('handles_information_list', '*')
-])
+@ATT_PDU.subclass([('handles_information_list', '*')])
class ATT_Find_By_Type_Value_Response(ATT_PDU):
'''
See Bluetooth spec @ Vol 3, Part F - 3.4.3.4 Find By Type Value Response
@@ -379,7 +396,9 @@ class ATT_Find_By_Type_Value_Response(ATT_PDU):
self.handles_information = []
offset = 0
while offset + 4 <= len(self.handles_information_list):
- found_attribute_handle, group_end_handle = struct.unpack_from('<HH', self.handles_information_list, offset)
+ found_attribute_handle, group_end_handle = struct.unpack_from(
+ '<HH', self.handles_information_list, offset
+ )
self.handles_information.append((found_attribute_handle, group_end_handle))
offset += 4
@@ -393,18 +412,34 @@ class ATT_Find_By_Type_Value_Response(ATT_PDU):
def __str__(self):
result = color(self.name, 'yellow')
- result += ':\n' + HCI_Object.format_fields(self.__dict__, [
- ('handles_information', {'mapper': lambda x: ', '.join([f'0x{handle1:04X}-0x{handle2:04X}' for handle1, handle2 in x])})
- ], ' ')
+ result += ':\n' + HCI_Object.format_fields(
+ self.__dict__,
+ [
+ (
+ 'handles_information',
+ {
+ 'mapper': lambda x: ', '.join(
+ [
+ f'0x{handle1:04X}-0x{handle2:04X}'
+ for handle1, handle2 in x
+ ]
+ )
+ },
+ )
+ ],
+ ' ',
+ )
return result
# -----------------------------------------------------------------------------
-@ATT_PDU.subclass([
- ('starting_handle', HANDLE_FIELD_SPEC),
- ('ending_handle', HANDLE_FIELD_SPEC),
- ('attribute_type', UUID_2_16_FIELD_SPEC)
-])
+@ATT_PDU.subclass(
+ [
+ ('starting_handle', HANDLE_FIELD_SPEC),
+ ('ending_handle', HANDLE_FIELD_SPEC),
+ ('attribute_type', UUID_2_16_FIELD_SPEC),
+ ]
+)
class ATT_Read_By_Type_Request(ATT_PDU):
'''
See Bluetooth spec @ Vol 3, Part F - 3.4.4.1 Read By Type Request
@@ -412,10 +447,7 @@ class ATT_Read_By_Type_Request(ATT_PDU):
# -----------------------------------------------------------------------------
-@ATT_PDU.subclass([
- ('length', 1),
- ('attribute_data_list', '*')
-])
+@ATT_PDU.subclass([('length', 1), ('attribute_data_list', '*')])
class ATT_Read_By_Type_Response(ATT_PDU):
'''
See Bluetooth spec @ Vol 3, Part F - 3.4.4.2 Read By Type Response
@@ -424,9 +456,15 @@ class ATT_Read_By_Type_Response(ATT_PDU):
def parse_attribute_data_list(self):
self.attributes = []
offset = 0
- while self.length != 0 and offset + self.length <= len(self.attribute_data_list):
- attribute_handle, = struct.unpack_from('<H', self.attribute_data_list, offset)
- attribute_value = self.attribute_data_list[offset + 2:offset + self.length]
+ while self.length != 0 and offset + self.length <= len(
+ self.attribute_data_list
+ ):
+ (attribute_handle,) = struct.unpack_from(
+ '<H', self.attribute_data_list, offset
+ )
+ attribute_value = self.attribute_data_list[
+ offset + 2 : offset + self.length
+ ]
self.attributes.append((attribute_handle, attribute_value))
offset += self.length
@@ -440,17 +478,26 @@ class ATT_Read_By_Type_Response(ATT_PDU):
def __str__(self):
result = color(self.name, 'yellow')
- result += ':\n' + HCI_Object.format_fields(self.__dict__, [
- ('length', 1),
- ('attributes', {'mapper': lambda x: ', '.join([f'0x{handle:04X}:{value.hex()}' for handle, value in x])})
- ], ' ')
+ result += ':\n' + HCI_Object.format_fields(
+ self.__dict__,
+ [
+ ('length', 1),
+ (
+ 'attributes',
+ {
+ 'mapper': lambda x: ', '.join(
+ [f'0x{handle:04X}:{value.hex()}' for handle, value in x]
+ )
+ },
+ ),
+ ],
+ ' ',
+ )
return result
# -----------------------------------------------------------------------------
-@ATT_PDU.subclass([
- ('attribute_handle', HANDLE_FIELD_SPEC)
-])
+@ATT_PDU.subclass([('attribute_handle', HANDLE_FIELD_SPEC)])
class ATT_Read_Request(ATT_PDU):
'''
See Bluetooth spec @ Vol 3, Part F - 3.4.4.3 Read Request
@@ -458,9 +505,7 @@ class ATT_Read_Request(ATT_PDU):
# -----------------------------------------------------------------------------
-@ATT_PDU.subclass([
- ('attribute_value', '*')
-])
+@ATT_PDU.subclass([('attribute_value', '*')])
class ATT_Read_Response(ATT_PDU):
'''
See Bluetooth spec @ Vol 3, Part F - 3.4.4.4 Read Response
@@ -468,10 +513,7 @@ class ATT_Read_Response(ATT_PDU):
# -----------------------------------------------------------------------------
-@ATT_PDU.subclass([
- ('attribute_handle', HANDLE_FIELD_SPEC),
- ('value_offset', 2)
-])
+@ATT_PDU.subclass([('attribute_handle', HANDLE_FIELD_SPEC), ('value_offset', 2)])
class ATT_Read_Blob_Request(ATT_PDU):
'''
See Bluetooth spec @ Vol 3, Part F - 3.4.4.5 Read Blob Request
@@ -479,9 +521,7 @@ class ATT_Read_Blob_Request(ATT_PDU):
# -----------------------------------------------------------------------------
-@ATT_PDU.subclass([
- ('part_attribute_value', '*')
-])
+@ATT_PDU.subclass([('part_attribute_value', '*')])
class ATT_Read_Blob_Response(ATT_PDU):
'''
See Bluetooth spec @ Vol 3, Part F - 3.4.4.6 Read Blob Response
@@ -489,9 +529,7 @@ class ATT_Read_Blob_Response(ATT_PDU):
# -----------------------------------------------------------------------------
-@ATT_PDU.subclass([
- ('set_of_handles', '*')
-])
+@ATT_PDU.subclass([('set_of_handles', '*')])
class ATT_Read_Multiple_Request(ATT_PDU):
'''
See Bluetooth spec @ Vol 3, Part F - 3.4.4.7 Read Multiple Request
@@ -499,9 +537,7 @@ class ATT_Read_Multiple_Request(ATT_PDU):
# -----------------------------------------------------------------------------
-@ATT_PDU.subclass([
- ('set_of_values', '*')
-])
+@ATT_PDU.subclass([('set_of_values', '*')])
class ATT_Read_Multiple_Response(ATT_PDU):
'''
See Bluetooth spec @ Vol 3, Part F - 3.4.4.8 Read Multiple Response
@@ -509,11 +545,13 @@ class ATT_Read_Multiple_Response(ATT_PDU):
# -----------------------------------------------------------------------------
-@ATT_PDU.subclass([
- ('starting_handle', HANDLE_FIELD_SPEC),
- ('ending_handle', HANDLE_FIELD_SPEC),
- ('attribute_group_type', UUID_2_16_FIELD_SPEC)
-])
+@ATT_PDU.subclass(
+ [
+ ('starting_handle', HANDLE_FIELD_SPEC),
+ ('ending_handle', HANDLE_FIELD_SPEC),
+ ('attribute_group_type', UUID_2_16_FIELD_SPEC),
+ ]
+)
class ATT_Read_By_Group_Type_Request(ATT_PDU):
'''
See Bluetooth spec @ Vol 3, Part F - 3.4.4.9 Read by Group Type Request
@@ -521,10 +559,7 @@ class ATT_Read_By_Group_Type_Request(ATT_PDU):
# -----------------------------------------------------------------------------
-@ATT_PDU.subclass([
- ('length', 1),
- ('attribute_data_list', '*')
-])
+@ATT_PDU.subclass([('length', 1), ('attribute_data_list', '*')])
class ATT_Read_By_Group_Type_Response(ATT_PDU):
'''
See Bluetooth spec @ Vol 3, Part F - 3.4.4.10 Read by Group Type Response
@@ -533,10 +568,18 @@ class ATT_Read_By_Group_Type_Response(ATT_PDU):
def parse_attribute_data_list(self):
self.attributes = []
offset = 0
- while self.length != 0 and offset + self.length <= len(self.attribute_data_list):
- attribute_handle, end_group_handle = struct.unpack_from('<HH', self.attribute_data_list, offset)
- attribute_value = self.attribute_data_list[offset + 4:offset + self.length]
- self.attributes.append((attribute_handle, end_group_handle, attribute_value))
+ while self.length != 0 and offset + self.length <= len(
+ self.attribute_data_list
+ ):
+ attribute_handle, end_group_handle = struct.unpack_from(
+ '<HH', self.attribute_data_list, offset
+ )
+ attribute_value = self.attribute_data_list[
+ offset + 4 : offset + self.length
+ ]
+ self.attributes.append(
+ (attribute_handle, end_group_handle, attribute_value)
+ )
offset += self.length
def __init__(self, *args, **kwargs):
@@ -549,18 +592,29 @@ class ATT_Read_By_Group_Type_Response(ATT_PDU):
def __str__(self):
result = color(self.name, 'yellow')
- result += ':\n' + HCI_Object.format_fields(self.__dict__, [
- ('length', 1),
- ('attributes', {'mapper': lambda x: ', '.join([f'0x{handle:04X}-0x{end:04X}:{value.hex()}' for handle, end, value in x])})
- ], ' ')
+ result += ':\n' + HCI_Object.format_fields(
+ self.__dict__,
+ [
+ ('length', 1),
+ (
+ 'attributes',
+ {
+ 'mapper': lambda x: ', '.join(
+ [
+ f'0x{handle:04X}-0x{end:04X}:{value.hex()}'
+ for handle, end, value in x
+ ]
+ )
+ },
+ ),
+ ],
+ ' ',
+ )
return result
# -----------------------------------------------------------------------------
-@ATT_PDU.subclass([
- ('attribute_handle', HANDLE_FIELD_SPEC),
- ('attribute_value', '*')
-])
+@ATT_PDU.subclass([('attribute_handle', HANDLE_FIELD_SPEC), ('attribute_value', '*')])
class ATT_Write_Request(ATT_PDU):
'''
See Bluetooth spec @ Vol 3, Part F - 3.4.5.1 Write Request
@@ -576,10 +630,7 @@ class ATT_Write_Response(ATT_PDU):
# -----------------------------------------------------------------------------
-@ATT_PDU.subclass([
- ('attribute_handle', HANDLE_FIELD_SPEC),
- ('attribute_value', '*')
-])
+@ATT_PDU.subclass([('attribute_handle', HANDLE_FIELD_SPEC), ('attribute_value', '*')])
class ATT_Write_Command(ATT_PDU):
'''
See Bluetooth spec @ Vol 3, Part F - 3.4.5.3 Write Command
@@ -587,11 +638,13 @@ class ATT_Write_Command(ATT_PDU):
# -----------------------------------------------------------------------------
-@ATT_PDU.subclass([
- ('attribute_handle', HANDLE_FIELD_SPEC),
- ('attribute_value', '*')
- # ('authentication_signature', 'TODO')
-])
+@ATT_PDU.subclass(
+ [
+ ('attribute_handle', HANDLE_FIELD_SPEC),
+ ('attribute_value', '*')
+ # ('authentication_signature', 'TODO')
+ ]
+)
class ATT_Signed_Write_Command(ATT_PDU):
'''
See Bluetooth spec @ Vol 3, Part F - 3.4.5.4 Signed Write Command
@@ -599,11 +652,13 @@ class ATT_Signed_Write_Command(ATT_PDU):
# -----------------------------------------------------------------------------
-@ATT_PDU.subclass([
- ('attribute_handle', HANDLE_FIELD_SPEC),
- ('value_offset', 2),
- ('part_attribute_value', '*')
-])
+@ATT_PDU.subclass(
+ [
+ ('attribute_handle', HANDLE_FIELD_SPEC),
+ ('value_offset', 2),
+ ('part_attribute_value', '*'),
+ ]
+)
class ATT_Prepare_Write_Request(ATT_PDU):
'''
See Bluetooth spec @ Vol 3, Part F - 3.4.6.1 Prepare Write Request
@@ -611,11 +666,13 @@ class ATT_Prepare_Write_Request(ATT_PDU):
# -----------------------------------------------------------------------------
-@ATT_PDU.subclass([
- ('attribute_handle', HANDLE_FIELD_SPEC),
- ('value_offset', 2),
- ('part_attribute_value', '*')
-])
+@ATT_PDU.subclass(
+ [
+ ('attribute_handle', HANDLE_FIELD_SPEC),
+ ('value_offset', 2),
+ ('part_attribute_value', '*'),
+ ]
+)
class ATT_Prepare_Write_Response(ATT_PDU):
'''
See Bluetooth spec @ Vol 3, Part F - 3.4.6.2 Prepare Write Response
@@ -639,10 +696,7 @@ class ATT_Execute_Write_Response(ATT_PDU):
# -----------------------------------------------------------------------------
-@ATT_PDU.subclass([
- ('attribute_handle', HANDLE_FIELD_SPEC),
- ('attribute_value', '*')
-])
+@ATT_PDU.subclass([('attribute_handle', HANDLE_FIELD_SPEC), ('attribute_value', '*')])
class ATT_Handle_Value_Notification(ATT_PDU):
'''
See Bluetooth spec @ Vol 3, Part F - 3.4.7.1 Handle Value Notification
@@ -650,10 +704,7 @@ class ATT_Handle_Value_Notification(ATT_PDU):
# -----------------------------------------------------------------------------
-@ATT_PDU.subclass([
- ('attribute_handle', HANDLE_FIELD_SPEC),
- ('attribute_value', '*')
-])
+@ATT_PDU.subclass([('attribute_handle', HANDLE_FIELD_SPEC), ('attribute_value', '*')])
class ATT_Handle_Value_Indication(ATT_PDU):
'''
See Bluetooth spec @ Vol 3, Part F - 3.4.7.2 Handle Value Indication
@@ -671,58 +722,143 @@ class ATT_Handle_Value_Confirmation(ATT_PDU):
# -----------------------------------------------------------------------------
class Attribute(EventEmitter):
# Permission flags
- READABLE = 0x01
- WRITEABLE = 0x02
- READ_REQUIRES_ENCRYPTION = 0x04
- WRITE_REQUIRES_ENCRYPTION = 0x08
- READ_REQUIRES_AUTHENTICATION = 0x10
+ READABLE = 0x01
+ WRITEABLE = 0x02
+ READ_REQUIRES_ENCRYPTION = 0x04
+ WRITE_REQUIRES_ENCRYPTION = 0x08
+ READ_REQUIRES_AUTHENTICATION = 0x10
WRITE_REQUIRES_AUTHENTICATION = 0x20
- READ_REQUIRES_AUTHORIZATION = 0x40
- WRITE_REQUIRES_AUTHORIZATION = 0x80
+ READ_REQUIRES_AUTHORIZATION = 0x40
+ WRITE_REQUIRES_AUTHORIZATION = 0x80
+
+ PERMISSION_NAMES = {
+ READABLE: 'READABLE',
+ WRITEABLE: 'WRITEABLE',
+ READ_REQUIRES_ENCRYPTION: 'READ_REQUIRES_ENCRYPTION',
+ WRITE_REQUIRES_ENCRYPTION: 'WRITE_REQUIRES_ENCRYPTION',
+ READ_REQUIRES_AUTHENTICATION: 'READ_REQUIRES_AUTHENTICATION',
+ WRITE_REQUIRES_AUTHENTICATION: 'WRITE_REQUIRES_AUTHENTICATION',
+ READ_REQUIRES_AUTHORIZATION: 'READ_REQUIRES_AUTHORIZATION',
+ WRITE_REQUIRES_AUTHORIZATION: 'WRITE_REQUIRES_AUTHORIZATION',
+ }
- def __init__(self, attribute_type, permissions, value = b''):
+ @staticmethod
+ def string_to_permissions(permissions_str: str):
+ try:
+ return functools.reduce(
+ lambda x, y: x | get_dict_key_by_value(Attribute.PERMISSION_NAMES, y),
+ permissions_str.split(","),
+ 0,
+ )
+ except TypeError as exc:
+ raise TypeError(
+ f"Attribute::permissions error:\nExpected a string containing any of the keys, separated by commas: {','.join(Attribute.PERMISSION_NAMES.values())}\nGot: {permissions_str}"
+ ) from exc
+
+ def __init__(self, attribute_type, permissions, value=b''):
EventEmitter.__init__(self)
- self.handle = 0
+ self.handle = 0
self.end_group_handle = 0
- self.permissions = permissions
+ if isinstance(permissions, str):
+ self.permissions = self.string_to_permissions(permissions)
+ else:
+ self.permissions = permissions
# Convert the type to a UUID object if it isn't already
- if type(attribute_type) is str:
+ if isinstance(attribute_type, str):
self.type = UUID(attribute_type)
- elif type(attribute_type) is bytes:
+ elif isinstance(attribute_type, bytes):
self.type = UUID.from_bytes(attribute_type)
else:
self.type = attribute_type
# Convert the value to a byte array
- if type(value) is str:
+ if isinstance(value, str):
self.value = bytes(value, 'utf-8')
else:
self.value = value
- def read_value(self, connection):
+ def encode_value(self, value):
+ return value
+
+ def decode_value(self, value_bytes):
+ return value_bytes
+
+ def read_value(self, connection: Connection):
+ if (
+ self.permissions & self.READ_REQUIRES_ENCRYPTION
+ ) and not connection.encryption:
+ raise ATT_Error(
+ error_code=ATT_INSUFFICIENT_ENCRYPTION_ERROR, att_handle=self.handle
+ )
+ if (
+ self.permissions & self.READ_REQUIRES_AUTHENTICATION
+ ) and not connection.authenticated:
+ raise ATT_Error(
+ error_code=ATT_INSUFFICIENT_AUTHENTICATION_ERROR, att_handle=self.handle
+ )
+ if self.permissions & self.READ_REQUIRES_AUTHORIZATION:
+ # TODO: handle authorization better
+ raise ATT_Error(
+ error_code=ATT_INSUFFICIENT_AUTHORIZATION_ERROR, att_handle=self.handle
+ )
+
if read := getattr(self.value, 'read', None):
try:
- return read(connection)
+ value = read(connection) # pylint: disable=not-callable
except ATT_Error as error:
- raise ATT_Error(error_code=error.error_code, att_handle=self.handle)
+ raise ATT_Error(
+ error_code=error.error_code, att_handle=self.handle
+ ) from error
else:
- return self.value
+ value = self.value
+
+ return self.encode_value(value)
+
+ def write_value(self, connection: Connection, value_bytes):
+ if (
+ self.permissions & self.WRITE_REQUIRES_ENCRYPTION
+ ) and not connection.encryption:
+ raise ATT_Error(
+ error_code=ATT_INSUFFICIENT_ENCRYPTION_ERROR, att_handle=self.handle
+ )
+ if (
+ self.permissions & self.WRITE_REQUIRES_AUTHENTICATION
+ ) and not connection.authenticated:
+ raise ATT_Error(
+ error_code=ATT_INSUFFICIENT_AUTHENTICATION_ERROR, att_handle=self.handle
+ )
+ if self.permissions & self.WRITE_REQUIRES_AUTHORIZATION:
+ # TODO: handle authorization better
+ raise ATT_Error(
+ error_code=ATT_INSUFFICIENT_AUTHORIZATION_ERROR, att_handle=self.handle
+ )
+
+ value = self.decode_value(value_bytes)
- def write_value(self, connection, value):
if write := getattr(self.value, 'write', None):
try:
- write(connection, value)
+ write(connection, value) # pylint: disable=not-callable
except ATT_Error as error:
- raise ATT_Error(error_code=error.error_code, att_handle=self.handle)
+ raise ATT_Error(
+ error_code=error.error_code, att_handle=self.handle
+ ) from error
else:
self.value = value
self.emit('write', connection, value)
def __repr__(self):
- if len(self.value) > 0:
+ if isinstance(self.value, bytes):
+ value_str = self.value.hex()
+ else:
+ value_str = str(self.value)
+ if value_str:
value_string = f', value={self.value.hex()}'
else:
value_string = ''
- return f'Attribute(handle=0x{self.handle:04X}, type={self.type}, permissions={self.permissions}{value_string})'
+ return (
+ f'Attribute(handle=0x{self.handle:04X}, '
+ f'type={self.type}, '
+ f'permissions={self.permissions}{value_string})'
+ )
diff --git a/bumble/avdtp.py b/bumble/avdtp.py
index 759e38c..238036d 100644
--- a/bumble/avdtp.py
+++ b/bumble/avdtp.py
@@ -15,18 +15,19 @@
# -----------------------------------------------------------------------------
# Imports
# -----------------------------------------------------------------------------
+from __future__ import annotations
import asyncio
import struct
import time
import logging
-from colors import color
from pyee import EventEmitter
+from typing import Dict, Type
from .core import (
BT_ADVANCED_AUDIO_DISTRIBUTION_SERVICE,
InvalidStateError,
ProtocolError,
- name_or_number
+ name_or_number,
)
from .a2dp import (
A2DP_CODEC_TYPE_NAMES,
@@ -35,9 +36,10 @@ from .a2dp import (
A2DP_SBC_CODEC_TYPE,
AacMediaCodecInformation,
SbcMediaCodecInformation,
- VendorSpecificMediaCodecInformation
+ VendorSpecificMediaCodecInformation,
)
from . import sdp
+from .colors import color
# -----------------------------------------------------------------------------
# Logging
@@ -48,6 +50,9 @@ logger = logging.getLogger(__name__)
# -----------------------------------------------------------------------------
# Constants
# -----------------------------------------------------------------------------
+# fmt: off
+# pylint: disable=line-too-long
+
AVDTP_PSM = 0x0019
AVDTP_DEFAULT_RTX_SIG_TIMER = 5 # Seconds
@@ -195,6 +200,10 @@ AVDTP_STATE_NAMES = {
AVDTP_ABORTING_STATE: 'AVDTP_ABORTING_STATE'
}
+# fmt: on
+# pylint: enable=line-too-long
+# pylint: disable=invalid-name
+
# -----------------------------------------------------------------------------
async def find_avdtp_service_with_sdp_client(sdp_client):
@@ -206,14 +215,11 @@ async def find_avdtp_service_with_sdp_client(sdp_client):
# Search for services with an Audio Sink service class
search_result = await sdp_client.search_attributes(
[BT_ADVANCED_AUDIO_DISTRIBUTION_SERVICE],
- [
- sdp.SDP_BLUETOOTH_PROFILE_DESCRIPTOR_LIST_ATTRIBUTE_ID
- ]
+ [sdp.SDP_BLUETOOTH_PROFILE_DESCRIPTOR_LIST_ATTRIBUTE_ID],
)
for attribute_list in search_result:
profile_descriptor_list = sdp.ServiceAttribute.find_attribute_in_list(
- attribute_list,
- sdp.SDP_BLUETOOTH_PROFILE_DESCRIPTOR_LIST_ATTRIBUTE_ID
+ attribute_list, sdp.SDP_BLUETOOTH_PROFILE_DESCRIPTOR_LIST_ATTRIBUTE_ID
)
if profile_descriptor_list:
for profile_descriptor in profile_descriptor_list.value:
@@ -251,17 +257,19 @@ class RealtimeClock:
class MediaPacket:
@staticmethod
def from_bytes(data):
- version = (data[0] >> 6) & 0x03
- padding = (data[0] >> 5) & 0x01
- extension = (data[0] >> 4) & 0x01
- csrc_count = data[0] & 0x0F
- marker = (data[1] >> 7) & 0x01
- payload_type = data[1] & 0x7F
+ version = (data[0] >> 6) & 0x03
+ padding = (data[0] >> 5) & 0x01
+ extension = (data[0] >> 4) & 0x01
+ csrc_count = data[0] & 0x0F
+ marker = (data[1] >> 7) & 0x01
+ payload_type = data[1] & 0x7F
sequence_number = struct.unpack_from('>H', data, 2)[0]
- timestamp = struct.unpack_from('>I', data, 4)[0]
- ssrc = struct.unpack_from('>I', data, 8)[0]
- csrc_list = [struct.unpack_from('>I', data, 12 + i)[0] for i in range(csrc_count)]
- payload = data[12 + csrc_count * 4:]
+ timestamp = struct.unpack_from('>I', data, 4)[0]
+ ssrc = struct.unpack_from('>I', data, 8)[0]
+ csrc_list = [
+ struct.unpack_from('>I', data, 12 + i)[0] for i in range(csrc_count)
+ ]
+ payload = data[12 + csrc_count * 4 :]
return MediaPacket(
version,
@@ -273,7 +281,7 @@ class MediaPacket:
ssrc,
csrc_list,
payload_type,
- payload
+ payload,
)
def __init__(
@@ -287,45 +295,58 @@ class MediaPacket:
ssrc,
csrc_list,
payload_type,
- payload
+ payload,
):
- self.version = version
- self.padding = padding
- self.extension = extension
- self.marker = marker
+ self.version = version
+ self.padding = padding
+ self.extension = extension
+ self.marker = marker
self.sequence_number = sequence_number
- self.timestamp = timestamp
- self.ssrc = ssrc
- self.csrc_list = csrc_list
- self.payload_type = payload_type
- self.payload = payload
+ self.timestamp = timestamp
+ self.ssrc = ssrc
+ self.csrc_list = csrc_list
+ self.payload_type = payload_type
+ self.payload = payload
def __bytes__(self):
- header = (
- bytes([
- self.version << 6 | self.padding << 5 | self.extension << 4 | len(self.csrc_list),
- self.marker << 7 | self.payload_type
- ]) +
- struct.pack('>HII', self.sequence_number, self.timestamp, self.ssrc)
- )
+ header = bytes(
+ [
+ self.version << 6
+ | self.padding << 5
+ | self.extension << 4
+ | len(self.csrc_list),
+ self.marker << 7 | self.payload_type,
+ ]
+ ) + struct.pack('>HII', self.sequence_number, self.timestamp, self.ssrc)
for csrc in self.csrc_list:
header += struct.pack('>I', csrc)
return header + self.payload
def __str__(self):
- return f'RTP(v={self.version},p={self.padding},x={self.extension},m={self.marker},pt={self.payload_type},sn={self.sequence_number},ts={self.timestamp},ssrc={self.ssrc},csrcs={self.csrc_list},payload_size={len(self.payload)})'
+ return (
+ f'RTP(v={self.version},'
+ f'p={self.padding},'
+ f'x={self.extension},'
+ f'm={self.marker},'
+ f'pt={self.payload_type},'
+ f'sn={self.sequence_number},'
+ f'ts={self.timestamp},'
+ f'ssrc={self.ssrc},'
+ f'csrcs={self.csrc_list},'
+ f'payload_size={len(self.payload)})'
+ )
# -----------------------------------------------------------------------------
class MediaPacketPump:
def __init__(self, packets, clock=RealtimeClock()):
- self.packets = packets
- self.clock = clock
+ self.packets = packets
+ self.clock = clock
self.pump_task = None
async def start(self, rtp_channel):
async def pump_packets():
- start_time = 0
+ start_time = 0
start_timestamp = 0
try:
@@ -333,7 +354,7 @@ class MediaPacketPump:
async for packet in self.packets:
# Capture the timestamp of the first packet
if start_time == 0:
- start_time = self.clock.now()
+ start_time = self.clock.now()
start_timestamp = packet.timestamp_seconds
# Wait until we can send
@@ -346,12 +367,14 @@ class MediaPacketPump:
# Emit
rtp_channel.send_pdu(bytes(packet))
- logger.debug(f'{color(">>> sending RTP packet:", "green")} {packet}')
+ logger.debug(
+ f'{color(">>> sending RTP packet:", "green")} {packet}'
+ )
except asyncio.exceptions.CancelledError:
logger.debug('pump canceled')
# Pump packets
- self.pump_task = asyncio.get_running_loop().create_task(pump_packets())
+ self.pump_task = asyncio.create_task(pump_packets())
async def stop(self):
# Stop the pump
@@ -362,73 +385,96 @@ class MediaPacketPump:
# -----------------------------------------------------------------------------
-class MessageAssembler:
+class MessageAssembler: # pylint: disable=attribute-defined-outside-init
def __init__(self, callback):
self.callback = callback
self.reset()
def reset(self):
- self.transaction_label = 0
- self.message = None
- self.message_type = 0
- self.signal_identifier = 0
+ self.transaction_label = 0
+ self.message = None
+ self.message_type = 0
+ self.signal_identifier = 0
self.number_of_signal_packets = 0
- self.packet_count = 0
+ self.packet_count = 0
def on_pdu(self, pdu):
self.packet_count += 1
transaction_label = pdu[0] >> 4
- packet_type = (pdu[0] >> 2) & 3
- message_type = pdu[0] & 3
+ packet_type = (pdu[0] >> 2) & 3
+ message_type = pdu[0] & 3
- logger.debug(f'transaction_label={transaction_label}, packet_type={Protocol.packet_type_name(packet_type)}, message_type={Message.message_type_name(message_type)}')
- if packet_type == Protocol.SINGLE_PACKET or packet_type == Protocol.START_PACKET:
+ logger.debug(
+ f'transaction_label={transaction_label}, '
+ f'packet_type={Protocol.packet_type_name(packet_type)}, '
+ f'message_type={Message.message_type_name(message_type)}'
+ )
+ if packet_type in (Protocol.SINGLE_PACKET, Protocol.START_PACKET):
if self.message is not None:
# The previous message has not been terminated
- logger.warning('received a start or single packet when expecting an end or continuation')
+ logger.warning(
+ 'received a start or single packet when expecting an end or '
+ 'continuation'
+ )
self.reset()
self.transaction_label = transaction_label
self.signal_identifier = pdu[1] & 0x3F
- self.message_type = message_type
+ self.message_type = message_type
if packet_type == Protocol.SINGLE_PACKET:
self.message = pdu[2:]
self.on_message_complete()
else:
self.number_of_signal_packets = pdu[2]
- self.message = pdu[3:]
- elif packet_type == Protocol.CONTINUE_PACKET or packet_type == Protocol.END_PACKET:
+ self.message = pdu[3:]
+ elif packet_type in (Protocol.CONTINUE_PACKET, Protocol.END_PACKET):
if self.packet_count == 0:
logger.warning('unexpected continuation')
return
if transaction_label != self.transaction_label:
- logger.warning(f'transaction label mismatch: expected {self.transaction_label}, received {transaction_label}')
+ logger.warning(
+ f'transaction label mismatch: expected {self.transaction_label}, '
+ f'received {transaction_label}'
+ )
return
if message_type != self.message_type:
- logger.warning(f'message type mismatch: expected {self.message_type}, received {message_type}')
+ logger.warning(
+ f'message type mismatch: expected {self.message_type}, '
+ f'received {message_type}'
+ )
return
self.message += pdu[1:]
if packet_type == Protocol.END_PACKET:
if self.packet_count != self.number_of_signal_packets:
- logger.warning(f'incomplete fragmented message: expected {self.number_of_signal_packets} packets, received {self.packet_count}')
+ logger.warning(
+ 'incomplete fragmented message: '
+ f'expected {self.number_of_signal_packets} packets, '
+ f'received {self.packet_count}'
+ )
self.reset()
return
self.on_message_complete()
else:
if self.packet_count > self.number_of_signal_packets:
- logger.warning(f'too many packets: expected {self.number_of_signal_packets}, received {self.packet_count}')
+ logger.warning(
+ 'too many packets: '
+ f'expected {self.number_of_signal_packets}, '
+ f'received {self.packet_count}'
+ )
self.reset()
return
def on_message_complete(self):
- message = Message.create(self.signal_identifier, self.message_type, self.message)
+ message = Message.create(
+ self.signal_identifier, self.message_type, self.message
+ )
try:
self.callback(self.transaction_label, message)
@@ -460,12 +506,14 @@ class ServiceCapabilities:
def parse_capabilities(payload):
capabilities = []
while payload:
- service_category = payload[0]
+ service_category = payload[0]
length_of_service_capabilities = payload[1]
- service_capabilities_bytes = payload[2:2 + length_of_service_capabilities]
- capabilities.append(ServiceCapabilities.create(service_category, service_capabilities_bytes))
+ service_capabilities_bytes = payload[2 : 2 + length_of_service_capabilities]
+ capabilities.append(
+ ServiceCapabilities.create(service_category, service_capabilities_bytes)
+ )
- payload = payload[2 + length_of_service_capabilities:]
+ payload = payload[2 + length_of_service_capabilities :]
return capabilities
@@ -473,21 +521,24 @@ class ServiceCapabilities:
def serialize_capabilities(capabilities):
serialized = b''
for item in capabilities:
- serialized += bytes([
- item.service_category,
- len(item.service_capabilities_bytes)
- ]) + item.service_capabilities_bytes
+ serialized += (
+ bytes([item.service_category, len(item.service_capabilities_bytes)])
+ + item.service_capabilities_bytes
+ )
return serialized
def init_from_bytes(self):
pass
def __init__(self, service_category, service_capabilities_bytes=b''):
- self.service_category = service_category
+ self.service_category = service_category
self.service_capabilities_bytes = service_capabilities_bytes
- def to_string(self, details=[]):
- attributes = ','.join([name_or_number(AVDTP_SERVICE_CATEGORY_NAMES, self.service_category)] + details)
+ def to_string(self, details=[]): # pylint: disable=dangerous-default-value
+ attributes = ','.join(
+ [name_or_number(AVDTP_SERVICE_CATEGORY_NAMES, self.service_category)]
+ + details
+ )
return f'ServiceCapabilities({attributes})'
def __str__(self):
@@ -501,31 +552,45 @@ class ServiceCapabilities:
# -----------------------------------------------------------------------------
class MediaCodecCapabilities(ServiceCapabilities):
def init_from_bytes(self):
- self.media_type = self.service_capabilities_bytes[0]
- self.media_codec_type = self.service_capabilities_bytes[1]
+ self.media_type = self.service_capabilities_bytes[0]
+ self.media_codec_type = self.service_capabilities_bytes[1]
self.media_codec_information = self.service_capabilities_bytes[2:]
if self.media_codec_type == A2DP_SBC_CODEC_TYPE:
- self.media_codec_information = SbcMediaCodecInformation.from_bytes(self.media_codec_information)
+ self.media_codec_information = SbcMediaCodecInformation.from_bytes(
+ self.media_codec_information
+ )
elif self.media_codec_type == A2DP_MPEG_2_4_AAC_CODEC_TYPE:
- self.media_codec_information = AacMediaCodecInformation.from_bytes(self.media_codec_information)
+ self.media_codec_information = AacMediaCodecInformation.from_bytes(
+ self.media_codec_information
+ )
elif self.media_codec_type == A2DP_NON_A2DP_CODEC_TYPE:
- self.media_codec_information = VendorSpecificMediaCodecInformation.from_bytes(self.media_codec_information)
+ self.media_codec_information = (
+ VendorSpecificMediaCodecInformation.from_bytes(
+ self.media_codec_information
+ )
+ )
def __init__(self, media_type, media_codec_type, media_codec_information):
super().__init__(
AVDTP_MEDIA_CODEC_SERVICE_CATEGORY,
- bytes([media_type, media_codec_type]) + bytes(media_codec_information)
+ bytes([media_type, media_codec_type]) + bytes(media_codec_information),
)
- self.media_type = media_type
- self.media_codec_type = media_codec_type
+ self.media_type = media_type
+ self.media_codec_type = media_codec_type
self.media_codec_information = media_codec_information
def __str__(self):
+ codec_info = (
+ self.media_codec_information.hex()
+ if isinstance(self.media_codec_information, bytes)
+ else str(self.media_codec_information)
+ )
+
details = [
f'media_type={name_or_number(AVDTP_MEDIA_TYPE_NAMES, self.media_type)}',
f'codec={name_or_number(A2DP_CODEC_TYPE_NAMES, self.media_codec_type)}',
- f'codec_info={self.media_codec_information.hex() if type(self.media_codec_information) is bytes else str(self.media_codec_information)}'
+ f'codec_info={codec_info}',
]
return self.to_string(details)
@@ -535,51 +600,48 @@ class EndPointInfo:
@staticmethod
def from_bytes(payload):
return EndPointInfo(
- payload[0] >> 2,
- payload[0] >> 1 & 1,
- payload[1] >> 4,
- payload[1] >> 3 & 1
+ payload[0] >> 2, payload[0] >> 1 & 1, payload[1] >> 4, payload[1] >> 3 & 1
)
def __bytes__(self):
- return bytes([
- self.seid << 2 | self.in_use << 1,
- self.media_type << 4 | self.tsep << 3
- ])
+ return bytes(
+ [self.seid << 2 | self.in_use << 1, self.media_type << 4 | self.tsep << 3]
+ )
def __init__(self, seid, in_use, media_type, tsep):
- self.seid = seid
- self.in_use = in_use
+ self.seid = seid
+ self.in_use = in_use
self.media_type = media_type
- self.tsep = tsep
+ self.tsep = tsep
# -----------------------------------------------------------------------------
-class Message:
- COMMAND = 0
- GENERAL_REJECT = 1
+class Message: # pylint:disable=attribute-defined-outside-init
+ COMMAND = 0
+ GENERAL_REJECT = 1
RESPONSE_ACCEPT = 2
RESPONSE_REJECT = 3
MESSAGE_TYPE_NAMES = {
- COMMAND: 'COMMAND',
- GENERAL_REJECT: 'GENERAL_REJECT',
+ COMMAND: 'COMMAND',
+ GENERAL_REJECT: 'GENERAL_REJECT',
RESPONSE_ACCEPT: 'RESPONSE_ACCEPT',
- RESPONSE_REJECT: 'RESPONSE_REJECT'
+ RESPONSE_REJECT: 'RESPONSE_REJECT',
}
- subclasses = {} # Subclasses, by signal identifier and message type
+ # Subclasses, by signal identifier and message type
+ subclasses: Dict[int, Dict[int, Type[Message]]] = {}
@staticmethod
def message_type_name(message_type):
return name_or_number(Message.MESSAGE_TYPE_NAMES, message_type)
@staticmethod
- def subclass(cls):
+ def subclass(subclass):
# Infer the signal identifier and message subtype from the class name
- name = cls.__name__
+ name = subclass.__name__
if name == 'General_Reject':
- cls.signal_identifier = 0
+ subclass.signal_identifier = 0
signal_identifier_str = None
message_type = Message.COMMAND
elif name.endswith('_Command'):
@@ -594,20 +656,23 @@ class Message:
else:
raise ValueError('invalid class name')
- cls.message_type = message_type
+ subclass.message_type = message_type
if signal_identifier_str is not None:
for (name, signal_identifier) in AVDTP_SIGNAL_IDENTIFIERS.items():
if name.lower().endswith(signal_identifier_str.lower()):
- cls.signal_identifier = signal_identifier
+ subclass.signal_identifier = signal_identifier
break
# Register the subclass
- Message.subclasses.setdefault(cls.signal_identifier, {})[cls.message_type] = cls
+ Message.subclasses.setdefault(subclass.signal_identifier, {})[
+ subclass.message_type
+ ] = subclass
- return cls
+ return subclass
- # Factory method to create a subclass based on the signal identifier and message type
+ # Factory method to create a subclass based on the signal identifier and message
+ # type
@staticmethod
def create(signal_identifier, message_type, payload):
# Look for a registered subclass
@@ -635,17 +700,26 @@ class Message:
pass
def __init__(self, payload=b''):
- self.payload = payload
+ self.payload = payload
def to_string(self, details):
- base = f'{color(f"{name_or_number(AVDTP_SIGNAL_NAMES, self.signal_identifier)}_{Message.message_type_name(self.message_type)}", "yellow")}'
+ base = color(
+ f'{name_or_number(AVDTP_SIGNAL_NAMES, self.signal_identifier)}_'
+ f'{Message.message_type_name(self.message_type)}',
+ 'yellow',
+ )
+
if details:
- if type(details) is str:
+ if isinstance(details, str):
return f'{base}: {details}'
- else:
- return base + ':\n' + '\n'.join([' ' + color(detail, 'cyan') for detail in details])
- else:
- return base
+
+ return (
+ base
+ + ':\n'
+ + '\n'.join([' ' + color(detail, 'cyan') for detail in details])
+ )
+
+ return base
def __str__(self):
return self.to_string(self.payload.hex())
@@ -661,8 +735,8 @@ class Simple_Command(Message):
self.acp_seid = self.payload[0] >> 2
def __init__(self, seid):
+ super().__init__(payload=bytes([seid << 2]))
self.acp_seid = seid
- self.payload = bytes([seid << 2])
def __str__(self):
return self.to_string([f'ACP SEID: {self.acp_seid}'])
@@ -678,13 +752,11 @@ class Simple_Reject(Message):
self.error_code = self.payload[0]
def __init__(self, error_code):
+ super().__init__(payload=bytes([error_code]))
self.error_code = error_code
- self.payload = bytes([self.error_code])
def __str__(self):
- details = [
- f'error_code: {name_or_number(AVDTP_ERROR_NAMES, self.error_code)}'
- ]
+ details = [f'error_code: {name_or_number(AVDTP_ERROR_NAMES, self.error_code)}']
return self.to_string(details)
@@ -707,21 +779,24 @@ class Discover_Response(Message):
self.endpoints = []
endpoint_count = len(self.payload) // 2
for i in range(endpoint_count):
- self.endpoints.append(EndPointInfo.from_bytes(self.payload[i * 2:(i + 1) * 2]))
+ self.endpoints.append(
+ EndPointInfo.from_bytes(self.payload[i * 2 : (i + 1) * 2])
+ )
def __init__(self, endpoints):
+ super().__init__(payload=b''.join([bytes(endpoint) for endpoint in endpoints]))
self.endpoints = endpoints
- self.payload = b''.join([bytes(endpoint) for endpoint in endpoints])
def __str__(self):
details = []
for endpoint in self.endpoints:
details.extend(
+ # pylint: disable=line-too-long
[
f'ACP SEID: {endpoint.seid}',
f' in_use: {endpoint.in_use}',
f' media_type: {name_or_number(AVDTP_MEDIA_TYPE_NAMES, endpoint.media_type)}',
- f' tsep: {name_or_number(AVDTP_TSEP_NAMES, endpoint.tsep)}'
+ f' tsep: {name_or_number(AVDTP_TSEP_NAMES, endpoint.tsep)}',
]
)
return self.to_string(details)
@@ -746,8 +821,10 @@ class Get_Capabilities_Response(Message):
self.capabilities = ServiceCapabilities.parse_capabilities(self.payload)
def __init__(self, capabilities):
+ super().__init__(
+ payload=ServiceCapabilities.serialize_capabilities(capabilities)
+ )
self.capabilities = capabilities
- self.payload = ServiceCapabilities.serialize_capabilities(capabilities)
def __str__(self):
details = [str(capability) for capability in self.capabilities]
@@ -794,21 +871,23 @@ class Set_Configuration_Command(Message):
'''
def init_from_payload(self):
- self.acp_seid = self.payload[0] >> 2
- self.int_seid = self.payload[1] >> 2
+ self.acp_seid = self.payload[0] >> 2
+ self.int_seid = self.payload[1] >> 2
self.capabilities = ServiceCapabilities.parse_capabilities(self.payload[2:])
def __init__(self, acp_seid, int_seid, capabilities):
- self.acp_seid = acp_seid
- self.int_seid = int_seid
+ super().__init__(
+ payload=bytes([acp_seid << 2, int_seid << 2])
+ + ServiceCapabilities.serialize_capabilities(capabilities)
+ )
+ self.acp_seid = acp_seid
+ self.int_seid = int_seid
self.capabilities = capabilities
- self.payload = bytes([acp_seid << 2, int_seid << 2]) + ServiceCapabilities.serialize_capabilities(capabilities)
def __str__(self):
- details = [
- f'ACP SEID: {self.acp_seid}',
- f'INT SEID: {self.int_seid}'
- ] + [str(capability) for capability in self.capabilities]
+ details = [f'ACP SEID: {self.acp_seid}', f'INT SEID: {self.int_seid}'] + [
+ str(capability) for capability in self.capabilities
+ ]
return self.to_string(details)
@@ -829,17 +908,23 @@ class Set_Configuration_Reject(Message):
def init_from_payload(self):
self.service_category = self.payload[0]
- self.error_code = self.payload[1]
+ self.error_code = self.payload[1]
def __init__(self, service_category, error_code):
+ super().__init__(payload=bytes([service_category, error_code]))
self.service_category = service_category
- self.error_code = error_code
- self.payload = bytes([service_category, self.error_code])
+ self.error_code = error_code
def __str__(self):
details = [
- f'service_category: {name_or_number(AVDTP_SERVICE_CATEGORY_NAMES, self.service_category)}',
- f'error_code: {name_or_number(AVDTP_ERROR_NAMES, self.error_code)}'
+ (
+ 'service_category: '
+ f'{name_or_number(AVDTP_SERVICE_CATEGORY_NAMES, self.service_category)}'
+ ),
+ (
+ 'error_code: '
+ f'{name_or_number(AVDTP_ERROR_NAMES, self.error_code)}'
+ ),
]
return self.to_string(details)
@@ -863,8 +948,10 @@ class Get_Configuration_Response(Message):
self.capabilities = ServiceCapabilities.parse_capabilities(self.payload)
def __init__(self, capabilities):
+ super().__init__(
+ payload=ServiceCapabilities.serialize_capabilities(capabilities)
+ )
self.capabilities = capabilities
- self.payload = ServiceCapabilities.serialize_capabilities(capabilities)
def __str__(self):
details = [str(capability) for capability in self.capabilities]
@@ -887,7 +974,8 @@ class Reconfigure_Command(Message):
'''
def init_from_payload(self):
- self.acp_seid = self.payload[0] >> 2
+ # pylint: disable=attribute-defined-outside-init
+ self.acp_seid = self.payload[0] >> 2
self.capabilities = ServiceCapabilities.parse_capabilities(self.payload[1:])
def __str__(self):
@@ -948,8 +1036,8 @@ class Start_Command(Message):
self.acp_seids = [x >> 2 for x in self.payload]
def __init__(self, seids):
+ super().__init__(payload=bytes([seid << 2 for seid in seids]))
self.acp_seids = seids
- self.payload = bytes([seid << 2 for seid in self.acp_seids])
def __str__(self):
return self.to_string([f'ACP SEIDs: {self.acp_seids}'])
@@ -971,18 +1059,18 @@ class Start_Reject(Message):
'''
def init_from_payload(self):
- self.acp_seid = self.payload[0] >> 2
+ self.acp_seid = self.payload[0] >> 2
self.error_code = self.payload[1]
def __init__(self, acp_seid, error_code):
- self.acp_seid = acp_seid
+ super().__init__(payload=bytes([acp_seid << 2, error_code]))
+ self.acp_seid = acp_seid
self.error_code = error_code
- self.payload = bytes([self.acp_seid << 2, self.error_code])
def __str__(self):
details = [
f'acp_seid: {self.acp_seid}',
- f'error_code: {name_or_number(AVDTP_ERROR_NAMES, self.error_code)}'
+ f'error_code: {name_or_number(AVDTP_ERROR_NAMES, self.error_code)}',
]
return self.to_string(details)
@@ -1083,7 +1171,7 @@ class General_Reject(Message):
'''
def to_string(self, details):
- return f'{color(f"GENERAL_REJECT", "yellow")}'
+ return color('GENERAL_REJECT', 'yellow')
# -----------------------------------------------------------------------------
@@ -1094,14 +1182,12 @@ class DelayReport_Command(Message):
'''
def init_from_payload(self):
+ # pylint: disable=attribute-defined-outside-init
self.acp_seid = self.payload[0] >> 2
- self.delay = (self.payload[1] << 8) | (self.payload[2])
+ self.delay = (self.payload[1] << 8) | (self.payload[2])
def __str__(self):
- return self.to_string([
- f'ACP_SEID: {self.acp_seid}',
- f'delay: {self.delay}'
- ])
+ return self.to_string([f'ACP_SEID: {self.acp_seid}', f'delay: {self.delay}'])
# -----------------------------------------------------------------------------
@@ -1122,16 +1208,16 @@ class DelayReport_Reject(Simple_Reject):
# -----------------------------------------------------------------------------
class Protocol:
- SINGLE_PACKET = 0
- START_PACKET = 1
+ SINGLE_PACKET = 0
+ START_PACKET = 1
CONTINUE_PACKET = 2
- END_PACKET = 3
+ END_PACKET = 3
PACKET_TYPE_NAMES = {
- SINGLE_PACKET: 'SINGLE_PACKET',
- START_PACKET: 'START_PACKET',
+ SINGLE_PACKET: 'SINGLE_PACKET',
+ START_PACKET: 'START_PACKET',
CONTINUE_PACKET: 'CONTINUE_PACKET',
- END_PACKET: 'END_PACKET'
+ END_PACKET: 'END_PACKET',
}
@staticmethod
@@ -1148,27 +1234,29 @@ class Protocol:
return protocol
def __init__(self, l2cap_channel, version=(1, 3)):
- self.l2cap_channel = l2cap_channel
- self.version = version
- self.rtx_sig_timer = AVDTP_DEFAULT_RTX_SIG_TIMER
- self.message_assembler = MessageAssembler(self.on_message)
- self.transaction_results = [None] * 16 # Futures for up to 16 transactions
+ self.l2cap_channel = l2cap_channel
+ self.version = version
+ self.rtx_sig_timer = AVDTP_DEFAULT_RTX_SIG_TIMER
+ self.message_assembler = MessageAssembler(self.on_message)
+ self.transaction_results = [None] * 16 # Futures for up to 16 transactions
self.transaction_semaphore = asyncio.Semaphore(16)
- self.transaction_count = 0
- self.channel_acceptor = None
- self.channel_connector = None
- self.local_endpoints = [] # Local endpoints, with contiguous seid values
- self.remote_endpoints = {} # Remote stream endpoints, by seid
- self.streams = {} # Streams, by seid
+ self.transaction_count = 0
+ self.channel_acceptor = None
+ self.channel_connector = None
+ self.local_endpoints = [] # Local endpoints, with contiguous seid values
+ self.remote_endpoints = {} # Remote stream endpoints, by seid
+ self.streams = {} # Streams, by seid
# Register to receive PDUs from the channel
l2cap_channel.sink = self.on_pdu
l2cap_channel.on('open', self.on_l2cap_channel_open)
def get_local_endpoint_by_seid(self, seid):
- if seid > 0 and seid <= len(self.local_endpoints):
+ if 0 < seid <= len(self.local_endpoints):
return self.local_endpoints[seid - 1]
+ return None
+
def add_source(self, codec_capabilities, packet_pump):
seid = len(self.local_endpoints) + 1
source = LocalSource(self, seid, codec_capabilities, packet_pump)
@@ -1205,7 +1293,9 @@ class Protocol:
response = await self.send_command(Discover_Command())
for endpoint_entry in response.endpoints:
- logger.debug(f'getting endpoint capabilities for endpoint {endpoint_entry.seid}')
+ logger.debug(
+ f'getting endpoint capabilities for endpoint {endpoint_entry.seid}'
+ )
get_capabilities_response = await self.get_capabilities(endpoint_entry.seid)
endpoint = DiscoveredStreamEndPoint(
self,
@@ -1213,7 +1303,7 @@ class Protocol:
endpoint_entry.media_type,
endpoint_entry.tsep,
endpoint_entry.in_use,
- get_capabilities_response.capabilities
+ get_capabilities_response.capabilities,
)
self.remote_endpoints[endpoint_entry.seid] = endpoint
@@ -1221,23 +1311,41 @@ class Protocol:
def find_remote_sink_by_codec(self, media_type, codec_type):
for endpoint in self.remote_endpoints.values():
- if not endpoint.in_use and endpoint.media_type == media_type and endpoint.tsep == AVDTP_TSEP_SNK:
+ if (
+ not endpoint.in_use
+ and endpoint.media_type == media_type
+ and endpoint.tsep == AVDTP_TSEP_SNK
+ ):
has_media_transport = False
has_codec = False
for capabilities in endpoint.capabilities:
- if capabilities.service_category == AVDTP_MEDIA_TRANSPORT_SERVICE_CATEGORY:
+ if (
+ capabilities.service_category
+ == AVDTP_MEDIA_TRANSPORT_SERVICE_CATEGORY
+ ):
has_media_transport = True
- elif capabilities.service_category == AVDTP_MEDIA_CODEC_SERVICE_CATEGORY:
- if capabilities.media_type == AVDTP_AUDIO_MEDIA_TYPE and capabilities.media_codec_type == codec_type:
+ elif (
+ capabilities.service_category
+ == AVDTP_MEDIA_CODEC_SERVICE_CATEGORY
+ ):
+ if (
+ capabilities.media_type == AVDTP_AUDIO_MEDIA_TYPE
+ and capabilities.media_codec_type == codec_type
+ ):
has_codec = True
if has_media_transport and has_codec:
return endpoint
+ return None
+
def on_pdu(self, pdu):
self.message_assembler.on_pdu(pdu)
def on_message(self, transaction_label, message):
- logger.debug(f'{color("<<< Received AVDTP message", "magenta")}: [{transaction_label}] {message}')
+ logger.debug(
+ f'{color("<<< Received AVDTP message", "magenta")}: '
+ f'[{transaction_label}] {message}'
+ )
# Check that the identifier is not reserved
if message.signal_identifier == 0:
@@ -1245,20 +1353,30 @@ class Protocol:
return
# Check that the identifier is valid
- if message.signal_identifier < 0 or message.signal_identifier > AVDTP_DELAYREPORT:
+ if (
+ message.signal_identifier < 0
+ or message.signal_identifier > AVDTP_DELAYREPORT
+ ):
logger.warning('!!! invalid signal identifier')
self.send_message(transaction_label, General_Reject())
if message.message_type == Message.COMMAND:
# Command
- handler_name = f'on_{AVDTP_SIGNAL_NAMES.get(message.signal_identifier,"").replace("AVDTP_","").lower()}_command'
+ signal_name = (
+ AVDTP_SIGNAL_NAMES.get(message.signal_identifier, "")
+ .replace("AVDTP_", "")
+ .lower()
+ )
+ handler_name = f'on_{signal_name}_command'
handler = getattr(self, handler_name, None)
if handler:
try:
response = handler(message)
self.send_message(transaction_label, response)
except Exception as error:
- logger.warning(f'{color("!!! Exception in handler:", "red")} {error}')
+ logger.warning(
+ f'{color("!!! Exception in handler:", "red")} {error}'
+ )
else:
logger.warning('unhandled command')
else:
@@ -1281,8 +1399,13 @@ class Protocol:
logger.debug(color('<<< L2CAP channel open', 'magenta'))
def send_message(self, transaction_label, message):
- logger.debug(f'{color(">>> Sending AVDTP message", "magenta")}: [{transaction_label}] {message}')
- max_fragment_size = self.l2cap_channel.mtu - 3 # Enough space for a 3-byte start packet header
+ logger.debug(
+ f'{color(">>> Sending AVDTP message", "magenta")}: '
+ f'[{transaction_label}] {message}'
+ )
+ max_fragment_size = (
+ self.l2cap_channel.mtu - 3
+ ) # Enough space for a 3-byte start packet header
payload = message.payload
if len(payload) + 2 <= self.l2cap_channel.mtu:
# Fits in a single packet
@@ -1292,13 +1415,19 @@ class Protocol:
done = False
while not done:
- first_header_byte = transaction_label << 4 | packet_type << 2 | message.message_type
+ first_header_byte = (
+ transaction_label << 4 | packet_type << 2 | message.message_type
+ )
if packet_type == self.SINGLE_PACKET:
header = bytes([first_header_byte, message.signal_identifier])
elif packet_type == self.START_PACKET:
- packet_count = (max_fragment_size - 1 + len(payload)) // max_fragment_size
- header = bytes([first_header_byte, message.signal_identifier, packet_count])
+ packet_count = (
+ max_fragment_size - 1 + len(payload)
+ ) // max_fragment_size
+ header = bytes(
+ [first_header_byte, message.signal_identifier, packet_count]
+ )
else:
header = bytes([first_header_byte])
@@ -1308,7 +1437,11 @@ class Protocol:
# Prepare for the next packet
payload = payload[max_fragment_size:]
if payload:
- packet_type = self.CONTINUE_PACKET if payload > max_fragment_size else self.END_PACKET
+ packet_type = (
+ self.CONTINUE_PACKET
+ if payload > max_fragment_size
+ else self.END_PACKET
+ )
else:
done = True
@@ -1322,7 +1455,7 @@ class Protocol:
response = await transaction_result
# Check for errors
- if response.message_type == Message.GENERAL_REJECT or response.message_type == Message.RESPONSE_REJECT:
+ if response.message_type in (Message.GENERAL_REJECT, Message.RESPONSE_REJECT):
raise ProtocolError(response.error_code, 'avdtp')
return response
@@ -1340,16 +1473,18 @@ class Protocol:
self.transaction_count += 1
return (transaction_label, transaction_result)
- assert(False) # Should never reach this
+ assert False # Should never reach this
async def get_capabilities(self, seid):
if self.version > (1, 2):
return await self.send_command(Get_All_Capabilities_Command(seid))
- else:
- return await self.send_command(Get_Capabilities_Command(seid))
+
+ return await self.send_command(Get_Capabilities_Command(seid))
async def set_configuration(self, acp_seid, int_seid, capabilities):
- return await self.send_command(Set_Configuration_Command(acp_seid, int_seid, capabilities))
+ return await self.send_command(
+ Set_Configuration_Command(acp_seid, int_seid, capabilities)
+ )
async def get_configuration(self, seid):
response = await self.send_command(Get_Configuration_Command(seid))
@@ -1370,7 +1505,7 @@ class Protocol:
async def abort(self, seid):
return await self.send_command(Abort_Command(seid))
- def on_discover_command(self, command):
+ def on_discover_command(self, _command):
endpoint_infos = [
EndPointInfo(endpoint.seid, 0, endpoint.media_type, endpoint.tsep)
for endpoint in self.local_endpoints
@@ -1537,6 +1672,7 @@ class Listener(EventEmitter):
server = Protocol(channel, self.version)
self.set_server(channel.connection, server)
self.emit('connection', server)
+
channel.on('open', on_channel_open)
@@ -1562,8 +1698,7 @@ class Stream:
raise InvalidStateError('current state is not IDLE')
await self.remote_endpoint.set_configuration(
- self.local_endpoint.seid,
- self.local_endpoint.configuration
+ self.local_endpoint.seid, self.local_endpoint.configuration
)
self.change_state(AVDTP_CONFIGURED_STATE)
@@ -1608,7 +1743,7 @@ class Stream:
self.change_state(AVDTP_OPEN_STATE)
async def close(self):
- if self.state not in {AVDTP_OPEN_STATE, AVDTP_STREAMING_STATE}:
+ if self.state not in (AVDTP_OPEN_STATE, AVDTP_STREAMING_STATE):
raise InvalidStateError('current state is not OPEN or STREAMING')
logger.debug('closing local endpoint')
@@ -1637,9 +1772,14 @@ class Stream:
return result
self.change_state(AVDTP_CONFIGURED_STATE)
+ return None
def on_get_configuration_command(self, configuration):
- if self.state not in {AVDTP_CONFIGURED_STATE, AVDTP_OPEN_STATE, AVDTP_STREAMING_STATE}:
+ if self.state not in (
+ AVDTP_CONFIGURED_STATE,
+ AVDTP_OPEN_STATE,
+ AVDTP_STREAMING_STATE,
+ ):
return Get_Configuration_Reject(AVDTP_BAD_STATE_ERROR)
return self.local_endpoint.on_get_configuration_command(configuration)
@@ -1652,6 +1792,8 @@ class Stream:
if result is not None:
return result
+ return None
+
def on_open_command(self):
if self.state != AVDTP_CONFIGURED_STATE:
return Open_Reject(AVDTP_BAD_STATE_ERROR)
@@ -1664,6 +1806,7 @@ class Stream:
self.protocol.channel_acceptor = self
self.change_state(AVDTP_OPEN_STATE)
+ return None
def on_start_command(self):
if self.state != AVDTP_OPEN_STATE:
@@ -1679,6 +1822,7 @@ class Stream:
return result
self.change_state(AVDTP_STREAMING_STATE)
+ return None
def on_suspend_command(self):
if self.state != AVDTP_STREAMING_STATE:
@@ -1689,9 +1833,10 @@ class Stream:
return result
self.change_state(AVDTP_OPEN_STATE)
+ return None
def on_close_command(self):
- if self.state not in {AVDTP_OPEN_STATE, AVDTP_STREAMING_STATE}:
+ if self.state not in (AVDTP_OPEN_STATE, AVDTP_STREAMING_STATE):
return Open_Reject(AVDTP_BAD_STATE_ERROR)
result = self.local_endpoint.on_close_command()
@@ -1707,6 +1852,8 @@ class Stream:
# TODO: set a timer as we wait for the RTP channel to be closed
pass
+ return None
+
def on_abort_command(self):
if self.rtp_channel is None:
# No need to wait
@@ -1718,7 +1865,7 @@ class Stream:
def on_l2cap_connection(self, channel):
logger.debug(color('<<< stream channel connected', 'magenta'))
self.rtp_channel = channel
- channel.on('open', self.on_l2cap_channel_open)
+ channel.on('open', self.on_l2cap_channel_open)
channel.on('close', self.on_l2cap_channel_close)
# We don't need more channels
@@ -1734,7 +1881,7 @@ class Stream:
self.local_endpoint.in_use = 0
self.rtp_channel = None
- if self.state in {AVDTP_CLOSING_STATE, AVDTP_ABORTING_STATE}:
+ if self.state in (AVDTP_CLOSING_STATE, AVDTP_ABORTING_STATE):
self.change_state(AVDTP_IDLE_STATE)
else:
logger.warning('unexpected channel close while not CLOSING or ABORTING')
@@ -1744,54 +1891,57 @@ class Stream:
remote_endpoint must be a subclass of StreamEndPointProxy
'''
- self.protocol = protocol
- self.local_endpoint = local_endpoint
+ self.protocol = protocol
+ self.local_endpoint = local_endpoint
self.remote_endpoint = remote_endpoint
- self.rtp_channel = None
- self.state = AVDTP_IDLE_STATE
+ self.rtp_channel = None
+ self.state = AVDTP_IDLE_STATE
local_endpoint.stream = self
local_endpoint.in_use = 1
def __str__(self):
- return f'Stream({self.local_endpoint.seid} -> {self.remote_endpoint.seid} {self.state_name(self.state)})'
+ return (
+ f'Stream({self.local_endpoint.seid} -> '
+ f'{self.remote_endpoint.seid} {self.state_name(self.state)})'
+ )
# -----------------------------------------------------------------------------
class StreamEndPoint:
def __init__(self, seid, media_type, tsep, in_use, capabilities):
- self.seid = seid
- self.media_type = media_type
- self.tsep = tsep
- self.in_use = in_use
+ self.seid = seid
+ self.media_type = media_type
+ self.tsep = tsep
+ self.in_use = in_use
self.capabilities = capabilities
def __str__(self):
- return '\n'.join([
- 'SEP(',
- f' seid={self.seid}',
- f' media_type={name_or_number(AVDTP_MEDIA_TYPE_NAMES, self.media_type)}',
- f' tsep={name_or_number(AVDTP_TSEP_NAMES, self.tsep)}',
- f' in_use={self.in_use}',
- ' capabilities=[',
- '\n'.join([f' {x}' for x in self.capabilities]),
- ' ]',
- ')'
- ])
+ media_type = f'{name_or_number(AVDTP_MEDIA_TYPE_NAMES, self.media_type)}'
+ tsep = f'{name_or_number(AVDTP_TSEP_NAMES, self.tsep)}'
+ return '\n'.join(
+ [
+ 'SEP(',
+ f' seid={self.seid}',
+ f' media_type={media_type}',
+ f' tsep={tsep}',
+ f' in_use={self.in_use}',
+ ' capabilities=[',
+ '\n'.join([f' {x}' for x in self.capabilities]),
+ ' ]',
+ ')',
+ ]
+ )
# -----------------------------------------------------------------------------
class StreamEndPointProxy:
def __init__(self, protocol, seid):
- self.seid = seid
+ self.seid = seid
self.protocol = protocol
async def set_configuration(self, int_seid, configuration):
- return await self.protocol.set_configuration(
- self.seid,
- int_seid,
- configuration
- )
+ return await self.protocol.set_configuration(self.seid, int_seid, configuration)
async def open(self):
return await self.protocol.open(self.seid)
@@ -1818,11 +1968,13 @@ class DiscoveredStreamEndPoint(StreamEndPoint, StreamEndPointProxy):
# -----------------------------------------------------------------------------
class LocalStreamEndPoint(StreamEndPoint):
- def __init__(self, protocol, seid, media_type, tsep, capabilities, configuration=[]):
+ def __init__(
+ self, protocol, seid, media_type, tsep, capabilities, configuration=None
+ ):
super().__init__(seid, media_type, tsep, 0, capabilities)
- self.protocol = protocol
- self.configuration = configuration
- self.stream = None
+ self.protocol = protocol
+ self.configuration = configuration if configuration is not None else []
+ self.stream = None
async def start(self):
pass
@@ -1866,23 +2018,31 @@ class LocalSource(LocalStreamEndPoint, EventEmitter):
def __init__(self, protocol, seid, codec_capabilities, packet_pump):
capabilities = [
ServiceCapabilities(AVDTP_MEDIA_TRANSPORT_SERVICE_CATEGORY),
- codec_capabilities
+ codec_capabilities,
]
- LocalStreamEndPoint.__init__(self, protocol, seid, codec_capabilities.media_type, AVDTP_TSEP_SRC, capabilities, capabilities)
+ LocalStreamEndPoint.__init__(
+ self,
+ protocol,
+ seid,
+ codec_capabilities.media_type,
+ AVDTP_TSEP_SRC,
+ capabilities,
+ capabilities,
+ )
EventEmitter.__init__(self)
self.packet_pump = packet_pump
async def start(self):
if self.packet_pump:
return await self.packet_pump.start(self.stream.rtp_channel)
- else:
- self.emit('start', self.stream.rtp_channel)
+
+ self.emit('start', self.stream.rtp_channel)
async def stop(self):
if self.packet_pump:
return await self.packet_pump.stop()
- else:
- self.emit('stop')
+
+ self.emit('stop')
def on_set_configuration_command(self, configuration):
# For now, blindly accept the configuration
@@ -1890,10 +2050,10 @@ class LocalSource(LocalStreamEndPoint, EventEmitter):
self.configuration = configuration
def on_start_command(self):
- asyncio.get_running_loop().create_task(self.start())
+ asyncio.create_task(self.start())
def on_suspend_command(self):
- asyncio.get_running_loop().create_task(self.stop())
+ asyncio.create_task(self.stop())
# -----------------------------------------------------------------------------
@@ -1901,9 +2061,16 @@ class LocalSink(LocalStreamEndPoint, EventEmitter):
def __init__(self, protocol, seid, codec_capabilities):
capabilities = [
ServiceCapabilities(AVDTP_MEDIA_TRANSPORT_SERVICE_CATEGORY),
- codec_capabilities
+ codec_capabilities,
]
- LocalStreamEndPoint.__init__(self, protocol, seid, codec_capabilities.media_type, AVDTP_TSEP_SNK, capabilities)
+ LocalStreamEndPoint.__init__(
+ self,
+ protocol,
+ seid,
+ codec_capabilities.media_type,
+ AVDTP_TSEP_SNK,
+ capabilities,
+ )
EventEmitter.__init__(self)
def on_set_configuration_command(self, configuration):
@@ -1917,5 +2084,8 @@ class LocalSink(LocalStreamEndPoint, EventEmitter):
def on_avdtp_packet(self, packet):
rtp_packet = MediaPacket.from_bytes(packet)
- logger.debug(f'{color("<<< RTP Packet:", "green")} {rtp_packet} {rtp_packet.payload[:16].hex()}')
+ logger.debug(
+ f'{color("<<< RTP Packet:", "green")} '
+ f'{rtp_packet} {rtp_packet.payload[:16].hex()}'
+ )
self.emit('rtp_packet', rtp_packet)
diff --git a/bumble/bridge.py b/bumble/bridge.py
index 2b4cd94..ac3ba8a 100644
--- a/bumble/bridge.py
+++ b/bumble/bridge.py
@@ -30,10 +30,10 @@ logger = logging.getLogger(__name__)
class HCI_Bridge:
class Forwarder:
def __init__(self, hci_sink, sender_hci_sink, packet_filter, trace):
- self.hci_sink = hci_sink
+ self.hci_sink = hci_sink
self.sender_hci_sink = sender_hci_sink
- self.packet_filter = packet_filter
- self.trace = trace
+ self.packet_filter = packet_filter
+ self.trace = trace
def on_packet(self, packet):
# Convert the packet bytes to an object
@@ -61,15 +61,15 @@ class HCI_Bridge:
hci_host_sink,
hci_controller_source,
hci_controller_sink,
- host_to_controller_filter = None,
- controller_to_host_filter = None
+ host_to_controller_filter=None,
+ controller_to_host_filter=None,
):
tracer = PacketTracer(emit_message=logger.info)
host_to_controller_forwarder = HCI_Bridge.Forwarder(
hci_controller_sink,
hci_host_sink,
host_to_controller_filter,
- lambda packet: tracer.trace(packet, 0)
+ lambda packet: tracer.trace(packet, 0),
)
hci_host_source.set_packet_sink(host_to_controller_forwarder)
@@ -77,6 +77,6 @@ class HCI_Bridge:
hci_host_sink,
hci_controller_sink,
controller_to_host_filter,
- lambda packet: tracer.trace(packet, 1)
+ lambda packet: tracer.trace(packet, 1),
)
hci_controller_source.set_packet_sink(controller_to_host_forwarder)
diff --git a/bumble/colors.py b/bumble/colors.py
new file mode 100644
index 0000000..2813cfe
--- /dev/null
+++ b/bumble/colors.py
@@ -0,0 +1,103 @@
+# Copyright (c) 2012 Giorgos Verigakis <verigak@gmail.com>
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+from functools import partial
+from typing import List, Optional, Union
+
+
+# ANSI color names. There is also a "default"
+COLORS = ('black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white')
+
+# ANSI style names
+STYLES = (
+ 'none',
+ 'bold',
+ 'faint',
+ 'italic',
+ 'underline',
+ 'blink',
+ 'blink2',
+ 'negative',
+ 'concealed',
+ 'crossed',
+)
+
+
+ColorSpec = Union[str, int]
+
+
+def _join(*values: ColorSpec) -> str:
+ return ';'.join(str(v) for v in values)
+
+
+def _color_code(spec: ColorSpec, base: int) -> str:
+ if isinstance(spec, str):
+ spec = spec.strip().lower()
+
+ if spec == 'default':
+ return _join(base + 9)
+ elif spec in COLORS:
+ return _join(base + COLORS.index(spec))
+ elif isinstance(spec, int) and 0 <= spec <= 255:
+ return _join(base + 8, 5, spec)
+ else:
+ raise ValueError('Invalid color spec "%s"' % spec)
+
+
+def color(
+ s: str,
+ fg: Optional[ColorSpec] = None,
+ bg: Optional[ColorSpec] = None,
+ style: Optional[str] = None,
+) -> str:
+ codes: List[ColorSpec] = []
+
+ if fg:
+ codes.append(_color_code(fg, 30))
+ if bg:
+ codes.append(_color_code(bg, 40))
+ if style:
+ for style_part in style.split('+'):
+ if style_part in STYLES:
+ codes.append(STYLES.index(style_part))
+ else:
+ raise ValueError('Invalid style "%s"' % style_part)
+
+ if codes:
+ return '\x1b[{0}m{1}\x1b[0m'.format(_join(*codes), s)
+ else:
+ return s
+
+
+# Foreground color shortcuts
+black = partial(color, fg='black')
+red = partial(color, fg='red')
+green = partial(color, fg='green')
+yellow = partial(color, fg='yellow')
+blue = partial(color, fg='blue')
+magenta = partial(color, fg='magenta')
+cyan = partial(color, fg='cyan')
+white = partial(color, fg='white')
+
+# Style shortcuts
+bold = partial(color, style='bold')
+none = partial(color, style='none')
+faint = partial(color, style='faint')
+italic = partial(color, style='italic')
+underline = partial(color, style='underline')
+blink = partial(color, style='blink')
+blink2 = partial(color, style='blink2')
+negative = partial(color, style='negative')
+concealed = partial(color, style='concealed')
+crossed = partial(color, style='crossed')
diff --git a/bumble/company_ids.py b/bumble/company_ids.py
index c9c9d1a..1c40951 100644
--- a/bumble/company_ids.py
+++ b/bumble/company_ids.py
@@ -17,6 +17,7 @@
# the `generate_company_id_list.py` script
# -----------------------------------------------------------------------------
+# pylint: disable=line-too-long
COMPANY_IDENTIFIERS = {
0x0000: "Ericsson Technology Licensing",
0x0001: "Nokia Mobile Phones",
@@ -196,28 +197,28 @@ COMPANY_IDENTIFIERS = {
0x00AF: "Cinetix",
0x00B0: "Passif Semiconductor Corp",
0x00B1: "Saris Cycling Group, Inc",
- 0x00B2: "​Bekey A/S",
- 0x00B3: "​Clarinox Technologies Pty. Ltd.",
- 0x00B4: "​BDE Technology Co., Ltd.",
+ 0x00B2: "Bekey A/S",
+ 0x00B3: "Clarinox Technologies Pty. Ltd.",
+ 0x00B4: "BDE Technology Co., Ltd.",
0x00B5: "Swirl Networks",
- 0x00B6: "​Meso international",
- 0x00B7: "​TreLab Ltd",
- 0x00B8: "​Qualcomm Innovation Center, Inc. (QuIC)",
- 0x00B9: "​​Johnson Controls, Inc.",
- 0x00BA: "​Starkey Laboratories Inc.",
- 0x00BB: "​​S-Power Electronics Limited",
- 0x00BC: "​​Ace Sensor Inc",
- 0x00BD: "​​Aplix Corporation",
- 0x00BE: "​​AAMP of America",
- 0x00BF: "​​Stalmart Technology Limited",
- 0x00C0: "​​AMICCOM Electronics Corporation",
- 0x00C1: "​​Shenzhen Excelsecu Data Technology Co.,Ltd",
- 0x00C2: "​​Geneq Inc.",
- 0x00C3: "​​adidas AG",
- 0x00C4: "​​LG Electronics​",
- 0x00C5: "​Onset Computer Corporation",
- 0x00C6: "​Selfly BV",
- 0x00C7: "​Quuppa Oy.",
+ 0x00B6: "Meso international",
+ 0x00B7: "TreLab Ltd",
+ 0x00B8: "Qualcomm Innovation Center, Inc. (QuIC)",
+ 0x00B9: "Johnson Controls, Inc.",
+ 0x00BA: "Starkey Laboratories Inc.",
+ 0x00BB: "S-Power Electronics Limited",
+ 0x00BC: "Ace Sensor Inc",
+ 0x00BD: "Aplix Corporation",
+ 0x00BE: "AAMP of America",
+ 0x00BF: "Stalmart Technology Limited",
+ 0x00C0: "AMICCOM Electronics Corporation",
+ 0x00C1: "Shenzhen Excelsecu Data Technology Co.,Ltd",
+ 0x00C2: "Geneq Inc.",
+ 0x00C3: "adidas AG",
+ 0x00C4: "LG Electronics",
+ 0x00C5: "Onset Computer Corporation",
+ 0x00C6: "Selfly BV",
+ 0x00C7: "Quuppa Oy.",
0x00C8: "GeLo Inc",
0x00C9: "Evluma",
0x00CA: "MC10",
@@ -249,10 +250,10 @@ COMPANY_IDENTIFIERS = {
0x00E4: "Laird Connectivity, Inc. formerly L.S. Research Inc.",
0x00E5: "Eden Software Consultants Ltd.",
0x00E6: "Freshtemp",
- 0x00E7: "​KS Technologies",
- 0x00E8: "​ACTS Technologies",
- 0x00E9: "​Vtrack Systems",
- 0x00EA: "​Nielsen-Kellerman Company",
+ 0x00E7: "KS Technologies",
+ 0x00E8: "ACTS Technologies",
+ 0x00E9: "Vtrack Systems",
+ 0x00EA: "Nielsen-Kellerman Company",
0x00EB: "Server Technology Inc.",
0x00EC: "BioResearch Associates",
0x00ED: "Jolly Logic, LLC",
@@ -2704,5 +2705,5 @@ COMPANY_IDENTIFIERS = {
0x0A7C: "WAFERLOCK",
0x0A7D: "Freedman Electronics Pty Ltd",
0x0A7E: "Keba AG",
- 0x0A7F: "Intuity Medical"
-} \ No newline at end of file
+ 0x0A7F: "Intuity Medical",
+}
diff --git a/bumble/controller.py b/bumble/controller.py
index 35f7e92..cd7de3d 100644
--- a/bumble/controller.py
+++ b/bumble/controller.py
@@ -19,9 +19,47 @@ import logging
import asyncio
import itertools
import random
+import struct
+from bumble.colors import color
+from bumble.core import (
+ BT_CENTRAL_ROLE,
+ BT_PERIPHERAL_ROLE,
+ BT_LE_TRANSPORT,
+ BT_BR_EDR_TRANSPORT,
+)
+
+from bumble.hci import (
+ HCI_ACL_DATA_PACKET,
+ HCI_COMMAND_DISALLOWED_ERROR,
+ HCI_COMMAND_PACKET,
+ HCI_COMMAND_STATUS_PENDING,
+ HCI_CONNECTION_TIMEOUT_ERROR,
+ HCI_CONTROLLER_BUSY_ERROR,
+ HCI_EVENT_PACKET,
+ HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR,
+ HCI_LE_1M_PHY,
+ HCI_SUCCESS,
+ HCI_UNKNOWN_HCI_COMMAND_ERROR,
+ HCI_REMOTE_USER_TERMINATED_CONNECTION_ERROR,
+ HCI_VERSION_BLUETOOTH_CORE_5_0,
+ Address,
+ HCI_AclDataPacket,
+ HCI_AclDataPacketAssembler,
+ HCI_Command_Complete_Event,
+ HCI_Command_Status_Event,
+ HCI_Connection_Complete_Event,
+ HCI_Connection_Request_Event,
+ HCI_Disconnection_Complete_Event,
+ HCI_Encryption_Change_Event,
+ HCI_LE_Advertising_Report_Event,
+ HCI_LE_Connection_Complete_Event,
+ HCI_LE_Read_Remote_Features_Complete_Event,
+ HCI_Number_Of_Completed_Packets_Event,
+ HCI_Packet,
+ HCI_Role_Change_Event,
+)
+from typing import Optional, Union, Dict
-from .hci import *
-from .l2cap import *
# -----------------------------------------------------------------------------
# Logging
@@ -38,72 +76,108 @@ class DataObject:
# -----------------------------------------------------------------------------
class Connection:
- def __init__(self, controller, handle, role, peer_address, link):
- self.controller = controller
- self.handle = handle
- self.role = role
+ def __init__(self, controller, handle, role, peer_address, link, transport):
+ self.controller = controller
+ self.handle = handle
+ self.role = role
self.peer_address = peer_address
- self.link = link
- self.assembler = HCI_AclDataPacketAssembler(self.on_acl_pdu)
+ self.link = link
+ self.assembler = HCI_AclDataPacketAssembler(self.on_acl_pdu)
+ self.transport = transport
def on_hci_acl_data_packet(self, packet):
self.assembler.feed_packet(packet)
- self.controller.send_hci_packet(HCI_Number_Of_Completed_Packets_Event([(self.handle, 1)]))
+ self.controller.send_hci_packet(
+ HCI_Number_Of_Completed_Packets_Event([(self.handle, 1)])
+ )
def on_acl_pdu(self, data):
if self.link:
- self.link.send_acl_data(self.controller.random_address, self.peer_address, data)
+ self.link.send_acl_data(
+ self.controller, self.peer_address, self.transport, data
+ )
# -----------------------------------------------------------------------------
class Controller:
- def __init__(self, name, host_source = None, host_sink = None, link = None):
- self.name = name
+ def __init__(
+ self,
+ name,
+ host_source=None,
+ host_sink=None,
+ link=None,
+ public_address: Optional[Union[bytes, str, Address]] = None,
+ ):
+ self.name = name
self.hci_sink = None
- self.link = link
-
- self.central_connections = {} # Connections where this controller is the central
- self.peripheral_connections = {} # Connections where this controller is the peripheral
-
- self.hci_version = HCI_VERSION_BLUETOOTH_CORE_5_0
- self.hci_revision = 0
- self.lmp_version = HCI_VERSION_BLUETOOTH_CORE_5_0
- self.lmp_subversion = 0
- self.lmp_features = bytes.fromhex('0000000060000000') # BR/EDR Not Supported, LE Supported (Controller)
- self.manufacturer_name = 0xFFFF
- self.hc_le_data_packet_length = 27
+ self.link = link
+
+ self.central_connections: Dict[
+ Address, Connection
+ ] = {} # Connections where this controller is the central
+ self.peripheral_connections: Dict[
+ Address, Connection
+ ] = {} # Connections where this controller is the peripheral
+ self.classic_connections: Dict[
+ Address, Connection
+ ] = {} # Connections in BR/EDR
+
+ self.hci_version = HCI_VERSION_BLUETOOTH_CORE_5_0
+ self.hci_revision = 0
+ self.lmp_version = HCI_VERSION_BLUETOOTH_CORE_5_0
+ self.lmp_subversion = 0
+ self.lmp_features = bytes.fromhex(
+ '0000000060000000'
+ ) # BR/EDR Not Supported, LE Supported (Controller)
+ self.manufacturer_name = 0xFFFF
+ self.hc_le_data_packet_length = 27
self.hc_total_num_le_data_packets = 64
- self.supported_commands = bytes.fromhex('2000800000c000000000e40000002822000000000000040000f7ffff7f00000030f0f9ff01008004000000000000000000000000000000000000000000000000')
- self.le_features = bytes.fromhex('ff49010000000000')
- self.le_states = bytes.fromhex('ffff3fffff030000')
- self.avertising_channel_tx_power = 0
- self.white_list_size = 8
- self.resolving_list_size = 8
- self.supported_max_tx_octets = 27
- self.supported_max_tx_time = 10000 # microseconds
- self.supported_max_rx_octets = 27
- self.supported_max_rx_time = 10000 # microseconds
- self.suggested_max_tx_octets = 27
- self.suggested_max_tx_time = 0x0148 # microseconds
- self.default_phy = bytes([0, 0, 0])
- self.le_scan_type = 0
- self.le_scan_interval = 0x10
- self.le_scan_window = 0x10
- self.le_scan_enable = 0
- self.le_scan_own_address_type = Address.RANDOM_DEVICE_ADDRESS
- self.le_scanning_filter_policy = 0
- self.le_scan_response_data = None
- self.le_address_resolution = False
- self.le_rpa_timeout = 0
- self.sync_flow_control = False
- self.local_name = 'Bumble'
-
- self.advertising_interval = 2000 # Fixed for now
- self.advertising_data = None
+ self.event_mask = 0
+ self.event_mask_page_2 = 0
+ self.supported_commands = bytes.fromhex(
+ '2000800000c000000000e40000002822000000000000040000f7ffff7f000000'
+ '30f0f9ff01008004000000000000000000000000000000000000000000000000'
+ )
+ self.le_event_mask = 0
+ self.advertising_parameters = None
+ self.le_features = bytes.fromhex('ff49010000000000')
+ self.le_states = bytes.fromhex('ffff3fffff030000')
+ self.advertising_channel_tx_power = 0
+ self.filter_accept_list_size = 8
+ self.filter_duplicates = False
+ self.resolving_list_size = 8
+ self.supported_max_tx_octets = 27
+ self.supported_max_tx_time = 10000 # microseconds
+ self.supported_max_rx_octets = 27
+ self.supported_max_rx_time = 10000 # microseconds
+ self.suggested_max_tx_octets = 27
+ self.suggested_max_tx_time = 0x0148 # microseconds
+ self.default_phy = bytes([0, 0, 0])
+ self.le_scan_type = 0
+ self.le_scan_interval = 0x10
+ self.le_scan_window = 0x10
+ self.le_scan_enable = 0
+ self.le_scan_own_address_type = Address.RANDOM_DEVICE_ADDRESS
+ self.le_scanning_filter_policy = 0
+ self.le_scan_response_data = None
+ self.le_address_resolution = False
+ self.le_rpa_timeout = 0
+ self.sync_flow_control = False
+ self.local_name = 'Bumble'
+
+ self.advertising_interval = 2000 # Fixed for now
+ self.advertising_data = None
self.advertising_timer_handle = None
self._random_address = Address('00:00:00:00:00:00')
- self._public_address = None
+ if isinstance(public_address, Address):
+ self._public_address = public_address
+ elif public_address is not None:
+ self._public_address = Address(
+ public_address, Address.PUBLIC_DEVICE_ADDRESS
+ )
+ else:
+ self._public_address = Address('00:00:00:00:00:00')
# Set the source and sink interfaces
if host_source:
@@ -121,7 +195,8 @@ class Controller:
@host.setter
def host(self, host):
'''
- Sets the host (sink) for this controller, and set this controller as the controller (sink) for the host
+ Sets the host (sink) for this controller, and set this controller as the
+ controller (sink) for the host
'''
self.set_packet_sink(host)
if host:
@@ -139,7 +214,7 @@ class Controller:
@public_address.setter
def public_address(self, address):
- if type(address) is str:
+ if isinstance(address, str):
address = Address(address)
self._public_address = address
@@ -149,7 +224,7 @@ class Controller:
@random_address.setter
def random_address(self, address):
- if type(address) is str:
+ if isinstance(address, str):
address = Address(address)
self._random_address = address
logger.debug(f'new random address: {address}')
@@ -162,7 +237,10 @@ class Controller:
self.on_hci_packet(HCI_Packet.from_bytes(packet))
def on_hci_packet(self, packet):
- logger.debug(f'{color("<<<", "blue")} [{self.name}] {color("HOST -> CONTROLLER", "blue")}: {packet}')
+ logger.debug(
+ f'{color("<<<", "blue")} [{self.name}] '
+ f'{color("HOST -> CONTROLLER", "blue")}: {packet}'
+ )
# If the packet is a command, invoke the handler for this packet
if packet.hci_packet_type == HCI_COMMAND_PACKET:
@@ -178,28 +256,35 @@ class Controller:
handler_name = f'on_{command.name.lower()}'
handler = getattr(self, handler_name, self.on_hci_command)
result = handler(command)
- if type(result) is bytes:
- self.send_hci_packet(HCI_Command_Complete_Event(
- num_hci_command_packets = 1,
- command_opcode = command.op_code,
- return_parameters = result
- ))
-
- def on_hci_event_packet(self, event):
+ if isinstance(result, bytes):
+ self.send_hci_packet(
+ HCI_Command_Complete_Event(
+ num_hci_command_packets=1,
+ command_opcode=command.op_code,
+ return_parameters=result,
+ )
+ )
+
+ def on_hci_event_packet(self, _event):
logger.warning('!!! unexpected event packet')
def on_hci_acl_data_packet(self, packet):
# Look for the connection to which this data belongs
connection = self.find_connection_by_handle(packet.connection_handle)
if connection is None:
- logger.warning(f'!!! no connection for handle 0x{packet.connection_handle:04X}')
+ logger.warning(
+ f'!!! no connection for handle 0x{packet.connection_handle:04X}'
+ )
return
# Pass the packet to the connection
connection.on_hci_acl_data_packet(packet)
def send_hci_packet(self, packet):
- logger.debug(f'{color(">>>", "green")} [{self.name}] {color("CONTROLLER -> HOST", "green")}: {packet}')
+ logger.debug(
+ f'{color(">>>", "green")} [{self.name}] '
+ f'{color("CONTROLLER -> HOST", "green")}: {packet}'
+ )
if self.host:
self.host.on_packet(packet.to_bytes())
@@ -216,7 +301,8 @@ class Controller:
max_handle = 0
for connection in itertools.chain(
self.central_connections.values(),
- self.peripheral_connections.values()
+ self.peripheral_connections.values(),
+ self.classic_connections.values(),
):
max_handle = max(max_handle, connection.handle)
if connection.handle == handle:
@@ -224,13 +310,19 @@ class Controller:
handle = max_handle + 1
return handle
- def find_connection_by_address(self, address):
- return self.central_connections.get(address) or self.peripheral_connections.get(address)
+ def find_le_connection_by_address(self, address):
+ return self.central_connections.get(address) or self.peripheral_connections.get(
+ address
+ )
+
+ def find_classic_connection_by_address(self, address):
+ return self.classic_connections.get(address)
def find_connection_by_handle(self, handle):
for connection in itertools.chain(
self.central_connections.values(),
- self.peripheral_connections.values()
+ self.peripheral_connections.values(),
+ self.classic_connections.values(),
):
if connection.handle == handle:
return connection
@@ -242,6 +334,12 @@ class Controller:
return connection
return None
+ def find_classic_connection_by_handle(self, handle):
+ for connection in self.classic_connections.values():
+ if connection.handle == handle:
+ return connection
+ return None
+
def on_link_central_connected(self, central_address):
'''
Called when an incoming connection occurs from a central on the link
@@ -253,22 +351,31 @@ class Controller:
connection = self.peripheral_connections.get(peer_address)
if connection is None:
connection_handle = self.allocate_connection_handle()
- connection = Connection(self, connection_handle, BT_PERIPHERAL_ROLE, peer_address, self.link)
+ connection = Connection(
+ self,
+ connection_handle,
+ BT_PERIPHERAL_ROLE,
+ peer_address,
+ self.link,
+ BT_LE_TRANSPORT,
+ )
self.peripheral_connections[peer_address] = connection
logger.debug(f'New PERIPHERAL connection handle: 0x{connection_handle:04X}')
# Then say that the connection has completed
- self.send_hci_packet(HCI_LE_Connection_Complete_Event(
- status = HCI_SUCCESS,
- connection_handle = connection.handle,
- role = connection.role,
- peer_address_type = peer_address_type,
- peer_address = peer_address,
- conn_interval = 10, # FIXME
- conn_latency = 0, # FIXME
- supervision_timeout = 10, # FIXME
- master_clock_accuracy = 7 # FIXME
- ))
+ self.send_hci_packet(
+ HCI_LE_Connection_Complete_Event(
+ status=HCI_SUCCESS,
+ connection_handle=connection.handle,
+ role=connection.role,
+ peer_address_type=peer_address_type,
+ peer_address=peer_address,
+ connection_interval=10, # FIXME
+ peripheral_latency=0, # FIXME
+ supervision_timeout=10, # FIXME
+ central_clock_accuracy=7, # FIXME
+ )
+ )
def on_link_central_disconnected(self, peer_address, reason):
'''
@@ -277,18 +384,22 @@ class Controller:
# Send a disconnection complete event
if connection := self.peripheral_connections.get(peer_address):
- self.send_hci_packet(HCI_Disconnection_Complete_Event(
- status = HCI_SUCCESS,
- connection_handle = connection.handle,
- reason = reason
- ))
+ self.send_hci_packet(
+ HCI_Disconnection_Complete_Event(
+ status=HCI_SUCCESS,
+ connection_handle=connection.handle,
+ reason=reason,
+ )
+ )
# Remove the connection
del self.peripheral_connections[peer_address]
else:
- logger.warn(f'!!! No peripheral connection found for {peer_address}')
+ logger.warning(f'!!! No peripheral connection found for {peer_address}')
- def on_link_peripheral_connection_complete(self, le_create_connection_command, status):
+ def on_link_peripheral_connection_complete(
+ self, le_create_connection_command, status
+ ):
'''
Called by the link when a connection has been made or has failed to be made
'''
@@ -304,25 +415,31 @@ class Controller:
connection_handle,
BT_CENTRAL_ROLE,
peer_address,
- self.link
+ self.link,
+ BT_LE_TRANSPORT,
)
self.central_connections[peer_address] = connection
- logger.debug(f'New CENTRAL connection handle: 0x{connection_handle:04X}')
+ logger.debug(
+ f'New CENTRAL connection handle: 0x{connection_handle:04X}'
+ )
else:
connection = None
# Say that the connection has completed
- self.send_hci_packet(HCI_LE_Connection_Complete_Event(
- status = status,
- connection_handle = connection.handle if connection else 0,
- role = BT_CENTRAL_ROLE,
- peer_address_type = le_create_connection_command.peer_address_type,
- peer_address = le_create_connection_command.peer_address,
- conn_interval = le_create_connection_command.conn_interval_min,
- conn_latency = le_create_connection_command.conn_latency,
- supervision_timeout = le_create_connection_command.supervision_timeout,
- master_clock_accuracy = 0
- ))
+ self.send_hci_packet(
+ # pylint: disable=line-too-long
+ HCI_LE_Connection_Complete_Event(
+ status=status,
+ connection_handle=connection.handle if connection else 0,
+ role=BT_CENTRAL_ROLE,
+ peer_address_type=le_create_connection_command.peer_address_type,
+ peer_address=le_create_connection_command.peer_address,
+ connection_interval=le_create_connection_command.connection_interval_min,
+ peripheral_latency=le_create_connection_command.max_latency,
+ supervision_timeout=le_create_connection_command.supervision_timeout,
+ central_clock_accuracy=0,
+ )
+ )
def on_link_peripheral_disconnection_complete(self, disconnection_command, status):
'''
@@ -330,14 +447,18 @@ class Controller:
'''
# Send a disconnection complete event
- self.send_hci_packet(HCI_Disconnection_Complete_Event(
- status = status,
- connection_handle = disconnection_command.connection_handle,
- reason = disconnection_command.reason
- ))
+ self.send_hci_packet(
+ HCI_Disconnection_Complete_Event(
+ status=status,
+ connection_handle=disconnection_command.connection_handle,
+ reason=disconnection_command.reason,
+ )
+ )
# Remove the connection
- if connection := self.find_central_connection_by_handle(disconnection_command.connection_handle):
+ if connection := self.find_central_connection_by_handle(
+ disconnection_command.connection_handle
+ ):
logger.debug(f'CENTRAL Connection removed: {connection}')
del self.central_connections[connection.peer_address]
@@ -348,31 +469,34 @@ class Controller:
# Send a disconnection complete event
if connection := self.central_connections.get(peer_address):
- self.send_hci_packet(HCI_Disconnection_Complete_Event(
- status = HCI_SUCCESS,
- connection_handle = connection.handle,
- reason = HCI_CONNECTION_TIMEOUT_ERROR
- ))
+ self.send_hci_packet(
+ HCI_Disconnection_Complete_Event(
+ status=HCI_SUCCESS,
+ connection_handle=connection.handle,
+ reason=HCI_CONNECTION_TIMEOUT_ERROR,
+ )
+ )
# Remove the connection
del self.central_connections[peer_address]
else:
- logger.warn(f'!!! No central connection found for {peer_address}')
+ logger.warning(f'!!! No central connection found for {peer_address}')
- def on_link_encrypted(self, peer_address, rand, ediv, ltk):
+ def on_link_encrypted(self, peer_address, _rand, _ediv, _ltk):
# For now, just setup the encryption without asking the host
- if connection := self.find_connection_by_address(peer_address):
+ if connection := self.find_le_connection_by_address(peer_address):
self.send_hci_packet(
HCI_Encryption_Change_Event(
- status = 0,
- connection_handle = connection.handle,
- encryption_enabled = 1
+ status=0, connection_handle=connection.handle, encryption_enabled=1
)
)
- def on_link_acl_data(self, sender_address, data):
+ def on_link_acl_data(self, sender_address, transport, data):
# Look for the connection to which this data belongs
- connection = self.find_connection_by_address(sender_address)
+ if transport == BT_LE_TRANSPORT:
+ connection = self.find_le_connection_by_address(sender_address)
+ else:
+ connection = self.find_classic_connection_by_address(sender_address)
if connection is None:
logger.warning(f'!!! no connection for {sender_address}')
return
@@ -388,40 +512,125 @@ class Controller:
return
# Send a scan report
- report = HCI_Object(
- HCI_LE_Advertising_Report_Event.REPORT_FIELDS,
- event_type = HCI_LE_Advertising_Report_Event.ADV_IND,
- address_type = sender_address.address_type,
- address = sender_address,
- data = data,
- rssi = -50
+ report = HCI_LE_Advertising_Report_Event.Report(
+ HCI_LE_Advertising_Report_Event.Report.FIELDS,
+ event_type=HCI_LE_Advertising_Report_Event.ADV_IND,
+ address_type=sender_address.address_type,
+ address=sender_address,
+ data=data,
+ rssi=-50,
)
self.send_hci_packet(HCI_LE_Advertising_Report_Event([report]))
# Simulate a scan response
- report = HCI_Object(
- HCI_LE_Advertising_Report_Event.REPORT_FIELDS,
- event_type = HCI_LE_Advertising_Report_Event.SCAN_RSP,
- address_type = sender_address.address_type,
- address = sender_address,
- data = data,
- rssi = -50
+ report = HCI_LE_Advertising_Report_Event.Report(
+ HCI_LE_Advertising_Report_Event.Report.FIELDS,
+ event_type=HCI_LE_Advertising_Report_Event.SCAN_RSP,
+ address_type=sender_address.address_type,
+ address=sender_address,
+ data=data,
+ rssi=-50,
)
self.send_hci_packet(HCI_LE_Advertising_Report_Event([report]))
############################################################
+ # Classic link connections
+ ############################################################
+
+ def on_classic_connection_request(self, peer_address, link_type):
+ self.send_hci_packet(
+ HCI_Connection_Request_Event(
+ bd_addr=peer_address,
+ class_of_device=0,
+ link_type=link_type,
+ )
+ )
+
+ def on_classic_connection_complete(self, peer_address, status):
+ if status == HCI_SUCCESS:
+ # Allocate (or reuse) a connection handle
+ peer_address = peer_address
+ connection = self.classic_connections.get(peer_address)
+ if connection is None:
+ connection_handle = self.allocate_connection_handle()
+ connection = Connection(
+ controller=self,
+ handle=connection_handle,
+ # Role doesn't matter in Classic because they are managed by HCI_Role_Change and HCI_Role_Discovery
+ role=BT_CENTRAL_ROLE,
+ peer_address=peer_address,
+ link=self.link,
+ transport=BT_BR_EDR_TRANSPORT,
+ )
+ self.classic_connections[peer_address] = connection
+ logger.debug(
+ f'New CLASSIC connection handle: 0x{connection_handle:04X}'
+ )
+ else:
+ connection_handle = connection.handle
+ self.send_hci_packet(
+ HCI_Connection_Complete_Event(
+ status=status,
+ connection_handle=connection_handle,
+ bd_addr=peer_address,
+ encryption_enabled=False,
+ link_type=HCI_Connection_Complete_Event.ACL_LINK_TYPE,
+ )
+ )
+ else:
+ connection = None
+ self.send_hci_packet(
+ HCI_Connection_Complete_Event(
+ status=status,
+ connection_handle=0,
+ bd_addr=peer_address,
+ encryption_enabled=False,
+ link_type=HCI_Connection_Complete_Event.ACL_LINK_TYPE,
+ )
+ )
+
+ def on_classic_disconnected(self, peer_address, reason):
+ # Send a disconnection complete event
+ if connection := self.classic_connections.get(peer_address):
+ self.send_hci_packet(
+ HCI_Disconnection_Complete_Event(
+ status=HCI_SUCCESS,
+ connection_handle=connection.handle,
+ reason=reason,
+ )
+ )
+
+ # Remove the connection
+ del self.classic_connections[peer_address]
+ else:
+ logger.warning(f'!!! No classic connection found for {peer_address}')
+
+ def on_classic_role_change(self, peer_address, new_role):
+ self.send_hci_packet(
+ HCI_Role_Change_Event(
+ status=HCI_SUCCESS,
+ bd_addr=peer_address,
+ new_role=new_role,
+ )
+ )
+
+ ############################################################
# Advertising support
############################################################
def on_advertising_timer_fired(self):
self.send_advertising_data()
- self.advertising_timer_handle = asyncio.get_running_loop().call_later(self.advertising_interval / 1000.0, self.on_advertising_timer_fired)
+ self.advertising_timer_handle = asyncio.get_running_loop().call_later(
+ self.advertising_interval / 1000.0, self.on_advertising_timer_fired
+ )
def start_advertising(self):
# Stop any ongoing advertising before we start again
self.stop_advertising()
# Advertise now
- self.advertising_timer_handle = asyncio.get_running_loop().call_soon(self.on_advertising_timer_fired)
+ self.advertising_timer_handle = asyncio.get_running_loop().call_soon(
+ self.on_advertising_timer_fired
+ )
def stop_advertising(self):
if self.advertising_timer_handle is not None:
@@ -448,29 +657,97 @@ class Controller:
See Bluetooth spec Vol 2, Part E - 7.1.5 Create Connection command
'''
- # TODO: classic mode not supported yet
+ if self.link is None:
+ return
+ logger.debug(f'Connection request to {command.bd_addr}')
+
+ # Check that we don't already have a pending connection
+ if self.link.get_pending_connection():
+ self.send_hci_packet(
+ HCI_Command_Status_Event(
+ status=HCI_CONTROLLER_BUSY_ERROR,
+ num_hci_command_packets=1,
+ command_opcode=command.op_code,
+ )
+ )
+ return
+
+ self.link.classic_connect(self, command.bd_addr)
+
+ # Say that the connection is pending
+ self.send_hci_packet(
+ HCI_Command_Status_Event(
+ status=HCI_COMMAND_STATUS_PENDING,
+ num_hci_command_packets=1,
+ command_opcode=command.op_code,
+ )
+ )
def on_hci_disconnect_command(self, command):
'''
See Bluetooth spec Vol 2, Part E - 7.1.6 Disconnect Command
'''
# First, say that the disconnection is pending
- self.send_hci_packet(HCI_Command_Status_Event(
- status = HCI_COMMAND_STATUS_PENDING,
- num_hci_command_packets = 1,
- command_opcode = command.op_code
- ))
+ self.send_hci_packet(
+ HCI_Command_Status_Event(
+ status=HCI_COMMAND_STATUS_PENDING,
+ num_hci_command_packets=1,
+ command_opcode=command.op_code,
+ )
+ )
# Notify the link of the disconnection
- if not (connection := self.find_central_connection_by_handle(command.connection_handle)):
- logger.warn('connection not found')
+ handle = command.connection_handle
+ if connection := self.find_central_connection_by_handle(handle):
+ if self.link:
+ self.link.disconnect(
+ self.random_address, connection.peer_address, command
+ )
+ else:
+ # Remove the connection
+ del self.central_connections[connection.peer_address]
+ elif connection := self.find_classic_connection_by_handle(handle):
+ if self.link:
+ self.link.classic_disconnect(
+ self,
+ connection.peer_address,
+ HCI_REMOTE_USER_TERMINATED_CONNECTION_ERROR,
+ )
+ else:
+ # Remove the connection
+ del self.classic_connections[connection.peer_address]
+
+ def on_hci_accept_connection_request_command(self, command):
+ '''
+ See Bluetooth spec Vol 2, Part E - 7.1.8 Accept Connection Request command
+ '''
+
+ if self.link is None:
return
+ self.send_hci_packet(
+ HCI_Command_Status_Event(
+ status=HCI_SUCCESS,
+ num_hci_command_packets=1,
+ command_opcode=command.op_code,
+ )
+ )
+ self.link.classic_accept_connection(self, command.bd_addr, command.role)
- if self.link:
- self.link.disconnect(self.random_address, connection.peer_address, command)
- else:
- # Remove the connection
- del self.central_connections[connection.peer_address]
+ def on_hci_switch_role_command(self, command):
+ '''
+ See Bluetooth spec Vol 2, Part E - 7.2.8 Switch Role command
+ '''
+
+ if self.link is None:
+ return
+ self.send_hci_packet(
+ HCI_Command_Status_Event(
+ status=HCI_SUCCESS,
+ num_hci_command_packets=1,
+ command_opcode=command.op_code,
+ )
+ )
+ self.link.classic_switch_role(self, command.bd_addr, command.role)
def on_hci_set_event_mask_command(self, command):
'''
@@ -479,7 +756,7 @@ class Controller:
self.event_mask = command.event_mask
return bytes([HCI_SUCCESS])
- def on_hci_reset_command(self, command):
+ def on_hci_reset_command(self, _command):
'''
See Bluetooth spec Vol 2, Part E - 7.3.2 Reset Command
'''
@@ -501,7 +778,7 @@ class Controller:
pass
return bytes([HCI_SUCCESS])
- def on_hci_read_local_name_command(self, command):
+ def on_hci_read_local_name_command(self, _command):
'''
See Bluetooth spec Vol 2, Part E - 7.3.12 Read Local Name Command
'''
@@ -511,21 +788,22 @@ class Controller:
return bytes([HCI_SUCCESS]) + local_name
- def on_hci_read_class_of_device_command(self, command):
+ def on_hci_read_class_of_device_command(self, _command):
'''
See Bluetooth spec Vol 2, Part E - 7.3.25 Read Class of Device Command
'''
return bytes([HCI_SUCCESS, 0, 0, 0])
- def on_hci_write_class_of_device_command(self, command):
+ def on_hci_write_class_of_device_command(self, _command):
'''
See Bluetooth spec Vol 2, Part E - 7.3.26 Write Class of Device Command
'''
return bytes([HCI_SUCCESS])
- def on_hci_read_synchronous_flow_control_enable_command(self, command):
+ def on_hci_read_synchronous_flow_control_enable_command(self, _command):
'''
- See Bluetooth spec Vol 2, Part E - 7.3.36 Read Synchronous Flow Control Enable Command
+ See Bluetooth spec Vol 2, Part E - 7.3.36 Read Synchronous Flow Control Enable
+ Command
'''
if self.sync_flow_control:
ret = 1
@@ -535,7 +813,8 @@ class Controller:
def on_hci_write_synchronous_flow_control_enable_command(self, command):
'''
- See Bluetooth spec Vol 2, Part E - 7.3.37 Write Synchronous Flow Control Enable Command
+ See Bluetooth spec Vol 2, Part E - 7.3.37 Write Synchronous Flow Control Enable
+ Command
'''
ret = HCI_SUCCESS
if command.synchronous_flow_control_enable == 1:
@@ -546,7 +825,13 @@ class Controller:
ret = HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR
return bytes([ret])
- def on_hci_write_simple_pairing_mode_command(self, command):
+ def on_hci_write_extended_inquiry_response_command(self, _command):
+ '''
+ See Bluetooth spec Vol 2, Part E - 7.3.59 Write Simple Pairing Mode Command
+ '''
+ return bytes([HCI_SUCCESS])
+
+ def on_hci_write_simple_pairing_mode_command(self, _command):
'''
See Bluetooth spec Vol 2, Part E - 7.3.59 Write Simple Pairing Mode Command
'''
@@ -559,13 +844,13 @@ class Controller:
self.event_mask_page_2 = command.event_mask_page_2
return bytes([HCI_SUCCESS])
- def on_hci_read_le_host_support_command(self, command):
+ def on_hci_read_le_host_support_command(self, _command):
'''
See Bluetooth spec Vol 2, Part E - 7.3.78 Write LE Host Support Command
'''
return bytes([HCI_SUCCESS, 1, 0])
- def on_hci_write_le_host_support_command(self, command):
+ def on_hci_write_le_host_support_command(self, _command):
'''
See Bluetooth spec Vol 2, Part E - 7.3.79 Write LE Host Support Command
'''
@@ -574,40 +859,47 @@ class Controller:
def on_hci_write_authenticated_payload_timeout_command(self, command):
'''
- See Bluetooth spec Vol 2, Part E - 7.3.94 Write Authenticated Payload Timeout Command
+ See Bluetooth spec Vol 2, Part E - 7.3.94 Write Authenticated Payload Timeout
+ Command
'''
# TODO
return struct.pack('<BH', HCI_SUCCESS, command.connection_handle)
- def on_hci_read_local_version_information_command(self, command):
+ def on_hci_read_local_version_information_command(self, _command):
'''
See Bluetooth spec Vol 2, Part E - 7.4.1 Read Local Version Information Command
'''
- return struct.pack('<BBHBHH',
- HCI_SUCCESS,
- self.hci_version,
- self.hci_revision,
- self.lmp_version,
- self.manufacturer_name,
- self.lmp_subversion)
+ return struct.pack(
+ '<BBHBHH',
+ HCI_SUCCESS,
+ self.hci_version,
+ self.hci_revision,
+ self.lmp_version,
+ self.manufacturer_name,
+ self.lmp_subversion,
+ )
- def on_hci_read_local_supported_commands_command(self, command):
+ def on_hci_read_local_supported_commands_command(self, _command):
'''
See Bluetooth spec Vol 2, Part E - 7.4.2 Read Local Supported Commands Command
'''
return bytes([HCI_SUCCESS]) + self.supported_commands
- def on_hci_read_local_supported_features_command(self, command):
+ def on_hci_read_local_supported_features_command(self, _command):
'''
See Bluetooth spec Vol 2, Part E - 7.4.3 Read Local Supported Features Command
'''
return bytes([HCI_SUCCESS]) + self.lmp_features
- def on_hci_read_bd_addr_command(self, command):
+ def on_hci_read_bd_addr_command(self, _command):
'''
See Bluetooth spec Vol 2, Part E - 7.4.6 Read BD_ADDR Command
'''
- bd_addr = self._public_address.to_bytes() if self._public_address is not None else bytes(6)
+ bd_addr = (
+ self._public_address.to_bytes()
+ if self._public_address is not None
+ else bytes(6)
+ )
return bytes([HCI_SUCCESS]) + bd_addr
def on_hci_le_set_event_mask_command(self, command):
@@ -617,18 +909,21 @@ class Controller:
self.le_event_mask = command.le_event_mask
return bytes([HCI_SUCCESS])
- def on_hci_le_read_buffer_size_command(self, command):
+ def on_hci_le_read_buffer_size_command(self, _command):
'''
See Bluetooth spec Vol 2, Part E - 7.8.2 LE Read Buffer Size Command
'''
- return struct.pack('<BHB',
- HCI_SUCCESS,
- self.hc_le_data_packet_length,
- self.hc_total_num_le_data_packets)
+ return struct.pack(
+ '<BHB',
+ HCI_SUCCESS,
+ self.hc_le_data_packet_length,
+ self.hc_total_num_le_data_packets,
+ )
- def on_hci_le_read_local_supported_features_command(self, command):
+ def on_hci_le_read_local_supported_features_command(self, _command):
'''
- See Bluetooth spec Vol 2, Part E - 7.8.3 LE Read Local Supported Features Command
+ See Bluetooth spec Vol 2, Part E - 7.8.3 LE Read Local Supported Features
+ Command
'''
return bytes([HCI_SUCCESS]) + self.le_features
@@ -646,11 +941,12 @@ class Controller:
self.advertising_parameters = command
return bytes([HCI_SUCCESS])
- def on_hci_le_read_advertising_channel_tx_power_command(self, command):
+ def on_hci_le_read_advertising_physical_channel_tx_power_command(self, _command):
'''
- See Bluetooth spec Vol 2, Part E - 7.8.6 LE Read Advertising Channel Tx Power Command
+ See Bluetooth spec Vol 2, Part E - 7.8.6 LE Read Advertising Physical Channel
+ Tx Power Command
'''
- return bytes([HCI_SUCCESS, self.avertising_channel_tx_power])
+ return bytes([HCI_SUCCESS, self.advertising_channel_tx_power])
def on_hci_le_set_advertising_data_command(self, command):
'''
@@ -681,10 +977,10 @@ class Controller:
'''
See Bluetooth spec Vol 2, Part E - 7.8.10 LE Set Scan Parameters Command
'''
- self.le_scan_type = command.le_scan_type
- self.le_scan_interval = command.le_scan_interval
- self.le_scan_window = command.le_scan_window
- self.le_scan_own_address_type = command.own_address_type
+ self.le_scan_type = command.le_scan_type
+ self.le_scan_interval = command.le_scan_interval
+ self.le_scan_window = command.le_scan_window
+ self.le_scan_own_address_type = command.own_address_type
self.le_scanning_filter_policy = command.scanning_filter_policy
return bytes([HCI_SUCCESS])
@@ -692,7 +988,7 @@ class Controller:
'''
See Bluetooth spec Vol 2, Part E - 7.8.11 LE Set Scan Enable Command
'''
- self.le_scan_enable = command.le_scan_enable
+ self.le_scan_enable = command.le_scan_enable
self.filter_duplicates = command.filter_duplicates
return bytes([HCI_SUCCESS])
@@ -708,50 +1004,57 @@ class Controller:
# Check that we don't already have a pending connection
if self.link.get_pending_connection():
- self.send_hci_packet(HCI_Command_Status_Event(
- status = HCI_COMMAND_DISALLOWED_ERROR,
- num_hci_command_packets = 1,
- command_opcode = command.op_code
- ))
+ self.send_hci_packet(
+ HCI_Command_Status_Event(
+ status=HCI_COMMAND_DISALLOWED_ERROR,
+ num_hci_command_packets=1,
+ command_opcode=command.op_code,
+ )
+ )
return
# Initiate the connection
self.link.connect(self.random_address, command)
# Say that the connection is pending
- self.send_hci_packet(HCI_Command_Status_Event(
- status = HCI_COMMAND_STATUS_PENDING,
- num_hci_command_packets = 1,
- command_opcode = command.op_code
- ))
+ self.send_hci_packet(
+ HCI_Command_Status_Event(
+ status=HCI_COMMAND_STATUS_PENDING,
+ num_hci_command_packets=1,
+ command_opcode=command.op_code,
+ )
+ )
- def on_hci_le_create_connection_cancel_command(self, command):
+ def on_hci_le_create_connection_cancel_command(self, _command):
'''
See Bluetooth spec Vol 2, Part E - 7.8.13 LE Create Connection Cancel Command
'''
return bytes([HCI_SUCCESS])
- def on_hci_le_read_white_list_size_command(self, command):
+ def on_hci_le_read_filter_accept_list_size_command(self, _command):
'''
- See Bluetooth spec Vol 2, Part E - 7.8.14 LE Read White List Size Command
+ See Bluetooth spec Vol 2, Part E - 7.8.14 LE Read Filter Accept List Size
+ Command
'''
- return bytes([HCI_SUCCESS, self.white_list_size])
+ return bytes([HCI_SUCCESS, self.filter_accept_list_size])
- def on_hci_le_clear_white_list_command(self, command):
+ def on_hci_le_clear_filter_accept_list_command(self, _command):
'''
- See Bluetooth spec Vol 2, Part E - 7.8.15 LE Clear White List Command
+ See Bluetooth spec Vol 2, Part E - 7.8.15 LE Clear Filter Accept List Command
'''
return bytes([HCI_SUCCESS])
- def on_hci_le_add_device_to_white_list_command(self, command):
+ def on_hci_le_add_device_to_filter_accept_list_command(self, _command):
'''
- See Bluetooth spec Vol 2, Part E - 7.8.16 LE Add Device To White List Command
+ See Bluetooth spec Vol 2, Part E - 7.8.16 LE Add Device To Filter Accept List
+ Command
'''
return bytes([HCI_SUCCESS])
- def on_hci_le_remove_device_from_white_list_command(self, command):
+ def on_hci_le_remove_device_from_filter_accept_list_command(self, _command):
'''
- See Bluetooth spec Vol 2, Part E - 7.8.17 LE Remove Device From White List Command
+ See Bluetooth spec Vol 2, Part E - 7.8.17 LE Remove Device From Filter Accept
+ List Command
'''
return bytes([HCI_SUCCESS])
@@ -761,33 +1064,41 @@ class Controller:
'''
# First, say that the command is pending
- self.send_hci_packet(HCI_Command_Status_Event(
- status = HCI_COMMAND_STATUS_PENDING,
- num_hci_command_packets = 1,
- command_opcode = command.op_code
- ))
+ self.send_hci_packet(
+ HCI_Command_Status_Event(
+ status=HCI_COMMAND_STATUS_PENDING,
+ num_hci_command_packets=1,
+ command_opcode=command.op_code,
+ )
+ )
# Then send the remote features
- self.send_hci_packet(HCI_LE_Read_Remote_Features_Complete_Event(
- status = HCI_SUCCESS,
- connection_handle = 0,
- le_features = bytes.fromhex('dd40000000000000')
- ))
+ self.send_hci_packet(
+ HCI_LE_Read_Remote_Features_Complete_Event(
+ status=HCI_SUCCESS,
+ connection_handle=0,
+ le_features=bytes.fromhex('dd40000000000000'),
+ )
+ )
- def on_hci_le_rand_command(self, command):
+ def on_hci_le_rand_command(self, _command):
'''
See Bluetooth spec Vol 2, Part E - 7.8.23 LE Rand Command
'''
return bytes([HCI_SUCCESS]) + struct.pack('Q', random.randint(0, 1 << 64))
- def on_hci_le_start_encryption_command(self, command):
+ def on_hci_le_enable_encryption_command(self, command):
'''
- See Bluetooth spec Vol 2, Part E - 7.8.24 LE Start Encryption Command
+ See Bluetooth spec Vol 2, Part E - 7.8.24 LE Enable Encryption Command
'''
# Check the parameters
- if not (connection := self.find_central_connection_by_handle(command.connection_handle)):
- logger.warn('connection not found')
+ if not (
+ connection := self.find_central_connection_by_handle(
+ command.connection_handle
+ )
+ ):
+ logger.warning('connection not found')
return bytes([HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR])
# Notify that the connection is now encrypted
@@ -796,57 +1107,68 @@ class Controller:
connection.peer_address,
command.random_number,
command.encrypted_diversifier,
- command.long_term_key
+ command.long_term_key,
+ )
+
+ self.send_hci_packet(
+ HCI_Command_Status_Event(
+ status=HCI_COMMAND_STATUS_PENDING,
+ num_hci_command_packets=1,
+ command_opcode=command.op_code,
+ )
)
- self.send_hci_packet(HCI_Command_Status_Event(
- status = HCI_COMMAND_STATUS_PENDING,
- num_hci_command_packets = 1,
- command_opcode = command.op_code
- ))
+ return None
- def on_hci_le_read_supported_states_command(self, command):
+ def on_hci_le_read_supported_states_command(self, _command):
'''
See Bluetooth spec Vol 2, Part E - 7.8.27 LE Read Supported States Command
'''
return bytes([HCI_SUCCESS]) + self.le_states
- def on_hci_le_read_suggested_default_data_length_command(self, command):
+ def on_hci_le_read_suggested_default_data_length_command(self, _command):
'''
- See Bluetooth spec Vol 2, Part E - 7.8.34 LE Read Suggested Default Data Length Command
+ See Bluetooth spec Vol 2, Part E - 7.8.34 LE Read Suggested Default Data Length
+ Command
'''
- return struct.pack('<BHH',
- HCI_SUCCESS,
- self.suggested_max_tx_octets,
- self.suggested_max_tx_time)
+ return struct.pack(
+ '<BHH',
+ HCI_SUCCESS,
+ self.suggested_max_tx_octets,
+ self.suggested_max_tx_time,
+ )
def on_hci_le_write_suggested_default_data_length_command(self, command):
'''
- See Bluetooth spec Vol 2, Part E - 7.8.35 LE Write Suggested Default Data Length Command
+ See Bluetooth spec Vol 2, Part E - 7.8.35 LE Write Suggested Default Data Length
+ Command
'''
- self.suggested_max_tx_octets, self.suggested_max_tx_time = struct.unpack('<HH', command.parameters[:4])
+ self.suggested_max_tx_octets, self.suggested_max_tx_time = struct.unpack(
+ '<HH', command.parameters[:4]
+ )
return bytes([HCI_SUCCESS])
- def on_hci_le_read_local_p_256_public_key_command(self, command):
+ def on_hci_le_read_local_p_256_public_key_command(self, _command):
'''
See Bluetooth spec Vol 2, Part E - 7.8.36 LE Read P-256 Public Key Command
'''
# TODO create key and send HCI_LE_Read_Local_P-256_Public_Key_Complete event
return bytes([HCI_SUCCESS])
- def on_hci_le_add_device_to_resolving_list_command(self, command):
+ def on_hci_le_add_device_to_resolving_list_command(self, _command):
'''
- See Bluetooth spec Vol 2, Part E - 7.8.38 LE Add Device To Resolving List Command
+ See Bluetooth spec Vol 2, Part E - 7.8.38 LE Add Device To Resolving List
+ Command
'''
return bytes([HCI_SUCCESS])
- def on_hci_le_clear_resolving_list_command(self, command):
+ def on_hci_le_clear_resolving_list_command(self, _command):
'''
See Bluetooth spec Vol 2, Part E - 7.8.40 LE Clear Resolving List Command
'''
return bytes([HCI_SUCCESS])
- def on_hci_le_read_resolving_list_size_command(self, command):
+ def on_hci_le_read_resolving_list_size_command(self, _command):
'''
See Bluetooth spec Vol 2, Part E - 7.8.41 LE Read Resolving List Size Command
'''
@@ -854,12 +1176,13 @@ class Controller:
def on_hci_le_set_address_resolution_enable_command(self, command):
'''
- See Bluetooth spec Vol 2, Part E - 7.8.44 LE Set Address Resolution Enable Command
+ See Bluetooth spec Vol 2, Part E - 7.8.44 LE Set Address Resolution Enable
+ Command
'''
ret = HCI_SUCCESS
- if command.address_resolution == 1:
+ if command.address_resolution_enable == 1:
self.le_address_resolution = True
- elif command.address_resolution == 0:
+ elif command.address_resolution_enable == 0:
self.le_address_resolution = False
else:
ret = HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR
@@ -867,21 +1190,36 @@ class Controller:
def on_hci_le_set_resolvable_private_address_timeout_command(self, command):
'''
- See Bluetooth spec Vol 2, Part E - 7.8.45 LE Set Resolvable Private Address Timeout Command
+ See Bluetooth spec Vol 2, Part E - 7.8.45 LE Set Resolvable Private Address
+ Timeout Command
'''
self.le_rpa_timeout = command.rpa_timeout
return bytes([HCI_SUCCESS])
- def on_hci_le_read_maximum_data_length_command(self, command):
+ def on_hci_le_read_maximum_data_length_command(self, _command):
'''
See Bluetooth spec Vol 2, Part E - 7.8.46 LE Read Maximum Data Length Command
'''
- return struct.pack('<BHHHH',
- HCI_SUCCESS,
- self.supported_max_tx_octets,
- self.supported_max_tx_time,
- self.supported_max_rx_octets,
- self.supported_max_rx_time)
+ return struct.pack(
+ '<BHHHH',
+ HCI_SUCCESS,
+ self.supported_max_tx_octets,
+ self.supported_max_tx_time,
+ self.supported_max_rx_octets,
+ self.supported_max_rx_time,
+ )
+
+ def on_hci_le_read_phy_command(self, command):
+ '''
+ See Bluetooth spec Vol 2, Part E - 7.8.47 LE Read PHY Command
+ '''
+ return struct.pack(
+ '<BHBB',
+ HCI_SUCCESS,
+ command.connection_handle,
+ HCI_LE_1M_PHY,
+ HCI_LE_1M_PHY,
+ )
def on_hci_le_set_default_phy_command(self, command):
'''
@@ -889,7 +1227,13 @@ class Controller:
'''
self.default_phy = {
'all_phys': command.all_phys,
- 'tx_phys': command.tx_phys,
- 'rx_phys': command.rx_phys
+ 'tx_phys': command.tx_phys,
+ 'rx_phys': command.rx_phys,
}
return bytes([HCI_SUCCESS])
+
+ def on_hci_le_read_transmit_power_command(self, _command):
+ '''
+ See Bluetooth spec Vol 2, Part E - 7.8.74 LE Read Transmit Power Command
+ '''
+ return struct.pack('<BBB', HCI_SUCCESS, 0, 0)
diff --git a/bumble/core.py b/bumble/core.py
index 746a601..1cc10ec 100644
--- a/bumble/core.py
+++ b/bumble/core.py
@@ -15,7 +15,9 @@
# -----------------------------------------------------------------------------
# Imports
# -----------------------------------------------------------------------------
+from __future__ import annotations
import struct
+from typing import List, Optional, Tuple, Union, cast
from .company_ids import COMPANY_IDENTIFIERS
@@ -23,6 +25,8 @@ from .company_ids import COMPANY_IDENTIFIERS
# -----------------------------------------------------------------------------
# Constants
# -----------------------------------------------------------------------------
+# fmt: off
+
BT_CENTRAL_ROLE = 0
BT_PERIPHERAL_ROLE = 1
@@ -30,6 +34,9 @@ BT_BR_EDR_TRANSPORT = 0
BT_LE_TRANSPORT = 1
+# fmt: on
+
+
# -----------------------------------------------------------------------------
# Utils
# -----------------------------------------------------------------------------
@@ -58,17 +65,25 @@ def padded_bytes(buffer, size):
return buffer + bytes(padding_size)
+def get_dict_key_by_value(dictionary, value):
+ for key, val in dictionary.items():
+ if val == value:
+ return key
+ return None
+
+
# -----------------------------------------------------------------------------
# Exceptions
# -----------------------------------------------------------------------------
class BaseError(Exception):
- """ Base class for errors with an error code, error name and namespace"""
+ """Base class for errors with an error code, error name and namespace"""
+
def __init__(self, error_code, error_namespace='', error_name='', details=''):
super().__init__()
- self.error_code = error_code
+ self.error_code = error_code
self.error_namespace = error_namespace
- self.error_name = error_name
- self.details = details
+ self.error_name = error_name
+ self.details = details
def __str__(self):
if self.error_namespace:
@@ -84,22 +99,40 @@ class BaseError(Exception):
class ProtocolError(BaseError):
- """ Protocol Error """
+ """Protocol Error"""
+
+class TimeoutError(Exception): # pylint: disable=redefined-builtin
+ """Timeout Error"""
-class TimeoutError(Exception):
- """ Timeout Error """
+
+class CommandTimeoutError(Exception):
+ """Command Timeout Error"""
class InvalidStateError(Exception):
- """ Invalid State Error """
+ """Invalid State Error"""
+
+class ConnectionError(BaseError): # pylint: disable=redefined-builtin
+ """Connection Error"""
-class ConnectionError(BaseError):
- """ Connection Error """
- FAILURE = 0x01
+ FAILURE = 0x01
CONNECTION_REFUSED = 0x02
+ def __init__(
+ self,
+ error_code,
+ transport,
+ peer_address,
+ error_namespace='',
+ error_name='',
+ details='',
+ ):
+ super().__init__(error_code, error_namespace, error_name, details)
+ self.transport = transport
+ self.peer_address = peer_address
+
# -----------------------------------------------------------------------------
# UUID
@@ -111,27 +144,42 @@ class ConnectionError(BaseError):
class UUID:
'''
See Bluetooth spec Vol 3, Part B - 2.5.1 UUID
+
+ Note that this class expects and works in little-endian byte-order throughout.
+ The exception is when interacting with strings, which are in big-endian byte-order.
'''
- BASE_UUID = bytes.fromhex('00001000800000805F9B34FB')
- UUIDS = [] # Registry of all instances created
- def __init__(self, uuid_str_or_int, name = None):
- if type(uuid_str_or_int) is int:
+ BASE_UUID = bytes.fromhex('00001000800000805F9B34FB')[::-1] # little-endian
+ UUIDS: List[UUID] = [] # Registry of all instances created
+
+ uuid_bytes: bytes
+ name: Optional[str]
+
+ def __init__(
+ self, uuid_str_or_int: Union[str, int], name: Optional[str] = None
+ ) -> None:
+ if isinstance(uuid_str_or_int, int):
self.uuid_bytes = struct.pack('<H', uuid_str_or_int)
else:
if len(uuid_str_or_int) == 36:
- if uuid_str_or_int[8] != '-' or uuid_str_or_int[13] != '-' or uuid_str_or_int[18] != '-' or uuid_str_or_int[23] != '-':
+ if (
+ uuid_str_or_int[8] != '-'
+ or uuid_str_or_int[13] != '-'
+ or uuid_str_or_int[18] != '-'
+ or uuid_str_or_int[23] != '-'
+ ):
raise ValueError('invalid UUID format')
uuid_str = uuid_str_or_int.replace('-', '')
else:
uuid_str = uuid_str_or_int
if len(uuid_str) != 32 and len(uuid_str) != 8 and len(uuid_str) != 4:
- raise ValueError('invalid UUID format')
+ raise ValueError(f"invalid UUID format: {uuid_str}")
self.uuid_bytes = bytes(reversed(bytes.fromhex(uuid_str)))
self.name = name
- def register(self):
- # Register this object in the class registry, and update the entry's name if it wasn't set already
+ def register(self) -> UUID:
+ # Register this object in the class registry, and update the entry's name if
+ # it wasn't set already
for uuid in self.UUIDS:
if self == uuid:
if uuid.name is None:
@@ -142,102 +190,102 @@ class UUID:
return self
@classmethod
- def from_bytes(cls, uuid_bytes, name = None):
- if len(uuid_bytes) in {2, 4, 16}:
+ def from_bytes(cls, uuid_bytes: bytes, name: Optional[str] = None) -> UUID:
+ if len(uuid_bytes) in (2, 4, 16):
self = cls.__new__(cls)
self.uuid_bytes = uuid_bytes
self.name = name
return self.register()
- else:
- raise ValueError('only 2, 4 and 16 bytes are allowed')
+
+ raise ValueError('only 2, 4 and 16 bytes are allowed')
@classmethod
- def from_16_bits(cls, uuid_16, name = None):
+ def from_16_bits(cls, uuid_16: int, name: Optional[str] = None) -> UUID:
return cls.from_bytes(struct.pack('<H', uuid_16), name)
@classmethod
- def from_32_bits(cls, uuid_32, name = None):
+ def from_32_bits(cls, uuid_32: int, name: Optional[str] = None) -> UUID:
return cls.from_bytes(struct.pack('<I', uuid_32), name)
@classmethod
- def parse_uuid(cls, bytes, offset):
- return len(bytes), cls.from_bytes(bytes[offset:])
+ def parse_uuid(cls, uuid_as_bytes: bytes, offset: int) -> Tuple[int, UUID]:
+ return len(uuid_as_bytes), cls.from_bytes(uuid_as_bytes[offset:])
@classmethod
- def parse_uuid_2(cls, bytes, offset):
- return offset + 2, cls.from_bytes(bytes[offset:offset + 2])
+ def parse_uuid_2(cls, uuid_as_bytes: bytes, offset: int) -> Tuple[int, UUID]:
+ return offset + 2, cls.from_bytes(uuid_as_bytes[offset : offset + 2])
- def to_bytes(self, force_128 = False):
- if len(self.uuid_bytes) == 16 or not force_128:
+ def to_bytes(self, force_128: bool = False) -> bytes:
+ '''
+ Serialize UUID in little-endian byte-order
+ '''
+ if not force_128:
return self.uuid_bytes
+
+ if len(self.uuid_bytes) == 2:
+ return self.BASE_UUID + self.uuid_bytes + bytes([0, 0])
elif len(self.uuid_bytes) == 4:
- return self.uuid_bytes + UUID.BASE_UUID
+ return self.BASE_UUID + self.uuid_bytes
+ elif len(self.uuid_bytes) == 16:
+ return self.uuid_bytes
else:
- return self.uuid_bytes + bytes([0, 0]) + UUID.BASE_UUID
+ assert False, "unreachable"
- def to_pdu_bytes(self):
+ def to_pdu_bytes(self) -> bytes:
'''
Convert to bytes for use in an ATT PDU.
According to Vol 3, Part F - 3.2.1 Attribute Type:
"All 32-bit Attribute UUIDs shall be converted to 128-bit UUIDs when the
Attribute UUID is contained in an ATT PDU."
'''
- return self.to_bytes(force_128 = (len(self.uuid_bytes) == 4))
+ return self.to_bytes(force_128=(len(self.uuid_bytes) == 4))
- def to_hex_str(self):
+ def to_hex_str(self, separator: str = '') -> str:
if len(self.uuid_bytes) == 2 or len(self.uuid_bytes) == 4:
return bytes(reversed(self.uuid_bytes)).hex().upper()
- else:
- return ''.join([
+
+ return separator.join(
+ [
bytes(reversed(self.uuid_bytes[12:16])).hex(),
bytes(reversed(self.uuid_bytes[10:12])).hex(),
bytes(reversed(self.uuid_bytes[8:10])).hex(),
bytes(reversed(self.uuid_bytes[6:8])).hex(),
- bytes(reversed(self.uuid_bytes[0:6])).hex()
- ]).upper()
+ bytes(reversed(self.uuid_bytes[0:6])).hex(),
+ ]
+ ).upper()
- def __bytes__(self):
+ def __bytes__(self) -> bytes:
return self.to_bytes()
- def __eq__(self, other):
+ def __eq__(self, other: object) -> bool:
if isinstance(other, UUID):
- return self.to_bytes(force_128 = True) == other.to_bytes(force_128 = True)
- elif type(other) is str:
+ return self.to_bytes(force_128=True) == other.to_bytes(force_128=True)
+
+ if isinstance(other, str):
return UUID(other) == self
return False
- def __hash__(self):
+ def __hash__(self) -> int:
return hash(self.uuid_bytes)
- def __str__(self):
+ def __str__(self) -> str:
+ result = self.to_hex_str(separator='-')
if len(self.uuid_bytes) == 2:
- v = struct.unpack('<H', self.uuid_bytes)[0]
- result = f'UUID-16:{v:04X}'
+ result = 'UUID-16:' + result
elif len(self.uuid_bytes) == 4:
- v = struct.unpack('<I', self.uuid_bytes)[0]
- result = f'UUID-32:{v:08X}'
- else:
- result = '-'.join([
- bytes(reversed(self.uuid_bytes[12:16])).hex(),
- bytes(reversed(self.uuid_bytes[10:12])).hex(),
- bytes(reversed(self.uuid_bytes[8:10])).hex(),
- bytes(reversed(self.uuid_bytes[6:8])).hex(),
- bytes(reversed(self.uuid_bytes[0:6])).hex()
- ]).upper()
+ result = 'UUID-32:' + result
if self.name is not None:
- return result + f' ({self.name})'
- else:
- return result
-
- def __repr__(self):
- return str(self)
+ result += f' ({self.name})'
+ return result
# -----------------------------------------------------------------------------
# Common UUID constants
# -----------------------------------------------------------------------------
+# fmt: off
+# pylint: disable=line-too-long
# Protocol Identifiers
BT_SDP_PROTOCOL_ID = UUID.from_16_bits(0x0001, 'SDP')
@@ -343,11 +391,17 @@ BT_HDP_SERVICE = UUID.from_16_bits(0x1400,
BT_HDP_SOURCE_SERVICE = UUID.from_16_bits(0x1401, 'HDP Source')
BT_HDP_SINK_SERVICE = UUID.from_16_bits(0x1402, 'HDP Sink')
+# fmt: on
+# pylint: enable=line-too-long
+
# -----------------------------------------------------------------------------
# DeviceClass
# -----------------------------------------------------------------------------
class DeviceClass:
+ # fmt: off
+ # pylint: disable=line-too-long
+
# Major Service Classes (flags combined with OR)
LIMITED_DISCOVERABLE_MODE_SERVICE_CLASS = (1 << 0)
LE_AUDIO_SERVICE_CLASS = (1 << 1)
@@ -515,11 +569,18 @@ class DeviceClass:
PERIPHERAL_MAJOR_DEVICE_CLASS: PERIPHERAL_MINOR_DEVICE_CLASS_NAMES
}
+ # fmt: on
+ # pylint: enable=line-too-long
+
@staticmethod
def split_class_of_device(class_of_device):
# Split the bit fields of the composite class of device value into:
# (service_classes, major_device_class, minor_device_class)
- return ((class_of_device >> 13 & 0x7FF), (class_of_device >> 8 & 0x1F), (class_of_device >> 2 & 0x3F))
+ return (
+ (class_of_device >> 13 & 0x7FF),
+ (class_of_device >> 8 & 0x1F),
+ (class_of_device >> 2 & 0x3F),
+ )
@staticmethod
def pack_class_of_device(service_classes, major_device_class, minor_device_class):
@@ -527,7 +588,9 @@ class DeviceClass:
@staticmethod
def service_class_labels(service_class_flags):
- return bit_flags_to_strings(service_class_flags, DeviceClass.SERVICE_CLASS_LABELS)
+ return bit_flags_to_strings(
+ service_class_flags, DeviceClass.SERVICE_CLASS_LABELS
+ )
@staticmethod
def major_device_class_name(device_class):
@@ -544,7 +607,15 @@ class DeviceClass:
# -----------------------------------------------------------------------------
# Advertising Data
# -----------------------------------------------------------------------------
+AdvertisingObject = Union[
+ List[UUID], Tuple[UUID, bytes], bytes, str, int, Tuple[int, int], Tuple[int, bytes]
+]
+
+
class AdvertisingData:
+ # fmt: off
+ # pylint: disable=line-too-long
+
# This list is only partial, it still needs to be filled in from the spec
FLAGS = 0x01
INCOMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS = 0x02
@@ -656,7 +727,14 @@ class AdvertisingData:
BR_EDR_CONTROLLER_FLAG = 0x08
BR_EDR_HOST_FLAG = 0x10
- def __init__(self, ad_structures = []):
+ ad_structures: List[Tuple[int, bytes]]
+
+ # fmt: on
+ # pylint: enable=line-too-long
+
+ def __init__(self, ad_structures: Optional[List[Tuple[int, bytes]]] = None) -> None:
+ if ad_structures is None:
+ ad_structures = []
self.ad_structures = ad_structures[:]
@staticmethod
@@ -667,36 +745,36 @@ class AdvertisingData:
@staticmethod
def flags_to_string(flags, short=False):
- flag_names = [
- 'LE Limited',
- 'LE General',
- 'No BR/EDR',
- 'BR/EDR C',
- 'BR/EDR H'
- ] if short else [
- 'LE Limited Discoverable Mode',
- 'LE General Discoverable Mode',
- 'BR/EDR Not Supported',
- 'Simultaneous LE and BR/EDR (Controller)',
- 'Simultaneous LE and BR/EDR (Host)'
- ]
+ flag_names = (
+ ['LE Limited', 'LE General', 'No BR/EDR', 'BR/EDR C', 'BR/EDR H']
+ if short
+ else [
+ 'LE Limited Discoverable Mode',
+ 'LE General Discoverable Mode',
+ 'BR/EDR Not Supported',
+ 'Simultaneous LE and BR/EDR (Controller)',
+ 'Simultaneous LE and BR/EDR (Host)',
+ ]
+ )
return ','.join(bit_flags_to_strings(flags, flag_names))
@staticmethod
- def uuid_list_to_objects(ad_data, uuid_size):
+ def uuid_list_to_objects(ad_data: bytes, uuid_size: int) -> List[UUID]:
uuids = []
offset = 0
- while (uuid_size * (offset + 1)) <= len(ad_data):
- uuids.append(UUID.from_bytes(ad_data[offset:offset + uuid_size]))
+ while (offset + uuid_size) <= len(ad_data):
+ uuids.append(UUID.from_bytes(ad_data[offset : offset + uuid_size]))
offset += uuid_size
return uuids
@staticmethod
def uuid_list_to_string(ad_data, uuid_size):
- return ', '.join([
- str(uuid)
- for uuid in AdvertisingData.uuid_list_to_objects(ad_data, uuid_size)
- ])
+ return ', '.join(
+ [
+ str(uuid)
+ for uuid in AdvertisingData.uuid_list_to_objects(ad_data, uuid_size)
+ ]
+ )
@staticmethod
def ad_data_to_string(ad_type, ad_data):
@@ -756,40 +834,65 @@ class AdvertisingData:
return f'[{ad_type_str}]: {ad_data_str}'
+ # pylint: disable=too-many-return-statements
@staticmethod
- def ad_data_to_object(ad_type, ad_data):
- if ad_type in {
+ def ad_data_to_object(ad_type: int, ad_data: bytes) -> AdvertisingObject:
+ if ad_type in (
AdvertisingData.COMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS,
- AdvertisingData.INCOMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS
- }:
+ AdvertisingData.INCOMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS,
+ AdvertisingData.LIST_OF_16_BIT_SERVICE_SOLICITATION_UUIDS,
+ ):
return AdvertisingData.uuid_list_to_objects(ad_data, 2)
- elif ad_type in {
+
+ if ad_type in (
AdvertisingData.COMPLETE_LIST_OF_32_BIT_SERVICE_CLASS_UUIDS,
- AdvertisingData.INCOMPLETE_LIST_OF_32_BIT_SERVICE_CLASS_UUIDS
- }:
+ AdvertisingData.INCOMPLETE_LIST_OF_32_BIT_SERVICE_CLASS_UUIDS,
+ AdvertisingData.LIST_OF_32_BIT_SERVICE_SOLICITATION_UUIDS,
+ ):
return AdvertisingData.uuid_list_to_objects(ad_data, 4)
- elif ad_type in {
+
+ if ad_type in (
AdvertisingData.COMPLETE_LIST_OF_128_BIT_SERVICE_CLASS_UUIDS,
- AdvertisingData.INCOMPLETE_LIST_OF_128_BIT_SERVICE_CLASS_UUIDS
- }:
+ AdvertisingData.INCOMPLETE_LIST_OF_128_BIT_SERVICE_CLASS_UUIDS,
+ AdvertisingData.LIST_OF_128_BIT_SERVICE_SOLICITATION_UUIDS,
+ ):
return AdvertisingData.uuid_list_to_objects(ad_data, 16)
- elif ad_type == AdvertisingData.SERVICE_DATA_16_BIT_UUID:
+
+ if ad_type == AdvertisingData.SERVICE_DATA_16_BIT_UUID:
return (UUID.from_bytes(ad_data[:2]), ad_data[2:])
- elif ad_type == AdvertisingData.SERVICE_DATA_32_BIT_UUID:
+
+ if ad_type == AdvertisingData.SERVICE_DATA_32_BIT_UUID:
return (UUID.from_bytes(ad_data[:4]), ad_data[4:])
- elif ad_type == AdvertisingData.SERVICE_DATA_128_BIT_UUID:
+
+ if ad_type == AdvertisingData.SERVICE_DATA_128_BIT_UUID:
return (UUID.from_bytes(ad_data[:16]), ad_data[16:])
- elif ad_type in {
+
+ if ad_type in (
AdvertisingData.SHORTENED_LOCAL_NAME,
- AdvertisingData.COMPLETE_LOCAL_NAME
- }:
+ AdvertisingData.COMPLETE_LOCAL_NAME,
+ AdvertisingData.URI,
+ ):
return ad_data.decode("utf-8")
- elif ad_type == AdvertisingData.TX_POWER_LEVEL:
- return ad_data[0]
- elif ad_type == AdvertisingData.MANUFACTURER_SPECIFIC_DATA:
- return (struct.unpack_from('<H', ad_data, 0)[0], ad_data[2:])
- else:
- return ad_data
+
+ if ad_type in (AdvertisingData.TX_POWER_LEVEL, AdvertisingData.FLAGS):
+ return cast(int, struct.unpack('B', ad_data)[0])
+
+ if ad_type in (
+ AdvertisingData.APPEARANCE,
+ AdvertisingData.ADVERTISING_INTERVAL,
+ ):
+ return cast(int, struct.unpack('<H', ad_data)[0])
+
+ if ad_type == AdvertisingData.CLASS_OF_DEVICE:
+ return cast(int, struct.unpack('<I', bytes([*ad_data, 0]))[0])
+
+ if ad_type == AdvertisingData.PERIPHERAL_CONNECTION_INTERVAL_RANGE:
+ return cast(Tuple[int, int], struct.unpack('<HH', ad_data))
+
+ if ad_type == AdvertisingData.MANUFACTURER_SPECIFIC_DATA:
+ return (cast(int, struct.unpack_from('<H', ad_data, 0)[0]), ad_data[2:])
+
+ return ad_data
def append(self, data):
offset = 0
@@ -798,30 +901,41 @@ class AdvertisingData:
offset += 1
if length > 0:
ad_type = data[offset]
- ad_data = data[offset + 1:offset + length]
+ ad_data = data[offset + 1 : offset + length]
self.ad_structures.append((ad_type, ad_data))
offset += length
- def get(self, type_id, return_all=False, raw=True):
+ def get_all(self, type_id: int, raw: bool = False) -> List[AdvertisingObject]:
'''
Get Advertising Data Structure(s) with a given type
- If return_all is True, returns a (possibly empty) list of matches,
- else returns the first entry, or None if no structure matches.
+ Returns a (possibly empty) list of matches.
'''
- def process_ad_data(ad_data):
+
+ def process_ad_data(ad_data: bytes) -> AdvertisingObject:
return ad_data if raw else self.ad_data_to_object(type_id, ad_data)
- if return_all:
- return [process_ad_data(ad[1]) for ad in self.ad_structures if ad[0] == type_id]
- else:
- return next((process_ad_data(ad[1]) for ad in self.ad_structures if ad[0] == type_id), None)
+ return [process_ad_data(ad[1]) for ad in self.ad_structures if ad[0] == type_id]
+
+ def get(self, type_id: int, raw: bool = False) -> Optional[AdvertisingObject]:
+ '''
+ Get Advertising Data Structure(s) with a given type
+
+ Returns the first entry, or None if no structure matches.
+ '''
+
+ all = self.get_all(type_id, raw=raw)
+ return all[0] if all else None
def __bytes__(self):
- return b''.join([bytes([len(x[1]) + 1, x[0]]) + x[1] for x in self.ad_structures])
+ return b''.join(
+ [bytes([len(x[1]) + 1, x[0]]) + x[1] for x in self.ad_structures]
+ )
def to_string(self, separator=', '):
- return separator.join([AdvertisingData.ad_data_to_string(x[0], x[1]) for x in self.ad_structures])
+ return separator.join(
+ [AdvertisingData.ad_data_to_string(x[0], x[1]) for x in self.ad_structures]
+ )
def __str__(self):
return self.to_string()
@@ -831,13 +945,17 @@ class AdvertisingData:
# Connection Parameters
# -----------------------------------------------------------------------------
class ConnectionParameters:
- def __init__(self, connection_interval, connection_latency, supervision_timeout):
+ def __init__(self, connection_interval, peripheral_latency, supervision_timeout):
self.connection_interval = connection_interval
- self.connection_latency = connection_latency
+ self.peripheral_latency = peripheral_latency
self.supervision_timeout = supervision_timeout
def __str__(self):
- return f'ConnectionParameters(connection_interval={self.connection_interval}, connection_latency={self.connection_latency}, supervision_timeout={self.supervision_timeout}'
+ return (
+ f'ConnectionParameters(connection_interval={self.connection_interval}, '
+ f'peripheral_latency={self.peripheral_latency}, '
+ f'supervision_timeout={self.supervision_timeout}'
+ )
# -----------------------------------------------------------------------------
diff --git a/bumble/crypto.py b/bumble/crypto.py
index 4f13476..757594f 100644
--- a/bumble/crypto.py
+++ b/bumble/crypto.py
@@ -24,19 +24,16 @@
import logging
import operator
import platform
+
if platform.system() != 'Emscripten':
import secrets
- from cryptography.hazmat.primitives.ciphers import (
- Cipher,
- algorithms,
- modes
- )
+ from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives.asymmetric.ec import (
generate_private_key,
ECDH,
EllipticCurvePublicNumbers,
EllipticCurvePrivateNumbers,
- SECP256R1
+ SECP256R1,
)
from cryptography.hazmat.primitives import cmac
else:
@@ -66,16 +63,26 @@ class EccKey:
d = int.from_bytes(d_bytes, byteorder='big', signed=False)
x = int.from_bytes(x_bytes, byteorder='big', signed=False)
y = int.from_bytes(y_bytes, byteorder='big', signed=False)
- private_key = EllipticCurvePrivateNumbers(d, EllipticCurvePublicNumbers(x, y, SECP256R1())).private_key()
+ private_key = EllipticCurvePrivateNumbers(
+ d, EllipticCurvePublicNumbers(x, y, SECP256R1())
+ ).private_key()
return cls(private_key)
@property
def x(self):
- return self.private_key.public_key().public_numbers().x.to_bytes(32, byteorder='big')
+ return (
+ self.private_key.public_key()
+ .public_numbers()
+ .x.to_bytes(32, byteorder='big')
+ )
@property
def y(self):
- return self.private_key.public_key().public_numbers().y.to_bytes(32, byteorder='big')
+ return (
+ self.private_key.public_key()
+ .public_numbers()
+ .y.to_bytes(32, byteorder='big')
+ )
def dh(self, public_key_x, public_key_y):
x = int.from_bytes(public_key_x, byteorder='big', signed=False)
@@ -92,7 +99,7 @@ class EccKey:
# -----------------------------------------------------------------------------
def xor(x, y):
- assert(len(x) == len(y))
+ assert len(x) == len(y)
return bytes(map(operator.xor, x, y))
@@ -118,7 +125,7 @@ def e(key, data):
# -----------------------------------------------------------------------------
-def ah(k, r):
+def ah(k, r): # pylint: disable=redefined-outer-name
'''
See Bluetooth spec Vol 3, Part H - 2.2.2 Random Address Hash function ah
'''
@@ -129,9 +136,10 @@ def ah(k, r):
# -----------------------------------------------------------------------------
-def c1(k, r, preq, pres, iat, rat, ia, ra):
+def c1(k, r, preq, pres, iat, rat, ia, ra): # pylint: disable=redefined-outer-name
'''
- See Bluetooth spec, Vol 3, Part H - 2.2.3 Confirm value generation function c1 for LE Legacy Pairing
+ See Bluetooth spec, Vol 3, Part H - 2.2.3 Confirm value generation function c1 for
+ LE Legacy Pairing
'''
p1 = bytes([iat, rat]) + preq + pres
@@ -142,7 +150,8 @@ def c1(k, r, preq, pres, iat, rat, ia, ra):
# -----------------------------------------------------------------------------
def s1(k, r1, r2):
'''
- See Bluetooth spec, Vol 3, Part H - 2.2.4 Key generation function s1 for LE Legacy Pairing
+ See Bluetooth spec, Vol 3, Part H - 2.2.4 Key generation function s1 for LE Legacy
+ Pairing
'''
return e(k, r2[0:8] + r1[0:8])
@@ -163,71 +172,95 @@ def aes_cmac(m, k):
# -----------------------------------------------------------------------------
def f4(u, v, x, z):
'''
- See Bluetooth spec, Vol 3, Part H - 2.2.6 LE Secure Connections Confirm Value Generation Function f4
+ See Bluetooth spec, Vol 3, Part H - 2.2.6 LE Secure Connections Confirm Value
+ Generation Function f4
'''
- return bytes(reversed(aes_cmac(bytes(reversed(u)) + bytes(reversed(v)) + z, bytes(reversed(x)))))
+ return bytes(
+ reversed(
+ aes_cmac(bytes(reversed(u)) + bytes(reversed(v)) + z, bytes(reversed(x)))
+ )
+ )
# -----------------------------------------------------------------------------
def f5(w, n1, n2, a1, a2):
'''
- See Bluetooth spec, Vol 3, Part H - 2.2.7 LE Secure Connections Key Generation Function f5
+ See Bluetooth spec, Vol 3, Part H - 2.2.7 LE Secure Connections Key Generation
+ Function f5
NOTE: this returns a tuple: (MacKey, LTK) in little-endian byte order
'''
salt = bytes.fromhex('6C888391AAF5A53860370BDB5A6083BE')
t = aes_cmac(bytes(reversed(w)), salt)
- key_id = bytes([0x62, 0x74, 0x6c, 0x65])
+ key_id = bytes([0x62, 0x74, 0x6C, 0x65])
return (
- bytes(reversed(aes_cmac(
- bytes([0]) +
- key_id +
- bytes(reversed(n1)) +
- bytes(reversed(n2)) +
- bytes(reversed(a1)) +
- bytes(reversed(a2)) +
- bytes([1, 0]),
- t
- ))),
- bytes(reversed(aes_cmac(
- bytes([1]) +
- key_id +
- bytes(reversed(n1)) +
- bytes(reversed(n2)) +
- bytes(reversed(a1)) +
- bytes(reversed(a2)) +
- bytes([1, 0]),
- t
- )))
+ bytes(
+ reversed(
+ aes_cmac(
+ bytes([0])
+ + key_id
+ + bytes(reversed(n1))
+ + bytes(reversed(n2))
+ + bytes(reversed(a1))
+ + bytes(reversed(a2))
+ + bytes([1, 0]),
+ t,
+ )
+ )
+ ),
+ bytes(
+ reversed(
+ aes_cmac(
+ bytes([1])
+ + key_id
+ + bytes(reversed(n1))
+ + bytes(reversed(n2))
+ + bytes(reversed(a1))
+ + bytes(reversed(a2))
+ + bytes([1, 0]),
+ t,
+ )
+ )
+ ),
)
# -----------------------------------------------------------------------------
-def f6(w, n1, n2, r, io_cap, a1, a2):
+def f6(w, n1, n2, r, io_cap, a1, a2): # pylint: disable=redefined-outer-name
'''
- See Bluetooth spec, Vol 3, Part H - 2.2.8 LE Secure Connections Check Value Generation Function f6
+ See Bluetooth spec, Vol 3, Part H - 2.2.8 LE Secure Connections Check Value
+ Generation Function f6
'''
- return bytes(reversed(aes_cmac(
- bytes(reversed(n1)) +
- bytes(reversed(n2)) +
- bytes(reversed(r)) +
- bytes(reversed(io_cap)) +
- bytes(reversed(a1)) +
- bytes(reversed(a2)),
- bytes(reversed(w))
- )))
+ return bytes(
+ reversed(
+ aes_cmac(
+ bytes(reversed(n1))
+ + bytes(reversed(n2))
+ + bytes(reversed(r))
+ + bytes(reversed(io_cap))
+ + bytes(reversed(a1))
+ + bytes(reversed(a2)),
+ bytes(reversed(w)),
+ )
+ )
+ )
# -----------------------------------------------------------------------------
def g2(u, v, x, y):
'''
- See Bluetooth spec, Vol 3, Part H - 2.2.9 LE Secure Connections Numeric Comparison Value Generation Function g2
+ See Bluetooth spec, Vol 3, Part H - 2.2.9 LE Secure Connections Numeric Comparison
+ Value Generation Function g2
'''
return int.from_bytes(
- aes_cmac(bytes(reversed(u)) + bytes(reversed(v)) + bytes(reversed(y)), bytes(reversed(x)))[-4:],
- byteorder='big'
+ aes_cmac(
+ bytes(reversed(u)) + bytes(reversed(v)) + bytes(reversed(y)),
+ bytes(reversed(x)),
+ )[-4:],
+ byteorder='big',
)
+
# -----------------------------------------------------------------------------
def h6(w, key_id):
'''
@@ -235,6 +268,7 @@ def h6(w, key_id):
'''
return aes_cmac(key_id, w)
+
# -----------------------------------------------------------------------------
def h7(salt, w):
'''
diff --git a/bumble/decoder.py b/bumble/decoder.py
new file mode 100644
index 0000000..2eb70bc
--- /dev/null
+++ b/bumble/decoder.py
@@ -0,0 +1,416 @@
+# Copyright 2023 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# -----------------------------------------------------------------------------
+# Constants
+# -----------------------------------------------------------------------------
+# fmt: off
+
+WL = [-60, -30, 58, 172, 334, 538, 1198, 3042]
+RL42 = [0, 7, 6, 5, 4, 3, 2, 1, 7, 6, 5, 4, 3, 2, 1, 0]
+ILB = [
+ 2048,
+ 2093,
+ 2139,
+ 2186,
+ 2233,
+ 2282,
+ 2332,
+ 2383,
+ 2435,
+ 2489,
+ 2543,
+ 2599,
+ 2656,
+ 2714,
+ 2774,
+ 2834,
+ 2896,
+ 2960,
+ 3025,
+ 3091,
+ 3158,
+ 3228,
+ 3298,
+ 3371,
+ 3444,
+ 3520,
+ 3597,
+ 3676,
+ 3756,
+ 3838,
+ 3922,
+ 4008,
+]
+WH = [0, -214, 798]
+RH2 = [2, 1, 2, 1]
+# Values in QM2/QM4/QM6 left shift three bits than original g722 specification.
+QM2 = [-7408, -1616, 7408, 1616]
+QM4 = [
+ 0,
+ -20456,
+ -12896,
+ -8968,
+ -6288,
+ -4240,
+ -2584,
+ -1200,
+ 20456,
+ 12896,
+ 8968,
+ 6288,
+ 4240,
+ 2584,
+ 1200,
+ 0,
+]
+QM6 = [
+ -136,
+ -136,
+ -136,
+ -136,
+ -24808,
+ -21904,
+ -19008,
+ -16704,
+ -14984,
+ -13512,
+ -12280,
+ -11192,
+ -10232,
+ -9360,
+ -8576,
+ -7856,
+ -7192,
+ -6576,
+ -6000,
+ -5456,
+ -4944,
+ -4464,
+ -4008,
+ -3576,
+ -3168,
+ -2776,
+ -2400,
+ -2032,
+ -1688,
+ -1360,
+ -1040,
+ -728,
+ 24808,
+ 21904,
+ 19008,
+ 16704,
+ 14984,
+ 13512,
+ 12280,
+ 11192,
+ 10232,
+ 9360,
+ 8576,
+ 7856,
+ 7192,
+ 6576,
+ 6000,
+ 5456,
+ 4944,
+ 4464,
+ 4008,
+ 3576,
+ 3168,
+ 2776,
+ 2400,
+ 2032,
+ 1688,
+ 1360,
+ 1040,
+ 728,
+ 432,
+ 136,
+ -432,
+ -136,
+]
+QMF_COEFFS = [3, -11, 12, 32, -210, 951, 3876, -805, 362, -156, 53, -11]
+
+# fmt: on
+
+
+# -----------------------------------------------------------------------------
+# Classes
+# -----------------------------------------------------------------------------
+class G722Decoder(object):
+ """G.722 decoder with bitrate 64kbit/s.
+
+ For the Blocks in the sub-band decoders, please refer to the G.722
+ specification for the required information. G722 specification:
+ https://www.itu.int/rec/T-REC-G.722-201209-I
+ """
+
+ def __init__(self):
+ self._x = [0] * 24
+ self._band = [Band(), Band()]
+ # The initial value in BLOCK 3L
+ self._band[0].det = 32
+ # The initial value in BLOCK 3H
+ self._band[1].det = 8
+
+ def decode_frame(self, encoded_data) -> bytearray:
+ result_array = bytearray(len(encoded_data) * 4)
+ self.g722_decode(result_array, encoded_data)
+ return result_array
+
+ def g722_decode(self, result_array, encoded_data) -> int:
+ """Decode the data frame using g722 decoder."""
+ result_length = 0
+
+ for code in encoded_data:
+ higher_bits = (code >> 6) & 0x03
+ lower_bits = code & 0x3F
+
+ rlow = self.lower_sub_band_decoder(lower_bits)
+ rhigh = self.higher_sub_band_decoder(higher_bits)
+
+ # Apply the receive QMF
+ self._x[:22] = self._x[2:]
+ self._x[22] = rlow + rhigh
+ self._x[23] = rlow - rhigh
+
+ xout2 = sum(self._x[2 * i] * QMF_COEFFS[i] for i in range(12))
+ xout1 = sum(self._x[2 * i + 1] * QMF_COEFFS[11 - i] for i in range(12))
+
+ result_length = self.update_decoded_result(
+ xout1, result_length, result_array
+ )
+ result_length = self.update_decoded_result(
+ xout2, result_length, result_array
+ )
+
+ return result_length
+
+ def update_decoded_result(self, xout, byte_length, byte_array) -> int:
+ result = (int)(xout >> 11)
+ bytes_result = result.to_bytes(2, 'little', signed=True)
+ byte_array[byte_length] = bytes_result[0]
+ byte_array[byte_length + 1] = bytes_result[1]
+ return byte_length + 2
+
+ def lower_sub_band_decoder(self, lower_bits) -> int:
+ """Lower sub-band decoder for last six bits."""
+
+ # Block 5L
+ # INVQBL
+ wd1 = lower_bits
+ wd2 = QM6[wd1]
+ wd1 >>= 2
+ wd2 = (self._band[0].det * wd2) >> 15
+ # RECONS
+ rlow = self._band[0].s + wd2
+
+ # Block 6L
+ # LIMIT
+ if rlow > 16383:
+ rlow = 16383
+ elif rlow < -16384:
+ rlow = -16384
+
+ # Block 2L
+ # INVQAL
+ wd2 = QM4[wd1]
+ dlowt = (self._band[0].det * wd2) >> 15
+
+ # Block 3L
+ # LOGSCL
+ wd2 = RL42[wd1]
+ wd1 = (self._band[0].nb * 127) >> 7
+ wd1 += WL[wd2]
+
+ if wd1 < 0:
+ wd1 = 0
+ elif wd1 > 18432:
+ wd1 = 18432
+
+ self._band[0].nb = wd1
+
+ # SCALEL
+ wd1 = (self._band[0].nb >> 6) & 31
+ wd2 = 8 - (self._band[0].nb >> 11)
+
+ if wd2 < 0:
+ wd3 = ILB[wd1] << -wd2
+ else:
+ wd3 = ILB[wd1] >> wd2
+
+ self._band[0].det = wd3 << 2
+
+ # Block 4L
+ self._band[0].block4(dlowt)
+
+ return rlow
+
+ def higher_sub_band_decoder(self, higher_bits) -> int:
+ """Higher sub-band decoder for first two bits."""
+
+ # Block 2H
+ # INVQAH
+ wd2 = QM2[higher_bits]
+ dhigh = (self._band[1].det * wd2) >> 15
+
+ # Block 5H
+ # RECONS
+ rhigh = dhigh + self._band[1].s
+
+ # Block 6H
+ # LIMIT
+ if rhigh > 16383:
+ rhigh = 16383
+ elif rhigh < -16384:
+ rhigh = -16384
+
+ # Block 3H
+ # LOGSCH
+ wd2 = RH2[higher_bits]
+ wd1 = (self._band[1].nb * 127) >> 7
+ wd1 += WH[wd2]
+
+ if wd1 < 0:
+ wd1 = 0
+ elif wd1 > 22528:
+ wd1 = 22528
+ self._band[1].nb = wd1
+
+ # SCALEH
+ wd1 = (self._band[1].nb >> 6) & 31
+ wd2 = 10 - (self._band[1].nb >> 11)
+
+ if wd2 < 0:
+ wd3 = ILB[wd1] << -wd2
+ else:
+ wd3 = ILB[wd1] >> wd2
+ self._band[1].det = wd3 << 2
+
+ # Block 4H
+ self._band[1].block4(dhigh)
+
+ return rhigh
+
+
+# -----------------------------------------------------------------------------
+class Band(object):
+ """Structure for G722 decode proccessing."""
+
+ s: int = 0
+ nb: int = 0
+ det: int = 0
+
+ def __init__(self):
+ self._sp = 0
+ self._sz = 0
+ self._r = [0] * 3
+ self._a = [0] * 3
+ self._ap = [0] * 3
+ self._p = [0] * 3
+ self._d = [0] * 7
+ self._b = [0] * 7
+ self._bp = [0] * 7
+ self._sg = [0] * 7
+
+ def saturate(self, amp: int) -> int:
+ if amp > 32767:
+ return 32767
+ elif amp < -32768:
+ return -32768
+ else:
+ return amp
+
+ def block4(self, d: int) -> None:
+ """Block4 for both lower and higher sub-band decoder."""
+ wd1 = 0
+ wd2 = 0
+ wd3 = 0
+
+ # RECONS
+ self._d[0] = d
+ self._r[0] = self.saturate(self.s + d)
+
+ # PARREC
+ self._p[0] = self.saturate(self._sz + d)
+
+ # UPPOL2
+ for i in range(3):
+ self._sg[i] = (self._p[i]) >> 15
+ wd1 = self.saturate((self._a[1]) << 2)
+ wd2 = -wd1 if self._sg[0] == self._sg[1] else wd1
+
+ if wd2 > 32767:
+ wd2 = 32767
+
+ wd3 = 128 if self._sg[0] == self._sg[2] else -128
+ wd3 += wd2 >> 7
+ wd3 += (self._a[2] * 32512) >> 15
+
+ if wd3 > 12288:
+ wd3 = 12288
+ elif wd3 < -12288:
+ wd3 = -12288
+ self._ap[2] = wd3
+
+ # UPPOL1
+ self._sg[0] = (self._p[0]) >> 15
+ self._sg[1] = (self._p[1]) >> 15
+ wd1 = 192 if self._sg[0] == self._sg[1] else -192
+ wd2 = (self._a[1] * 32640) >> 15
+
+ self._ap[1] = self.saturate(wd1 + wd2)
+ wd3 = self.saturate(15360 - self._ap[2])
+
+ if self._ap[1] > wd3:
+ self._ap[1] = wd3
+ elif self._ap[1] < -wd3:
+ self._ap[1] = -wd3
+
+ # UPZERO
+ wd1 = 0 if d == 0 else 128
+ self._sg[0] = d >> 15
+ for i in range(1, 7):
+ self._sg[i] = (self._d[i]) >> 15
+ wd2 = wd1 if self._sg[i] == self._sg[0] else -wd1
+ wd3 = (self._b[i] * 32640) >> 15
+ self._bp[i] = self.saturate(wd2 + wd3)
+
+ # DELAYA
+ for i in range(6, 0, -1):
+ self._d[i] = self._d[i - 1]
+ self._b[i] = self._bp[i]
+
+ for i in range(2, 0, -1):
+ self._r[i] = self._r[i - 1]
+ self._p[i] = self._p[i - 1]
+ self._a[i] = self._ap[i]
+
+ # FILTEP
+ self._sp = 0
+ for i in range(1, 3):
+ wd1 = self.saturate(self._r[i] + self._r[i])
+ self._sp += (self._a[i] * wd1) >> 15
+ self._sp = self.saturate(self._sp)
+
+ # FILTEZ
+ self._sz = 0
+ for i in range(6, 0, -1):
+ wd1 = self.saturate(self._d[i] + self._d[i])
+ self._sz += (self._b[i] * wd1) >> 15
+ self._sz = self.saturate(self._sz)
+
+ # PREDIC
+ self.s = self.saturate(self._sp + self._sz)
diff --git a/bumble/device.py b/bumble/device.py
index 97ead5e..258a43d 100644
--- a/bumble/device.py
+++ b/bumble/device.py
@@ -15,22 +15,142 @@
# -----------------------------------------------------------------------------
# Imports
# -----------------------------------------------------------------------------
+from __future__ import annotations
+from enum import IntEnum
+import functools
import json
import asyncio
import logging
-
-from .hci import *
+from contextlib import asynccontextmanager, AsyncExitStack
+from dataclasses import dataclass
+from typing import Any, Callable, ClassVar, Dict, List, Optional, Tuple, Type, Union
+
+from .colors import color
+from .att import ATT_CID, ATT_DEFAULT_MTU, ATT_PDU
+from .gatt import Characteristic, Descriptor, Service
+from .hci import (
+ HCI_AUTHENTICATED_COMBINATION_KEY_GENERATED_FROM_P_192_TYPE,
+ HCI_AUTHENTICATED_COMBINATION_KEY_GENERATED_FROM_P_256_TYPE,
+ HCI_CENTRAL_ROLE,
+ HCI_COMMAND_STATUS_PENDING,
+ HCI_CONNECTION_REJECTED_DUE_TO_LIMITED_RESOURCES_ERROR,
+ HCI_DISPLAY_YES_NO_IO_CAPABILITY,
+ HCI_DISPLAY_ONLY_IO_CAPABILITY,
+ HCI_EXTENDED_INQUIRY_MODE,
+ HCI_GENERAL_INQUIRY_LAP,
+ HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR,
+ HCI_KEYBOARD_ONLY_IO_CAPABILITY,
+ HCI_LE_1M_PHY,
+ HCI_LE_1M_PHY_BIT,
+ HCI_LE_2M_PHY,
+ HCI_LE_2M_PHY_LE_SUPPORTED_FEATURE,
+ HCI_LE_CLEAR_RESOLVING_LIST_COMMAND,
+ HCI_LE_CODED_PHY,
+ HCI_LE_CODED_PHY_BIT,
+ HCI_LE_CODED_PHY_LE_SUPPORTED_FEATURE,
+ HCI_LE_EXTENDED_ADVERTISING_LE_SUPPORTED_FEATURE,
+ HCI_LE_EXTENDED_CREATE_CONNECTION_COMMAND,
+ HCI_LE_RAND_COMMAND,
+ HCI_LE_READ_PHY_COMMAND,
+ HCI_LE_SET_PHY_COMMAND,
+ HCI_MITM_NOT_REQUIRED_GENERAL_BONDING_AUTHENTICATION_REQUIREMENTS,
+ HCI_MITM_NOT_REQUIRED_NO_BONDING_AUTHENTICATION_REQUIREMENTS,
+ HCI_MITM_REQUIRED_GENERAL_BONDING_AUTHENTICATION_REQUIREMENTS,
+ HCI_MITM_REQUIRED_NO_BONDING_AUTHENTICATION_REQUIREMENTS,
+ HCI_NO_INPUT_NO_OUTPUT_IO_CAPABILITY,
+ HCI_R2_PAGE_SCAN_REPETITION_MODE,
+ HCI_REMOTE_USER_TERMINATED_CONNECTION_ERROR,
+ HCI_SUCCESS,
+ HCI_WRITE_LE_HOST_SUPPORT_COMMAND,
+ Address,
+ HCI_Accept_Connection_Request_Command,
+ HCI_Authentication_Requested_Command,
+ HCI_Command_Status_Event,
+ HCI_Constant,
+ HCI_Create_Connection_Cancel_Command,
+ HCI_Create_Connection_Command,
+ HCI_Disconnect_Command,
+ HCI_Encryption_Change_Event,
+ HCI_Error,
+ HCI_IO_Capability_Request_Reply_Command,
+ HCI_Inquiry_Cancel_Command,
+ HCI_Inquiry_Command,
+ HCI_LE_Add_Device_To_Resolving_List_Command,
+ HCI_LE_Advertising_Report_Event,
+ HCI_LE_Clear_Resolving_List_Command,
+ HCI_LE_Connection_Update_Command,
+ HCI_LE_Create_Connection_Cancel_Command,
+ HCI_LE_Create_Connection_Command,
+ HCI_LE_Enable_Encryption_Command,
+ HCI_LE_Extended_Advertising_Report_Event,
+ HCI_LE_Extended_Create_Connection_Command,
+ HCI_LE_Rand_Command,
+ HCI_LE_Read_PHY_Command,
+ HCI_LE_Set_Advertising_Data_Command,
+ HCI_LE_Set_Advertising_Enable_Command,
+ HCI_LE_Set_Advertising_Parameters_Command,
+ HCI_LE_Set_Default_PHY_Command,
+ HCI_LE_Set_Extended_Scan_Enable_Command,
+ HCI_LE_Set_Extended_Scan_Parameters_Command,
+ HCI_LE_Set_PHY_Command,
+ HCI_LE_Set_Random_Address_Command,
+ HCI_LE_Set_Scan_Enable_Command,
+ HCI_LE_Set_Scan_Parameters_Command,
+ HCI_LE_Set_Scan_Response_Data_Command,
+ HCI_PIN_Code_Request_Reply_Command,
+ HCI_PIN_Code_Request_Negative_Reply_Command,
+ HCI_Read_BD_ADDR_Command,
+ HCI_Read_RSSI_Command,
+ HCI_Reject_Connection_Request_Command,
+ HCI_Remote_Name_Request_Command,
+ HCI_Switch_Role_Command,
+ HCI_Set_Connection_Encryption_Command,
+ HCI_StatusError,
+ HCI_User_Confirmation_Request_Negative_Reply_Command,
+ HCI_User_Confirmation_Request_Reply_Command,
+ HCI_User_Passkey_Request_Negative_Reply_Command,
+ HCI_User_Passkey_Request_Reply_Command,
+ HCI_Write_Class_Of_Device_Command,
+ HCI_Write_Extended_Inquiry_Response_Command,
+ HCI_Write_Inquiry_Mode_Command,
+ HCI_Write_LE_Host_Support_Command,
+ HCI_Write_Local_Name_Command,
+ HCI_Write_Scan_Enable_Command,
+ HCI_Write_Secure_Connections_Host_Support_Command,
+ HCI_Write_Simple_Pairing_Mode_Command,
+ OwnAddressType,
+ phy_list_to_bits,
+)
from .host import Host
-from .gatt import *
from .gap import GenericAccessService
-from .core import AdvertisingData, BT_CENTRAL_ROLE, BT_PERIPHERAL_ROLE
-from .utils import AsyncRunner, CompositeEventEmitter, setup_event_forwarding, composite_listener
+from .core import (
+ BT_BR_EDR_TRANSPORT,
+ BT_CENTRAL_ROLE,
+ BT_LE_TRANSPORT,
+ BT_PERIPHERAL_ROLE,
+ AdvertisingData,
+ CommandTimeoutError,
+ ConnectionPHY,
+ InvalidStateError,
+)
+from .utils import (
+ AsyncRunner,
+ CompositeEventEmitter,
+ setup_event_forwarding,
+ composite_listener,
+)
+from .keys import (
+ KeyStore,
+ PairingKeys,
+)
+from .pairing import PairingConfig
from . import gatt_client
from . import gatt_server
from . import smp
from . import sdp
from . import l2cap
-from . import keys
+from . import core
+
# -----------------------------------------------------------------------------
# Logging
@@ -40,20 +160,42 @@ logger = logging.getLogger(__name__)
# -----------------------------------------------------------------------------
# Constants
# -----------------------------------------------------------------------------
-DEVICE_DEFAULT_ADDRESS = '00:00:00:00:00:00'
-DEVICE_DEFAULT_ADVERTISING_INTERVAL = 1000 # ms
-DEVICE_DEFAULT_ADVERTISING_DATA = ''
-DEVICE_DEFAULT_NAME = 'Bumble'
-DEVICE_DEFAULT_INQUIRY_LENGTH = 8 # 10.24 seconds
-DEVICE_DEFAULT_CLASS_OF_DEVICE = 0
-DEVICE_DEFAULT_SCAN_RESPONSE_DATA = b''
-DEVICE_DEFAULT_DATA_LENGTH = (27, 328, 27, 328)
-DEVICE_DEFAULT_SCAN_INTERVAL = 60 # ms
-DEVICE_DEFAULT_SCAN_WINDOW = 60 # ms
-DEVICE_MIN_SCAN_INTERVAL = 25
-DEVICE_MAX_SCAN_INTERVAL = 10240
-DEVICE_MIN_SCAN_WINDOW = 25
-DEVICE_MAX_SCAN_WINDOW = 10240
+# fmt: off
+# pylint: disable=line-too-long
+
+DEVICE_MIN_SCAN_INTERVAL = 25
+DEVICE_MAX_SCAN_INTERVAL = 10240
+DEVICE_MIN_SCAN_WINDOW = 25
+DEVICE_MAX_SCAN_WINDOW = 10240
+DEVICE_MIN_LE_RSSI = -127
+DEVICE_MAX_LE_RSSI = 20
+
+DEVICE_DEFAULT_ADDRESS = '00:00:00:00:00:00'
+DEVICE_DEFAULT_ADVERTISING_INTERVAL = 1000 # ms
+DEVICE_DEFAULT_ADVERTISING_DATA = ''
+DEVICE_DEFAULT_NAME = 'Bumble'
+DEVICE_DEFAULT_INQUIRY_LENGTH = 8 # 10.24 seconds
+DEVICE_DEFAULT_CLASS_OF_DEVICE = 0
+DEVICE_DEFAULT_SCAN_RESPONSE_DATA = b''
+DEVICE_DEFAULT_DATA_LENGTH = (27, 328, 27, 328)
+DEVICE_DEFAULT_SCAN_INTERVAL = 60 # ms
+DEVICE_DEFAULT_SCAN_WINDOW = 60 # ms
+DEVICE_DEFAULT_CONNECT_TIMEOUT = None # No timeout
+DEVICE_DEFAULT_CONNECT_SCAN_INTERVAL = 60 # ms
+DEVICE_DEFAULT_CONNECT_SCAN_WINDOW = 60 # ms
+DEVICE_DEFAULT_CONNECTION_INTERVAL_MIN = 15 # ms
+DEVICE_DEFAULT_CONNECTION_INTERVAL_MAX = 30 # ms
+DEVICE_DEFAULT_CONNECTION_MAX_LATENCY = 0
+DEVICE_DEFAULT_CONNECTION_SUPERVISION_TIMEOUT = 720 # ms
+DEVICE_DEFAULT_CONNECTION_MIN_CE_LENGTH = 0 # ms
+DEVICE_DEFAULT_CONNECTION_MAX_CE_LENGTH = 0 # ms
+DEVICE_DEFAULT_L2CAP_COC_MTU = l2cap.L2CAP_LE_CREDIT_BASED_CONNECTION_DEFAULT_MTU
+DEVICE_DEFAULT_L2CAP_COC_MPS = l2cap.L2CAP_LE_CREDIT_BASED_CONNECTION_DEFAULT_MPS
+DEVICE_DEFAULT_L2CAP_COC_MAX_CREDITS = l2cap.L2CAP_LE_CREDIT_BASED_CONNECTION_DEFAULT_INITIAL_CREDITS
+
+# fmt: on
+# pylint: enable=line-too-long
+
# -----------------------------------------------------------------------------
# Classes
@@ -61,28 +203,210 @@ DEVICE_MAX_SCAN_WINDOW = 10240
# -----------------------------------------------------------------------------
+class Advertisement:
+ address: Address
+
+ TX_POWER_NOT_AVAILABLE = (
+ HCI_LE_Extended_Advertising_Report_Event.TX_POWER_INFORMATION_NOT_AVAILABLE
+ )
+ RSSI_NOT_AVAILABLE = HCI_LE_Extended_Advertising_Report_Event.RSSI_NOT_AVAILABLE
+
+ @classmethod
+ def from_advertising_report(cls, report):
+ if isinstance(report, HCI_LE_Advertising_Report_Event.Report):
+ return LegacyAdvertisement.from_advertising_report(report)
+
+ if isinstance(report, HCI_LE_Extended_Advertising_Report_Event.Report):
+ return ExtendedAdvertisement.from_advertising_report(report)
+
+ return None
+
+ # pylint: disable=line-too-long
+ def __init__(
+ self,
+ address,
+ rssi=HCI_LE_Extended_Advertising_Report_Event.RSSI_NOT_AVAILABLE,
+ is_legacy=False,
+ is_anonymous=False,
+ is_connectable=False,
+ is_directed=False,
+ is_scannable=False,
+ is_scan_response=False,
+ is_complete=True,
+ is_truncated=False,
+ primary_phy=0,
+ secondary_phy=0,
+ tx_power=HCI_LE_Extended_Advertising_Report_Event.TX_POWER_INFORMATION_NOT_AVAILABLE,
+ sid=0,
+ data=b'',
+ ):
+ self.address = address
+ self.rssi = rssi
+ self.is_legacy = is_legacy
+ self.is_anonymous = is_anonymous
+ self.is_connectable = is_connectable
+ self.is_directed = is_directed
+ self.is_scannable = is_scannable
+ self.is_scan_response = is_scan_response
+ self.is_complete = is_complete
+ self.is_truncated = is_truncated
+ self.primary_phy = primary_phy
+ self.secondary_phy = secondary_phy
+ self.tx_power = tx_power
+ self.sid = sid
+ self.data = AdvertisingData.from_bytes(data)
+
+
+# -----------------------------------------------------------------------------
+class LegacyAdvertisement(Advertisement):
+ @classmethod
+ def from_advertising_report(cls, report):
+ return cls(
+ address=report.address,
+ rssi=report.rssi,
+ is_legacy=True,
+ is_connectable=report.event_type
+ in (
+ HCI_LE_Advertising_Report_Event.ADV_IND,
+ HCI_LE_Advertising_Report_Event.ADV_DIRECT_IND,
+ ),
+ is_directed=report.event_type
+ == HCI_LE_Advertising_Report_Event.ADV_DIRECT_IND,
+ is_scannable=report.event_type
+ in (
+ HCI_LE_Advertising_Report_Event.ADV_IND,
+ HCI_LE_Advertising_Report_Event.ADV_SCAN_IND,
+ ),
+ is_scan_response=report.event_type
+ == HCI_LE_Advertising_Report_Event.SCAN_RSP,
+ data=report.data,
+ )
+
+
+# -----------------------------------------------------------------------------
+class ExtendedAdvertisement(Advertisement):
+ @classmethod
+ def from_advertising_report(cls, report):
+ # fmt: off
+ # pylint: disable=line-too-long
+ return cls(
+ address = report.address,
+ rssi = report.rssi,
+ is_legacy = report.event_type & (1 << HCI_LE_Extended_Advertising_Report_Event.LEGACY_ADVERTISING_PDU_USED) != 0,
+ is_anonymous = report.address.address_type == HCI_LE_Extended_Advertising_Report_Event.ANONYMOUS_ADDRESS_TYPE,
+ is_connectable = report.event_type & (1 << HCI_LE_Extended_Advertising_Report_Event.CONNECTABLE_ADVERTISING) != 0,
+ is_directed = report.event_type & (1 << HCI_LE_Extended_Advertising_Report_Event.DIRECTED_ADVERTISING) != 0,
+ is_scannable = report.event_type & (1 << HCI_LE_Extended_Advertising_Report_Event.SCANNABLE_ADVERTISING) != 0,
+ is_scan_response = report.event_type & (1 << HCI_LE_Extended_Advertising_Report_Event.SCAN_RESPONSE) != 0,
+ is_complete = (report.event_type >> 5 & 3) == HCI_LE_Extended_Advertising_Report_Event.DATA_COMPLETE,
+ is_truncated = (report.event_type >> 5 & 3) == HCI_LE_Extended_Advertising_Report_Event.DATA_INCOMPLETE_TRUNCATED_NO_MORE_TO_COME,
+ primary_phy = report.primary_phy,
+ secondary_phy = report.secondary_phy,
+ tx_power = report.tx_power,
+ sid = report.advertising_sid,
+ data = report.data
+ )
+ # fmt: on
+
+
+# -----------------------------------------------------------------------------
class AdvertisementDataAccumulator:
- def __init__(self):
- self.advertising_data = AdvertisingData()
- self.last_advertisement_type = None
- self.connectable = False
- self.flushable = False
-
- def update(self, data, advertisement_type):
- if advertisement_type == HCI_LE_Advertising_Report_Event.SCAN_RSP:
- if self.last_advertisement_type != HCI_LE_Advertising_Report_Event.SCAN_RSP:
- self.advertising_data.append(data)
- self.flushable = True
+ def __init__(self, passive=False):
+ self.passive = passive
+ self.last_advertisement = None
+ self.last_data = b''
+
+ def update(self, report):
+ advertisement = Advertisement.from_advertising_report(report)
+ if advertisement is None:
+ return None
+
+ result = None
+
+ if advertisement.is_scan_response:
+ if (
+ self.last_advertisement is not None
+ and not self.last_advertisement.is_scan_response
+ ):
+ # This is the response to a scannable advertisement
+ result = Advertisement.from_advertising_report(report)
+ result.is_connectable = self.last_advertisement.is_connectable
+ result.is_scannable = True
+ result.data = AdvertisingData.from_bytes(self.last_data + report.data)
+ self.last_data = b''
else:
- self.advertising_data = AdvertisingData.from_bytes(data)
- self.flushable = self.last_advertisement_type != HCI_LE_Advertising_Report_Event.SCAN_RSP
+ if (
+ self.passive
+ or (not advertisement.is_scannable)
+ or (
+ self.last_advertisement is not None
+ and not self.last_advertisement.is_scan_response
+ )
+ ):
+ # Don't wait for a scan response
+ result = Advertisement.from_advertising_report(report)
+
+ self.last_data = report.data
- if advertisement_type == HCI_LE_Advertising_Report_Event.ADV_IND or advertisement_type == HCI_LE_Advertising_Report_Event.ADV_DIRECT_IND:
- self.connectable = True
- elif advertisement_type == HCI_LE_Advertising_Report_Event.ADV_SCAN_IND or advertisement_type == HCI_LE_Advertising_Report_Event.ADV_NONCONN_IND:
- self.connectable = False
+ self.last_advertisement = advertisement
- self.last_advertisement_type = advertisement_type
+ return result
+
+
+# -----------------------------------------------------------------------------
+class AdvertisingType(IntEnum):
+ # fmt: off
+ # pylint: disable=line-too-long
+ UNDIRECTED_CONNECTABLE_SCANNABLE = 0x00 # Undirected, connectable, scannable
+ DIRECTED_CONNECTABLE_HIGH_DUTY = 0x01 # Directed, connectable, non-scannable
+ UNDIRECTED_SCANNABLE = 0x02 # Undirected, non-connectable, scannable
+ UNDIRECTED = 0x03 # Undirected, non-connectable, non-scannable
+ DIRECTED_CONNECTABLE_LOW_DUTY = 0x04 # Directed, connectable, non-scannable
+ # fmt: on
+
+ @property
+ def has_data(self):
+ return self in (
+ AdvertisingType.UNDIRECTED_CONNECTABLE_SCANNABLE,
+ AdvertisingType.UNDIRECTED_SCANNABLE,
+ AdvertisingType.UNDIRECTED,
+ )
+
+ @property
+ def is_connectable(self):
+ return self in (
+ AdvertisingType.UNDIRECTED_CONNECTABLE_SCANNABLE,
+ AdvertisingType.DIRECTED_CONNECTABLE_HIGH_DUTY,
+ AdvertisingType.DIRECTED_CONNECTABLE_LOW_DUTY,
+ )
+
+ @property
+ def is_scannable(self):
+ return self in (
+ AdvertisingType.UNDIRECTED_CONNECTABLE_SCANNABLE,
+ AdvertisingType.UNDIRECTED_SCANNABLE,
+ )
+
+ @property
+ def is_directed(self):
+ return self in (
+ AdvertisingType.DIRECTED_CONNECTABLE_HIGH_DUTY,
+ AdvertisingType.DIRECTED_CONNECTABLE_LOW_DUTY,
+ )
+
+
+# -----------------------------------------------------------------------------
+class LePhyOptions:
+ # Coded PHY preference
+ ANY_CODED_PHY = 0
+ PREFER_S_2_CODED_PHY = 1
+ PREFER_S_8_CODED_PHY = 2
+
+ def __init__(self, coded_phy_preference=0):
+ self.coded_phy_preference = coded_phy_preference
+
+ def __int__(self):
+ return self.coded_phy_preference & 3
# -----------------------------------------------------------------------------
@@ -99,28 +423,41 @@ class Peer:
return self.gatt_client.services
async def request_mtu(self, mtu):
- return await self.gatt_client.request_mtu(mtu)
+ mtu = await self.gatt_client.request_mtu(mtu)
+ self.connection.emit('connection_att_mtu_update')
+ return mtu
async def discover_service(self, uuid):
return await self.gatt_client.discover_service(uuid)
- async def discover_services(self, uuids = []):
+ async def discover_services(self, uuids=()):
return await self.gatt_client.discover_services(uuids)
async def discover_included_services(self, service):
return await self.gatt_client.discover_included_services(service)
- async def discover_characteristics(self, uuids = [], service = None):
- return await self.gatt_client.discover_characteristics(uuids = uuids, service = service)
+ async def discover_characteristics(self, uuids=(), service=None):
+ return await self.gatt_client.discover_characteristics(
+ uuids=uuids, service=service
+ )
- async def discover_descriptors(self, characteristic = None, start_handle = None, end_handle = None):
- return await self.gatt_client.discover_descriptors(characteristic, start_handle, end_handle)
+ async def discover_descriptors(
+ self, characteristic=None, start_handle=None, end_handle=None
+ ):
+ return await self.gatt_client.discover_descriptors(
+ characteristic, start_handle, end_handle
+ )
async def discover_attributes(self):
return await self.gatt_client.discover_attributes()
- async def subscribe(self, characteristic, subscriber=None):
- return await self.gatt_client.subscribe(characteristic, subscriber)
+ async def subscribe(self, characteristic, subscriber=None, prefer_notify=True):
+ return await self.gatt_client.subscribe(
+ characteristic, subscriber, prefer_notify
+ )
+
+ async def unsubscribe(self, characteristic, subscriber=None):
+ return await self.gatt_client.unsubscribe(characteristic, subscriber)
async def read_value(self, attribute):
return await self.gatt_client.read_value(attribute)
@@ -134,7 +471,7 @@ class Peer:
def get_services_by_uuid(self, uuid):
return self.gatt_client.get_services_by_uuid(uuid)
- def get_characteristics_by_uuid(self, uuid, service = None):
+ def get_characteristics_by_uuid(self, uuid, service=None):
return self.gatt_client.get_characteristics_by_uuid(uuid, service)
def create_service_proxy(self, proxy_class):
@@ -148,16 +485,59 @@ class Peer:
await service.discover_characteristics()
return self.create_service_proxy(proxy_class)
+ async def sustain(self, timeout=None):
+ await self.connection.sustain(timeout)
+
# [Classic only]
async def request_name(self):
return await self.connection.request_remote_name()
+ async def __aenter__(self):
+ await self.discover_services()
+ for service in self.services:
+ await service.discover_characteristics()
+
+ return self
+
+ async def __aexit__(self, exc_type, exc_value, traceback):
+ pass
+
def __str__(self):
return f'{self.connection.peer_address} as {self.connection.role_name}'
# -----------------------------------------------------------------------------
+@dataclass
+class ConnectionParametersPreferences:
+ default: ClassVar[ConnectionParametersPreferences]
+ connection_interval_min: int = DEVICE_DEFAULT_CONNECTION_INTERVAL_MIN
+ connection_interval_max: int = DEVICE_DEFAULT_CONNECTION_INTERVAL_MAX
+ max_latency: int = DEVICE_DEFAULT_CONNECTION_MAX_LATENCY
+ supervision_timeout: int = DEVICE_DEFAULT_CONNECTION_SUPERVISION_TIMEOUT
+ min_ce_length: int = DEVICE_DEFAULT_CONNECTION_MIN_CE_LENGTH
+ max_ce_length: int = DEVICE_DEFAULT_CONNECTION_MAX_CE_LENGTH
+
+
+ConnectionParametersPreferences.default = ConnectionParametersPreferences()
+
+
+# -----------------------------------------------------------------------------
class Connection(CompositeEventEmitter):
+ device: Device
+ handle: int
+ transport: int
+ self_address: Address
+ peer_address: Address
+ peer_resolvable_address: Optional[Address]
+ role: int
+ encryption: int
+ authenticated: bool
+ sc: bool
+ link_key_type: int
+ gatt_client: gatt_client.Client
+ pairing_peer_io_capability: Optional[int]
+ pairing_peer_authentication_requirements: Optional[int]
+
@composite_listener
class Listener:
def on_disconnection(self, reason):
@@ -169,6 +549,9 @@ class Connection(CompositeEventEmitter):
def on_connection_parameters_update_failure(self, error):
pass
+ def on_connection_data_length_change(self):
+ pass
+
def on_connection_phy_update(self):
pass
@@ -184,110 +567,249 @@ class Connection(CompositeEventEmitter):
def on_connection_encryption_key_refresh(self):
pass
- def __init__(self, device, handle, transport, peer_address, peer_resolvable_address, role, parameters):
+ def __init__(
+ self,
+ device,
+ handle,
+ transport,
+ self_address,
+ peer_address,
+ peer_resolvable_address,
+ role,
+ parameters,
+ phy,
+ ):
super().__init__()
- self.device = device
- self.handle = handle
- self.transport = transport
- self.peer_address = peer_address
+ self.device = device
+ self.handle = handle
+ self.transport = transport
+ self.self_address = self_address
+ self.peer_address = peer_address
self.peer_resolvable_address = peer_resolvable_address
- self.peer_name = None # Classic only
- self.role = role
- self.parameters = parameters
- self.encryption = 0
- self.authenticated = False
- self.phy = ConnectionPHY(HCI_LE_1M_PHY, HCI_LE_1M_PHY)
- self.att_mtu = ATT_DEFAULT_MTU
- self.data_length = DEVICE_DEFAULT_DATA_LENGTH
- self.gatt_client = None # Per-connection client
- self.gatt_server = device.gatt_server # By default, use the device's shared server
+ self.peer_name = None # Classic only
+ self.role = role
+ self.parameters = parameters
+ self.encryption = 0
+ self.authenticated = False
+ self.sc = False
+ self.link_key_type = None
+ self.phy = phy
+ self.att_mtu = ATT_DEFAULT_MTU
+ self.data_length = DEVICE_DEFAULT_DATA_LENGTH
+ self.gatt_client = None # Per-connection client
+ self.gatt_server = (
+ device.gatt_server
+ ) # By default, use the device's shared server
+ self.pairing_peer_io_capability = None
+ self.pairing_peer_authentication_requirements = None
+
+ # [Classic only]
+ @classmethod
+ def incomplete(cls, device, peer_address, role):
+ """
+ Instantiate an incomplete connection (ie. one waiting for a HCI Connection
+ Complete event).
+ Once received it shall be completed using the `.complete` method.
+ """
+ return cls(
+ device,
+ None,
+ BT_BR_EDR_TRANSPORT,
+ device.public_address,
+ peer_address,
+ None,
+ role,
+ None,
+ None,
+ )
+
+ # [Classic only]
+ def complete(self, handle, parameters):
+ """
+ Finish an incomplete connection upon completion.
+ """
+ assert self.handle is None
+ assert self.transport == BT_BR_EDR_TRANSPORT
+ self.handle = handle
+ self.parameters = parameters
@property
def role_name(self):
- return 'CENTRAL' if self.role == BT_CENTRAL_ROLE else 'PERIPHERAL'
+ if self.role is None:
+ return 'NOT-SET'
+ if self.role == BT_CENTRAL_ROLE:
+ return 'CENTRAL'
+ if self.role == BT_PERIPHERAL_ROLE:
+ return 'PERIPHERAL'
+ return f'UNKNOWN[{self.role}]'
@property
def is_encrypted(self):
return self.encryption != 0
+ @property
+ def is_incomplete(self) -> bool:
+ return self.handle is None
+
def send_l2cap_pdu(self, cid, pdu):
self.device.send_l2cap_pdu(self.handle, cid, pdu)
def create_l2cap_connector(self, psm):
return self.device.create_l2cap_connector(self, psm)
- async def disconnect(self, reason = HCI_REMOTE_USER_TERMINATED_CONNECTION_ERROR):
- return await self.device.disconnect(self, reason)
+ async def open_l2cap_channel(
+ self,
+ psm,
+ max_credits=DEVICE_DEFAULT_L2CAP_COC_MAX_CREDITS,
+ mtu=DEVICE_DEFAULT_L2CAP_COC_MTU,
+ mps=DEVICE_DEFAULT_L2CAP_COC_MPS,
+ ):
+ return await self.device.open_l2cap_channel(self, psm, max_credits, mtu, mps)
+
+ async def disconnect(
+ self, reason: int = HCI_REMOTE_USER_TERMINATED_CONNECTION_ERROR
+ ) -> None:
+ await self.device.disconnect(self, reason)
- async def pair(self):
+ async def pair(self) -> None:
return await self.device.pair(self)
- def request_pairing(self):
+ def request_pairing(self) -> None:
return self.device.request_pairing(self)
# [Classic only]
- async def authenticate(self):
+ async def authenticate(self) -> None:
return await self.device.authenticate(self)
- async def encrypt(self):
- return await self.device.encrypt(self)
+ async def encrypt(self, enable: bool = True) -> None:
+ return await self.device.encrypt(self, enable)
+
+ async def switch_role(self, role: int) -> None:
+ return await self.device.switch_role(self, role)
+
+ async def sustain(self, timeout=None):
+ """Idles the current task waiting for a disconnect or timeout"""
+
+ abort = asyncio.get_running_loop().create_future()
+ self.on('disconnection', abort.set_result)
+ self.on('disconnection_failure', abort.set_exception)
+
+ try:
+ await asyncio.wait_for(self.device.abort_on('flush', abort), timeout)
+ except asyncio.TimeoutError:
+ pass
+
+ self.remove_listener('disconnection', abort.set_result)
+ self.remove_listener('disconnection_failure', abort.set_exception)
async def update_parameters(
self,
- conn_interval_min,
- conn_interval_max,
- conn_latency,
- supervision_timeout
+ connection_interval_min,
+ connection_interval_max,
+ max_latency,
+ supervision_timeout,
):
return await self.device.update_connection_parameters(
self,
- conn_interval_min,
- conn_interval_max,
- conn_latency,
- supervision_timeout
+ connection_interval_min,
+ connection_interval_max,
+ max_latency,
+ supervision_timeout,
)
+ async def set_phy(self, tx_phys=None, rx_phys=None, phy_options=None):
+ return await self.device.set_connection_phy(self, tx_phys, rx_phys, phy_options)
+
+ async def get_rssi(self):
+ return await self.device.get_connection_rssi(self)
+
+ async def get_phy(self):
+ return await self.device.get_connection_phy(self)
+
# [Classic only]
async def request_remote_name(self):
return await self.device.request_remote_name(self)
+ async def __aenter__(self):
+ return self
+
+ async def __aexit__(self, exc_type, exc_value, traceback):
+ if exc_type is None:
+ try:
+ await self.disconnect()
+ except HCI_StatusError as error:
+ # Invalid parameter means the connection is no longer valid
+ if error.error_code != HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR:
+ raise
+
def __str__(self):
- return f'Connection(handle=0x{self.handle:04X}, role={self.role_name}, address={self.peer_address})'
+ return (
+ f'Connection(handle=0x{self.handle:04X}, '
+ f'role={self.role_name}, '
+ f'address={self.peer_address})'
+ )
# -----------------------------------------------------------------------------
class DeviceConfiguration:
- def __init__(self):
+ def __init__(self) -> None:
# Setup defaults
- self.name = DEVICE_DEFAULT_NAME
- self.address = DEVICE_DEFAULT_ADDRESS
- self.class_of_device = DEVICE_DEFAULT_CLASS_OF_DEVICE
- self.scan_response_data = DEVICE_DEFAULT_SCAN_RESPONSE_DATA
+ self.name = DEVICE_DEFAULT_NAME
+ self.address = Address(DEVICE_DEFAULT_ADDRESS)
+ self.class_of_device = DEVICE_DEFAULT_CLASS_OF_DEVICE
+ self.scan_response_data = DEVICE_DEFAULT_SCAN_RESPONSE_DATA
self.advertising_interval_min = DEVICE_DEFAULT_ADVERTISING_INTERVAL
self.advertising_interval_max = DEVICE_DEFAULT_ADVERTISING_INTERVAL
- self.le_enabled = True
+ self.le_enabled = True
# LE host enable 2nd parameter
- self.le_simultaneous_enabled = True
- self.classic_sc_enabled = True
- self.classic_ssp_enabled = True
+ self.le_simultaneous_enabled = False
+ self.classic_enabled = False
+ self.classic_sc_enabled = True
+ self.classic_ssp_enabled = True
+ self.classic_smp_enabled = True
+ self.classic_accept_any = True
+ self.connectable = True
+ self.discoverable = True
self.advertising_data = bytes(
- AdvertisingData([(AdvertisingData.COMPLETE_LOCAL_NAME, bytes(self.name, 'utf-8'))])
+ AdvertisingData(
+ [(AdvertisingData.COMPLETE_LOCAL_NAME, bytes(self.name, 'utf-8'))]
+ )
)
- self.irk = bytes(16) # This really must be changed for any level of security
+ self.irk = bytes(16) # This really must be changed for any level of security
self.keystore = None
+ self.gatt_services: List[Dict[str, Any]] = []
- def load_from_dict(self, config):
+ def load_from_dict(self, config: Dict[str, Any]) -> None:
# Load simple properties
self.name = config.get('name', self.name)
- self.address = Address(config.get('address', self.address))
+ if address := config.get('address', None):
+ self.address = Address(address)
self.class_of_device = config.get('class_of_device', self.class_of_device)
- self.advertising_interval_min = config.get('advertising_interval', self.advertising_interval_min)
+ self.advertising_interval_min = config.get(
+ 'advertising_interval', self.advertising_interval_min
+ )
self.advertising_interval_max = self.advertising_interval_min
- self.keystore = config.get('keystore')
- self.le_enabled = config.get('le_enabled', self.le_enabled)
- self.le_simultaneous_enabled = config.get('le_simultaneous_enabled', self.le_simultaneous_enabled)
- self.classic_sc_enabled = config.get('classic_sc_enabled', self.classic_sc_enabled)
- self.classic_ssp_enabled = config.get('classic_ssp_enabled', self.classic_ssp_enabled)
+ self.keystore = config.get('keystore')
+ self.le_enabled = config.get('le_enabled', self.le_enabled)
+ self.le_simultaneous_enabled = config.get(
+ 'le_simultaneous_enabled', self.le_simultaneous_enabled
+ )
+ self.classic_enabled = config.get('classic_enabled', self.classic_enabled)
+ self.classic_sc_enabled = config.get(
+ 'classic_sc_enabled', self.classic_sc_enabled
+ )
+ self.classic_ssp_enabled = config.get(
+ 'classic_ssp_enabled', self.classic_ssp_enabled
+ )
+ self.classic_smp_enabled = config.get(
+ 'classic_smp_enabled', self.classic_smp_enabled
+ )
+ self.classic_accept_any = config.get(
+ 'classic_accept_any', self.classic_accept_any
+ )
+ self.connectable = config.get('connectable', self.connectable)
+ self.discoverable = config.get('discoverable', self.discoverable)
+ self.gatt_services = config.get('gatt_services', self.gatt_services)
# Load or synthesize an IRK
irk = config.get('irk')
@@ -295,7 +817,8 @@ class DeviceConfiguration:
self.irk = bytes.fromhex(irk)
else:
# Construct an IRK from the address bytes
- # NOTE: this is not secure, but will always give the same IRK for the same address
+ # NOTE: this is not secure, but will always give the same IRK for the same
+ # address
address_bytes = bytes(self.address)
self.irk = (address_bytes * 3)[:16]
@@ -305,22 +828,25 @@ class DeviceConfiguration:
self.advertising_data = bytes.fromhex(advertising_data)
def load_from_file(self, filename):
- with open(filename, 'r') as file:
+ with open(filename, 'r', encoding='utf-8') as file:
self.load_from_dict(json.load(file))
+
# -----------------------------------------------------------------------------
# Decorators used with the following Device class
# (we define them outside of the Device class, because defining decorators
# within a class requires unnecessarily complicated acrobatics)
# -----------------------------------------------------------------------------
+
# Decorator that converts the first argument from a connection handle to a connection
def with_connection_from_handle(function):
@functools.wraps(function)
def wrapper(self, connection_handle, *args, **kwargs):
if (connection := self.lookup_connection(connection_handle)) is None:
- raise ValueError('no connection for handle')
+ raise ValueError(f"no connection for handle: 0x{connection_handle:04x}")
return function(self, connection, *args, **kwargs)
+
return wrapper
@@ -328,10 +854,28 @@ def with_connection_from_handle(function):
def with_connection_from_address(function):
@functools.wraps(function)
def wrapper(self, address, *args, **kwargs):
+ if connection := self.pending_connections.get(address, False):
+ return function(self, connection, *args, **kwargs)
for connection in self.connections.values():
if connection.peer_address == address:
return function(self, connection, *args, **kwargs)
raise ValueError('no connection for address')
+
+ return wrapper
+
+
+# Decorator that tries to convert the first argument from a bluetooth address to a
+# connection
+def try_with_connection_from_address(function):
+ @functools.wraps(function)
+ def wrapper(self, address, *args, **kwargs):
+ if connection := self.pending_connections.get(address, False):
+ return function(self, connection, address, *args, **kwargs)
+ for connection in self.connections.values():
+ if connection.peer_address == address:
+ return function(self, connection, address, *args, **kwargs)
+ return function(self, None, address, *args, **kwargs)
+
return wrapper
@@ -345,15 +889,31 @@ def host_event_handler(function):
# List of host event handlers for the Device class.
# (we define this list outside the class, because referencing a class in method
# decorators is not straightforward)
-device_host_event_handlers = []
+device_host_event_handlers: List[str] = []
# -----------------------------------------------------------------------------
class Device(CompositeEventEmitter):
+ # Incomplete list of fields.
+ random_address: Address
+ public_address: Address
+ classic_enabled: bool
+ name: str
+ class_of_device: int
+ gatt_server: gatt_server.Server
+ advertising_data: bytes
+ scan_response_data: bytes
+ connections: Dict[int, Connection]
+ pending_connections: Dict[Address, Connection]
+ classic_pending_accepts: Dict[
+ Address, List[asyncio.Future[Union[Connection, Tuple[Address, int, int]]]]
+ ]
+ advertisement_accumulators: Dict[Address, AdvertisementDataAccumulator]
+ config: DeviceConfiguration
@composite_listener
class Listener:
- def on_advertisement(self, address, data, rssi, advertisement_type):
+ def on_advertisement(self, advertisement):
pass
def on_inquiry_result(self, address, class_of_device, data, rssi):
@@ -365,7 +925,12 @@ class Device(CompositeEventEmitter):
def on_connection_failure(self, error):
pass
- def on_characteristic_subscription(self, connection, characteristic, notify_enabled, indicate_enabled):
+ def on_connection_request(self, bd_addr, class_of_device, link_type):
+ pass
+
+ def on_characteristic_subscription(
+ self, connection, characteristic, notify_enabled, indicate_enabled
+ ):
pass
@classmethod
@@ -374,8 +939,8 @@ class Device(CompositeEventEmitter):
Create a Device instance with a Host configured to communicate with a controller
through an HCI source/sink
'''
- host = Host(controller_source = hci_source, controller_sink = hci_sink)
- return cls(name = name, address = address, host = host)
+ host = Host(controller_source=hci_source, controller_sink=hci_sink)
+ return cls(name=name, address=address, host=host)
@classmethod
def from_config_file(cls, filename):
@@ -387,49 +952,100 @@ class Device(CompositeEventEmitter):
def from_config_file_with_hci(cls, filename, hci_source, hci_sink):
config = DeviceConfiguration()
config.load_from_file(filename)
- host = Host(controller_source = hci_source, controller_sink = hci_sink)
- return cls(config = config, host = host)
+ host = Host(controller_source=hci_source, controller_sink=hci_sink)
+ return cls(config=config, host=host)
- def __init__(self, name = None, address = None, config = None, host = None, generic_access_service = True):
+ def __init__(
+ self,
+ name: Optional[str] = None,
+ address: Optional[Address] = None,
+ config: Optional[DeviceConfiguration] = None,
+ host: Optional[Host] = None,
+ generic_access_service: bool = True,
+ ) -> None:
super().__init__()
- self._host = None
- self.powered_on = False
- self.advertising = False
+ self._host = None
+ self.powered_on = False
+ self.advertising = False
+ self.advertising_type = None
+ self.auto_restart_inquiry = True
self.auto_restart_advertising = False
- self.command_timeout = 10 # seconds
- self.gatt_server = gatt_server.Server(self)
- self.sdp_server = sdp.Server(self)
- self.l2cap_channel_manager = l2cap.ChannelManager()
- self.advertisement_data = {}
- self.scanning = False
- self.discovering = False
- self.connecting = False
- self.disconnecting = False
- self.connections = {} # Connections, by connection handle
- self.classic_enabled = False
- self.discoverable = False
- self.connectable = False
- self.inquiry_response = None
- self.address_resolver = None
+ self.command_timeout = 10 # seconds
+ self.gatt_server = gatt_server.Server(self)
+ self.sdp_server = sdp.Server(self)
+ self.l2cap_channel_manager = l2cap.ChannelManager(
+ [l2cap.L2CAP_Information_Request.EXTENDED_FEATURE_FIXED_CHANNELS]
+ )
+ self.advertisement_accumulators = {} # Accumulators, by address
+ self.scanning = False
+ self.scanning_is_passive = False
+ self.discovering = False
+ self.le_connecting = False
+ self.disconnecting = False
+ self.connections = {} # Connections, by connection handle
+ self.pending_connections = {} # Connections, by BD address (BR/EDR only)
+ self.classic_enabled = False
+ self.inquiry_response = None
+ self.address_resolver = None
+ self.classic_pending_accepts = {
+ Address.ANY: []
+ } # Futures, by BD address OR [Futures] for Address.ANY
+
+ # Own address type cache
+ self.advertising_own_address_type = None
+ self.connect_own_address_type = None
# Use the initial config or a default
+ config = config or DeviceConfiguration()
+ self.config = config
+
self.public_address = Address('00:00:00:00:00:00')
- if config is None:
- config = DeviceConfiguration()
- self.name = config.name
- self.random_address = config.address
- self.class_of_device = config.class_of_device
- self.scan_response_data = config.scan_response_data
- self.advertising_data = config.advertising_data
+ self.name = config.name
+ self.random_address = config.address
+ self.class_of_device = config.class_of_device
+ self.scan_response_data = config.scan_response_data
+ self.advertising_data = config.advertising_data
self.advertising_interval_min = config.advertising_interval_min
self.advertising_interval_max = config.advertising_interval_max
- self.keystore = keys.KeyStore.create_for_device(config)
- self.irk = config.irk
- self.le_enabled = config.le_enabled
- self.le_simultaneous_enabled = config.le_simultaneous_enabled
- self.classic_ssp_enabled = config.classic_ssp_enabled
- self.classic_sc_enabled = config.classic_sc_enabled
+ self.keystore = None
+ self.irk = config.irk
+ self.le_enabled = config.le_enabled
+ self.classic_enabled = config.classic_enabled
+ self.le_simultaneous_enabled = config.le_simultaneous_enabled
+ self.classic_sc_enabled = config.classic_sc_enabled
+ self.classic_ssp_enabled = config.classic_ssp_enabled
+ self.classic_smp_enabled = config.classic_smp_enabled
+ self.discoverable = config.discoverable
+ self.connectable = config.connectable
+ self.classic_accept_any = config.classic_accept_any
+
+ for service in config.gatt_services:
+ characteristics = []
+ for characteristic in service.get("characteristics", []):
+ descriptors = []
+ for descriptor in characteristic.get("descriptors", []):
+ # Leave this check until 5/25/2023
+ if descriptor.get("permission", False):
+ raise Exception(
+ "Error parsing Device Config's GATT Services. The key 'permission' must be renamed to 'permissions'"
+ )
+ new_descriptor = Descriptor(
+ attribute_type=descriptor["descriptor_type"],
+ permissions=descriptor["permissions"],
+ )
+ descriptors.append(new_descriptor)
+ new_characteristic = Characteristic(
+ uuid=characteristic["uuid"],
+ properties=Characteristic.Properties.from_string(
+ characteristic["properties"]
+ ),
+ permissions=characteristic["permissions"],
+ descriptors=descriptors,
+ )
+ characteristics.append(new_characteristic)
+ new_service = Service(uuid=service["uuid"], characteristics=characteristics)
+ self.gatt_server.add_service(new_service)
# If a name is passed, override the name from the config
if name:
@@ -437,29 +1053,33 @@ class Device(CompositeEventEmitter):
# If an address is passed, override the address from the config
if address:
- if type(address) is str:
+ if isinstance(address, str):
address = Address(address)
self.random_address = address
# Setup SMP
- # TODO: allow using a public address
- self.smp_manager = smp.Manager(self, self.random_address)
+ self.smp_manager = smp.Manager(
+ self, pairing_config_factory=lambda connection: PairingConfig()
+ )
+
+ self.l2cap_channel_manager.register_fixed_channel(smp.SMP_CID, self.on_smp_pdu)
# Register the SDP server with the L2CAP Channel Manager
self.sdp_server.register(self.l2cap_channel_manager)
- # Add a GAP Service if requested
- if generic_access_service:
- self.gatt_server.add_service(GenericAccessService(self.name))
+ self.add_default_services(generic_access_service)
+ self.l2cap_channel_manager.register_fixed_channel(ATT_CID, self.on_gatt_pdu)
# Forward some events
setup_event_forwarding(self.gatt_server, self, 'characteristic_subscription')
# Set the initial host
- self.host = host
+ if host:
+ self.host = host
@property
- def host(self):
+ def host(self) -> Host:
+ assert self._host
return self._host
@host.setter
@@ -467,7 +1087,9 @@ class Device(CompositeEventEmitter):
# Unsubscribe from events from the current host
if self._host:
for event_name in device_host_event_handlers:
- self._host.remove_listener(event_name, getattr(self, f'on_{event_name}'))
+ self._host.remove_listener(
+ event_name, getattr(self, f'on_{event_name}')
+ )
# Subscribe to events from the new host
if host:
@@ -475,13 +1097,13 @@ class Device(CompositeEventEmitter):
host.on(event_name, getattr(self, f'on_{event_name}'))
# Update the references to the new host
- self._host = host
+ self._host = host
self.l2cap_channel_manager.host = host
# Set providers for the new host
if host:
host.long_term_key_provider = self.get_long_term_key
- host.link_key_provider = self.get_link_key
+ host.link_key_provider = self.get_link_key
@property
def sdp_service_records(self):
@@ -491,18 +1113,29 @@ class Device(CompositeEventEmitter):
def sdp_service_records(self, service_records):
self.sdp_server.service_records = service_records
- def lookup_connection(self, connection_handle):
+ def lookup_connection(self, connection_handle: int) -> Optional[Connection]:
if connection := self.connections.get(connection_handle):
return connection
- def find_connection_by_bd_addr(self, bd_addr, transport=None):
+ return None
+
+ def find_connection_by_bd_addr(
+ self,
+ bd_addr: Address,
+ transport: Optional[int] = None,
+ check_address_type: bool = False,
+ ) -> Optional[Connection]:
for connection in self.connections.values():
- if connection.peer_address.get_bytes() == bd_addr.get_bytes():
+ if connection.peer_address.to_bytes() == bd_addr.to_bytes():
+ if (
+ check_address_type
+ and connection.peer_address.address_type != bd_addr.address_type
+ ):
+ continue
if transport is None or connection.transport == transport:
return connection
- def register_l2cap_server(self, psm, server):
- self.l2cap_channel_manager.register_server(psm, server)
+ return None
def create_l2cap_connector(self, connection, psm):
return lambda: self.l2cap_channel_manager.connect(connection, psm)
@@ -510,53 +1143,130 @@ class Device(CompositeEventEmitter):
def create_l2cap_registrar(self, psm):
return lambda handler: self.register_l2cap_server(psm, handler)
+ def register_l2cap_server(self, psm, server):
+ self.l2cap_channel_manager.register_server(psm, server)
+
+ def register_l2cap_channel_server(
+ self,
+ psm,
+ server,
+ max_credits=DEVICE_DEFAULT_L2CAP_COC_MAX_CREDITS,
+ mtu=DEVICE_DEFAULT_L2CAP_COC_MTU,
+ mps=DEVICE_DEFAULT_L2CAP_COC_MPS,
+ ):
+ return self.l2cap_channel_manager.register_le_coc_server(
+ psm, server, max_credits, mtu, mps
+ )
+
+ async def open_l2cap_channel(
+ self,
+ connection,
+ psm,
+ max_credits=DEVICE_DEFAULT_L2CAP_COC_MAX_CREDITS,
+ mtu=DEVICE_DEFAULT_L2CAP_COC_MTU,
+ mps=DEVICE_DEFAULT_L2CAP_COC_MPS,
+ ):
+ return await self.l2cap_channel_manager.open_le_coc(
+ connection, psm, max_credits, mtu, mps
+ )
+
def send_l2cap_pdu(self, connection_handle, cid, pdu):
self.host.send_l2cap_pdu(connection_handle, cid, pdu)
- async def send_command(self, command):
+ async def send_command(self, command, check_result=False):
try:
- return await asyncio.wait_for(self.host.send_command(command), self.command_timeout)
- except asyncio.TimeoutError:
+ return await asyncio.wait_for(
+ self.host.send_command(command, check_result), self.command_timeout
+ )
+ except asyncio.TimeoutError as error:
logger.warning('!!! Command timed out')
+ raise CommandTimeoutError() from error
- async def power_on(self):
+ async def power_on(self) -> None:
# Reset the controller
await self.host.reset()
- response = await self.send_command(HCI_Read_BD_ADDR_Command())
+ # Try to get the public address from the controller
+ response = await self.send_command(HCI_Read_BD_ADDR_Command()) # type: ignore[call-arg]
if response.return_parameters.status == HCI_SUCCESS:
- logger.debug(color(f'BD_ADDR: {response.return_parameters.bd_addr}', 'yellow'))
+ logger.debug(
+ color(f'BD_ADDR: {response.return_parameters.bd_addr}', 'yellow')
+ )
self.public_address = response.return_parameters.bd_addr
+ # Instantiate the Key Store (we do this here rather than at __init__ time
+ # because some Key Store implementations use the public address as a namespace)
+ if self.keystore is None:
+ self.keystore = KeyStore.create_for_device(self)
+
+ # Finish setting up SMP based on post-init configurable options
+ if self.classic_smp_enabled:
+ self.l2cap_channel_manager.register_fixed_channel(
+ smp.SMP_BR_CID, self.on_smp_pdu
+ )
+
+ if self.host.supports_command(HCI_WRITE_LE_HOST_SUPPORT_COMMAND):
+ await self.send_command(
+ HCI_Write_LE_Host_Support_Command(
+ le_supported_host=int(self.le_enabled),
+ simultaneous_le_host=int(self.le_simultaneous_enabled),
+ ) # type: ignore[call-arg]
+ )
- await self.send_command(HCI_Write_LE_Host_Support_Command(
- le_supported_host = int(self.le_enabled),
- simultaneous_le_host = int(self.le_simultaneous_enabled),
- ))
if self.le_enabled:
# Set the controller address
- await self.send_command(HCI_LE_Set_Random_Address_Command(
- random_address = self.random_address
- ))
+ if self.random_address == Address.ANY_RANDOM:
+ # Try to use an address generated at random by the controller
+ if self.host.supports_command(HCI_LE_RAND_COMMAND):
+ # Get 8 random bytes
+ response = await self.send_command(
+ HCI_LE_Rand_Command(), check_result=True # type: ignore[call-arg]
+ )
+
+ # Ensure the address bytes can be a static random address
+ address_bytes = response.return_parameters.random_number[
+ :5
+ ] + bytes([response.return_parameters.random_number[5] | 0xC0])
+
+ # Create a static random address from the random bytes
+ self.random_address = Address(address_bytes)
+
+ if self.random_address != Address.ANY_RANDOM:
+ logger.debug(
+ color(
+ f'LE Random Address: {self.random_address}',
+ 'yellow',
+ )
+ )
+ await self.send_command(
+ HCI_LE_Set_Random_Address_Command(
+ random_address=self.random_address
+ ), # type: ignore[call-arg]
+ check_result=True,
+ )
# Load the address resolving list
- if self.keystore:
- await self.send_command(HCI_LE_Clear_Resolving_List_Command())
+ if self.keystore and self.host.supports_command(
+ HCI_LE_CLEAR_RESOLVING_LIST_COMMAND
+ ):
+ await self.send_command(HCI_LE_Clear_Resolving_List_Command()) # type: ignore[call-arg]
resolving_keys = await self.keystore.get_resolving_keys()
- for (irk, address) in resolving_keys:
+ for irk, address in resolving_keys:
await self.send_command(
HCI_LE_Add_Device_To_Resolving_List_Command(
- peer_identity_address_type = address.address_type,
- peer_identity_address = address,
- peer_irk = irk,
- local_irk = self.irk
- )
+ peer_identity_address_type=address.address_type,
+ peer_identity_address=address,
+ peer_irk=irk,
+ local_irk=self.irk,
+ ) # type: ignore[call-arg]
)
# Enable address resolution
# await self.send_command(
- # HCI_LE_Set_Address_Resolution_Enable_Command(address_resolution_enable=1)
+ # HCI_LE_Set_Address_Resolution_Enable_Command(
+ # address_resolution_enable=1)
+ # )
# )
# Create a host-side address resolver
@@ -564,72 +1274,126 @@ class Device(CompositeEventEmitter):
if self.classic_enabled:
await self.send_command(
- HCI_Write_Local_Name_Command(local_name=self.name.encode('utf8'))
+ HCI_Write_Local_Name_Command(local_name=self.name.encode('utf8')) # type: ignore[call-arg]
)
await self.send_command(
- HCI_Write_Class_Of_Device_Command(class_of_device = self.class_of_device)
+ HCI_Write_Class_Of_Device_Command(class_of_device=self.class_of_device) # type: ignore[call-arg]
)
await self.send_command(
HCI_Write_Simple_Pairing_Mode_Command(
- simple_pairing_mode=int(self.classic_ssp_enabled))
+ simple_pairing_mode=int(self.classic_ssp_enabled)
+ ) # type: ignore[call-arg]
)
await self.send_command(
HCI_Write_Secure_Connections_Host_Support_Command(
- secure_connections_host_support=int(self.classic_sc_enabled))
+ secure_connections_host_support=int(self.classic_sc_enabled)
+ ) # type: ignore[call-arg]
)
-
- # Let the SMP manager know about the address
- # TODO: allow using a public address
- self.smp_manager.address = self.random_address
+ await self.set_connectable(self.connectable)
+ await self.set_discoverable(self.discoverable)
# Done
self.powered_on = True
- async def start_advertising(self, auto_restart=False):
- self.auto_restart_advertising = auto_restart
+ async def power_off(self) -> None:
+ if self.powered_on:
+ await self.host.flush()
+ self.powered_on = False
+
+ def supports_le_feature(self, feature):
+ return self.host.supports_le_feature(feature)
+
+ def supports_le_phy(self, phy):
+ if phy == HCI_LE_1M_PHY:
+ return True
+
+ feature_map = {
+ HCI_LE_2M_PHY: HCI_LE_2M_PHY_LE_SUPPORTED_FEATURE,
+ HCI_LE_CODED_PHY: HCI_LE_CODED_PHY_LE_SUPPORTED_FEATURE,
+ }
+ if phy not in feature_map:
+ raise ValueError('invalid PHY')
+
+ return self.host.supports_le_feature(feature_map[phy])
+ async def start_advertising(
+ self,
+ advertising_type: AdvertisingType = AdvertisingType.UNDIRECTED_CONNECTABLE_SCANNABLE,
+ target: Optional[Address] = None,
+ own_address_type: int = OwnAddressType.RANDOM,
+ auto_restart: bool = False,
+ ) -> None:
# If we're advertising, stop first
if self.advertising:
await self.stop_advertising()
- # Set/update the advertising data
- await self.send_command(HCI_LE_Set_Advertising_Data_Command(
- advertising_data = self.advertising_data
- ))
+ # Set/update the advertising data if the advertising type allows it
+ if advertising_type.has_data:
+ await self.send_command(
+ HCI_LE_Set_Advertising_Data_Command(
+ advertising_data=self.advertising_data
+ ), # type: ignore[call-arg]
+ check_result=True,
+ )
+
+ # Set/update the scan response data if the advertising is scannable
+ if advertising_type.is_scannable:
+ await self.send_command(
+ HCI_LE_Set_Scan_Response_Data_Command(
+ scan_response_data=self.scan_response_data
+ ), # type: ignore[call-arg]
+ check_result=True,
+ )
- # Set/update the scan response data
- await self.send_command(HCI_LE_Set_Scan_Response_Data_Command(
- scan_response_data = self.scan_response_data
- ))
+ # Decide what peer address to use
+ if advertising_type.is_directed:
+ if target is None:
+ raise ValueError('directed advertising requires a target address')
+
+ peer_address = target
+ peer_address_type = target.address_type
+ else:
+ peer_address = Address('00:00:00:00:00:00')
+ peer_address_type = Address.PUBLIC_DEVICE_ADDRESS
# Set the advertising parameters
- await self.send_command(HCI_LE_Set_Advertising_Parameters_Command(
- # TODO: use real values, not fixed ones
- advertising_interval_min = self.advertising_interval_min,
- advertising_interval_max = self.advertising_interval_max,
- advertising_type = HCI_LE_Set_Advertising_Parameters_Command.ADV_IND,
- own_address_type = Address.RANDOM_DEVICE_ADDRESS, # TODO: allow using the public address
- peer_address_type = Address.PUBLIC_DEVICE_ADDRESS,
- peer_address = Address('00:00:00:00:00:00'),
- advertising_channel_map = 7,
- advertising_filter_policy = 0
- ))
+ await self.send_command(
+ HCI_LE_Set_Advertising_Parameters_Command(
+ advertising_interval_min=self.advertising_interval_min,
+ advertising_interval_max=self.advertising_interval_max,
+ advertising_type=int(advertising_type),
+ own_address_type=own_address_type,
+ peer_address_type=peer_address_type,
+ peer_address=peer_address,
+ advertising_channel_map=7,
+ advertising_filter_policy=0,
+ ), # type: ignore[call-arg]
+ check_result=True,
+ )
# Enable advertising
- await self.send_command(HCI_LE_Set_Advertising_Enable_Command(
- advertising_enable = 1
- ))
+ await self.send_command(
+ HCI_LE_Set_Advertising_Enable_Command(advertising_enable=1), # type: ignore[call-arg]
+ check_result=True,
+ )
+ self.advertising_own_address_type = own_address_type
+ self.auto_restart_advertising = auto_restart
+ self.advertising_type = advertising_type
self.advertising = True
- async def stop_advertising(self):
+ async def stop_advertising(self) -> None:
# Disable advertising
if self.advertising:
- await self.send_command(HCI_LE_Set_Advertising_Enable_Command(
- advertising_enable = 0
- ))
+ await self.send_command(
+ HCI_LE_Set_Advertising_Enable_Command(advertising_enable=0), # type: ignore[call-arg]
+ check_result=True,
+ )
+ self.advertising_own_address_type = None
self.advertising = False
+ self.advertising_type = None
+ self.auto_restart_advertising = False
@property
def is_advertising(self):
@@ -637,42 +1401,122 @@ class Device(CompositeEventEmitter):
async def start_scanning(
self,
- active=True,
- scan_interval=DEVICE_DEFAULT_SCAN_INTERVAL, # Scan interval in ms
- scan_window=DEVICE_DEFAULT_SCAN_WINDOW, # Scan window in ms
- own_address_type=Address.RANDOM_DEVICE_ADDRESS,
- filter_duplicates=False
- ):
+ legacy: bool = False,
+ active: bool = True,
+ scan_interval: int = DEVICE_DEFAULT_SCAN_INTERVAL, # Scan interval in ms
+ scan_window: int = DEVICE_DEFAULT_SCAN_WINDOW, # Scan window in ms
+ own_address_type: int = OwnAddressType.RANDOM,
+ filter_duplicates: bool = False,
+ scanning_phys: Tuple[int, int] = (HCI_LE_1M_PHY, HCI_LE_CODED_PHY),
+ ) -> None:
# Check that the arguments are legal
if scan_interval < scan_window:
raise ValueError('scan_interval must be >= scan_window')
- if scan_interval < DEVICE_MIN_SCAN_INTERVAL or scan_interval > DEVICE_MAX_SCAN_INTERVAL:
+ if (
+ scan_interval < DEVICE_MIN_SCAN_INTERVAL
+ or scan_interval > DEVICE_MAX_SCAN_INTERVAL
+ ):
raise ValueError('scan_interval out of range')
if scan_window < DEVICE_MIN_SCAN_WINDOW or scan_window > DEVICE_MAX_SCAN_WINDOW:
raise ValueError('scan_interval out of range')
- # Set the scanning parameters
- scan_type = HCI_LE_Set_Scan_Parameters_Command.ACTIVE_SCANNING if active else HCI_LE_Set_Scan_Parameters_Command.PASSIVE_SCANNING
- await self.send_command(HCI_LE_Set_Scan_Parameters_Command(
- le_scan_type = scan_type,
- le_scan_interval = int(scan_window / 0.625),
- le_scan_window = int(scan_window / 0.625),
- own_address_type = own_address_type,
- scanning_filter_policy = HCI_LE_Set_Scan_Parameters_Command.BASIC_UNFILTERED_POLICY
- ))
+ # Reset the accumulators
+ self.advertisement_accumulators = {}
# Enable scanning
- await self.send_command(HCI_LE_Set_Scan_Enable_Command(
- le_scan_enable = 1,
- filter_duplicates = 1 if filter_duplicates else 0
- ))
+ if not legacy and self.supports_le_feature(
+ HCI_LE_EXTENDED_ADVERTISING_LE_SUPPORTED_FEATURE
+ ):
+ # Set the scanning parameters
+ scan_type = (
+ HCI_LE_Set_Extended_Scan_Parameters_Command.ACTIVE_SCANNING
+ if active
+ else HCI_LE_Set_Extended_Scan_Parameters_Command.PASSIVE_SCANNING
+ )
+ scanning_filter_policy = (
+ HCI_LE_Set_Extended_Scan_Parameters_Command.BASIC_UNFILTERED_POLICY
+ ) # TODO: support other types
+
+ scanning_phy_count = 0
+ scanning_phys_bits = 0
+ if HCI_LE_1M_PHY in scanning_phys:
+ scanning_phys_bits |= 1 << HCI_LE_1M_PHY_BIT
+ scanning_phy_count += 1
+ if HCI_LE_CODED_PHY in scanning_phys:
+ if self.supports_le_feature(HCI_LE_CODED_PHY_LE_SUPPORTED_FEATURE):
+ scanning_phys_bits |= 1 << HCI_LE_CODED_PHY_BIT
+ scanning_phy_count += 1
+
+ if scanning_phy_count == 0:
+ raise ValueError('at least one scanning PHY must be enabled')
+
+ await self.send_command(
+ HCI_LE_Set_Extended_Scan_Parameters_Command(
+ own_address_type=own_address_type,
+ scanning_filter_policy=scanning_filter_policy,
+ scanning_phys=scanning_phys_bits,
+ scan_types=[scan_type] * scanning_phy_count,
+ scan_intervals=[int(scan_window / 0.625)] * scanning_phy_count,
+ scan_windows=[int(scan_window / 0.625)] * scanning_phy_count,
+ ), # type: ignore[call-arg]
+ check_result=True,
+ )
+
+ # Enable scanning
+ await self.send_command(
+ HCI_LE_Set_Extended_Scan_Enable_Command(
+ enable=1,
+ filter_duplicates=1 if filter_duplicates else 0,
+ duration=0, # TODO allow other values
+ period=0, # TODO allow other values
+ ), # type: ignore[call-arg]
+ check_result=True,
+ )
+ else:
+ # Set the scanning parameters
+ scan_type = (
+ HCI_LE_Set_Scan_Parameters_Command.ACTIVE_SCANNING
+ if active
+ else HCI_LE_Set_Scan_Parameters_Command.PASSIVE_SCANNING
+ )
+ await self.send_command(
+ # pylint: disable=line-too-long
+ HCI_LE_Set_Scan_Parameters_Command(
+ le_scan_type=scan_type,
+ le_scan_interval=int(scan_window / 0.625),
+ le_scan_window=int(scan_window / 0.625),
+ own_address_type=own_address_type,
+ scanning_filter_policy=HCI_LE_Set_Scan_Parameters_Command.BASIC_UNFILTERED_POLICY,
+ ), # type: ignore[call-arg]
+ check_result=True,
+ )
+
+ # Enable scanning
+ await self.send_command(
+ HCI_LE_Set_Scan_Enable_Command(
+ le_scan_enable=1, filter_duplicates=1 if filter_duplicates else 0
+ ), # type: ignore[call-arg]
+ check_result=True,
+ )
+
+ self.scanning_is_passive = not active
self.scanning = True
- async def stop_scanning(self):
- await self.send_command(HCI_LE_Set_Scan_Enable_Command(
- le_scan_enable = 0,
- filter_duplicates = 0
- ))
+ async def stop_scanning(self) -> None:
+ # Disable scanning
+ if self.supports_le_feature(HCI_LE_EXTENDED_ADVERTISING_LE_SUPPORTED_FEATURE):
+ await self.send_command(
+ HCI_LE_Set_Extended_Scan_Enable_Command(
+ enable=0, filter_duplicates=0, duration=0, period=0
+ ), # type: ignore[call-arg]
+ check_result=True,
+ )
+ else:
+ await self.send_command(
+ HCI_LE_Set_Scan_Enable_Command(le_scan_enable=0, filter_duplicates=0), # type: ignore[call-arg]
+ check_result=True,
+ )
+
self.scanning = False
@property
@@ -680,36 +1524,37 @@ class Device(CompositeEventEmitter):
return self.scanning
@host_event_handler
- def on_advertising_report(self, address, data, rssi, advertisement_type):
- if not (accumulator := self.advertisement_data.get(address)):
- accumulator = AdvertisementDataAccumulator()
- self.advertisement_data[address] = accumulator
- accumulator.update(data, advertisement_type)
- if accumulator.flushable:
- self.emit(
- 'advertisement',
- address,
- accumulator.advertising_data,
- rssi,
- accumulator.connectable
- )
-
- async def start_discovery(self):
- await self.host.send_command(HCI_Write_Inquiry_Mode_Command(inquiry_mode=HCI_EXTENDED_INQUIRY_MODE))
+ def on_advertising_report(self, report):
+ if not (accumulator := self.advertisement_accumulators.get(report.address)):
+ accumulator = AdvertisementDataAccumulator(passive=self.scanning_is_passive)
+ self.advertisement_accumulators[report.address] = accumulator
+ if advertisement := accumulator.update(report):
+ self.emit('advertisement', advertisement)
+
+ async def start_discovery(self, auto_restart: bool = True) -> None:
+ await self.send_command(
+ HCI_Write_Inquiry_Mode_Command(inquiry_mode=HCI_EXTENDED_INQUIRY_MODE), # type: ignore[call-arg]
+ check_result=True,
+ )
- response = await self.send_command(HCI_Inquiry_Command(
- lap = HCI_GENERAL_INQUIRY_LAP,
- inquiry_length = DEVICE_DEFAULT_INQUIRY_LENGTH,
- num_responses = 0 # Unlimited number of responses.
- ))
+ response = await self.send_command(
+ HCI_Inquiry_Command(
+ lap=HCI_GENERAL_INQUIRY_LAP,
+ inquiry_length=DEVICE_DEFAULT_INQUIRY_LENGTH,
+ num_responses=0, # Unlimited number of responses.
+ ) # type: ignore[call-arg]
+ )
if response.status != HCI_Command_Status_Event.PENDING:
self.discovering = False
- raise RuntimeError(f'HCI_Inquiry command failed: {HCI_Constant.status_name(response.status)} ({response.status})')
+ raise HCI_StatusError(response)
+ self.auto_restart_inquiry = auto_restart
self.discovering = True
- async def stop_discovery(self):
- await self.send_command(HCI_Inquiry_Cancel_Command())
+ async def stop_discovery(self) -> None:
+ if self.discovering:
+ await self.send_command(HCI_Inquiry_Cancel_Command(), check_result=True) # type: ignore[call-arg]
+ self.auto_restart_inquiry = True
self.discovering = False
@host_event_handler
@@ -719,7 +1564,7 @@ class Device(CompositeEventEmitter):
address,
class_of_device,
AdvertisingData.from_bytes(data),
- rssi
+ rssi,
)
async def set_scan_enable(self, inquiry_scan_enabled, page_scan_enabled):
@@ -732,45 +1577,73 @@ class Device(CompositeEventEmitter):
else:
scan_enable = 0x00
- return await self.send_command(HCI_Write_Scan_Enable_Command(scan_enable = scan_enable))
+ return await self.send_command(
+ HCI_Write_Scan_Enable_Command(scan_enable=scan_enable)
+ )
- async def set_discoverable(self, discoverable=True):
+ async def set_discoverable(self, discoverable: bool = True) -> None:
self.discoverable = discoverable
if self.classic_enabled:
# Synthesize an inquiry response if none is set already
if self.inquiry_response is None:
self.inquiry_response = bytes(
- AdvertisingData([
- (AdvertisingData.COMPLETE_LOCAL_NAME, bytes(self.name, 'utf-8'))
- ])
+ AdvertisingData(
+ [
+ (
+ AdvertisingData.COMPLETE_LOCAL_NAME,
+ bytes(self.name, 'utf-8'),
+ )
+ ]
+ )
)
# Update the controller
- await self.host.send_command(
+ await self.send_command(
HCI_Write_Extended_Inquiry_Response_Command(
- fec_required = 0,
- extended_inquiry_response = self.inquiry_response
- )
+ fec_required=0, extended_inquiry_response=self.inquiry_response
+ ), # type: ignore[call-arg]
+ check_result=True,
)
await self.set_scan_enable(
- inquiry_scan_enabled = self.discoverable,
- page_scan_enabled = self.connectable
+ inquiry_scan_enabled=self.discoverable,
+ page_scan_enabled=self.connectable,
)
- async def set_connectable(self, connectable=True):
+ async def set_connectable(self, connectable: bool = True) -> None:
self.connectable = connectable
if self.classic_enabled:
await self.set_scan_enable(
- inquiry_scan_enabled = self.discoverable,
- page_scan_enabled = self.connectable
+ inquiry_scan_enabled=self.discoverable,
+ page_scan_enabled=self.connectable,
)
- async def connect(self, peer_address, transport=BT_LE_TRANSPORT):
+ async def connect(
+ self,
+ peer_address: Union[Address, str],
+ transport: int = BT_LE_TRANSPORT,
+ connection_parameters_preferences: Optional[
+ Dict[int, ConnectionParametersPreferences]
+ ] = None,
+ own_address_type: int = OwnAddressType.RANDOM,
+ timeout: Optional[float] = DEVICE_DEFAULT_CONNECT_TIMEOUT,
+ ) -> Connection:
'''
Request a connection to a peer.
- This method cannot be called if there is already a pending connection.
+ When transport is BLE, this method cannot be called if there is already a
+ pending connection.
+
+ connection_parameters_preferences: (BLE only, ignored for BR/EDR)
+ * None: use the 1M PHY with default parameters
+ * map: each entry has a PHY as key and a ConnectionParametersPreferences
+ object as value
+
+ own_address_type: (BLE only)
'''
+ # Check parameters
+ if transport not in (BT_LE_TRANSPORT, BT_BR_EDR_TRANSPORT):
+ raise ValueError('invalid transport')
+
# Adjust the transport automatically if we need to
if transport == BT_LE_TRANSPORT and not self.le_enabled:
transport = BT_BR_EDR_TRANSPORT
@@ -778,74 +1651,383 @@ class Device(CompositeEventEmitter):
transport = BT_LE_TRANSPORT
# Check that there isn't already a pending connection
- if self.is_connecting:
+ if transport == BT_LE_TRANSPORT and self.is_le_connecting:
raise InvalidStateError('connection already pending')
- if type(peer_address) is str:
+ if isinstance(peer_address, str):
try:
- peer_address = Address(peer_address)
+ peer_address = Address.from_string_for_transport(
+ peer_address, transport
+ )
except ValueError:
- # If the address is not parssable, assume it is a name instead
+ # If the address is not parsable, assume it is a name instead
logger.debug('looking for peer by name')
- peer_address = await self.find_peer_by_name(peer_address, transport)
+ peer_address = await self.find_peer_by_name(
+ peer_address, transport
+ ) # TODO: timeout
+ else:
+ # All BR/EDR addresses should be public addresses
+ if (
+ transport == BT_BR_EDR_TRANSPORT
+ and peer_address.address_type != Address.PUBLIC_DEVICE_ADDRESS
+ ):
+ raise ValueError('BR/EDR addresses must be PUBLIC')
+
+ assert isinstance(peer_address, Address)
+
+ def on_connection(connection):
+ if transport == BT_LE_TRANSPORT or (
+ # match BR/EDR connection event against peer address
+ connection.transport == transport
+ and connection.peer_address == peer_address
+ ):
+ pending_connection.set_result(connection)
+
+ def on_connection_failure(error):
+ if transport == BT_LE_TRANSPORT or (
+ # match BR/EDR connection failure event against peer address
+ error.transport == transport
+ and error.peer_address == peer_address
+ ):
+ pending_connection.set_exception(error)
# Create a future so that we can wait for the connection's result
pending_connection = asyncio.get_running_loop().create_future()
- self.on('connection', pending_connection.set_result)
- self.on('connection_failure', pending_connection.set_exception)
-
- # Tell the controller to connect
- if transport == BT_LE_TRANSPORT:
- # TODO: use real values, not fixed ones
- result = await self.send_command(HCI_LE_Create_Connection_Command(
- le_scan_interval = 96,
- le_scan_window = 96,
- initiator_filter_policy = 0,
- peer_address_type = peer_address.address_type,
- peer_address = peer_address,
- own_address_type = Address.RANDOM_DEVICE_ADDRESS,
- conn_interval_min = 12,
- conn_interval_max = 24,
- conn_latency = 0,
- supervision_timeout = 72,
- minimum_ce_length = 0,
- maximum_ce_length = 0
- ))
- else:
- # TODO: use real values, not fixed ones
- result = await self.send_command(HCI_Create_Connection_Command(
- bd_addr = peer_address,
- packet_type = 0xCC18, # FIXME: change
- page_scan_repetition_mode = HCI_R2_PAGE_SCAN_REPETITION_MODE,
- clock_offset = 0x0000,
- allow_role_switch = 0x01,
- reserved = 0
- ))
+ self.on('connection', on_connection)
+ self.on('connection_failure', on_connection_failure)
try:
+ # Tell the controller to connect
+ if transport == BT_LE_TRANSPORT:
+ if connection_parameters_preferences is None:
+ if connection_parameters_preferences is None:
+ connection_parameters_preferences = {
+ HCI_LE_1M_PHY: ConnectionParametersPreferences.default
+ }
+
+ self.connect_own_address_type = own_address_type
+
+ if self.host.supports_command(
+ HCI_LE_EXTENDED_CREATE_CONNECTION_COMMAND
+ ):
+ # Only keep supported PHYs
+ phys = sorted(
+ list(
+ set(
+ filter(
+ self.supports_le_phy,
+ connection_parameters_preferences.keys(),
+ )
+ )
+ )
+ )
+ if not phys:
+ raise ValueError('at least one supported PHY needed')
+
+ phy_count = len(phys)
+ initiating_phys = phy_list_to_bits(phys)
+
+ connection_interval_mins = [
+ int(
+ connection_parameters_preferences[
+ phy
+ ].connection_interval_min
+ / 1.25
+ )
+ for phy in phys
+ ]
+ connection_interval_maxs = [
+ int(
+ connection_parameters_preferences[
+ phy
+ ].connection_interval_max
+ / 1.25
+ )
+ for phy in phys
+ ]
+ max_latencies = [
+ connection_parameters_preferences[phy].max_latency
+ for phy in phys
+ ]
+ supervision_timeouts = [
+ int(
+ connection_parameters_preferences[phy].supervision_timeout
+ / 10
+ )
+ for phy in phys
+ ]
+ min_ce_lengths = [
+ int(
+ connection_parameters_preferences[phy].min_ce_length / 0.625
+ )
+ for phy in phys
+ ]
+ max_ce_lengths = [
+ int(
+ connection_parameters_preferences[phy].max_ce_length / 0.625
+ )
+ for phy in phys
+ ]
+
+ result = await self.send_command(
+ HCI_LE_Extended_Create_Connection_Command(
+ initiator_filter_policy=0,
+ own_address_type=own_address_type,
+ peer_address_type=peer_address.address_type,
+ peer_address=peer_address,
+ initiating_phys=initiating_phys,
+ scan_intervals=(
+ int(DEVICE_DEFAULT_CONNECT_SCAN_INTERVAL / 0.625),
+ )
+ * phy_count,
+ scan_windows=(
+ int(DEVICE_DEFAULT_CONNECT_SCAN_WINDOW / 0.625),
+ )
+ * phy_count,
+ connection_interval_mins=connection_interval_mins,
+ connection_interval_maxs=connection_interval_maxs,
+ max_latencies=max_latencies,
+ supervision_timeouts=supervision_timeouts,
+ min_ce_lengths=min_ce_lengths,
+ max_ce_lengths=max_ce_lengths,
+ ) # type: ignore[call-arg]
+ )
+ else:
+ if HCI_LE_1M_PHY not in connection_parameters_preferences:
+ raise ValueError('1M PHY preferences required')
+
+ prefs = connection_parameters_preferences[HCI_LE_1M_PHY]
+ result = await self.send_command(
+ HCI_LE_Create_Connection_Command(
+ le_scan_interval=int(
+ DEVICE_DEFAULT_CONNECT_SCAN_INTERVAL / 0.625
+ ),
+ le_scan_window=int(
+ DEVICE_DEFAULT_CONNECT_SCAN_WINDOW / 0.625
+ ),
+ initiator_filter_policy=0,
+ peer_address_type=peer_address.address_type,
+ peer_address=peer_address,
+ own_address_type=own_address_type,
+ connection_interval_min=int(
+ prefs.connection_interval_min / 1.25
+ ),
+ connection_interval_max=int(
+ prefs.connection_interval_max / 1.25
+ ),
+ max_latency=prefs.max_latency,
+ supervision_timeout=int(prefs.supervision_timeout / 10),
+ min_ce_length=int(prefs.min_ce_length / 0.625),
+ max_ce_length=int(prefs.max_ce_length / 0.625),
+ ) # type: ignore[call-arg]
+ )
+ else:
+ # Save pending connection
+ self.pending_connections[peer_address] = Connection.incomplete(
+ self, peer_address, BT_CENTRAL_ROLE
+ )
+
+ # TODO: allow passing other settings
+ result = await self.send_command(
+ HCI_Create_Connection_Command(
+ bd_addr=peer_address,
+ packet_type=0xCC18, # FIXME: change
+ page_scan_repetition_mode=HCI_R2_PAGE_SCAN_REPETITION_MODE,
+ clock_offset=0x0000,
+ allow_role_switch=0x01,
+ reserved=0,
+ ) # type: ignore[call-arg]
+ )
+
if result.status != HCI_Command_Status_Event.PENDING:
- raise RuntimeError(f'HCI_LE_Create_Connection_Command failed: {HCI_Constant.status_name(result.status)} ({result.status})')
+ raise HCI_StatusError(result)
# Wait for the connection process to complete
- self.connecting = True
- return await pending_connection
+ if transport == BT_LE_TRANSPORT:
+ self.le_connecting = True
+
+ if timeout is None:
+ return await self.abort_on('flush', pending_connection)
+
+ try:
+ return await asyncio.wait_for(
+ asyncio.shield(pending_connection), timeout
+ )
+ except asyncio.TimeoutError:
+ if transport == BT_LE_TRANSPORT:
+ await self.send_command(HCI_LE_Create_Connection_Cancel_Command()) # type: ignore[call-arg]
+ else:
+ await self.send_command(
+ HCI_Create_Connection_Cancel_Command(bd_addr=peer_address) # type: ignore[call-arg]
+ )
+
+ try:
+ return await self.abort_on('flush', pending_connection)
+ except core.ConnectionError as error:
+ raise core.TimeoutError() from error
finally:
- self.remove_listener('connection', pending_connection.set_result)
- self.remove_listener('connection_failure', pending_connection.set_exception)
- self.connecting = False
+ self.remove_listener('connection', on_connection)
+ self.remove_listener('connection_failure', on_connection_failure)
+ if transport == BT_LE_TRANSPORT:
+ self.le_connecting = False
+ self.connect_own_address_type = None
+ else:
+ self.pending_connections.pop(peer_address, None)
+
+ async def accept(
+ self,
+ peer_address: Union[Address, str] = Address.ANY,
+ role: int = BT_PERIPHERAL_ROLE,
+ timeout: Optional[float] = DEVICE_DEFAULT_CONNECT_TIMEOUT,
+ ) -> Connection:
+ '''
+ Wait and accept any incoming connection or a connection from `peer_address` when
+ set.
+
+ Notes:
+ * A `connect` to the same peer will not complete this call.
+ * The `timeout` parameter is only handled while waiting for the connection
+ request, once received and accepted, the controller shall issue a connection
+ complete event.
+ '''
+
+ if isinstance(peer_address, str):
+ try:
+ peer_address = Address(peer_address)
+ except ValueError:
+ # If the address is not parsable, assume it is a name instead
+ logger.debug('looking for peer by name')
+ peer_address = await self.find_peer_by_name(
+ peer_address, BT_BR_EDR_TRANSPORT
+ ) # TODO: timeout
+
+ assert isinstance(peer_address, Address)
+
+ if peer_address == Address.NIL:
+ raise ValueError('accept on nil address')
+
+ # Create a future so that we can wait for the request
+ pending_request_fut = asyncio.get_running_loop().create_future()
+
+ if peer_address == Address.ANY:
+ self.classic_pending_accepts[Address.ANY].append(pending_request_fut)
+ elif peer_address in self.classic_pending_accepts:
+ raise InvalidStateError('accept connection already pending')
+ else:
+ self.classic_pending_accepts[peer_address] = [pending_request_fut]
+
+ try:
+ # Wait for a request or a completed connection
+ pending_request = self.abort_on('flush', pending_request_fut)
+ result = await (
+ asyncio.wait_for(pending_request, timeout)
+ if timeout
+ else pending_request
+ )
+ except Exception:
+ # Remove future from device context
+ if peer_address == Address.ANY:
+ self.classic_pending_accepts[Address.ANY].remove(pending_request_fut)
+ else:
+ self.classic_pending_accepts.pop(peer_address)
+ raise
+
+ # Result may already be a completed connection,
+ # see `on_connection` for details
+ if isinstance(result, Connection):
+ return result
+
+ # Otherwise, result came from `on_connection_request`
+ peer_address, _class_of_device, _link_type = result
+ assert isinstance(peer_address, Address)
+
+ # Create a future so that we can wait for the connection's result
+ pending_connection = asyncio.get_running_loop().create_future()
+
+ def on_connection(connection):
+ if (
+ connection.transport == BT_BR_EDR_TRANSPORT
+ and connection.peer_address == peer_address
+ ):
+ pending_connection.set_result(connection)
+
+ def on_connection_failure(error):
+ if (
+ error.transport == BT_BR_EDR_TRANSPORT
+ and error.peer_address == peer_address
+ ):
+ pending_connection.set_exception(error)
+
+ self.on('connection', on_connection)
+ self.on('connection_failure', on_connection_failure)
+
+ # Save pending connection, with the Peripheral role.
+ # Even if we requested a role switch in the HCI_Accept_Connection_Request
+ # command, this connection is still considered Peripheral until an eventual
+ # role change event.
+ self.pending_connections[peer_address] = Connection.incomplete(
+ self, peer_address, BT_PERIPHERAL_ROLE
+ )
+
+ try:
+ # Accept connection request
+ await self.send_command(
+ HCI_Accept_Connection_Request_Command(bd_addr=peer_address, role=role) # type: ignore[call-arg]
+ )
+
+ # Wait for connection complete
+ return await self.abort_on('flush', pending_connection)
+
+ finally:
+ self.remove_listener('connection', on_connection)
+ self.remove_listener('connection_failure', on_connection_failure)
+ self.pending_connections.pop(peer_address, None)
+
+ @asynccontextmanager
+ async def connect_as_gatt(self, peer_address):
+ async with AsyncExitStack() as stack:
+ connection = await stack.enter_async_context(
+ await self.connect(peer_address)
+ )
+ peer = await stack.enter_async_context(Peer(connection))
+
+ yield peer
@property
- def is_connecting(self):
- return self.connecting
+ def is_le_connecting(self):
+ return self.le_connecting
@property
def is_disconnecting(self):
return self.disconnecting
- async def cancel_connection(self):
- if not self.is_connecting:
- return
- await self.send_command(HCI_LE_Create_Connection_Cancel_Command())
+ async def cancel_connection(self, peer_address=None):
+ # Low-energy: cancel ongoing connection
+ if peer_address is None:
+ if not self.is_le_connecting:
+ return
+ await self.send_command(
+ HCI_LE_Create_Connection_Cancel_Command(), check_result=True
+ )
+
+ # BR/EDR: try to cancel to ongoing connection
+ # NOTE: This API does not prevent from trying to cancel a connection which is
+ # not currently being created
+ else:
+ if isinstance(peer_address, str):
+ try:
+ peer_address = Address(peer_address)
+ except ValueError:
+ # If the address is not parsable, assume it is a name instead
+ logger.debug('looking for peer by name')
+ peer_address = await self.find_peer_by_name(
+ peer_address, BT_BR_EDR_TRANSPORT
+ ) # TODO: timeout
+
+ await self.send_command(
+ HCI_Create_Connection_Cancel_Command(bd_addr=peer_address),
+ check_result=True,
+ )
async def disconnect(self, connection, reason):
# Create a future so that we can wait for the disconnection's result
@@ -854,43 +2036,108 @@ class Device(CompositeEventEmitter):
connection.on('disconnection_failure', pending_disconnection.set_exception)
# Request a disconnection
- result = await self.send_command(HCI_Disconnect_Command(connection_handle = connection.handle, reason = reason))
+ result = await self.send_command(
+ HCI_Disconnect_Command(connection_handle=connection.handle, reason=reason)
+ )
try:
if result.status != HCI_Command_Status_Event.PENDING:
- raise RuntimeError(f'HCI_Disconnect_Command failed: {HCI_Constant.status_name(result.status)} ({result.status})')
+ raise HCI_StatusError(result)
# Wait for the disconnection process to complete
self.disconnecting = True
- return await pending_disconnection
+ return await self.abort_on('flush', pending_disconnection)
finally:
- connection.remove_listener('disconnection', pending_disconnection.set_result)
- connection.remove_listener('disconnection_failure', pending_disconnection.set_exception)
+ connection.remove_listener(
+ 'disconnection', pending_disconnection.set_result
+ )
+ connection.remove_listener(
+ 'disconnection_failure', pending_disconnection.set_exception
+ )
self.disconnecting = False
async def update_connection_parameters(
self,
connection,
- conn_interval_min,
- conn_interval_max,
- conn_latency,
+ connection_interval_min,
+ connection_interval_max,
+ max_latency,
supervision_timeout,
- minimum_ce_length = 0,
- maximum_ce_length = 0
+ min_ce_length=0,
+ max_ce_length=0,
):
'''
- NOTE: the name of the parameters may look odd, but it just follows the names used in the Bluetooth spec.
+ NOTE: the name of the parameters may look odd, but it just follows the names
+ used in the Bluetooth spec.
'''
- await self.send_command(HCI_LE_Connection_Update_Command(
- connection_handle = connection.handle,
- conn_interval_min = conn_interval_min,
- conn_interval_max = conn_interval_max,
- conn_latency = conn_latency,
- supervision_timeout = supervision_timeout,
- minimum_ce_length = minimum_ce_length,
- maximum_ce_length = maximum_ce_length
- ))
- # TODO: check result
+ result = await self.send_command(
+ HCI_LE_Connection_Update_Command(
+ connection_handle=connection.handle,
+ connection_interval_min=connection_interval_min,
+ connection_interval_max=connection_interval_max,
+ max_latency=max_latency,
+ supervision_timeout=supervision_timeout,
+ min_ce_length=min_ce_length,
+ max_ce_length=max_ce_length,
+ )
+ )
+ if result.status != HCI_Command_Status_Event.PENDING:
+ raise HCI_StatusError(result)
+
+ async def get_connection_rssi(self, connection):
+ result = await self.send_command(
+ HCI_Read_RSSI_Command(handle=connection.handle), check_result=True
+ )
+ return result.return_parameters.rssi
+
+ async def get_connection_phy(self, connection):
+ result = await self.send_command(
+ HCI_LE_Read_PHY_Command(connection_handle=connection.handle),
+ check_result=True,
+ )
+ return (result.return_parameters.tx_phy, result.return_parameters.rx_phy)
+
+ async def set_connection_phy(
+ self, connection, tx_phys=None, rx_phys=None, phy_options=None
+ ):
+ if not self.host.supports_command(HCI_LE_SET_PHY_COMMAND):
+ logger.warning('ignoring request, command not supported')
+ return
+
+ all_phys_bits = (1 if tx_phys is None else 0) | (
+ (1 if rx_phys is None else 0) << 1
+ )
+
+ result = await self.send_command(
+ HCI_LE_Set_PHY_Command(
+ connection_handle=connection.handle,
+ all_phys=all_phys_bits,
+ tx_phys=phy_list_to_bits(tx_phys),
+ rx_phys=phy_list_to_bits(rx_phys),
+ phy_options=0 if phy_options is None else int(phy_options),
+ )
+ )
+
+ if result.status != HCI_COMMAND_STATUS_PENDING:
+ logger.warning(
+ 'HCI_LE_Set_PHY_Command failed: '
+ f'{HCI_Constant.error_name(result.status)}'
+ )
+ raise HCI_StatusError(result)
+
+ async def set_default_phy(self, tx_phys=None, rx_phys=None):
+ all_phys_bits = (1 if tx_phys is None else 0) | (
+ (1 if rx_phys is None else 0) << 1
+ )
+
+ return await self.send_command(
+ HCI_LE_Set_Default_PHY_Command(
+ all_phys=all_phys_bits,
+ tx_phys=phy_list_to_bits(tx_phys),
+ rx_phys=phy_list_to_bits(rx_phys),
+ ),
+ check_result=True,
+ )
async def find_peer_by_name(self, name, transport=BT_LE_TRANSPORT):
"""
@@ -902,23 +2149,26 @@ class Device(CompositeEventEmitter):
# Scan/inquire with event handlers to handle scan/inquiry results
def on_peer_found(address, ad_data):
- local_name = ad_data.get(AdvertisingData.COMPLETE_LOCAL_NAME)
+ local_name = ad_data.get(AdvertisingData.COMPLETE_LOCAL_NAME, raw=True)
if local_name is None:
- local_name = ad_data.get(AdvertisingData.SHORTENED_LOCAL_NAME)
+ local_name = ad_data.get(AdvertisingData.SHORTENED_LOCAL_NAME, raw=True)
if local_name is not None:
if local_name.decode('utf-8') == name:
peer_address.set_result(address)
+
+ handler = None
+ was_scanning = self.scanning
+ was_discovering = self.discovering
try:
- handler = None
if transport == BT_LE_TRANSPORT:
event_name = 'advertisement'
handler = self.on(
event_name,
- lambda address, ad_data, rssi, connectable:
- on_peer_found(address, ad_data)
+ lambda advertisement: on_peer_found(
+ advertisement.address, advertisement.data
+ ),
)
- was_scanning = self.scanning
if not self.scanning:
await self.start_scanning(filter_duplicates=True)
@@ -926,17 +2176,17 @@ class Device(CompositeEventEmitter):
event_name = 'inquiry_result'
handler = self.on(
event_name,
- lambda address, class_of_device, eir_data, rssi:
- on_peer_found(address, eir_data)
+ lambda address, class_of_device, eir_data, rssi: on_peer_found(
+ address, eir_data
+ ),
)
- was_discovering = self.discovering
if not self.discovering:
await self.start_discovery()
else:
return None
- return await peer_address
+ return await self.abort_on('flush', peer_address)
finally:
if handler is not None:
self.remove_listener(event_name, handler)
@@ -947,13 +2197,23 @@ class Device(CompositeEventEmitter):
await self.stop_discovery()
@property
- def pairing_config_factory(self):
+ def pairing_config_factory(self) -> Callable[[Connection], PairingConfig]:
return self.smp_manager.pairing_config_factory
@pairing_config_factory.setter
- def pairing_config_factory(self, pairing_config_factory):
+ def pairing_config_factory(
+ self, pairing_config_factory: Callable[[Connection], PairingConfig]
+ ) -> None:
self.smp_manager.pairing_config_factory = pairing_config_factory
+ @property
+ def smp_session_proxy(self) -> Type[smp.Session]:
+ return self.smp_manager.session_proxy
+
+ @smp_session_proxy.setter
+ def smp_session_proxy(self, session_proxy: Type[smp.Session]) -> None:
+ self.smp_manager.session_proxy = session_proxy
+
async def pair(self, connection):
return await self.smp_manager.pair(connection)
@@ -976,18 +2236,25 @@ class Device(CompositeEventEmitter):
logger.debug('found keys in the key store')
if keys.ltk:
return keys.ltk.value
- elif connection.role == BT_CENTRAL_ROLE and keys.ltk_central:
+
+ if connection.role == BT_CENTRAL_ROLE and keys.ltk_central:
return keys.ltk_central.value
- elif connection.role == BT_PERIPHERAL_ROLE and keys.ltk_peripheral:
+
+ if connection.role == BT_PERIPHERAL_ROLE and keys.ltk_peripheral:
return keys.ltk_peripheral.value
- async def get_link_key(self, address):
+ async def get_link_key(self, address: Address) -> Optional[bytes]:
# Look for the key in the keystore
if self.keystore is not None:
keys = await self.keystore.get(str(address))
if keys is not None:
logger.debug('found keys in the key store')
+ if keys.link_key is None:
+ logger.warning('no link key')
+ return None
+
return keys.link_key.value
+ return None
# [Classic only]
async def authenticate(self, connection):
@@ -1001,24 +2268,34 @@ class Device(CompositeEventEmitter):
pending_authentication.set_exception(HCI_Error(error_code))
connection.on('connection_authentication', on_authentication)
- connection.on('connection_authentication_failure', on_authentication_failure)
+ connection.on('connection_authentication_failure', on_authentication_failure)
# Request the authentication
try:
result = await self.send_command(
- HCI_Authentication_Requested_Command(connection_handle = connection.handle)
+ HCI_Authentication_Requested_Command(
+ connection_handle=connection.handle
+ )
)
if result.status != HCI_COMMAND_STATUS_PENDING:
- logger.warn(f'HCI_Authentication_Requested_Command failed: {HCI_Constant.error_name(result.status)}')
- raise HCI_Error(result.status)
+ logger.warning(
+ 'HCI_Authentication_Requested_Command failed: '
+ f'{HCI_Constant.error_name(result.status)}'
+ )
+ raise HCI_StatusError(result)
# Wait for the authentication to complete
- await pending_authentication
+ await connection.abort_on('disconnection', pending_authentication)
finally:
connection.remove_listener('connection_authentication', on_authentication)
- connection.remove_listener('connection_authentication_failure', on_authentication_failure)
+ connection.remove_listener(
+ 'connection_authentication_failure', on_authentication_failure
+ )
+
+ async def encrypt(self, connection, enable=True):
+ if not enable and connection.transport == BT_LE_TRANSPORT:
+ raise ValueError('`enable` parameter is classic only.')
- async def encrypt(self, connection):
# Set up event handlers
pending_encryption = asyncio.get_running_loop().create_future()
@@ -1028,7 +2305,7 @@ class Device(CompositeEventEmitter):
def on_encryption_failure(error_code):
pending_encryption.set_exception(HCI_Error(error_code))
- connection.on('connection_encryption_change', on_encryption_change)
+ connection.on('connection_encryption_change', on_encryption_change)
connection.on('connection_encryption_failure', on_encryption_failure)
# Request the encryption
@@ -1043,11 +2320,11 @@ class Device(CompositeEventEmitter):
raise RuntimeError('keys not found in key store')
if keys.ltk is not None:
- ltk = keys.ltk.value
+ ltk = keys.ltk.value
rand = bytes(8)
ediv = 0
elif keys.ltk_central is not None:
- ltk = keys.ltk_central.value
+ ltk = keys.ltk_central.value
rand = keys.ltk_central.rand
ediv = keys.ltk_central.ediv
else:
@@ -1057,84 +2334,151 @@ class Device(CompositeEventEmitter):
raise InvalidStateError('only centrals can start encryption')
result = await self.send_command(
- HCI_LE_Start_Encryption_Command(
- connection_handle = connection.handle,
- random_number = rand,
- encrypted_diversifier = ediv,
- long_term_key = ltk
+ HCI_LE_Enable_Encryption_Command(
+ connection_handle=connection.handle,
+ random_number=rand,
+ encrypted_diversifier=ediv,
+ long_term_key=ltk,
)
)
if result.status != HCI_COMMAND_STATUS_PENDING:
- logger.warn(f'HCI_LE_Start_Encryption_Command failed: {HCI_Constant.error_name(result.status)}')
- raise HCI_Error(result.status)
+ logger.warning(
+ 'HCI_LE_Enable_Encryption_Command failed: '
+ f'{HCI_Constant.error_name(result.status)}'
+ )
+ raise HCI_StatusError(result)
else:
result = await self.send_command(
HCI_Set_Connection_Encryption_Command(
- connection_handle = connection.handle,
- encryption_enable = 0x01
+ connection_handle=connection.handle,
+ encryption_enable=0x01 if enable else 0x00,
)
)
if result.status != HCI_COMMAND_STATUS_PENDING:
- logger.warn(f'HCI_Set_Connection_Encryption_Command failed: {HCI_Constant.error_name(result.status)}')
- raise HCI_Error(result.status)
+ logger.warning(
+ 'HCI_Set_Connection_Encryption_Command failed: '
+ f'{HCI_Constant.error_name(result.status)}'
+ )
+ raise HCI_StatusError(result)
# Wait for the result
- await pending_encryption
+ await connection.abort_on('disconnection', pending_encryption)
+ finally:
+ connection.remove_listener(
+ 'connection_encryption_change', on_encryption_change
+ )
+ connection.remove_listener(
+ 'connection_encryption_failure', on_encryption_failure
+ )
+
+ # [Classic only]
+ async def switch_role(self, connection: Connection, role: int):
+ pending_role_change = asyncio.get_running_loop().create_future()
+
+ def on_role_change(new_role):
+ pending_role_change.set_result(new_role)
+
+ def on_role_change_failure(error_code):
+ pending_role_change.set_exception(HCI_Error(error_code))
+
+ connection.on('role_change', on_role_change)
+ connection.on('role_change_failure', on_role_change_failure)
+
+ try:
+ result = await self.send_command(
+ HCI_Switch_Role_Command(bd_addr=connection.peer_address, role=role) # type: ignore[call-arg]
+ )
+ if result.status != HCI_COMMAND_STATUS_PENDING:
+ logger.warning(
+ 'HCI_Switch_Role_Command failed: '
+ f'{HCI_Constant.error_name(result.status)}'
+ )
+ raise HCI_StatusError(result)
+ await connection.abort_on('disconnection', pending_role_change)
finally:
- connection.remove_listener('connection_encryption_change', on_encryption_change)
- connection.remove_listener('connection_encryption_failure', on_encryption_failure)
+ connection.remove_listener('role_change', on_role_change)
+ connection.remove_listener('role_change_failure', on_role_change_failure)
# [Classic only]
- async def request_remote_name(self, connection):
+ async def request_remote_name(self, remote: Union[Address, Connection]) -> str:
# Set up event handlers
pending_name = asyncio.get_running_loop().create_future()
- def on_remote_name():
- pending_name.set_result(connection.peer_name)
-
- def on_remote_name_failure(error_code):
- pending_name.set_exception(HCI_Error(error_code))
+ peer_address = remote if isinstance(remote, Address) else remote.peer_address
- connection.on('remote_name', on_remote_name)
- connection.on('remote_name_failure', on_remote_name_failure)
+ handler = self.on(
+ 'remote_name',
+ lambda address, remote_name: pending_name.set_result(remote_name)
+ if address == peer_address
+ else None,
+ )
+ failure_handler = self.on(
+ 'remote_name_failure',
+ lambda address, error_code: pending_name.set_exception(
+ HCI_Error(error_code)
+ )
+ if address == peer_address
+ else None,
+ )
try:
result = await self.send_command(
HCI_Remote_Name_Request_Command(
- bd_addr = connection.peer_address,
- page_scan_repetition_mode = HCI_Remote_Name_Request_Command.R0, # TODO investigate other options
- reserved = 0,
- clock_offset = 0 # TODO investigate non-0 values
- )
+ bd_addr=peer_address,
+ page_scan_repetition_mode=HCI_Remote_Name_Request_Command.R2,
+ reserved=0,
+ clock_offset=0, # TODO investigate non-0 values
+ ) # type: ignore[call-arg]
)
if result.status != HCI_COMMAND_STATUS_PENDING:
- logger.warn(f'HCI_Set_Connection_Encryption_Command failed: {HCI_Constant.error_name(result.status)}')
- raise HCI_Error(result.status)
+ logger.warning(
+ 'HCI_Set_Connection_Encryption_Command failed: '
+ f'{HCI_Constant.error_name(result.status)}'
+ )
+ raise HCI_StatusError(result)
# Wait for the result
- return await pending_name
+ return await self.abort_on('flush', pending_name)
finally:
- connection.remove_listener('remote_name', on_remote_name)
- connection.remove_listener('remote_name_failure', on_remote_name_failure)
+ self.remove_listener('remote_name', handler)
+ self.remove_listener('remote_name_failure', failure_handler)
+
+ @host_event_handler
+ def on_flush(self):
+ self.emit('flush')
+ for _, connection in self.connections.items():
+ connection.emit('disconnection', 0)
+ self.connections = {}
# [Classic only]
@host_event_handler
def on_link_key(self, bd_addr, link_key, key_type):
# Store the keys in the key store
if self.keystore:
- pairing_keys = keys.PairingKeys()
- pairing_keys.link_key = keys.PairingKeys.Key(value = link_key)
+ authenticated = key_type in (
+ HCI_AUTHENTICATED_COMBINATION_KEY_GENERATED_FROM_P_192_TYPE,
+ HCI_AUTHENTICATED_COMBINATION_KEY_GENERATED_FROM_P_256_TYPE,
+ )
+ pairing_keys = PairingKeys()
+ pairing_keys.link_key = PairingKeys.Key(
+ value=link_key, authenticated=authenticated
+ )
async def store_keys():
try:
await self.keystore.update(str(bd_addr), pairing_keys)
except Exception as error:
- logger.warn(f'!!! error while storing keys: {error}')
+ logger.warning(f'!!! error while storing keys: {error}')
+
+ self.abort_on('flush', store_keys())
- asyncio.create_task(store_keys())
+ if connection := self.find_connection_by_bd_addr(
+ bd_addr, transport=BT_BR_EDR_TRANSPORT
+ ):
+ connection.link_key_type = key_type
def add_service(self, service):
self.gatt_server.add_service(service)
@@ -1142,65 +2486,184 @@ class Device(CompositeEventEmitter):
def add_services(self, services):
self.gatt_server.add_services(services)
- async def notify_subscriber(self, connection, attribute, force=False):
- await self.gatt_server.notify_subscriber(connection, attribute, force)
+ def add_default_services(self, generic_access_service=True):
+ # Add a GAP Service if requested
+ if generic_access_service:
+ self.gatt_server.add_service(GenericAccessService(self.name))
+
+ async def notify_subscriber(self, connection, attribute, value=None, force=False):
+ await self.gatt_server.notify_subscriber(connection, attribute, value, force)
- async def notify_subscribers(self, attribute, force=False):
- await self.gatt_server.notify_subscribers(attribute, force)
+ async def notify_subscribers(self, attribute, value=None, force=False):
+ await self.gatt_server.notify_subscribers(attribute, value, force)
- async def indicate_subscriber(self, connection, attribute, force=False):
- await self.gatt_server.indicate_subscriber(connection, attribute, force)
+ async def indicate_subscriber(self, connection, attribute, value=None, force=False):
+ await self.gatt_server.indicate_subscriber(connection, attribute, value, force)
- async def indicate_subscribers(self, attribute):
- await self.gatt_server.indicate_subscribers(attribute)
+ async def indicate_subscribers(self, attribute, value=None, force=False):
+ await self.gatt_server.indicate_subscribers(attribute, value, force)
@host_event_handler
- def on_connection(self, connection_handle, transport, peer_address, peer_resolvable_address, role, connection_parameters):
- logger.debug(f'*** Connection: [0x{connection_handle:04X}] {peer_address} as {HCI_Constant.role_name(role)}')
- if connection_handle in self.connections:
- logger.warn('new connection reuses the same handle as a previous connection')
-
- # Resolve the peer address if we can
- if self.address_resolver:
- if peer_address.is_resolvable:
- resolved_address = self.address_resolver.resolve(peer_address)
- if resolved_address is not None:
- logger.debug(f'*** Address resolved as {resolved_address}')
- peer_resolvable_address = peer_address
- peer_address = resolved_address
-
- # Create a new connection
- connection = Connection(
- self,
- connection_handle,
- transport,
- peer_address,
- peer_resolvable_address,
- role,
- connection_parameters
+ def on_connection(
+ self,
+ connection_handle,
+ transport,
+ peer_address,
+ role,
+ connection_parameters,
+ ):
+ logger.debug(
+ f'*** Connection: [0x{connection_handle:04X}] '
+ f'{peer_address} {"" if role is None else HCI_Constant.role_name(role)}'
)
- self.connections[connection_handle] = connection
+ if connection_handle in self.connections:
+ logger.warning(
+ 'new connection reuses the same handle as a previous connection'
+ )
- # We are no longer advertising
- self.advertising = False
+ peer_resolvable_address = None
+
+ if transport == BT_BR_EDR_TRANSPORT:
+ # Create a new connection
+ connection = self.pending_connections.pop(peer_address)
+ connection.complete(connection_handle, connection_parameters)
+ self.connections[connection_handle] = connection
+
+ # Emit an event to notify listeners of the new connection
+ self.emit('connection', connection)
+ else:
+ # Resolve the peer address if we can
+ if self.address_resolver:
+ if peer_address.is_resolvable:
+ resolved_address = self.address_resolver.resolve(peer_address)
+ if resolved_address is not None:
+ logger.debug(f'*** Address resolved as {resolved_address}')
+ peer_resolvable_address = peer_address
+ peer_address = resolved_address
+
+ # Guess which own address type is used for this connection.
+ # This logic is somewhat correct but may need to be improved
+ # when multiple advertising are run simultaneously.
+ if self.connect_own_address_type is not None:
+ own_address_type = self.connect_own_address_type
+ else:
+ own_address_type = self.advertising_own_address_type
+
+ # We are no longer advertising
+ self.advertising_own_address_type = None
+ self.advertising = False
+
+ if own_address_type in (
+ OwnAddressType.PUBLIC,
+ OwnAddressType.RESOLVABLE_OR_PUBLIC,
+ ):
+ self_address = self.public_address
+ else:
+ self_address = self.random_address
+
+ # Create a new connection
+ connection = Connection(
+ self,
+ connection_handle,
+ transport,
+ self_address,
+ peer_address,
+ peer_resolvable_address,
+ role,
+ connection_parameters,
+ ConnectionPHY(HCI_LE_1M_PHY, HCI_LE_1M_PHY),
+ )
+ self.connections[connection_handle] = connection
- # Emit an event to notify listeners of the new connection
- self.emit('connection', connection)
+ # If supported, read which PHY we're connected with before
+ # notifying listeners of the new connection.
+ if self.host.supports_command(HCI_LE_READ_PHY_COMMAND):
+
+ async def read_phy():
+ result = await self.send_command(
+ HCI_LE_Read_PHY_Command(connection_handle=connection_handle),
+ check_result=True,
+ )
+ connection.phy = ConnectionPHY(
+ result.return_parameters.tx_phy, result.return_parameters.rx_phy
+ )
+ # Emit an event to notify listeners of the new connection
+ self.emit('connection', connection)
+
+ # Do so asynchronously to not block the current event handler
+ connection.abort_on('disconnection', read_phy())
+
+ else:
+ # Emit an event to notify listeners of the new connection
+ self.emit('connection', connection)
@host_event_handler
- def on_connection_failure(self, error_code):
- logger.debug(f'*** Connection failed: {error_code}')
- error = ConnectionError(
+ def on_connection_failure(self, transport, peer_address, error_code):
+ logger.debug(f'*** Connection failed: {HCI_Constant.error_name(error_code)}')
+
+ # For directed advertising, this means a timeout
+ if (
+ transport == BT_LE_TRANSPORT
+ and self.advertising
+ and self.advertising_type.is_directed
+ ):
+ self.advertising_own_address_type = None
+ self.advertising = False
+
+ # Notify listeners
+ error = core.ConnectionError(
error_code,
+ transport,
+ peer_address,
'hci',
- HCI_Constant.error_name(error_code)
+ HCI_Constant.error_name(error_code),
)
self.emit('connection_failure', error)
+ # FIXME: Explore a delegate-model for BR/EDR wait connection #56.
+ @host_event_handler
+ def on_connection_request(self, bd_addr, class_of_device, link_type):
+ logger.debug(f'*** Connection request: {bd_addr}')
+
+ # match a pending future using `bd_addr`
+ if bd_addr in self.classic_pending_accepts:
+ future, *_ = self.classic_pending_accepts.pop(bd_addr)
+ future.set_result((bd_addr, class_of_device, link_type))
+
+ # match first pending future for ANY address
+ elif len(self.classic_pending_accepts[Address.ANY]) > 0:
+ future = self.classic_pending_accepts[Address.ANY].pop(0)
+ future.set_result((bd_addr, class_of_device, link_type))
+
+ # device configuration is set to accept any incoming connection
+ elif self.classic_accept_any:
+ # Save pending connection
+ self.pending_connections[bd_addr] = Connection.incomplete(
+ self, bd_addr, BT_PERIPHERAL_ROLE
+ )
+
+ self.host.send_command_sync(
+ HCI_Accept_Connection_Request_Command(
+ bd_addr=bd_addr, role=0x01 # Remain the peripheral
+ )
+ )
+
+ # reject incoming connection
+ else:
+ self.host.send_command_sync(
+ HCI_Reject_Connection_Request_Command(
+ bd_addr=bd_addr,
+ reason=HCI_CONNECTION_REJECTED_DUE_TO_LIMITED_RESOURCES_ERROR,
+ )
+ )
+
@host_event_handler
@with_connection_from_handle
def on_disconnection(self, connection, reason):
- logger.debug(f'*** Disconnection: [0x{connection.handle:04X}] {connection.peer_address} as {connection.role_name}, reason={reason}')
+ logger.debug(
+ f'*** Disconnection: [0x{connection.handle:04X}] '
+ f'{connection.peer_address} as {connection.role_name}, reason={reason}'
+ )
connection.emit('disconnection', reason)
# Remove the connection from the map
@@ -1212,39 +2675,70 @@ class Device(CompositeEventEmitter):
# Restart advertising if auto-restart is enabled
if self.auto_restart_advertising:
logger.debug('restarting advertising')
- asyncio.create_task(self.start_advertising(auto_restart=self.auto_restart_advertising))
+ self.abort_on(
+ 'flush',
+ self.start_advertising(
+ advertising_type=self.advertising_type, auto_restart=True
+ ),
+ )
@host_event_handler
@with_connection_from_handle
def on_disconnection_failure(self, connection, error_code):
logger.debug(f'*** Disconnection failed: {error_code}')
- error = ConnectionError(
+ error = core.ConnectionError(
error_code,
+ connection.transport,
+ connection.peer_address,
'hci',
- HCI_Constant.error_name(error_code)
+ HCI_Constant.error_name(error_code),
)
connection.emit('disconnection_failure', error)
@host_event_handler
@AsyncRunner.run_in_task()
async def on_inquiry_complete(self):
- if self.discovering:
+ if self.auto_restart_inquiry:
# Inquire again
- await self.start_discovery()
+ await self.start_discovery(auto_restart=True)
+ else:
+ self.auto_restart_inquiry = True
+ self.discovering = False
+ self.emit('inquiry_complete')
@host_event_handler
@with_connection_from_handle
def on_connection_authentication(self, connection):
- logger.debug(f'*** Connection Authentication: [0x{connection.handle:04X}] {connection.peer_address} as {connection.role_name}')
+ logger.debug(
+ f'*** Connection Authentication: [0x{connection.handle:04X}] '
+ f'{connection.peer_address} as {connection.role_name}'
+ )
connection.authenticated = True
connection.emit('connection_authentication')
@host_event_handler
@with_connection_from_handle
def on_connection_authentication_failure(self, connection, error):
- logger.debug(f'*** Connection Authentication Failure: [0x{connection.handle:04X}] {connection.peer_address} as {connection.role_name}, error={error}')
+ logger.debug(
+ f'*** Connection Authentication Failure: [0x{connection.handle:04X}] '
+ f'{connection.peer_address} as {connection.role_name}, error={error}'
+ )
connection.emit('connection_authentication_failure', error)
+ @host_event_handler
+ @with_connection_from_address
+ def on_ssp_complete(self, connection):
+ # On Secure Simple Pairing complete, in case:
+ # - Connection isn't already authenticated
+ # - AND we are not the initiator of the authentication
+ # We must trigger authentication to know if we are truly authenticated
+ if not connection.authenticating and not connection.authenticated:
+ logger.debug(
+ f'*** Trigger Connection Authentication: [0x{connection.handle:04X}] '
+ f'{connection.peer_address}'
+ )
+ asyncio.create_task(connection.authenticate())
+
# [Classic only]
@host_event_handler
@with_connection_from_address
@@ -1252,197 +2746,356 @@ class Device(CompositeEventEmitter):
# Ask what the pairing config should be for this connection
pairing_config = self.pairing_config_factory(connection)
- # Map the SMP IO capability to a Classic IO capability
- io_capability = {
- smp.SMP_DISPLAY_ONLY_IO_CAPABILITY: HCI_DISPLAY_ONLY_IO_CAPABILITY,
- smp.SMP_DISPLAY_YES_NO_IO_CAPABILITY: HCI_DISPLAY_YES_NO_IO_CAPABILITY,
- smp.SMP_KEYBOARD_ONLY_IO_CAPABILITY: HCI_KEYBOARD_ONLY_IO_CAPABILITY,
- smp.SMP_NO_INPUT_NO_OUTPUT_IO_CAPABILITY: HCI_NO_INPUT_NO_OUTPUT_IO_CAPABILITY,
- smp.SMP_KEYBOARD_DISPLAY_IO_CAPABILITY: HCI_DISPLAY_YES_NO_IO_CAPABILITY
- }.get(pairing_config.delegate.io_capability)
-
- if io_capability is None:
- logger.warning(f'cannot map IO capability ({pairing_config.delegate.io_capability}')
- io_capability = HCI_NO_INPUT_NO_OUTPUT_IO_CAPABILITY
-
# Compute the authentication requirements
authentication_requirements = (
# No Bonding
(
HCI_MITM_NOT_REQUIRED_NO_BONDING_AUTHENTICATION_REQUIREMENTS,
- HCI_MITM_REQUIRED_NO_BONDING_AUTHENTICATION_REQUIREMENTS
+ HCI_MITM_REQUIRED_NO_BONDING_AUTHENTICATION_REQUIREMENTS,
),
# General Bonding
(
HCI_MITM_NOT_REQUIRED_GENERAL_BONDING_AUTHENTICATION_REQUIREMENTS,
- HCI_MITM_REQUIRED_GENERAL_BONDING_AUTHENTICATION_REQUIREMENTS
- )
+ HCI_MITM_REQUIRED_GENERAL_BONDING_AUTHENTICATION_REQUIREMENTS,
+ ),
)[1 if pairing_config.bonding else 0][1 if pairing_config.mitm else 0]
# Respond
self.host.send_command_sync(
HCI_IO_Capability_Request_Reply_Command(
- bd_addr = connection.peer_address,
- io_capability = io_capability,
- oob_data_present = 0x00, # Not present
- authentication_requirements = authentication_requirements
+ bd_addr=connection.peer_address,
+ io_capability=pairing_config.delegate.classic_io_capability,
+ oob_data_present=0x00, # Not present
+ authentication_requirements=authentication_requirements,
)
)
# [Classic only]
@host_event_handler
@with_connection_from_address
- def on_authentication_user_confirmation_request(self, connection, code):
+ def on_authentication_io_capability_response(
+ self, connection, io_capability, authentication_requirements
+ ):
+ connection.peer_pairing_io_capability = io_capability
+ connection.peer_pairing_authentication_requirements = (
+ authentication_requirements
+ )
+
+ # [Classic only]
+ @host_event_handler
+ @with_connection_from_address
+ def on_authentication_user_confirmation_request(self, connection, code) -> None:
# Ask what the pairing config should be for this connection
pairing_config = self.pairing_config_factory(connection)
-
- can_confirm = pairing_config.delegate.io_capability not in {
- smp.SMP_NO_INPUT_NO_OUTPUT_IO_CAPABILITY,
- smp.SMP_DISPLAY_ONLY_IO_CAPABILITY
+ io_capability = pairing_config.delegate.classic_io_capability
+ peer_io_capability = connection.peer_pairing_io_capability
+
+ async def confirm() -> bool:
+ # Ask the user to confirm the pairing, without display
+ return await pairing_config.delegate.confirm()
+
+ async def auto_confirm() -> bool:
+ # Ask the user to auto-confirm the pairing, without display
+ return await pairing_config.delegate.confirm(auto=True)
+
+ async def display_confirm() -> bool:
+ # Display the code and ask the user to compare
+ return await pairing_config.delegate.compare_numbers(code, digits=6)
+
+ async def display_auto_confirm() -> bool:
+ # Display the code to the user and ask the delegate to auto-confirm
+ await pairing_config.delegate.display_number(code, digits=6)
+ return await pairing_config.delegate.confirm(auto=True)
+
+ async def na() -> bool:
+ assert False, "N/A: unreachable"
+
+ # See Bluetooth spec @ Vol 3, Part C 5.2.2.6
+ methods = {
+ HCI_DISPLAY_ONLY_IO_CAPABILITY: {
+ HCI_DISPLAY_ONLY_IO_CAPABILITY: display_auto_confirm,
+ HCI_DISPLAY_YES_NO_IO_CAPABILITY: display_confirm,
+ HCI_KEYBOARD_ONLY_IO_CAPABILITY: na,
+ HCI_NO_INPUT_NO_OUTPUT_IO_CAPABILITY: auto_confirm,
+ },
+ HCI_DISPLAY_YES_NO_IO_CAPABILITY: {
+ HCI_DISPLAY_ONLY_IO_CAPABILITY: display_auto_confirm,
+ HCI_DISPLAY_YES_NO_IO_CAPABILITY: display_confirm,
+ HCI_KEYBOARD_ONLY_IO_CAPABILITY: na,
+ HCI_NO_INPUT_NO_OUTPUT_IO_CAPABILITY: auto_confirm,
+ },
+ HCI_KEYBOARD_ONLY_IO_CAPABILITY: {
+ HCI_DISPLAY_ONLY_IO_CAPABILITY: na,
+ HCI_DISPLAY_YES_NO_IO_CAPABILITY: na,
+ HCI_KEYBOARD_ONLY_IO_CAPABILITY: na,
+ HCI_NO_INPUT_NO_OUTPUT_IO_CAPABILITY: auto_confirm,
+ },
+ HCI_NO_INPUT_NO_OUTPUT_IO_CAPABILITY: {
+ HCI_DISPLAY_ONLY_IO_CAPABILITY: confirm,
+ HCI_DISPLAY_YES_NO_IO_CAPABILITY: confirm,
+ HCI_KEYBOARD_ONLY_IO_CAPABILITY: auto_confirm,
+ HCI_NO_INPUT_NO_OUTPUT_IO_CAPABILITY: auto_confirm,
+ },
}
- # Respond
- if can_confirm and pairing_config.delegate:
- async def compare_numbers():
- numbers_match = await pairing_config.delegate.compare_numbers(code, digits=6)
- if numbers_match:
- self.host.send_command_sync(
- HCI_User_Confirmation_Request_Reply_Command(bd_addr=connection.peer_address)
+ method = methods[peer_io_capability][io_capability]
+
+ async def reply() -> None:
+ if await connection.abort_on('disconnection', method()):
+ await self.host.send_command(
+ HCI_User_Confirmation_Request_Reply_Command( # type: ignore[call-arg]
+ bd_addr=connection.peer_address
)
- else:
- self.host.send_command_sync(
- HCI_User_Confirmation_Request_Negative_Reply_Command(bd_addr=connection.peer_address)
+ )
+ else:
+ await self.host.send_command(
+ HCI_User_Confirmation_Request_Negative_Reply_Command( # type: ignore[call-arg]
+ bd_addr=connection.peer_address
)
+ )
- asyncio.create_task(compare_numbers())
- else:
- self.host.send_command_sync(
- HCI_User_Confirmation_Request_Reply_Command(bd_addr=connection.peer_address)
- )
+ AsyncRunner.spawn(reply())
# [Classic only]
@host_event_handler
@with_connection_from_address
- def on_authentication_user_passkey_request(self, connection):
+ def on_authentication_user_passkey_request(self, connection) -> None:
# Ask what the pairing config should be for this connection
pairing_config = self.pairing_config_factory(connection)
- can_input = pairing_config.delegate.io_capability in {
- smp.SMP_KEYBOARD_ONLY_IO_CAPABILITY,
- smp.SMP_KEYBOARD_DISPLAY_IO_CAPABILITY
- }
+ async def reply() -> None:
+ number = await connection.abort_on(
+ 'disconnection', pairing_config.delegate.get_number()
+ )
+ if number is not None:
+ await self.host.send_command(
+ HCI_User_Passkey_Request_Reply_Command( # type: ignore[call-arg]
+ bd_addr=connection.peer_address, numeric_value=number
+ )
+ )
+ else:
+ await self.host.send_command(
+ HCI_User_Passkey_Request_Negative_Reply_Command( # type: ignore[call-arg]
+ bd_addr=connection.peer_address
+ )
+ )
+
+ AsyncRunner.spawn(reply())
+
+ # [Classic only]
+ @host_event_handler
+ @with_connection_from_address
+ def on_pin_code_request(self, connection):
+ # Classic legacy pairing
+ # Ask what the pairing config should be for this connection
+ pairing_config = self.pairing_config_factory(connection)
+ io_capability = pairing_config.delegate.classic_io_capability
# Respond
- if can_input and pairing_config.delegate:
- async def get_number():
- number = await pairing_config.delegate.get_number()
- if number is not None:
- self.host.send_command_sync(
- HCI_User_Passkey_Request_Reply_Command(
- bd_addr = connection.peer_address,
- numeric_value = number)
+ if io_capability == HCI_KEYBOARD_ONLY_IO_CAPABILITY:
+ # Ask the user to enter a string
+ async def get_pin_code():
+ pin_code = await connection.abort_on(
+ 'disconnection', pairing_config.delegate.get_string(16)
+ )
+
+ if pin_code is not None:
+ pin_code = bytes(pin_code, encoding='utf-8')
+ pin_code_len = len(pin_code)
+ assert 0 < pin_code_len <= 16, "pin_code should be 1-16 bytes"
+ await self.host.send_command(
+ HCI_PIN_Code_Request_Reply_Command(
+ bd_addr=connection.peer_address,
+ pin_code_length=pin_code_len,
+ pin_code=pin_code,
+ )
)
else:
- self.host.send_command_sync(
- HCI_User_Passkey_Request_Negative_Reply_Command(bd_addr=connection.peer_address)
+ logger.debug("delegate.get_string() returned None")
+ await self.host.send_command(
+ HCI_PIN_Code_Request_Negative_Reply_Command(
+ bd_addr=connection.peer_address
+ )
)
- asyncio.create_task(get_number())
+ asyncio.create_task(get_pin_code())
else:
self.host.send_command_sync(
- HCI_User_Passkey_Request_Negative_Reply_Command(bd_addr=connection.peer_address)
+ HCI_PIN_Code_Request_Negative_Reply_Command(
+ bd_addr=connection.peer_address
+ )
)
# [Classic only]
@host_event_handler
@with_connection_from_address
- def on_remote_name(self, connection, remote_name):
+ def on_authentication_user_passkey_notification(self, connection, passkey):
+ # Ask what the pairing config should be for this connection
+ pairing_config = self.pairing_config_factory(connection)
+
+ # Show the passkey to the user
+ connection.abort_on(
+ 'disconnection', pairing_config.delegate.display_number(passkey)
+ )
+
+ # [Classic only]
+ @host_event_handler
+ @try_with_connection_from_address
+ def on_remote_name(self, connection: Connection, address, remote_name):
# Try to decode the name
try:
- connection.peer_name = remote_name.decode('utf-8')
- connection.emit('remote_name')
+ remote_name = remote_name.decode('utf-8')
+ if connection:
+ connection.peer_name = remote_name
+ connection.emit('remote_name')
+ self.emit('remote_name', address, remote_name)
except UnicodeDecodeError as error:
logger.warning('peer name is not valid UTF-8')
- connection.emit('remote_name_failure', error)
+ if connection:
+ connection.emit('remote_name_failure', error)
+ else:
+ self.emit('remote_name_failure', address, error)
# [Classic only]
@host_event_handler
- @with_connection_from_address
- def on_remote_name_failure(self, connection, error):
- connection.emit('remote_name_failure', error)
+ @try_with_connection_from_address
+ def on_remote_name_failure(self, connection: Connection, address, error):
+ if connection:
+ connection.emit('remote_name_failure', error)
+ self.emit('remote_name_failure', address, error)
@host_event_handler
@with_connection_from_handle
def on_connection_encryption_change(self, connection, encryption):
- logger.debug(f'*** Connection Encryption Change: [0x{connection.handle:04X}] {connection.peer_address} as {connection.role_name}, encryption={encryption}')
+ logger.debug(
+ f'*** Connection Encryption Change: [0x{connection.handle:04X}] '
+ f'{connection.peer_address} as {connection.role_name}, '
+ f'encryption={encryption}'
+ )
connection.encryption = encryption
+ if (
+ not connection.authenticated
+ and encryption == HCI_Encryption_Change_Event.AES_CCM
+ ):
+ connection.authenticated = True
+ connection.sc = True
connection.emit('connection_encryption_change')
@host_event_handler
@with_connection_from_handle
def on_connection_encryption_failure(self, connection, error):
- logger.debug(f'*** Connection Encryption Failure: [0x{connection.handle:04X}] {connection.peer_address} as {connection.role_name}, error={error}')
+ logger.debug(
+ f'*** Connection Encryption Failure: [0x{connection.handle:04X}] '
+ f'{connection.peer_address} as {connection.role_name}, '
+ f'error={error}'
+ )
connection.emit('connection_encryption_failure', error)
@host_event_handler
@with_connection_from_handle
def on_connection_encryption_key_refresh(self, connection):
- logger.debug(f'*** Connection Key Refresh: [0x{connection.handle:04X}] {connection.peer_address} as {connection.role_name}')
+ logger.debug(
+ f'*** Connection Key Refresh: [0x{connection.handle:04X}] '
+ f'{connection.peer_address} as {connection.role_name}'
+ )
connection.emit('connection_encryption_key_refresh')
@host_event_handler
@with_connection_from_handle
def on_connection_parameters_update(self, connection, connection_parameters):
- logger.debug(f'*** Connection Parameters Update: [0x{connection.handle:04X}] {connection.peer_address} as {connection.role_name}, {connection_parameters}')
+ logger.debug(
+ f'*** Connection Parameters Update: [0x{connection.handle:04X}] '
+ f'{connection.peer_address} as {connection.role_name}, '
+ f'{connection_parameters}'
+ )
connection.parameters = connection_parameters
connection.emit('connection_parameters_update')
@host_event_handler
@with_connection_from_handle
def on_connection_parameters_update_failure(self, connection, error):
- logger.debug(f'*** Connection Parameters Update Failed: [0x{connection.handle:04X}] {connection.peer_address} as {connection.role_name}, error={error}')
+ logger.debug(
+ f'*** Connection Parameters Update Failed: [0x{connection.handle:04X}] '
+ f'{connection.peer_address} as {connection.role_name}, '
+ f'error={error}'
+ )
connection.emit('connection_parameters_update_failure', error)
@host_event_handler
@with_connection_from_handle
def on_connection_phy_update(self, connection, connection_phy):
- logger.debug(f'*** Connection PHY Update: [0x{connection.handle:04X}] {connection.peer_address} as {connection.role_name}, {connection_phy}')
+ logger.debug(
+ f'*** Connection PHY Update: [0x{connection.handle:04X}] '
+ f'{connection.peer_address} as {connection.role_name}, '
+ f'{connection_phy}'
+ )
connection.phy = connection_phy
connection.emit('connection_phy_update')
@host_event_handler
@with_connection_from_handle
def on_connection_phy_update_failure(self, connection, error):
- logger.debug(f'*** Connection PHY Update Failed: [0x{connection.handle:04X}] {connection.peer_address} as {connection.role_name}, error={error}')
+ logger.debug(
+ f'*** Connection PHY Update Failed: [0x{connection.handle:04X}] '
+ f'{connection.peer_address} as {connection.role_name}, '
+ f'error={error}'
+ )
connection.emit('connection_phy_update_failure', error)
@host_event_handler
@with_connection_from_handle
def on_connection_att_mtu_update(self, connection, att_mtu):
- logger.debug(f'*** Connection ATT MTU Update: [0x{connection.handle:04X}] {connection.peer_address} as {connection.role_name}, {att_mtu}')
+ logger.debug(
+ f'*** Connection ATT MTU Update: [0x{connection.handle:04X}] '
+ f'{connection.peer_address} as {connection.role_name}, '
+ f'{att_mtu}'
+ )
connection.att_mtu = att_mtu
connection.emit('connection_att_mtu_update')
@host_event_handler
@with_connection_from_handle
- def on_connection_data_length_change(self, connection, max_tx_octets, max_tx_time, max_rx_octets, max_rx_time):
- logger.debug(f'*** Connection Data Length Change: [0x{connection.handle:04X}] {connection.peer_address} as {connection.role_name}')
- connection.data_length = (max_tx_octets, max_tx_time, max_rx_octets, max_rx_time)
+ def on_connection_data_length_change(
+ self, connection, max_tx_octets, max_tx_time, max_rx_octets, max_rx_time
+ ):
+ logger.debug(
+ f'*** Connection Data Length Change: [0x{connection.handle:04X}] '
+ f'{connection.peer_address} as {connection.role_name}'
+ )
+ connection.data_length = (
+ max_tx_octets,
+ max_tx_time,
+ max_rx_octets,
+ max_rx_time,
+ )
connection.emit('connection_data_length_change')
- @with_connection_from_handle
- def on_pairing_start(self, connection):
+ # [Classic only]
+ @host_event_handler
+ @with_connection_from_address
+ def on_role_change(self, connection, new_role):
+ connection.role = new_role
+ connection.emit('role_change', new_role)
+
+ # [Classic only]
+ @host_event_handler
+ @try_with_connection_from_address
+ def on_role_change_failure(self, connection, address, error):
+ if connection:
+ connection.emit('role_change_failure', error)
+ self.emit('role_change_failure', address, error)
+
+ def on_pairing_start(self, connection: Connection) -> None:
connection.emit('pairing_start')
- @with_connection_from_handle
- def on_pairing(self, connection, keys):
+ def on_pairing(self, connection: Connection, keys: PairingKeys, sc: bool) -> None:
+ connection.sc = sc
+ connection.authenticated = True
connection.emit('pairing', keys)
- @with_connection_from_handle
- def on_pairing_failure(self, connection, reason):
+ def on_pairing_failure(self, connection: Connection, reason: int) -> None:
connection.emit('pairing_failure', reason)
- @host_event_handler
@with_connection_from_handle
def on_gatt_pdu(self, connection, pdu):
# Parse the L2CAP payload into an ATT PDU object
@@ -1452,16 +3105,19 @@ class Device(CompositeEventEmitter):
# odd-numbered ones are server->client
if att_pdu.op_code & 1:
if connection.gatt_client is None:
- logger.warn(color('no GATT client for connection 0x{connection_handle:04X}'))
+ logger.warning(
+ color('no GATT client for connection 0x{connection_handle:04X}')
+ )
return
connection.gatt_client.on_gatt_pdu(att_pdu)
else:
if connection.gatt_server is None:
- logger.warn(color('no GATT server for connection 0x{connection_handle:04X}'))
+ logger.warning(
+ color('no GATT server for connection 0x{connection_handle:04X}')
+ )
return
connection.gatt_server.on_gatt_pdu(connection, att_pdu)
- @host_event_handler
@with_connection_from_handle
def on_smp_pdu(self, connection, pdu):
self.smp_manager.on_smp_pdu(connection, pdu)
@@ -1472,4 +3128,8 @@ class Device(CompositeEventEmitter):
self.l2cap_channel_manager.on_pdu(connection, cid, pdu)
def __str__(self):
- return f'Device(name="{self.name}", random_address="{self.random_address}"", public_address="{self.public_address}")'
+ return (
+ f'Device(name="{self.name}", '
+ f'random_address="{self.random_address}", '
+ f'public_address="{self.public_address}")'
+ )
diff --git a/bumble/gap.py b/bumble/gap.py
index 8341215..29df89f 100644
--- a/bumble/gap.py
+++ b/bumble/gap.py
@@ -23,7 +23,7 @@ from .gatt import (
Characteristic,
GATT_GENERIC_ACCESS_SERVICE,
GATT_DEVICE_NAME_CHARACTERISTIC,
- GATT_APPEARANCE_CHARACTERISTIC
+ GATT_APPEARANCE_CHARACTERISTIC,
)
# -----------------------------------------------------------------------------
@@ -38,22 +38,22 @@ logger = logging.getLogger(__name__)
# -----------------------------------------------------------------------------
class GenericAccessService(Service):
- def __init__(self, device_name, appearance = (0, 0)):
+ def __init__(self, device_name, appearance=(0, 0)):
device_name_characteristic = Characteristic(
GATT_DEVICE_NAME_CHARACTERISTIC,
- Characteristic.READ,
+ Characteristic.Properties.READ,
Characteristic.READABLE,
- device_name.encode('utf-8')[:248]
+ device_name.encode('utf-8')[:248],
)
appearance_characteristic = Characteristic(
GATT_APPEARANCE_CHARACTERISTIC,
- Characteristic.READ,
+ Characteristic.Properties.READ,
Characteristic.READABLE,
- struct.pack('<H', (appearance[0] << 6) | appearance[1])
+ struct.pack('<H', (appearance[0] << 6) | appearance[1]),
)
- super().__init__(GATT_GENERIC_ACCESS_SERVICE, [
- device_name_characteristic,
- appearance_characteristic
- ])
+ super().__init__(
+ GATT_GENERIC_ACCESS_SERVICE,
+ [device_name_characteristic, appearance_characteristic],
+ )
diff --git a/bumble/gatt.py b/bumble/gatt.py
index df760c3..ea2b690 100644
--- a/bumble/gatt.py
+++ b/bumble/gatt.py
@@ -22,14 +22,18 @@
# -----------------------------------------------------------------------------
# Imports
# -----------------------------------------------------------------------------
+from __future__ import annotations
import asyncio
-import types
+import enum
+import functools
import logging
-from colors import color
+import struct
+from typing import Optional, Sequence, List
+
+from .colors import color
+from .core import UUID, get_dict_key_by_value
+from .att import Attribute
-from .core import *
-from .hci import *
-from .att import *
# -----------------------------------------------------------------------------
# Logging
@@ -39,6 +43,9 @@ logger = logging.getLogger(__name__)
# -----------------------------------------------------------------------------
# Constants
# -----------------------------------------------------------------------------
+# fmt: off
+# pylint: disable=line-too-long
+
GATT_REQUEST_TIMEOUT = 30 # seconds
GATT_MAX_ATTRIBUTE_VALUE_SIZE = 512
@@ -134,13 +141,29 @@ GATT_MANUFACTURER_NAME_STRING_CHARACTERISTIC = UUID.from_16_bits(0x2A2
GATT_REGULATORY_CERTIFICATION_DATA_LIST_CHARACTERISTIC = UUID.from_16_bits(0x2A2A, 'IEEE 11073-20601 Regulatory Certification Data List')
GATT_PNP_ID_CHARACTERISTIC = UUID.from_16_bits(0x2A50, 'PnP ID')
-# Human Interface Device
+# Human Interface Device Service
GATT_HID_INFORMATION_CHARACTERISTIC = UUID.from_16_bits(0x2A4A, 'HID Information')
GATT_REPORT_MAP_CHARACTERISTIC = UUID.from_16_bits(0x2A4B, 'Report Map')
GATT_HID_CONTROL_POINT_CHARACTERISTIC = UUID.from_16_bits(0x2A4C, 'HID Control Point')
GATT_REPORT_CHARACTERISTIC = UUID.from_16_bits(0x2A4D, 'Report')
GATT_PROTOCOL_MODE_CHARACTERISTIC = UUID.from_16_bits(0x2A4E, 'Protocol Mode')
+# Heart Rate Service
+GATT_HEART_RATE_MEASUREMENT_CHARACTERISTIC = UUID.from_16_bits(0x2A37, 'Heart Rate Measurement')
+GATT_BODY_SENSOR_LOCATION_CHARACTERISTIC = UUID.from_16_bits(0x2A38, 'Body Sensor Location')
+GATT_HEART_RATE_CONTROL_POINT_CHARACTERISTIC = UUID.from_16_bits(0x2A39, 'Heart Rate Control Point')
+
+# Battery Service
+GATT_BATTERY_LEVEL_CHARACTERISTIC = UUID.from_16_bits(0x2A19, 'Battery Level')
+
+# ASHA Service
+GATT_ASHA_SERVICE = UUID.from_16_bits(0xFDF0, 'Audio Streaming for Hearing Aid')
+GATT_ASHA_READ_ONLY_PROPERTIES_CHARACTERISTIC = UUID('6333651e-c481-4a3e-9169-7c902aad37bb', 'ReadOnlyProperties')
+GATT_ASHA_AUDIO_CONTROL_POINT_CHARACTERISTIC = UUID('f0d4de7e-4a88-476c-9d9f-1937b0996cc0', 'AudioControlPoint')
+GATT_ASHA_AUDIO_STATUS_CHARACTERISTIC = UUID('38663f1a-e711-4cac-b641-326b56404837', 'AudioStatus')
+GATT_ASHA_VOLUME_CHARACTERISTIC = UUID('00e4ca9e-ab14-41e4-8823-f9e70c7e91df', 'Volume')
+GATT_ASHA_LE_PSM_OUT_CHARACTERISTIC = UUID('2d410339-82b6-42aa-b34e-e2e01df8cc1a', 'LE_PSM_OUT')
+
# Misc
GATT_DEVICE_NAME_CHARACTERISTIC = UUID.from_16_bits(0x2A00, 'Device Name')
GATT_APPEARANCE_CHARACTERISTIC = UUID.from_16_bits(0x2A01, 'Appearance')
@@ -150,17 +173,20 @@ GATT_PERIPHERAL_PREFERRED_CONNECTION_PARAMETERS_CHARACTERISTIC = UUID.from_16_bi
GATT_SERVICE_CHANGED_CHARACTERISTIC = UUID.from_16_bits(0x2A05, 'Service Changed')
GATT_ALERT_LEVEL_CHARACTERISTIC = UUID.from_16_bits(0x2A06, 'Alert Level')
GATT_TX_POWER_LEVEL_CHARACTERISTIC = UUID.from_16_bits(0x2A07, 'Tx Power Level')
-GATT_BATTERY_LEVEL_CHARACTERISTIC = UUID.from_16_bits(0x2A19, 'Battery Level')
GATT_BOOT_KEYBOARD_INPUT_REPORT_CHARACTERISTIC = UUID.from_16_bits(0x2A22, 'Boot Keyboard Input Report')
GATT_CURRENT_TIME_CHARACTERISTIC = UUID.from_16_bits(0x2A2B, 'Current Time')
GATT_BOOT_KEYBOARD_OUTPUT_REPORT_CHARACTERISTIC = UUID.from_16_bits(0x2A32, 'Boot Keyboard Output Report')
GATT_CENTRAL_ADDRESS_RESOLUTION__CHARACTERISTIC = UUID.from_16_bits(0x2AA6, 'Central Address Resolution')
+# fmt: on
+# pylint: enable=line-too-long
+
# -----------------------------------------------------------------------------
# Utils
# -----------------------------------------------------------------------------
+
def show_services(services):
for service in services:
print(color(str(service), 'cyan'))
@@ -178,23 +204,48 @@ class Service(Attribute):
See Vol 3, Part G - 3.1 SERVICE DEFINITION
'''
- def __init__(self, uuid, characteristics, primary=True):
+ uuid: UUID
+ characteristics: List[Characteristic]
+ included_services: List[Service]
+
+ def __init__(
+ self,
+ uuid,
+ characteristics: List[Characteristic],
+ primary=True,
+ included_services: List[Service] = [],
+ ):
# Convert the uuid to a UUID object if it isn't already
- if type(uuid) is str:
+ if isinstance(uuid, str):
uuid = UUID(uuid)
super().__init__(
- GATT_PRIMARY_SERVICE_ATTRIBUTE_TYPE if primary else GATT_SECONDARY_SERVICE_ATTRIBUTE_TYPE,
+ GATT_PRIMARY_SERVICE_ATTRIBUTE_TYPE
+ if primary
+ else GATT_SECONDARY_SERVICE_ATTRIBUTE_TYPE,
Attribute.READABLE,
- uuid.to_pdu_bytes()
+ uuid.to_pdu_bytes(),
)
- self.uuid = uuid
- self.included_services = []
- self.characteristics = characteristics[:]
- self.primary = primary
+ self.uuid = uuid
+ self.included_services = included_services[:]
+ self.characteristics = characteristics[:]
+ self.primary = primary
+
+ def get_advertising_data(self) -> Optional[bytes]:
+ """
+ Get Service specific advertising data
+ Defined by each Service, default value is empty
+ :return Service data for advertising
+ """
+ return None
def __str__(self):
- return f'Service(handle=0x{self.handle:04X}, end=0x{self.end_group_handle:04X}, uuid={self.uuid}){"" if self.primary else "*"}'
+ return (
+ f'Service(handle=0x{self.handle:04X}, '
+ f'end=0x{self.end_group_handle:04X}, '
+ f'uuid={self.uuid})'
+ f'{"" if self.primary else "*"}'
+ )
# -----------------------------------------------------------------------------
@@ -203,63 +254,155 @@ class TemplateService(Service):
Convenience abstract class that can be used by profile-specific subclasses that want
to expose their UUID as a class property
'''
- UUID = None
+
+ UUID: Optional[UUID] = None
def __init__(self, characteristics, primary=True):
super().__init__(self.UUID, characteristics, primary)
# -----------------------------------------------------------------------------
+class IncludedServiceDeclaration(Attribute):
+ '''
+ See Vol 3, Part G - 3.2 INCLUDE DEFINITION
+ '''
+
+ service: Service
+
+ def __init__(self, service):
+ declaration_bytes = struct.pack(
+ '<HH2s', service.handle, service.end_group_handle, service.uuid.to_bytes()
+ )
+ super().__init__(
+ GATT_INCLUDE_ATTRIBUTE_TYPE, Attribute.READABLE, declaration_bytes
+ )
+ self.service = service
+
+ def __str__(self):
+ return (
+ f'IncludedServiceDefinition(handle=0x{self.handle:04X}, '
+ f'group_starting_handle=0x{self.service.handle:04X}, '
+ f'group_ending_handle=0x{self.service.end_group_handle:04X}, '
+ f'uuid={self.service.uuid}, '
+ f'{self.service.properties!s})'
+ )
+
+
+# -----------------------------------------------------------------------------
class Characteristic(Attribute):
'''
See Vol 3, Part G - 3.3 CHARACTERISTIC DEFINITION
'''
- # Property flags
- BROADCAST = 0x01
- READ = 0x02
- WRITE_WITHOUT_RESPONSE = 0x04
- WRITE = 0x08
- NOTIFY = 0x10
- INDICATE = 0X20
- AUTHENTICATED_SIGNED_WRITES = 0X40
- EXTENDED_PROPERTIES = 0X80
-
- PROPERTY_NAMES = {
- BROADCAST: 'BROADCAST',
- READ: 'READ',
- WRITE_WITHOUT_RESPONSE: 'WRITE_WITHOUT_RESPONSE',
- WRITE: 'WRITE',
- NOTIFY: 'NOTIFY',
- INDICATE: 'INDICATE',
- AUTHENTICATED_SIGNED_WRITES: 'AUTHENTICATED_SIGNED_WRITES',
- EXTENDED_PROPERTIES: 'EXTENDED_PROPERTIES'
- }
-
- @staticmethod
- def property_name(property):
- return Characteristic.PROPERTY_NAMES.get(property, '')
-
- @staticmethod
- def properties_as_string(properties):
- return ','.join([
- Characteristic.property_name(p) for p in Characteristic.PROPERTY_NAMES.keys()
- if properties & p
- ])
-
- def __init__(self, uuid, properties, permissions, value = b'', descriptors = []):
+ uuid: UUID
+ properties: Characteristic.Properties
+
+ class Properties(enum.IntFlag):
+ """Property flags"""
+
+ BROADCAST = 0x01
+ READ = 0x02
+ WRITE_WITHOUT_RESPONSE = 0x04
+ WRITE = 0x08
+ NOTIFY = 0x10
+ INDICATE = 0x20
+ AUTHENTICATED_SIGNED_WRITES = 0x40
+ EXTENDED_PROPERTIES = 0x80
+
+ @staticmethod
+ def from_string(properties_str: str) -> Characteristic.Properties:
+ property_names: List[str] = []
+ for property in Characteristic.Properties:
+ if property.name is None:
+ raise TypeError()
+ property_names.append(property.name)
+
+ def string_to_property(property_string) -> Characteristic.Properties:
+ for property in zip(Characteristic.Properties, property_names):
+ if property_string == property[1]:
+ return property[0]
+ raise TypeError(f"Unable to convert {property_string} to Property")
+
+ try:
+ return functools.reduce(
+ lambda x, y: x | string_to_property(y),
+ properties_str.split(","),
+ Characteristic.Properties(0),
+ )
+ except TypeError:
+ raise TypeError(
+ f"Characteristic.Properties::from_string() error:\nExpected a string containing any of the keys, separated by commas: {','.join(property_names)}\nGot: {properties_str}"
+ )
+
+ # For backwards compatibility these are defined here
+ # For new code, please use Characteristic.Properties.X
+ BROADCAST = Properties.BROADCAST
+ READ = Properties.READ
+ WRITE_WITHOUT_RESPONSE = Properties.WRITE_WITHOUT_RESPONSE
+ WRITE = Properties.WRITE
+ NOTIFY = Properties.NOTIFY
+ INDICATE = Properties.INDICATE
+ AUTHENTICATED_SIGNED_WRITES = Properties.AUTHENTICATED_SIGNED_WRITES
+ EXTENDED_PROPERTIES = Properties.EXTENDED_PROPERTIES
+
+ def __init__(
+ self,
+ uuid,
+ properties: Characteristic.Properties,
+ permissions,
+ value=b'',
+ descriptors: Sequence[Descriptor] = (),
+ ):
super().__init__(uuid, permissions, value)
- self.uuid = self.type
- self.properties = properties
+ self.uuid = self.type
+ self.properties = properties
self.descriptors = descriptors
def get_descriptor(self, descriptor_type):
for descriptor in self.descriptors:
- if descriptor.uuid == descriptor_type:
+ if descriptor.type == descriptor_type:
return descriptor
+ return None
+
+ def has_properties(self, properties: Characteristic.Properties) -> bool:
+ return self.properties & properties == properties
+
+ def __str__(self):
+ return (
+ f'Characteristic(handle=0x{self.handle:04X}, '
+ f'end=0x{self.end_group_handle:04X}, '
+ f'uuid={self.uuid}, '
+ f'{self.properties!s})'
+ )
+
+
+# -----------------------------------------------------------------------------
+class CharacteristicDeclaration(Attribute):
+ '''
+ See Vol 3, Part G - 3.3.1 CHARACTERISTIC DECLARATION
+ '''
+
+ characteristic: Characteristic
+
+ def __init__(self, characteristic, value_handle):
+ declaration_bytes = (
+ struct.pack('<BH', characteristic.properties, value_handle)
+ + characteristic.uuid.to_pdu_bytes()
+ )
+ super().__init__(
+ GATT_CHARACTERISTIC_ATTRIBUTE_TYPE, Attribute.READABLE, declaration_bytes
+ )
+ self.value_handle = value_handle
+ self.characteristic = characteristic
+
def __str__(self):
- return f'Characteristic(handle=0x{self.handle:04X}, end=0x{self.end_group_handle:04X}, uuid={self.uuid}, properties={Characteristic.properties_as_string(self.properties)})'
+ return (
+ f'CharacteristicDeclaration(handle=0x{self.handle:04X}, '
+ f'value_handle=0x{self.value_handle:04X}, '
+ f'uuid={self.characteristic.uuid}, '
+ f'{self.characteristic.properties!s})'
+ )
# -----------------------------------------------------------------------------
@@ -268,6 +411,7 @@ class CharacteristicValue:
Characteristic value where reading and/or writing is delegated to functions
passed as arguments to the constructor.
'''
+
def __init__(self, read=None, write=None):
self._read = read
self._write = write
@@ -294,36 +438,57 @@ class CharacteristicAdapter:
If the characteristic has a `subscribe` method, it is wrapped with one where
the values are decoded before being passed to the subscriber.
'''
+
def __init__(self, characteristic):
self.wrapped_characteristic = characteristic
+ self.subscribers = {} # Map from subscriber to proxy subscriber
- if (
- asyncio.iscoroutinefunction(characteristic.read_value) and
- asyncio.iscoroutinefunction(characteristic.write_value)
- ):
- self.read_value = self.read_decoded_value
+ if asyncio.iscoroutinefunction(
+ characteristic.read_value
+ ) and asyncio.iscoroutinefunction(characteristic.write_value):
+ self.read_value = self.read_decoded_value
self.write_value = self.write_decoded_value
else:
- self.read_value = self.read_encoded_value
+ self.read_value = self.read_encoded_value
self.write_value = self.write_encoded_value
if hasattr(self.wrapped_characteristic, 'subscribe'):
self.subscribe = self.wrapped_subscribe
+ if hasattr(self.wrapped_characteristic, 'unsubscribe'):
+ self.unsubscribe = self.wrapped_unsubscribe
+
def __getattr__(self, name):
return getattr(self.wrapped_characteristic, name)
+ def __setattr__(self, name, value):
+ if name in (
+ 'wrapped_characteristic',
+ 'subscribers',
+ 'read_value',
+ 'write_value',
+ 'subscribe',
+ 'unsubscribe',
+ ):
+ super().__setattr__(name, value)
+ else:
+ setattr(self.wrapped_characteristic, name, value)
+
def read_encoded_value(self, connection):
return self.encode_value(self.wrapped_characteristic.read_value(connection))
def write_encoded_value(self, connection, value):
- return self.wrapped_characteristic.write_value(connection, self.decode_value(value))
+ return self.wrapped_characteristic.write_value(
+ connection, self.decode_value(value)
+ )
async def read_decoded_value(self):
return self.decode_value(await self.wrapped_characteristic.read_value())
- async def write_decoded_value(self, value):
- return await self.wrapped_characteristic.write_value(self.encode_value(value))
+ async def write_decoded_value(self, value, with_response=False):
+ return await self.wrapped_characteristic.write_value(
+ self.encode_value(value), with_response
+ )
def encode_value(self, value):
return value
@@ -332,23 +497,49 @@ class CharacteristicAdapter:
return value
def wrapped_subscribe(self, subscriber=None):
- return self.wrapped_characteristic.subscribe(
- None if subscriber is None else lambda value: subscriber(self.decode_value(value))
- )
+ if subscriber is not None:
+ if subscriber in self.subscribers:
+ # We already have a proxy subscriber
+ subscriber = self.subscribers[subscriber]
+ else:
+ # Create and register a proxy that will decode the value
+ original_subscriber = subscriber
+
+ def on_change(value):
+ original_subscriber(self.decode_value(value))
+
+ self.subscribers[subscriber] = on_change
+ subscriber = on_change
+
+ return self.wrapped_characteristic.subscribe(subscriber)
+
+ def wrapped_unsubscribe(self, subscriber=None):
+ if subscriber in self.subscribers:
+ subscriber = self.subscribers.pop(subscriber)
+
+ return self.wrapped_characteristic.unsubscribe(subscriber)
+
+ def __str__(self):
+ wrapped = str(self.wrapped_characteristic)
+ return f'{self.__class__.__name__}({wrapped})'
# -----------------------------------------------------------------------------
class DelegatedCharacteristicAdapter(CharacteristicAdapter):
- def __init__(self, characteristic, encode, decode):
+ '''
+ Adapter that converts bytes values using an encode and a decode function.
+ '''
+
+ def __init__(self, characteristic, encode=None, decode=None):
super().__init__(characteristic)
self.encode = encode
self.decode = decode
def encode_value(self, value):
- return self.encode(value)
+ return self.encode(value) if self.encode else value
def decode_value(self, value):
- return self.decode(value)
+ return self.decode(value) if self.decode else value
# -----------------------------------------------------------------------------
@@ -361,9 +552,10 @@ class PackedCharacteristicAdapter(CharacteristicAdapter):
they return/accept a tuple with the same number of elements as is required for
the format.
'''
- def __init__(self, characteristic, format):
+
+ def __init__(self, characteristic, pack_format):
super().__init__(characteristic)
- self.struct = struct.Struct(format)
+ self.struct = struct.Struct(pack_format)
def pack(self, *values):
return self.struct.pack(*values)
@@ -372,7 +564,7 @@ class PackedCharacteristicAdapter(CharacteristicAdapter):
return self.struct.unpack(buffer)
def encode_value(self, value):
- return self.pack(*value if type(value) is tuple else (value,))
+ return self.pack(*value if isinstance(value, tuple) else (value,))
def decode_value(self, value):
unpacked = self.unpack(value)
@@ -385,13 +577,15 @@ class MappedCharacteristicAdapter(PackedCharacteristicAdapter):
Adapter that packs/unpacks characteristic values according to a standard
Python `struct` format.
The adapted `read_value` and `write_value` methods return/accept aa dictionary which
- is packed/unpacked according to format, with the arguments extracted from the dictionary
- by key, in the same order as they occur in the `keys` parameter.
+ is packed/unpacked according to format, with the arguments extracted from the
+ dictionary by key, in the same order as they occur in the `keys` parameter.
'''
- def __init__(self, characteristic, format, keys):
- super().__init__(characteristic, format)
+
+ def __init__(self, characteristic, pack_format, keys):
+ super().__init__(characteristic, pack_format)
self.keys = keys
+ # pylint: disable=arguments-differ
def pack(self, values):
return super().pack(*(values[key] for key in self.keys))
@@ -404,6 +598,7 @@ class UTF8CharacteristicAdapter(CharacteristicAdapter):
'''
Adapter that converts strings to/from bytes using UTF-8 encoding
'''
+
def encode_value(self, value):
return value.encode('utf-8')
@@ -417,8 +612,20 @@ class Descriptor(Attribute):
See Vol 3, Part G - 3.3.3 Characteristic Descriptor Declarations
'''
- def __init__(self, descriptor_type, permissions, value = b''):
- super().__init__(descriptor_type, permissions, value)
-
def __str__(self):
- return f'Descriptor(handle=0x{self.handle:04X}, type={self.type}, value={self.read_value(None).hex()})'
+ return (
+ f'Descriptor(handle=0x{self.handle:04X}, '
+ f'type={self.type}, '
+ f'value={self.read_value(None).hex()})'
+ )
+
+
+class ClientCharacteristicConfigurationBits(enum.IntFlag):
+ '''
+ See Vol 3, Part G - 3.3.3.3 - Table 3.11 Client Characteristic Configuration bit
+ field definition
+ '''
+
+ DEFAULT = 0x0000
+ NOTIFICATION = 0x0001
+ INDICATION = 0x0002
diff --git a/bumble/gatt_client.py b/bumble/gatt_client.py
index e817e2e..a33039e 100644
--- a/bumble/gatt_client.py
+++ b/bumble/gatt_client.py
@@ -23,21 +23,49 @@
# -----------------------------------------------------------------------------
# Imports
# -----------------------------------------------------------------------------
+from __future__ import annotations
import asyncio
import logging
import struct
-from colors import color
-
-from .core import ProtocolError, TimeoutError
-from .hci import *
-from .att import *
+from datetime import datetime
+from typing import List, Optional, Dict, Tuple, Callable, Union, Any
+
+from pyee import EventEmitter
+
+from .colors import color
+from .hci import HCI_Constant
+from .att import (
+ ATT_ATTRIBUTE_NOT_FOUND_ERROR,
+ ATT_ATTRIBUTE_NOT_LONG_ERROR,
+ ATT_CID,
+ ATT_DEFAULT_MTU,
+ ATT_ERROR_RESPONSE,
+ ATT_INVALID_OFFSET_ERROR,
+ ATT_PDU,
+ ATT_RESPONSES,
+ ATT_Exchange_MTU_Request,
+ ATT_Find_By_Type_Value_Request,
+ ATT_Find_Information_Request,
+ ATT_Handle_Value_Confirmation,
+ ATT_Read_Blob_Request,
+ ATT_Read_By_Group_Type_Request,
+ ATT_Read_By_Type_Request,
+ ATT_Read_Request,
+ ATT_Write_Command,
+ ATT_Write_Request,
+ ATT_Error,
+)
+from . import core
+from .core import UUID, InvalidStateError, ProtocolError
from .gatt import (
+ GATT_CHARACTERISTIC_ATTRIBUTE_TYPE,
GATT_CLIENT_CHARACTERISTIC_CONFIGURATION_DESCRIPTOR,
- GATT_REQUEST_TIMEOUT,
GATT_PRIMARY_SERVICE_ATTRIBUTE_TYPE,
+ GATT_REQUEST_TIMEOUT,
GATT_SECONDARY_SERVICE_ATTRIBUTE_TYPE,
- GATT_CHARACTERISTIC_ATTRIBUTE_TYPE,
- Characteristic
+ GATT_INCLUDE_ATTRIBUTE_TYPE,
+ Characteristic,
+ ClientCharacteristicConfigurationBits,
)
# -----------------------------------------------------------------------------
@@ -50,38 +78,59 @@ logger = logging.getLogger(__name__)
# Proxies
# -----------------------------------------------------------------------------
class AttributeProxy(EventEmitter):
+ client: Client
+
def __init__(self, client, handle, end_group_handle, attribute_type):
EventEmitter.__init__(self)
- self.client = client
- self.handle = handle
+ self.client = client
+ self.handle = handle
self.end_group_handle = end_group_handle
- self.type = attribute_type
+ self.type = attribute_type
async def read_value(self, no_long_read=False):
- return await self.client.read_value(self.handle, no_long_read)
+ return self.decode_value(
+ await self.client.read_value(self.handle, no_long_read)
+ )
async def write_value(self, value, with_response=False):
- return await self.client.write_value(self.handle, value, with_response)
+ return await self.client.write_value(
+ self.handle, self.encode_value(value), with_response
+ )
+
+ def encode_value(self, value):
+ return value
+
+ def decode_value(self, value_bytes):
+ return value_bytes
def __str__(self):
- return f'Attribute(handle=0x{self.handle:04X}, type={self.uuid})'
+ return f'Attribute(handle=0x{self.handle:04X}, type={self.type})'
class ServiceProxy(AttributeProxy):
+ uuid: UUID
+ characteristics: List[CharacteristicProxy]
+ included_services: List[ServiceProxy]
+
@staticmethod
- def from_client(cls, client, service_uuid):
- # The service and its characteristics are considered to have already been discovered
+ def from_client(service_class, client, service_uuid):
+ # The service and its characteristics are considered to have already been
+ # discovered
services = client.get_services_by_uuid(service_uuid)
service = services[0] if services else None
- return cls(service) if service else None
+ return service_class(service) if service else None
def __init__(self, client, handle, end_group_handle, uuid, primary=True):
- attribute_type = GATT_PRIMARY_SERVICE_ATTRIBUTE_TYPE if primary else GATT_SECONDARY_SERVICE_ATTRIBUTE_TYPE
+ attribute_type = (
+ GATT_PRIMARY_SERVICE_ATTRIBUTE_TYPE
+ if primary
+ else GATT_SECONDARY_SERVICE_ATTRIBUTE_TYPE
+ )
super().__init__(client, handle, end_group_handle, attribute_type)
- self.uuid = uuid
+ self.uuid = uuid
self.characteristics = []
- async def discover_characteristics(self, uuids=[]):
+ async def discover_characteristics(self, uuids=()):
return await self.client.discover_characteristics(uuids, self)
def get_characteristics_by_uuid(self, uuid):
@@ -92,26 +141,66 @@ class ServiceProxy(AttributeProxy):
class CharacteristicProxy(AttributeProxy):
- def __init__(self, client, handle, end_group_handle, uuid, properties):
+ properties: Characteristic.Properties
+ descriptors: List[DescriptorProxy]
+ subscribers: Dict[Any, Callable]
+
+ def __init__(
+ self,
+ client,
+ handle,
+ end_group_handle,
+ uuid,
+ properties: int,
+ ):
super().__init__(client, handle, end_group_handle, uuid)
- self.uuid = uuid
- self.properties = properties
- self.descriptors = []
+ self.uuid = uuid
+ self.properties = Characteristic.Properties(properties)
+ self.descriptors = []
self.descriptors_discovered = False
+ self.subscribers = {} # Map from subscriber to proxy subscriber
def get_descriptor(self, descriptor_type):
for descriptor in self.descriptors:
if descriptor.type == descriptor_type:
return descriptor
+ return None
+
async def discover_descriptors(self):
return await self.client.discover_descriptors(self)
- async def subscribe(self, subscriber=None):
- return await self.client.subscribe(self, subscriber)
+ async def subscribe(
+ self, subscriber: Optional[Callable] = None, prefer_notify=True
+ ):
+ if subscriber is not None:
+ if subscriber in self.subscribers:
+ # We already have a proxy subscriber
+ subscriber = self.subscribers[subscriber]
+ else:
+ # Create and register a proxy that will decode the value
+ original_subscriber = subscriber
+
+ def on_change(value):
+ original_subscriber(self.decode_value(value))
+
+ self.subscribers[subscriber] = on_change
+ subscriber = on_change
+
+ return await self.client.subscribe(self, subscriber, prefer_notify)
+
+ async def unsubscribe(self, subscriber=None):
+ if subscriber in self.subscribers:
+ subscriber = self.subscribers.pop(subscriber)
+
+ return await self.client.unsubscribe(self, subscriber)
def __str__(self):
- return f'Characteristic(handle=0x{self.handle:04X}, uuid={self.uuid}, properties={Characteristic.properties_as_string(self.properties)})'
+ return (
+ f'Characteristic(handle=0x{self.handle:04X}, '
+ f'uuid={self.uuid}, '
+ f'{self.properties!s})'
+ )
class DescriptorProxy(AttributeProxy):
@@ -126,6 +215,7 @@ class ProfileServiceProxy:
'''
Base class for profile-specific service proxies
'''
+
@classmethod
def from_client(cls, client):
return ServiceProxy.from_client(cls, client, cls.SERVICE_CLASS.UUID)
@@ -135,51 +225,65 @@ class ProfileServiceProxy:
# GATT Client
# -----------------------------------------------------------------------------
class Client:
+ services: List[ServiceProxy]
+ cached_values: Dict[int, Tuple[datetime, bytes]]
+
def __init__(self, connection):
- self.connection = connection
- self.mtu = ATT_DEFAULT_MTU
- self.mtu_exchange_done = False
- self.request_semaphore = asyncio.Semaphore(1)
- self.pending_request = None
- self.pending_response = None
- self.notification_subscribers = {} # Notification subscribers, by attribute handle
- self.indication_subscribers = {} # Indication subscribers, by attribute handle
- self.services = []
+ self.connection = connection
+ self.mtu_exchange_done = False
+ self.request_semaphore = asyncio.Semaphore(1)
+ self.pending_request = None
+ self.pending_response = None
+ self.notification_subscribers = (
+ {}
+ ) # Notification subscribers, by attribute handle
+ self.indication_subscribers = {} # Indication subscribers, by attribute handle
+ self.services = []
+ self.cached_values = {}
def send_gatt_pdu(self, pdu):
self.connection.send_l2cap_pdu(ATT_CID, pdu)
async def send_command(self, command):
- logger.debug(f'GATT Command from client: [0x{self.connection.handle:04X}] {command}')
+ logger.debug(
+ f'GATT Command from client: [0x{self.connection.handle:04X}] {command}'
+ )
self.send_gatt_pdu(command.to_bytes())
async def send_request(self, request):
- logger.debug(f'GATT Request from client: [0x{self.connection.handle:04X}] {request}')
+ logger.debug(
+ f'GATT Request from client: [0x{self.connection.handle:04X}] {request}'
+ )
# Wait until we can send (only one pending command at a time for the connection)
response = None
async with self.request_semaphore:
- assert(self.pending_request is None)
- assert(self.pending_response is None)
+ assert self.pending_request is None
+ assert self.pending_response is None
# Create a future value to hold the eventual response
self.pending_response = asyncio.get_running_loop().create_future()
- self.pending_request = request
+ self.pending_request = request
try:
self.send_gatt_pdu(request.to_bytes())
- response = await asyncio.wait_for(self.pending_response, GATT_REQUEST_TIMEOUT)
- except asyncio.TimeoutError:
+ response = await asyncio.wait_for(
+ self.pending_response, GATT_REQUEST_TIMEOUT
+ )
+ except asyncio.TimeoutError as error:
logger.warning(color('!!! GATT Request timeout', 'red'))
- raise TimeoutError(f'GATT timeout for {request.name}')
+ raise core.TimeoutError(f'GATT timeout for {request.name}') from error
finally:
- self.pending_request = None
+ self.pending_request = None
self.pending_response = None
return response
def send_confirmation(self, confirmation):
- logger.debug(f'GATT Confirmation from client: [0x{self.connection.handle:04X}] {confirmation}')
+ logger.debug(
+ f'GATT Confirmation from client: [0x{self.connection.handle:04X}] '
+ f'{confirmation}'
+ )
self.send_gatt_pdu(confirmation.to_bytes())
async def request_mtu(self, mtu):
@@ -191,31 +295,66 @@ class Client:
# We can only send one request per connection
if self.mtu_exchange_done:
- return
+ return self.connection.att_mtu
# Send the request
self.mtu_exchange_done = True
- response = await self.send_request(ATT_Exchange_MTU_Request(client_rx_mtu = mtu))
+ response = await self.send_request(ATT_Exchange_MTU_Request(client_rx_mtu=mtu))
if response.op_code == ATT_ERROR_RESPONSE:
raise ProtocolError(
response.error_code,
'att',
ATT_PDU.error_name(response.error_code),
- response
+ response,
)
- self.mtu = max(ATT_DEFAULT_MTU, response.server_rx_mtu)
- return self.mtu
+ # Compute the final MTU
+ self.connection.att_mtu = min(mtu, response.server_rx_mtu)
+
+ return self.connection.att_mtu
def get_services_by_uuid(self, uuid):
return [service for service in self.services if service.uuid == uuid]
- def get_characteristics_by_uuid(self, uuid, service = None):
+ def get_characteristics_by_uuid(self, uuid, service=None):
services = [service] if service else self.services
- return [c for c in [c for s in services for c in s.characteristics] if c.uuid == uuid]
+ return [
+ c
+ for c in [c for s in services for c in s.characteristics]
+ if c.uuid == uuid
+ ]
+
+ def get_attribute_grouping(
+ self, attribute_handle: int
+ ) -> Optional[
+ Union[
+ ServiceProxy,
+ Tuple[ServiceProxy, CharacteristicProxy],
+ Tuple[ServiceProxy, CharacteristicProxy, DescriptorProxy],
+ ]
+ ]:
+ """
+ Get the attribute(s) associated with an attribute handle
+ """
+ for service in self.services:
+ if service.handle == attribute_handle:
+ return service
+ if service.handle <= attribute_handle <= service.end_group_handle:
+ for characteristic in service.characteristics:
+ if characteristic.handle == attribute_handle:
+ return (service, characteristic)
+ if (
+ characteristic.handle
+ <= attribute_handle
+ <= characteristic.end_group_handle
+ ):
+ for descriptor in characteristic.descriptors:
+ if descriptor.handle == attribute_handle:
+ return (service, characteristic, descriptor)
+ return None
def on_service_discovered(self, service):
- ''' Add a service to the service list if it wasn't already there '''
+ '''Add a service to the service list if it wasn't already there'''
already_known = False
for existing_service in self.services:
if existing_service.handle == service.handle:
@@ -224,7 +363,7 @@ class Client:
if not already_known:
self.services.append(service)
- async def discover_services(self, uuids = None):
+ async def discover_services(self, uuids=None) -> List[ServiceProxy]:
'''
See Vol 3, Part G - 4.4.1 Discover All Primary Services
'''
@@ -233,9 +372,9 @@ class Client:
while starting_handle < 0xFFFF:
response = await self.send_request(
ATT_Read_By_Group_Type_Request(
- starting_handle = starting_handle,
- ending_handle = 0xFFFF,
- attribute_group_type = GATT_PRIMARY_SERVICE_ATTRIBUTE_TYPE
+ starting_handle=starting_handle,
+ ending_handle=0xFFFF,
+ attribute_group_type=GATT_PRIMARY_SERVICE_ATTRIBUTE_TYPE,
)
)
if response is None:
@@ -246,16 +385,30 @@ class Client:
if response.op_code == ATT_ERROR_RESPONSE:
if response.error_code != ATT_ATTRIBUTE_NOT_FOUND_ERROR:
# Unexpected end
- logger.waning(f'!!! unexpected error while discovering services: {HCI_Constant.error_name(response.error_code)}')
- # TODO raise appropriate exception
- return
+ logger.warning(
+ '!!! unexpected error while discovering services: '
+ f'{HCI_Constant.error_name(response.error_code)}'
+ )
+ raise ATT_Error(
+ error_code=response.error_code,
+ message='Unexpected error while discovering services',
+ )
break
- for attribute_handle, end_group_handle, attribute_value in response.attributes:
- if attribute_handle < starting_handle or end_group_handle < attribute_handle:
+ for (
+ attribute_handle,
+ end_group_handle,
+ attribute_value,
+ ) in response.attributes:
+ if (
+ attribute_handle < starting_handle
+ or end_group_handle < attribute_handle
+ ):
# Something's not right
- logger.warning(f'bogus handle values: {attribute_handle} {end_group_handle}')
- return
+ logger.warning(
+ f'bogus handle values: {attribute_handle} {end_group_handle}'
+ )
+ return []
# Create a service proxy for this service
service = ServiceProxy(
@@ -263,7 +416,7 @@ class Client:
attribute_handle,
end_group_handle,
UUID.from_bytes(attribute_value),
- True
+ True,
)
# Filter out returned services based on the given uuids list
@@ -288,7 +441,7 @@ class Client:
'''
# Force uuid to be a UUID object
- if type(uuid) is str:
+ if isinstance(uuid, str):
uuid = UUID(uuid)
starting_handle = 0x0001
@@ -296,10 +449,10 @@ class Client:
while starting_handle < 0xFFFF:
response = await self.send_request(
ATT_Find_By_Type_Value_Request(
- starting_handle = starting_handle,
- ending_handle = 0xFFFF,
- attribute_type = GATT_PRIMARY_SERVICE_ATTRIBUTE_TYPE,
- attribute_value = uuid.to_pdu_bytes()
+ starting_handle=starting_handle,
+ ending_handle=0xFFFF,
+ attribute_type=GATT_PRIMARY_SERVICE_ATTRIBUTE_TYPE,
+ attribute_value=uuid.to_pdu_bytes(),
)
)
if response is None:
@@ -310,19 +463,29 @@ class Client:
if response.op_code == ATT_ERROR_RESPONSE:
if response.error_code != ATT_ATTRIBUTE_NOT_FOUND_ERROR:
# Unexpected end
- logger.waning(f'!!! unexpected error while discovering services: {HCI_Constant.error_name(response.error_code)}')
+ logger.warning(
+ '!!! unexpected error while discovering services: '
+ f'{HCI_Constant.error_name(response.error_code)}'
+ )
# TODO raise appropriate exception
return
break
for attribute_handle, end_group_handle in response.handles_information:
- if attribute_handle < starting_handle or end_group_handle < attribute_handle:
+ if (
+ attribute_handle < starting_handle
+ or end_group_handle < attribute_handle
+ ):
# Something's not right
- logger.warning(f'bogus handle values: {attribute_handle} {end_group_handle}')
+ logger.warning(
+ f'bogus handle values: {attribute_handle} {end_group_handle}'
+ )
return
# Create a service proxy for this service
- service = ServiceProxy(self, attribute_handle, end_group_handle, uuid, True)
+ service = ServiceProxy(
+ self, attribute_handle, end_group_handle, uuid, True
+ )
# Add the service to the peer's service list
services.append(service)
@@ -341,37 +504,97 @@ class Client:
return services
- async def discover_included_services(self, service):
+ async def discover_included_services(
+ self, service: ServiceProxy
+ ) -> List[ServiceProxy]:
'''
See Vol 3, Part G - 4.5.1 Find Included Services
'''
- # TODO
- return []
- async def discover_characteristics(self, uuids, service):
+ starting_handle = service.handle
+ ending_handle = service.end_group_handle
+
+ included_services: List[ServiceProxy] = []
+ while starting_handle <= ending_handle:
+ response = await self.send_request(
+ ATT_Read_By_Type_Request(
+ starting_handle=starting_handle,
+ ending_handle=ending_handle,
+ attribute_type=GATT_INCLUDE_ATTRIBUTE_TYPE,
+ )
+ )
+ if response is None:
+ # TODO raise appropriate exception
+ return []
+
+ # Check if we reached the end of the iteration
+ if response.op_code == ATT_ERROR_RESPONSE:
+ if response.error_code != ATT_ATTRIBUTE_NOT_FOUND_ERROR:
+ # Unexpected end
+ logger.warning(
+ '!!! unexpected error while discovering included services: '
+ f'{HCI_Constant.error_name(response.error_code)}'
+ )
+ raise ATT_Error(
+ error_code=response.error_code,
+ message='Unexpected error while discovering included services',
+ )
+ break
+
+ # Stop if for some reason the list was empty
+ if not response.attributes:
+ break
+
+ # Process all included services returned in this iteration
+ for attribute_handle, attribute_value in response.attributes:
+ if attribute_handle < starting_handle:
+ # Something's not right
+ logger.warning(f'bogus handle value: {attribute_handle}')
+ return []
+
+ group_starting_handle, group_ending_handle = struct.unpack_from(
+ '<HH', attribute_value
+ )
+ service_uuid = UUID.from_bytes(attribute_value[4:])
+ included_service = ServiceProxy(
+ self, group_starting_handle, group_ending_handle, service_uuid, True
+ )
+
+ included_services.append(included_service)
+
+ # Move on to the next included services
+ starting_handle = response.attributes[-1][0] + 1
+
+ service.included_services = included_services
+ return included_services
+
+ async def discover_characteristics(
+ self, uuids, service: Optional[ServiceProxy]
+ ) -> List[CharacteristicProxy]:
'''
- See Vol 3, Part G - 4.6.1 Discover All Characteristics of a Service and 4.6.2 Discover Characteristics by UUID
+ See Vol 3, Part G - 4.6.1 Discover All Characteristics of a Service and 4.6.2
+ Discover Characteristics by UUID
'''
# Cast the UUIDs type from string to object if needed
- uuids = [UUID(uuid) if type(uuid) is str else uuid for uuid in uuids]
+ uuids = [UUID(uuid) if isinstance(uuid, str) else uuid for uuid in uuids]
# Decide which services to discover for
services = [service] if service else self.services
# Perform characteristic discovery for each service
- discovered_characteristics = []
+ discovered_characteristics: List[CharacteristicProxy] = []
for service in services:
starting_handle = service.handle
- ending_handle = service.end_group_handle
+ ending_handle = service.end_group_handle
- characteristics = []
+ characteristics: List[CharacteristicProxy] = []
while starting_handle <= ending_handle:
response = await self.send_request(
ATT_Read_By_Type_Request(
- starting_handle = starting_handle,
- ending_handle = ending_handle,
- attribute_type = GATT_CHARACTERISTIC_ATTRIBUTE_TYPE
+ starting_handle=starting_handle,
+ ending_handle=ending_handle,
+ attribute_type=GATT_CHARACTERISTIC_ATTRIBUTE_TYPE,
)
)
if response is None:
@@ -382,9 +605,14 @@ class Client:
if response.op_code == ATT_ERROR_RESPONSE:
if response.error_code != ATT_ATTRIBUTE_NOT_FOUND_ERROR:
# Unexpected end
- logger.warning(f'!!! unexpected error while discovering characteristics: {HCI_Constant.error_name(response.error_code)}')
- # TODO raise appropriate exception
- return
+ logger.warning(
+ '!!! unexpected error while discovering characteristics: '
+ f'{HCI_Constant.error_name(response.error_code)}'
+ )
+ raise ATT_Error(
+ error_code=response.error_code,
+ message='Unexpected error while discovering characteristics',
+ )
break
# Stop if for some reason the list was empty
@@ -400,7 +628,9 @@ class Client:
properties, handle = struct.unpack_from('<BH', attribute_value)
characteristic_uuid = UUID.from_bytes(attribute_value[3:])
- characteristic = CharacteristicProxy(self, handle, 0, characteristic_uuid, properties)
+ characteristic = CharacteristicProxy(
+ self, handle, 0, characteristic_uuid, properties
+ )
# Set the previous characteristic's end handle
if characteristics:
@@ -416,31 +646,37 @@ class Client:
characteristics[-1].end_group_handle = service.end_group_handle
# Set the service's characteristics
- characteristics = [c for c in characteristics if not uuids or c.uuid in uuids]
+ characteristics = [
+ c for c in characteristics if not uuids or c.uuid in uuids
+ ]
service.characteristics = characteristics
discovered_characteristics.extend(characteristics)
return discovered_characteristics
- async def discover_descriptors(self, characteristic = None, start_handle = None, end_handle = None):
+ async def discover_descriptors(
+ self,
+ characteristic: Optional[CharacteristicProxy] = None,
+ start_handle=None,
+ end_handle=None,
+ ) -> List[DescriptorProxy]:
'''
See Vol 3, Part G - 4.7.1 Discover All Characteristic Descriptors
'''
if characteristic:
starting_handle = characteristic.handle + 1
- ending_handle = characteristic.end_group_handle
+ ending_handle = characteristic.end_group_handle
elif start_handle and end_handle:
starting_handle = start_handle
- ending_handle = end_handle
+ ending_handle = end_handle
else:
return []
- descriptors = []
+ descriptors: List[DescriptorProxy] = []
while starting_handle <= ending_handle:
response = await self.send_request(
ATT_Find_Information_Request(
- starting_handle = starting_handle,
- ending_handle = ending_handle
+ starting_handle=starting_handle, ending_handle=ending_handle
)
)
if response is None:
@@ -451,7 +687,10 @@ class Client:
if response.op_code == ATT_ERROR_RESPONSE:
if response.error_code != ATT_ATTRIBUTE_NOT_FOUND_ERROR:
# Unexpected end
- logger.warning(f'!!! unexpected error while discovering descriptors: {HCI_Constant.error_name(response.error_code)}')
+ logger.warning(
+ '!!! unexpected error while discovering descriptors: '
+ f'{HCI_Constant.error_name(response.error_code)}'
+ )
# TODO raise appropriate exception
return []
break
@@ -467,7 +706,9 @@ class Client:
logger.warning(f'bogus handle value: {attribute_handle}')
return []
- descriptor = DescriptorProxy(self, attribute_handle, UUID.from_bytes(attribute_uuid))
+ descriptor = DescriptorProxy(
+ self, attribute_handle, UUID.from_bytes(attribute_uuid)
+ )
descriptors.append(descriptor)
# TODO: read descriptor value
@@ -485,13 +726,12 @@ class Client:
Discover all attributes, regardless of type
'''
starting_handle = 0x0001
- ending_handle = 0xFFFF
+ ending_handle = 0xFFFF
attributes = []
while True:
response = await self.send_request(
ATT_Find_Information_Request(
- starting_handle = starting_handle,
- ending_handle = ending_handle
+ starting_handle=starting_handle, ending_handle=ending_handle
)
)
if response is None:
@@ -501,7 +741,10 @@ class Client:
if response.op_code == ATT_ERROR_RESPONSE:
if response.error_code != ATT_ATTRIBUTE_NOT_FOUND_ERROR:
# Unexpected end
- logger.warning(f'!!! unexpected error while discovering attributes: {HCI_Constant.error_name(response.error_code)}')
+ logger.warning(
+ '!!! unexpected error while discovering attributes: '
+ f'{HCI_Constant.error_name(response.error_code)}'
+ )
return []
break
@@ -511,7 +754,9 @@ class Client:
logger.warning(f'bogus handle value: {attribute_handle}')
return []
- attribute = AttributeProxy(self, attribute_handle, 0, UUID.from_bytes(attribute_uuid))
+ attribute = AttributeProxy(
+ self, attribute_handle, 0, UUID.from_bytes(attribute_uuid)
+ )
attributes.append(attribute)
# Move on to the next attributes
@@ -519,35 +764,86 @@ class Client:
return attributes
- async def subscribe(self, characteristic, subscriber=None):
- # If we haven't already discovered the descriptors for this characteristic, do it now
+ async def subscribe(self, characteristic, subscriber=None, prefer_notify=True):
+ # If we haven't already discovered the descriptors for this characteristic,
+ # do it now
if not characteristic.descriptors_discovered:
await self.discover_descriptors(characteristic)
# Look for the CCCD descriptor
- cccd = characteristic.get_descriptor(GATT_CLIENT_CHARACTERISTIC_CONFIGURATION_DESCRIPTOR)
+ cccd = characteristic.get_descriptor(
+ GATT_CLIENT_CHARACTERISTIC_CONFIGURATION_DESCRIPTOR
+ )
if not cccd:
logger.warning('subscribing to characteristic with no CCCD descriptor')
return
- # Set the subscription bits and select the subscriber set
- bits = 0
- subscriber_sets = []
- if characteristic.properties & Characteristic.NOTIFY:
- bits |= 0x0001
- subscriber_sets.append(self.notification_subscribers.setdefault(characteristic.handle, set()))
- if characteristic.properties & Characteristic.INDICATE:
- bits |= 0x0002
- subscriber_sets.append(self.indication_subscribers.setdefault(characteristic.handle, set()))
+ if (
+ characteristic.properties & Characteristic.Properties.NOTIFY
+ and characteristic.properties & Characteristic.Properties.INDICATE
+ ):
+ if prefer_notify:
+ bits = ClientCharacteristicConfigurationBits.NOTIFICATION
+ subscribers = self.notification_subscribers
+ else:
+ bits = ClientCharacteristicConfigurationBits.INDICATION
+ subscribers = self.indication_subscribers
+ elif characteristic.properties & Characteristic.Properties.NOTIFY:
+ bits = ClientCharacteristicConfigurationBits.NOTIFICATION
+ subscribers = self.notification_subscribers
+ elif characteristic.properties & Characteristic.Properties.INDICATE:
+ bits = ClientCharacteristicConfigurationBits.INDICATION
+ subscribers = self.indication_subscribers
+ else:
+ raise InvalidStateError("characteristic is not notify or indicate")
# Add subscribers to the sets
- for subscriber_set in subscriber_sets:
- if subscriber is not None:
- subscriber_set.add(subscriber)
- subscriber_set.add(lambda value: characteristic.emit('update', self.connection, value))
+ subscriber_set = subscribers.setdefault(characteristic.handle, set())
+ if subscriber is not None:
+ subscriber_set.add(subscriber)
+ # Add the characteristic as a subscriber, which will result in the
+ # characteristic emitting an 'update' event when a notification or indication
+ # is received
+ subscriber_set.add(characteristic)
await self.write_value(cccd, struct.pack('<H', bits), with_response=True)
+ async def unsubscribe(self, characteristic, subscriber=None):
+ # If we haven't already discovered the descriptors for this characteristic,
+ # do it now
+ if not characteristic.descriptors_discovered:
+ await self.discover_descriptors(characteristic)
+
+ # Look for the CCCD descriptor
+ cccd = characteristic.get_descriptor(
+ GATT_CLIENT_CHARACTERISTIC_CONFIGURATION_DESCRIPTOR
+ )
+ if not cccd:
+ logger.warning('unsubscribing from characteristic with no CCCD descriptor')
+ return
+
+ if subscriber is not None:
+ # Remove matching subscriber from subscriber sets
+ for subscriber_set in (
+ self.notification_subscribers,
+ self.indication_subscribers,
+ ):
+ subscribers = subscriber_set.get(characteristic.handle, [])
+ if subscriber in subscribers:
+ subscribers.remove(subscriber)
+
+ # Cleanup if we removed the last one
+ if not subscribers:
+ del subscriber_set[characteristic.handle]
+ else:
+ # Remove all subscribers for this attribute from the sets!
+ self.notification_subscribers.pop(characteristic.handle, None)
+ self.indication_subscribers.pop(characteristic.handle, None)
+
+ if not self.notification_subscribers and not self.indication_subscribers:
+ # No more subscribers left
+ await self.write_value(cccd, b'\x00\x00', with_response=True)
+
async def read_value(self, attribute, no_long_read=False):
'''
See Vol 3, Part G - 4.8.1 Read Characteristic Value
@@ -556,8 +852,10 @@ class Client:
'''
# Send a request to read
- attribute_handle = attribute if type(attribute) is int else attribute.handle
- response = await self.send_request(ATT_Read_Request(attribute_handle = attribute_handle))
+ attribute_handle = attribute if isinstance(attribute, int) else attribute.handle
+ response = await self.send_request(
+ ATT_Read_Request(attribute_handle=attribute_handle)
+ )
if response is None:
raise TimeoutError('read timeout')
if response.op_code == ATT_ERROR_RESPONSE:
@@ -565,39 +863,45 @@ class Client:
response.error_code,
'att',
ATT_PDU.error_name(response.error_code),
- response
+ response,
)
# If the value is the max size for the MTU, try to read more unless the caller
# specifically asked not to do that
attribute_value = response.attribute_value
- if not no_long_read and len(attribute_value) == self.mtu - 1:
+ if not no_long_read and len(attribute_value) == self.connection.att_mtu - 1:
logger.debug('using READ BLOB to get the rest of the value')
offset = len(attribute_value)
while True:
response = await self.send_request(
- ATT_Read_Blob_Request(attribute_handle = attribute_handle, value_offset = offset)
+ ATT_Read_Blob_Request(
+ attribute_handle=attribute_handle, value_offset=offset
+ )
)
if response is None:
raise TimeoutError('read timeout')
if response.op_code == ATT_ERROR_RESPONSE:
- if response.error_code == ATT_ATTRIBUTE_NOT_LONG_ERROR or response.error_code == ATT_INVALID_OFFSET_ERROR:
+ if response.error_code in (
+ ATT_ATTRIBUTE_NOT_LONG_ERROR,
+ ATT_INVALID_OFFSET_ERROR,
+ ):
break
raise ProtocolError(
response.error_code,
'att',
ATT_PDU.error_name(response.error_code),
- response
+ response,
)
part = response.part_attribute_value
attribute_value += part
- if len(part) < self.mtu - 1:
+ if len(part) < self.connection.att_mtu - 1:
break
offset += len(part)
+ self.cache_value(attribute_handle, attribute_value)
# Return the value as bytes
return attribute_value
@@ -608,18 +912,18 @@ class Client:
if service is None:
starting_handle = 0x0001
- ending_handle = 0xFFFF
+ ending_handle = 0xFFFF
else:
starting_handle = service.handle
- ending_handle = service.end_group_handle
+ ending_handle = service.end_group_handle
characteristics_values = []
while starting_handle <= ending_handle:
response = await self.send_request(
ATT_Read_By_Type_Request(
- starting_handle = starting_handle,
- ending_handle = ending_handle,
- attribute_type = uuid
+ starting_handle=starting_handle,
+ ending_handle=ending_handle,
+ attribute_type=uuid,
)
)
if response is None:
@@ -630,7 +934,10 @@ class Client:
if response.op_code == ATT_ERROR_RESPONSE:
if response.error_code != ATT_ATTRIBUTE_NOT_FOUND_ERROR:
# Unexpected end
- logger.warning(f'!!! unexpected error while reading characteristics: {HCI_Constant.error_name(response.error_code)}')
+ logger.warning(
+ '!!! unexpected error while reading characteristics: '
+ f'{HCI_Constant.error_name(response.error_code)}'
+ )
# TODO raise appropriate exception
return []
break
@@ -655,47 +962,54 @@ class Client:
async def write_value(self, attribute, value, with_response=False):
'''
- See Vol 3, Part G - 4.9.1 Write Without Response & 4.9.3 Write Characteristic Value
+ See Vol 3, Part G - 4.9.1 Write Without Response & 4.9.3 Write Characteristic
+ Value
`attribute` can be an Attribute object, or a handle value
'''
# Send a request or command to write
- attribute_handle = attribute if type(attribute) is int else attribute.handle
+ attribute_handle = attribute if isinstance(attribute, int) else attribute.handle
if with_response:
response = await self.send_request(
ATT_Write_Request(
- attribute_handle = attribute_handle,
- attribute_value = value
+ attribute_handle=attribute_handle, attribute_value=value
)
)
if response.op_code == ATT_ERROR_RESPONSE:
raise ProtocolError(
response.error_code,
'att',
- ATT_PDU.error_name(response.error_code), response
+ ATT_PDU.error_name(response.error_code),
+ response,
)
else:
await self.send_command(
ATT_Write_Command(
- attribute_handle = attribute_handle,
- attribute_value = value
+ attribute_handle=attribute_handle, attribute_value=value
)
)
def on_gatt_pdu(self, att_pdu):
- logger.debug(f'GATT Response to client: [0x{self.connection.handle:04X}] {att_pdu}')
+ logger.debug(
+ f'GATT Response to client: [0x{self.connection.handle:04X}] {att_pdu}'
+ )
if att_pdu.op_code in ATT_RESPONSES:
if self.pending_request is None:
# Not expected!
logger.warning('!!! unexpected response, there is no pending request')
return
- # Sanity check: the response should match the pending request unless it is an error response
+ # Sanity check: the response should match the pending request unless it is
+ # an error response
if att_pdu.op_code != ATT_ERROR_RESPONSE:
- expected_response_name = self.pending_request.name.replace('_REQUEST', '_RESPONSE')
+ expected_response_name = self.pending_request.name.replace(
+ '_REQUEST', '_RESPONSE'
+ )
if att_pdu.name != expected_response_name:
- logger.warning(f'!!! mismatched response: expected {expected_response_name}')
+ logger.warning(
+ f'!!! mismatched response: expected {expected_response_name}'
+ )
return
# Return the response to the coroutine that is waiting for it
@@ -706,23 +1020,48 @@ class Client:
if handler is not None:
handler(att_pdu)
else:
- logger.warning(f'{color(f"--- Ignoring GATT Response from [0x{self.connection.handle:04X}]:", "red")} {att_pdu}')
+ logger.warning(
+ color(
+ '--- Ignoring GATT Response from '
+ f'[0x{self.connection.handle:04X}]: ',
+ 'red',
+ )
+ + str(att_pdu)
+ )
def on_att_handle_value_notification(self, notification):
# Call all subscribers
- subscribers = self.notification_subscribers.get(notification.attribute_handle, [])
+ subscribers = self.notification_subscribers.get(
+ notification.attribute_handle, []
+ )
if not subscribers:
logger.warning('!!! received notification with no subscriber')
+
+ self.cache_value(notification.attribute_handle, notification.attribute_value)
for subscriber in subscribers:
- subscriber(notification.attribute_value)
+ if callable(subscriber):
+ subscriber(notification.attribute_value)
+ else:
+ subscriber.emit('update', notification.attribute_value)
def on_att_handle_value_indication(self, indication):
# Call all subscribers
subscribers = self.indication_subscribers.get(indication.attribute_handle, [])
if not subscribers:
logger.warning('!!! received indication with no subscriber')
+
+ self.cache_value(indication.attribute_handle, indication.attribute_value)
for subscriber in subscribers:
- subscriber(indication.attribute_value)
+ if callable(subscriber):
+ subscriber(indication.attribute_value)
+ else:
+ subscriber.emit('update', indication.attribute_value)
# Confirm that we received the indication
self.send_confirmation(ATT_Handle_Value_Confirmation())
+
+ def cache_value(self, attribute_handle: int, value: bytes):
+ self.cached_values[attribute_handle] = (
+ datetime.now(),
+ value,
+ )
diff --git a/bumble/gatt_server.py b/bumble/gatt_server.py
index 3afcecc..3624905 100644
--- a/bumble/gatt_server.py
+++ b/bumble/gatt_server.py
@@ -26,13 +26,53 @@
import asyncio
import logging
from collections import defaultdict
+import struct
+from typing import List, Tuple, Optional, TypeVar, Type
from pyee import EventEmitter
-from colors import color
-from .core import *
-from .hci import *
-from .att import *
-from .gatt import *
+from .colors import color
+from .core import UUID
+from .att import (
+ ATT_ATTRIBUTE_NOT_FOUND_ERROR,
+ ATT_ATTRIBUTE_NOT_LONG_ERROR,
+ ATT_CID,
+ ATT_DEFAULT_MTU,
+ ATT_INVALID_ATTRIBUTE_LENGTH_ERROR,
+ ATT_INVALID_HANDLE_ERROR,
+ ATT_INVALID_OFFSET_ERROR,
+ ATT_REQUEST_NOT_SUPPORTED_ERROR,
+ ATT_REQUESTS,
+ ATT_UNLIKELY_ERROR_ERROR,
+ ATT_UNSUPPORTED_GROUP_TYPE_ERROR,
+ ATT_Error,
+ ATT_Error_Response,
+ ATT_Exchange_MTU_Response,
+ ATT_Find_By_Type_Value_Response,
+ ATT_Find_Information_Response,
+ ATT_Handle_Value_Indication,
+ ATT_Handle_Value_Notification,
+ ATT_Read_Blob_Response,
+ ATT_Read_By_Group_Type_Response,
+ ATT_Read_By_Type_Response,
+ ATT_Read_Response,
+ ATT_Write_Response,
+ Attribute,
+)
+from .gatt import (
+ GATT_CHARACTERISTIC_ATTRIBUTE_TYPE,
+ GATT_CLIENT_CHARACTERISTIC_CONFIGURATION_DESCRIPTOR,
+ GATT_MAX_ATTRIBUTE_VALUE_SIZE,
+ GATT_PRIMARY_SERVICE_ATTRIBUTE_TYPE,
+ GATT_REQUEST_TIMEOUT,
+ GATT_SECONDARY_SERVICE_ATTRIBUTE_TYPE,
+ Characteristic,
+ CharacteristicDeclaration,
+ CharacteristicValue,
+ IncludedServiceDeclaration,
+ Descriptor,
+ Service,
+)
+
# -----------------------------------------------------------------------------
# Logging
@@ -41,26 +81,49 @@ logger = logging.getLogger(__name__)
# -----------------------------------------------------------------------------
+# Constants
+# -----------------------------------------------------------------------------
+GATT_SERVER_DEFAULT_MAX_MTU = 517
+
+
+# -----------------------------------------------------------------------------
# GATT Server
# -----------------------------------------------------------------------------
class Server(EventEmitter):
+ attributes: List[Attribute]
+
def __init__(self, device):
super().__init__()
- self.device = device
- self.attributes = [] # Attributes, ordered by increasing handle values
- self.attributes_by_handle = {} # Map for fast attribute access by handle
- self.max_mtu = 23 # FIXME: 517 # The max MTU we're willing to negotiate
- self.subscribers = {} # Map of subscriber states by connection handle and attribute handle
- self.mtus = {} # Map of ATT MTU values by connection handle
+ self.device = device
+ self.services = []
+ self.attributes = [] # Attributes, ordered by increasing handle values
+ self.attributes_by_handle = {} # Map for fast attribute access by handle
+ self.max_mtu = (
+ GATT_SERVER_DEFAULT_MAX_MTU # The max MTU we're willing to negotiate
+ )
+ self.subscribers = (
+ {}
+ ) # Map of subscriber states by connection handle and attribute handle
self.indication_semaphores = defaultdict(lambda: asyncio.Semaphore(1))
self.pending_confirmations = defaultdict(lambda: None)
+ def __str__(self):
+ return "\n".join(map(str, self.attributes))
+
def send_gatt_pdu(self, connection_handle, pdu):
self.device.send_l2cap_pdu(connection_handle, ATT_CID, pdu)
def next_handle(self):
return 1 + len(self.attributes)
+ def get_advertising_service_data(self):
+ return {
+ attribute: data
+ for attribute in self.attributes
+ if isinstance(attribute, Service)
+ and (data := attribute.get_advertising_data())
+ }
+
def get_attribute(self, handle):
attribute = self.attributes_by_handle.get(handle)
if attribute:
@@ -74,32 +137,107 @@ class Server(EventEmitter):
return attribute
return None
+ AttributeGroupType = TypeVar('AttributeGroupType', Service, Characteristic)
+
+ def get_attribute_group(
+ self, handle: int, group_type: Type[AttributeGroupType]
+ ) -> Optional[AttributeGroupType]:
+ return next(
+ (
+ attribute
+ for attribute in self.attributes
+ if isinstance(attribute, group_type)
+ and attribute.handle <= handle <= attribute.end_group_handle
+ ),
+ None,
+ )
+
+ def get_service_attribute(self, service_uuid: UUID) -> Optional[Service]:
+ return next(
+ (
+ attribute
+ for attribute in self.attributes
+ if attribute.type == GATT_PRIMARY_SERVICE_ATTRIBUTE_TYPE
+ and isinstance(attribute, Service)
+ and attribute.uuid == service_uuid
+ ),
+ None,
+ )
+
+ def get_characteristic_attributes(
+ self, service_uuid: UUID, characteristic_uuid: UUID
+ ) -> Optional[Tuple[CharacteristicDeclaration, Characteristic]]:
+ service_handle = self.get_service_attribute(service_uuid)
+ if not service_handle:
+ return None
+
+ return next(
+ (
+ (attribute, self.get_attribute(attribute.characteristic.handle))
+ for attribute in map(
+ self.get_attribute,
+ range(service_handle.handle, service_handle.end_group_handle + 1),
+ )
+ if attribute.type == GATT_CHARACTERISTIC_ATTRIBUTE_TYPE
+ and attribute.characteristic.uuid == characteristic_uuid
+ ),
+ None,
+ )
+
+ def get_descriptor_attribute(
+ self, service_uuid: UUID, characteristic_uuid: UUID, descriptor_uuid: UUID
+ ) -> Optional[Descriptor]:
+ characteristics = self.get_characteristic_attributes(
+ service_uuid, characteristic_uuid
+ )
+ if not characteristics:
+ return None
+
+ (_, characteristic_value) = characteristics
+
+ return next(
+ (
+ attribute
+ for attribute in map(
+ self.get_attribute,
+ range(
+ characteristic_value.handle + 1,
+ characteristic_value.end_group_handle + 1,
+ ),
+ )
+ if attribute.type == descriptor_uuid
+ ),
+ None,
+ )
+
def add_attribute(self, attribute):
# Assign a handle to this attribute
attribute.handle = self.next_handle()
- attribute.end_group_handle = attribute.handle # TODO: keep track of descriptors in the group
+ attribute.end_group_handle = (
+ attribute.handle
+ ) # TODO: keep track of descriptors in the group
# Add this attribute to the list
self.attributes.append(attribute)
- def add_service(self, service):
+ def add_service(self, service: Service):
# Add the service attribute to the DB
self.add_attribute(service)
- # TODO: add included services
+ # Add all included service
+ for included_service in service.included_services:
+ # Not registered yet, register the included service first.
+ if included_service not in self.services:
+ self.add_service(included_service)
+ # TODO: Handle circular service reference
+ include_declaration = IncludedServiceDeclaration(included_service)
+ self.add_attribute(include_declaration)
# Add all characteristics
for characteristic in service.characteristics:
- # Add a Characteristic Declaration (Vol 3, Part G - 3.3.1 Characteristic Declaration)
- declaration_bytes = struct.pack(
- '<BH',
- characteristic.properties,
- self.next_handle() + 1, # The value will be the next attribute after this declaration
- ) + characteristic.uuid.to_pdu_bytes()
- characteristic_declaration = Attribute(
- GATT_CHARACTERISTIC_ATTRIBUTE_TYPE,
- Attribute.READABLE,
- declaration_bytes
+ # Add a Characteristic Declaration
+ characteristic_declaration = CharacteristicDeclaration(
+ characteristic, self.next_handle() + 1
)
self.add_attribute(characteristic_declaration)
@@ -113,17 +251,29 @@ class Server(EventEmitter):
# If the characteristic supports subscriptions, add a CCCD descriptor
# unless there is one already
if (
- characteristic.properties & (Characteristic.NOTIFY | Characteristic.INDICATE) and
- characteristic.get_descriptor(GATT_CLIENT_CHARACTERISTIC_CONFIGURATION_DESCRIPTOR) is None
+ characteristic.properties
+ & (
+ Characteristic.Properties.NOTIFY
+ | Characteristic.Properties.INDICATE
+ )
+ and characteristic.get_descriptor(
+ GATT_CLIENT_CHARACTERISTIC_CONFIGURATION_DESCRIPTOR
+ )
+ is None
):
self.add_attribute(
+ # pylint: disable=line-too-long
Descriptor(
GATT_CLIENT_CHARACTERISTIC_CONFIGURATION_DESCRIPTOR,
Attribute.READABLE | Attribute.WRITEABLE,
CharacteristicValue(
- read=lambda connection, characteristic=characteristic: self.read_cccd(connection, characteristic),
- write=lambda connection, value, characteristic=characteristic: self.write_cccd(connection, characteristic, value)
- )
+ read=lambda connection, characteristic=characteristic: self.read_cccd(
+ connection, characteristic
+ ),
+ write=lambda connection, value, characteristic=characteristic: self.write_cccd(
+ connection, characteristic, value
+ ),
+ ),
)
)
@@ -133,6 +283,7 @@ class Server(EventEmitter):
# Update the service group end
service.end_group_handle = self.attributes[-1].handle
+ self.services.append(service)
def add_services(self, services):
for service in services:
@@ -150,26 +301,39 @@ class Server(EventEmitter):
return cccd or bytes([0, 0])
def write_cccd(self, connection, characteristic, value):
- logger.debug(f'Subscription update for connection={connection.handle:04X}, handle={characteristic.handle:04X}: {value.hex()}')
+ logger.debug(
+ f'Subscription update for connection=0x{connection.handle:04X}, '
+ f'handle=0x{characteristic.handle:04X}: {value.hex()}'
+ )
# Sanity check
if len(value) != 2:
- logger.warn('CCCD value not 2 bytes long')
+ logger.warning('CCCD value not 2 bytes long')
return
cccds = self.subscribers.setdefault(connection.handle, {})
cccds[characteristic.handle] = value
logger.debug(f'CCCDs: {cccds}')
- notify_enabled = (value[0] & 0x01 != 0)
- indicate_enabled = (value[0] & 0x02 != 0)
- characteristic.emit('subscription', connection, notify_enabled, indicate_enabled)
- self.emit('characteristic_subscription', connection, characteristic, notify_enabled, indicate_enabled)
+ notify_enabled = value[0] & 0x01 != 0
+ indicate_enabled = value[0] & 0x02 != 0
+ characteristic.emit(
+ 'subscription', connection, notify_enabled, indicate_enabled
+ )
+ self.emit(
+ 'characteristic_subscription',
+ connection,
+ characteristic,
+ notify_enabled,
+ indicate_enabled,
+ )
def send_response(self, connection, response):
- logger.debug(f'GATT Response from server: [0x{connection.handle:04X}] {response}')
+ logger.debug(
+ f'GATT Response from server: [0x{connection.handle:04X}] {response}'
+ )
self.send_gatt_pdu(connection.handle, response.to_bytes())
- async def notify_subscriber(self, connection, attribute, force=False):
+ async def notify_subscriber(self, connection, attribute, value=None, force=False):
# Check if there's a subscriber
if not force:
subscribers = self.subscribers.get(connection.handle)
@@ -178,47 +342,35 @@ class Server(EventEmitter):
return
cccd = subscribers.get(attribute.handle)
if not cccd:
- logger.debug(f'not notifying, no subscribers for handle {attribute.handle:04X}')
+ logger.debug(
+ f'not notifying, no subscribers for handle {attribute.handle:04X}'
+ )
return
if len(cccd) != 2 or (cccd[0] & 0x01 == 0):
logger.debug(f'not notifying, cccd={cccd.hex()}')
return
- # Get the value
- value = attribute.read_value(connection)
+ # Get or encode the value
+ value = (
+ attribute.read_value(connection)
+ if value is None
+ else attribute.encode_value(value)
+ )
# Truncate if needed
- mtu = self.get_mtu(connection)
- if len(value) > mtu - 3:
- value = value[:mtu - 3]
+ if len(value) > connection.att_mtu - 3:
+ value = value[: connection.att_mtu - 3]
# Notify
notification = ATT_Handle_Value_Notification(
- attribute_handle = attribute.handle,
- attribute_value = value
+ attribute_handle=attribute.handle, attribute_value=value
)
- logger.debug(f'GATT Notify from server: [0x{connection.handle:04X}] {notification}')
- self.send_gatt_pdu(connection.handle, notification.to_bytes())
-
- async def notify_subscribers(self, attribute, force=False):
- # Get all the connections for which there's at least one subscription
- connections = [
- connection for connection in [
- self.device.lookup_connection(connection_handle)
- for (connection_handle, subscribers) in self.subscribers.items()
- if force or subscribers.get(attribute.handle)
- ]
- if connection is not None
- ]
-
- # Notify for each connection
- if connections:
- await asyncio.wait([
- self.notify_subscriber(connection, attribute, force)
- for connection in connections
- ])
+ logger.debug(
+ f'GATT Notify from server: [0x{connection.handle:04X}] {notification}'
+ )
+ self.send_gatt_pdu(connection.handle, bytes(notification))
- async def indicate_subscriber(self, connection, attribute, force=False):
+ async def indicate_subscriber(self, connection, attribute, value=None, force=False):
# Check if there's a subscriber
if not force:
subscribers = self.subscribers.get(connection.handle)
@@ -227,64 +379,84 @@ class Server(EventEmitter):
return
cccd = subscribers.get(attribute.handle)
if not cccd:
- logger.debug(f'not indicating, no subscribers for handle {attribute.handle:04X}')
+ logger.debug(
+ f'not indicating, no subscribers for handle {attribute.handle:04X}'
+ )
return
if len(cccd) != 2 or (cccd[0] & 0x02 == 0):
logger.debug(f'not indicating, cccd={cccd.hex()}')
return
- # Get the value
- value = attribute.read_value(connection)
+ # Get or encode the value
+ value = (
+ attribute.read_value(connection)
+ if value is None
+ else attribute.encode_value(value)
+ )
# Truncate if needed
- mtu = self.get_mtu(connection)
- if len(value) > mtu - 3:
- value = value[:mtu - 3]
+ if len(value) > connection.att_mtu - 3:
+ value = value[: connection.att_mtu - 3]
# Indicate
indication = ATT_Handle_Value_Indication(
- attribute_handle = attribute.handle,
- attribute_value = value
+ attribute_handle=attribute.handle, attribute_value=value
+ )
+ logger.debug(
+ f'GATT Indicate from server: [0x{connection.handle:04X}] {indication}'
)
- logger.debug(f'GATT Indicate from server: [0x{connection.handle:04X}] {indication}')
# Wait until we can send (only one pending indication at a time per connection)
async with self.indication_semaphores[connection.handle]:
- assert(self.pending_confirmations[connection.handle] is None)
+ assert self.pending_confirmations[connection.handle] is None
# Create a future value to hold the eventual response
- self.pending_confirmations[connection.handle] = asyncio.get_running_loop().create_future()
+ self.pending_confirmations[
+ connection.handle
+ ] = asyncio.get_running_loop().create_future()
try:
self.send_gatt_pdu(connection.handle, indication.to_bytes())
- await asyncio.wait_for(self.pending_confirmations[connection.handle], GATT_REQUEST_TIMEOUT)
- except asyncio.TimeoutError:
+ await asyncio.wait_for(
+ self.pending_confirmations[connection.handle], GATT_REQUEST_TIMEOUT
+ )
+ except asyncio.TimeoutError as error:
logger.warning(color('!!! GATT Indicate timeout', 'red'))
- raise TimeoutError(f'GATT timeout for {indication.name}')
+ raise TimeoutError(f'GATT timeout for {indication.name}') from error
finally:
self.pending_confirmations[connection.handle] = None
- async def indicate_subscribers(self, attribute):
+ async def notify_or_indicate_subscribers(
+ self, indicate, attribute, value=None, force=False
+ ):
# Get all the connections for which there's at least one subscription
connections = [
- connection for connection in [
+ connection
+ for connection in [
self.device.lookup_connection(connection_handle)
for (connection_handle, subscribers) in self.subscribers.items()
- if subscribers.get(attribute.handle)
+ if force or subscribers.get(attribute.handle)
]
if connection is not None
]
- # Indicate for each connection
+ # Indicate or notify for each connection
if connections:
- await asyncio.wait([
- self.indicate_subscriber(connection, attribute)
- for connection in connections
- ])
+ coroutine = self.indicate_subscriber if indicate else self.notify_subscriber
+ await asyncio.wait(
+ [
+ asyncio.create_task(coroutine(connection, attribute, value, force))
+ for connection in connections
+ ]
+ )
+
+ async def notify_subscribers(self, attribute, value=None, force=False):
+ return await self.notify_or_indicate_subscribers(False, attribute, value, force)
+
+ async def indicate_subscribers(self, attribute, value=None, force=False):
+ return await self.notify_or_indicate_subscribers(True, attribute, value, force)
def on_disconnection(self, connection):
- if connection.handle in self.mtus:
- del self.mtus[connection.handle]
if connection.handle in self.subscribers:
del self.subscribers[connection.handle]
if connection.handle in self.indication_semaphores:
@@ -302,17 +474,17 @@ class Server(EventEmitter):
except ATT_Error as error:
logger.debug(f'normal exception returned by handler: {error}')
response = ATT_Error_Response(
- request_opcode_in_error = att_pdu.op_code,
- attribute_handle_in_error = error.att_handle,
- error_code = error.error_code
+ request_opcode_in_error=att_pdu.op_code,
+ attribute_handle_in_error=error.att_handle,
+ error_code=error.error_code,
)
self.send_response(connection, response)
except Exception as error:
logger.warning(f'{color("!!! Exception in handler:", "red")} {error}')
response = ATT_Error_Response(
- request_opcode_in_error = att_pdu.op_code,
- attribute_handle_in_error = 0x0000,
- error_code = ATT_UNLIKELY_ERROR_ERROR
+ request_opcode_in_error=att_pdu.op_code,
+ attribute_handle_in_error=0x0000,
+ error_code=ATT_UNLIKELY_ERROR_ERROR,
)
self.send_response(connection, response)
raise error
@@ -323,10 +495,13 @@ class Server(EventEmitter):
self.on_att_request(connection, att_pdu)
else:
# Just ignore
- logger.warning(f'{color("--- Ignoring GATT Request from [0x{connection.handle:04X}]:", "red")} {att_pdu}')
-
- def get_mtu(self, connection):
- return self.mtus.get(connection.handle, ATT_DEFAULT_MTU)
+ logger.warning(
+ color(
+ f'--- Ignoring GATT Request from [0x{connection.handle:04X}]: ',
+ 'red',
+ )
+ + str(att_pdu)
+ )
#######################################################
# ATT handlers
@@ -335,11 +510,16 @@ class Server(EventEmitter):
'''
Handler for requests without a more specific handler
'''
- logger.warning(f'{color(f"--- Unsupported ATT Request from [0x{connection.handle:04X}]:", "red")} {pdu}')
+ logger.warning(
+ color(
+ f'--- Unsupported ATT Request from [0x{connection.handle:04X}]: ', 'red'
+ )
+ + str(pdu)
+ )
response = ATT_Error_Response(
- request_opcode_in_error = pdu.op_code,
- attribute_handle_in_error = 0x0000,
- error_code = ATT_REQUEST_NOT_SUPPORTED_ERROR
+ request_opcode_in_error=pdu.op_code,
+ attribute_handle_in_error=0x0000,
+ error_code=ATT_REQUEST_NOT_SUPPORTED_ERROR,
)
self.send_response(connection, response)
@@ -347,12 +527,18 @@ class Server(EventEmitter):
'''
See Bluetooth spec Vol 3, Part F - 3.4.2.1 Exchange MTU Request
'''
- mtu = max(ATT_DEFAULT_MTU, min(self.max_mtu, request.client_rx_mtu))
- self.mtus[connection.handle] = mtu
- self.send_response(connection, ATT_Exchange_MTU_Response(server_rx_mtu = mtu))
+ self.send_response(
+ connection, ATT_Exchange_MTU_Response(server_rx_mtu=self.max_mtu)
+ )
- # Notify the device
- self.device.on_connection_att_mtu_update(connection.handle, mtu)
+ # Compute the final MTU
+ if request.client_rx_mtu >= ATT_DEFAULT_MTU:
+ mtu = min(self.max_mtu, request.client_rx_mtu)
+
+ # Notify the device
+ self.device.on_connection_att_mtu_update(connection.handle, mtu)
+ else:
+ logger.warning('invalid client_rx_mtu received, MTU not changed')
def on_att_find_information_request(self, connection, request):
'''
@@ -360,25 +546,30 @@ class Server(EventEmitter):
'''
# Check the request parameters
- if request.starting_handle == 0 or request.starting_handle > request.ending_handle:
- self.send_response(connection, ATT_Error_Response(
- request_opcode_in_error = request.op_code,
- attribute_handle_in_error = request.starting_handle,
- error_code = ATT_INVALID_HANDLE_ERROR
- ))
+ if (
+ request.starting_handle == 0
+ or request.starting_handle > request.ending_handle
+ ):
+ self.send_response(
+ connection,
+ ATT_Error_Response(
+ request_opcode_in_error=request.op_code,
+ attribute_handle_in_error=request.starting_handle,
+ error_code=ATT_INVALID_HANDLE_ERROR,
+ ),
+ )
return
# Build list of returned attributes
- pdu_space_available = self.get_mtu(connection) - 2
+ pdu_space_available = connection.att_mtu - 2
attributes = []
uuid_size = 0
for attribute in (
- attribute for attribute in self.attributes if
- attribute.handle >= request.starting_handle and
- attribute.handle <= request.ending_handle
+ attribute
+ for attribute in self.attributes
+ if attribute.handle >= request.starting_handle
+ and attribute.handle <= request.ending_handle
):
- # TODO: check permissions
-
this_uuid_size = len(attribute.type.to_pdu_bytes())
if attributes:
@@ -402,14 +593,14 @@ class Server(EventEmitter):
for attribute in attributes
]
response = ATT_Find_Information_Response(
- format = 1 if len(attributes[0].type.to_pdu_bytes()) == 2 else 2,
- information_data = b''.join(information_data_list)
+ format=1 if len(attributes[0].type.to_pdu_bytes()) == 2 else 2,
+ information_data=b''.join(information_data_list),
)
else:
response = ATT_Error_Response(
- request_opcode_in_error = request.op_code,
- attribute_handle_in_error = request.starting_handle,
- error_code = ATT_ATTRIBUTE_NOT_FOUND_ERROR
+ request_opcode_in_error=request.op_code,
+ attribute_handle_in_error=request.starting_handle,
+ error_code=ATT_ATTRIBUTE_NOT_FOUND_ERROR,
)
self.send_response(connection, response)
@@ -420,15 +611,16 @@ class Server(EventEmitter):
'''
# Build list of returned attributes
- pdu_space_available = self.get_mtu(connection) - 2
+ pdu_space_available = connection.att_mtu - 2
attributes = []
for attribute in (
- attribute for attribute in self.attributes if
- attribute.handle >= request.starting_handle and
- attribute.handle <= request.ending_handle and
- attribute.type == request.attribute_type and
- attribute.read_value(connection) == request.attribute_value and
- pdu_space_available >= 4
+ attribute
+ for attribute in self.attributes
+ if attribute.handle >= request.starting_handle
+ and attribute.handle <= request.ending_handle
+ and attribute.type == request.attribute_type
+ and attribute.read_value(connection) == request.attribute_value
+ and pdu_space_available >= 4
):
# TODO: check permissions
@@ -440,25 +632,27 @@ class Server(EventEmitter):
if attributes:
handles_information_list = []
for attribute in attributes:
- if attribute.type in {
+ if attribute.type in (
GATT_PRIMARY_SERVICE_ATTRIBUTE_TYPE,
GATT_SECONDARY_SERVICE_ATTRIBUTE_TYPE,
- GATT_CHARACTERISTIC_ATTRIBUTE_TYPE
- }:
+ GATT_CHARACTERISTIC_ATTRIBUTE_TYPE,
+ ):
# Part of a group
group_end_handle = attribute.end_group_handle
else:
# Not part of a group
group_end_handle = attribute.handle
- handles_information_list.append(struct.pack('<HH', attribute.handle, group_end_handle))
+ handles_information_list.append(
+ struct.pack('<HH', attribute.handle, group_end_handle)
+ )
response = ATT_Find_By_Type_Value_Response(
- handles_information_list = b''.join(handles_information_list)
+ handles_information_list=b''.join(handles_information_list)
)
else:
response = ATT_Error_Response(
- request_opcode_in_error = request.op_code,
- attribute_handle_in_error = request.starting_handle,
- error_code = ATT_ATTRIBUTE_NOT_FOUND_ERROR
+ request_opcode_in_error=request.op_code,
+ attribute_handle_in_error=request.starting_handle,
+ error_code=ATT_ATTRIBUTE_NOT_FOUND_ERROR,
)
self.send_response(connection, response)
@@ -468,21 +662,39 @@ class Server(EventEmitter):
See Bluetooth spec Vol 3, Part F - 3.4.4.1 Read By Type Request
'''
- mtu = self.get_mtu(connection)
- pdu_space_available = mtu - 2
+ pdu_space_available = connection.att_mtu - 2
+
+ response = ATT_Error_Response(
+ request_opcode_in_error=request.op_code,
+ attribute_handle_in_error=request.starting_handle,
+ error_code=ATT_ATTRIBUTE_NOT_FOUND_ERROR,
+ )
+
attributes = []
for attribute in (
- attribute for attribute in self.attributes if
- attribute.type == request.attribute_type and
- attribute.handle >= request.starting_handle and
- attribute.handle <= request.ending_handle and
- pdu_space_available
+ attribute
+ for attribute in self.attributes
+ if attribute.type == request.attribute_type
+ and attribute.handle >= request.starting_handle
+ and attribute.handle <= request.ending_handle
+ and pdu_space_available
):
- # TODO: check permissions
+
+ try:
+ attribute_value = attribute.read_value(connection)
+ except ATT_Error as error:
+ # If the first attribute is unreadable, return an error
+ # Otherwise return attributes up to this point
+ if not attributes:
+ response = ATT_Error_Response(
+ request_opcode_in_error=request.op_code,
+ attribute_handle_in_error=attribute.handle,
+ error_code=error.error_code,
+ )
+ break
# Check the attribute value size
- attribute_value = attribute.read_value(connection)
- max_attribute_size = min(mtu - 4, 253)
+ max_attribute_size = min(connection.att_mtu - 4, 253)
if len(attribute_value) > max_attribute_size:
# We need to truncate
attribute_value = attribute_value[:max_attribute_size]
@@ -500,17 +712,14 @@ class Server(EventEmitter):
pdu_space_available -= entry_size
if attributes:
- attribute_data_list = [struct.pack('<H', handle) + value for handle, value in attributes]
+ attribute_data_list = [
+ struct.pack('<H', handle) + value for handle, value in attributes
+ ]
response = ATT_Read_By_Type_Response(
- length = entry_size,
- attribute_data_list = b''.join(attribute_data_list)
+ length=entry_size, attribute_data_list=b''.join(attribute_data_list)
)
else:
- response = ATT_Error_Response(
- request_opcode_in_error = request.op_code,
- attribute_handle_in_error = request.starting_handle,
- error_code = ATT_ATTRIBUTE_NOT_FOUND_ERROR
- )
+ logging.debug(f"not found {request}")
self.send_response(connection, response)
@@ -520,17 +729,22 @@ class Server(EventEmitter):
'''
if attribute := self.get_attribute(request.attribute_handle):
- # TODO: check permissions
- value = attribute.read_value(connection)
- value_size = min(self.get_mtu(connection) - 1, len(value))
- response = ATT_Read_Response(
- attribute_value = value[:value_size]
- )
+ try:
+ value = attribute.read_value(connection)
+ except ATT_Error as error:
+ response = ATT_Error_Response(
+ request_opcode_in_error=request.op_code,
+ attribute_handle_in_error=request.attribute_handle,
+ error_code=error.error_code,
+ )
+ else:
+ value_size = min(connection.att_mtu - 1, len(value))
+ response = ATT_Read_Response(attribute_value=value[:value_size])
else:
response = ATT_Error_Response(
- request_opcode_in_error = request.op_code,
- attribute_handle_in_error = request.attribute_handle,
- error_code = ATT_INVALID_HANDLE_ERROR
+ request_opcode_in_error=request.op_code,
+ attribute_handle_in_error=request.attribute_handle,
+ error_code=ATT_INVALID_HANDLE_ERROR,
)
self.send_response(connection, response)
@@ -540,31 +754,41 @@ class Server(EventEmitter):
'''
if attribute := self.get_attribute(request.attribute_handle):
- # TODO: check permissions
- mtu = self.get_mtu(connection)
- value = attribute.read_value(connection)
- if request.value_offset > len(value):
- response = ATT_Error_Response(
- request_opcode_in_error = request.op_code,
- attribute_handle_in_error = request.attribute_handle,
- error_code = ATT_INVALID_OFFSET_ERROR
- )
- elif len(value) <= mtu - 1:
+ try:
+ value = attribute.read_value(connection)
+ except ATT_Error as error:
response = ATT_Error_Response(
- request_opcode_in_error = request.op_code,
- attribute_handle_in_error = request.attribute_handle,
- error_code = ATT_ATTRIBUTE_NOT_LONG_ERROR
+ request_opcode_in_error=request.op_code,
+ attribute_handle_in_error=request.attribute_handle,
+ error_code=error.error_code,
)
else:
- part_size = min(mtu - 1, len(value) - request.value_offset)
- response = ATT_Read_Blob_Response(
- part_attribute_value = value[request.value_offset:request.value_offset + part_size]
- )
+ if request.value_offset > len(value):
+ response = ATT_Error_Response(
+ request_opcode_in_error=request.op_code,
+ attribute_handle_in_error=request.attribute_handle,
+ error_code=ATT_INVALID_OFFSET_ERROR,
+ )
+ elif len(value) <= connection.att_mtu - 1:
+ response = ATT_Error_Response(
+ request_opcode_in_error=request.op_code,
+ attribute_handle_in_error=request.attribute_handle,
+ error_code=ATT_ATTRIBUTE_NOT_LONG_ERROR,
+ )
+ else:
+ part_size = min(
+ connection.att_mtu - 1, len(value) - request.value_offset
+ )
+ response = ATT_Read_Blob_Response(
+ part_attribute_value=value[
+ request.value_offset : request.value_offset + part_size
+ ]
+ )
else:
response = ATT_Error_Response(
- request_opcode_in_error = request.op_code,
- attribute_handle_in_error = request.attribute_handle,
- error_code = ATT_INVALID_HANDLE_ERROR
+ request_opcode_in_error=request.op_code,
+ attribute_handle_in_error=request.attribute_handle,
+ error_code=ATT_INVALID_HANDLE_ERROR,
)
self.send_response(connection, response)
@@ -572,32 +796,33 @@ class Server(EventEmitter):
'''
See Bluetooth spec Vol 3, Part F - 3.4.4.9 Read by Group Type Request
'''
- if request.attribute_group_type not in {
+ if request.attribute_group_type not in (
GATT_PRIMARY_SERVICE_ATTRIBUTE_TYPE,
GATT_SECONDARY_SERVICE_ATTRIBUTE_TYPE,
- GATT_INCLUDE_ATTRIBUTE_TYPE
- }:
+ ):
response = ATT_Error_Response(
- request_opcode_in_error = request.op_code,
- attribute_handle_in_error = request.starting_handle,
- error_code = ATT_UNSUPPORTED_GROUP_TYPE_ERROR
+ request_opcode_in_error=request.op_code,
+ attribute_handle_in_error=request.starting_handle,
+ error_code=ATT_UNSUPPORTED_GROUP_TYPE_ERROR,
)
self.send_response(connection, response)
return
- mtu = self.get_mtu(connection)
- pdu_space_available = mtu - 2
+ pdu_space_available = connection.att_mtu - 2
attributes = []
for attribute in (
- attribute for attribute in self.attributes if
- attribute.type == request.attribute_group_type and
- attribute.handle >= request.starting_handle and
- attribute.handle <= request.ending_handle and
- pdu_space_available
+ attribute
+ for attribute in self.attributes
+ if attribute.type == request.attribute_group_type
+ and attribute.handle >= request.starting_handle
+ and attribute.handle <= request.ending_handle
+ and pdu_space_available
):
- # Check the attribute value size
+ # No need to catch permission errors here, since these attributes
+ # must all be world-readable
attribute_value = attribute.read_value(connection)
- max_attribute_size = min(mtu - 6, 251)
+ # Check the attribute value size
+ max_attribute_size = min(connection.att_mtu - 6, 251)
if len(attribute_value) > max_attribute_size:
# We need to truncate
attribute_value = attribute_value[:max_attribute_size]
@@ -611,7 +836,9 @@ class Server(EventEmitter):
break
# Add the attribute to the list
- attributes.append((attribute.handle, attribute.end_group_handle, attribute_value))
+ attributes.append(
+ (attribute.handle, attribute.end_group_handle, attribute_value)
+ )
pdu_space_available -= entry_size
if attributes:
@@ -620,14 +847,14 @@ class Server(EventEmitter):
for handle, end_group_handle, value in attributes
]
response = ATT_Read_By_Group_Type_Response(
- length = len(attribute_data_list[0]),
- attribute_data_list = b''.join(attribute_data_list)
+ length=len(attribute_data_list[0]),
+ attribute_data_list=b''.join(attribute_data_list),
)
else:
response = ATT_Error_Response(
- request_opcode_in_error = request.op_code,
- attribute_handle_in_error = request.starting_handle,
- error_code = ATT_ATTRIBUTE_NOT_FOUND_ERROR
+ request_opcode_in_error=request.op_code,
+ attribute_handle_in_error=request.starting_handle,
+ error_code=ATT_ATTRIBUTE_NOT_FOUND_ERROR,
)
self.send_response(connection, response)
@@ -640,22 +867,28 @@ class Server(EventEmitter):
# Check that the attribute exists
attribute = self.get_attribute(request.attribute_handle)
if attribute is None:
- self.send_response(connection, ATT_Error_Response(
- request_opcode_in_error = request.op_code,
- attribute_handle_in_error = request.attribute_handle,
- error_code = ATT_INVALID_HANDLE_ERROR
- ))
+ self.send_response(
+ connection,
+ ATT_Error_Response(
+ request_opcode_in_error=request.op_code,
+ attribute_handle_in_error=request.attribute_handle,
+ error_code=ATT_INVALID_HANDLE_ERROR,
+ ),
+ )
return
# TODO: check permissions
# Check the request parameters
if len(request.attribute_value) > GATT_MAX_ATTRIBUTE_VALUE_SIZE:
- self.send_response(connection, ATT_Error_Response(
- request_opcode_in_error = request.op_code,
- attribute_handle_in_error = request.attribute_handle,
- error_code = ATT_INVALID_ATTRIBUTE_LENGTH_ERROR
- ))
+ self.send_response(
+ connection,
+ ATT_Error_Response(
+ request_opcode_in_error=request.op_code,
+ attribute_handle_in_error=request.attribute_handle,
+ error_code=ATT_INVALID_ATTRIBUTE_LENGTH_ERROR,
+ ),
+ )
return
# Accept the value
@@ -686,13 +919,15 @@ class Server(EventEmitter):
except Exception as error:
logger.warning(f'!!! ignoring exception: {error}')
- def on_att_handle_value_confirmation(self, connection, confirmation):
+ def on_att_handle_value_confirmation(self, connection, _confirmation):
'''
See Bluetooth spec Vol 3, Part F - 3.4.7.3 Handle Value Confirmation
'''
if self.pending_confirmations[connection.handle] is None:
# Not expected!
- logger.warning('!!! unexpected confirmation, there is no pending indication')
+ logger.warning(
+ '!!! unexpected confirmation, there is no pending indication'
+ )
return
self.pending_confirmations[connection.handle].set_result(None)
diff --git a/bumble/hci.py b/bumble/hci.py
index 8358e30..9b5793d 100644
--- a/bumble/hci.py
+++ b/bumble/hci.py
@@ -15,13 +15,24 @@
# -----------------------------------------------------------------------------
# Imports
# -----------------------------------------------------------------------------
+from __future__ import annotations
import struct
import collections
import logging
import functools
-from colors import color
+from typing import Dict, Type, Union
+
+from .colors import color
+from .core import (
+ BT_BR_EDR_TRANSPORT,
+ AdvertisingData,
+ DeviceClass,
+ ProtocolError,
+ bit_flags_to_strings,
+ name_or_number,
+ padded_bytes,
+)
-from .core import *
# -----------------------------------------------------------------------------
# Logging
@@ -33,7 +44,7 @@ logger = logging.getLogger(__name__)
# Utils
# -----------------------------------------------------------------------------
def hci_command_op_code(ogf, ocf):
- return (ogf << 10 | ocf)
+ return ogf << 10 | ocf
def key_with_value(dictionary, target_value):
@@ -43,8 +54,8 @@ def key_with_value(dictionary, target_value):
return None
-def indent_lines(str):
- return '\n'.join([' ' + line for line in str.split('\n')])
+def indent_lines(string):
+ return '\n'.join([' ' + line for line in string.split('\n')])
def map_null_terminated_utf8_string(utf8_bytes):
@@ -58,13 +69,37 @@ def map_null_terminated_utf8_string(utf8_bytes):
def map_class_of_device(class_of_device):
- service_classes, major_device_class, minor_device_class = DeviceClass.split_class_of_device(class_of_device)
- return f'[{class_of_device:06X}] Services({",".join(DeviceClass.service_class_labels(service_classes))}),Class({DeviceClass.major_device_class_name(major_device_class)}|{DeviceClass.minor_device_class_name(major_device_class, minor_device_class)})'
+ (
+ service_classes,
+ major_device_class,
+ minor_device_class,
+ ) = DeviceClass.split_class_of_device(class_of_device)
+ return (
+ f'[{class_of_device:06X}] Services('
+ f'{",".join(DeviceClass.service_class_labels(service_classes))}),'
+ f'Class({DeviceClass.major_device_class_name(major_device_class)}|'
+ f'{DeviceClass.minor_device_class_name(major_device_class, minor_device_class)}'
+ ')'
+ )
+
+
+def phy_list_to_bits(phys):
+ if phys is None:
+ return 0
+
+ phy_bits = 0
+ for phy in phys:
+ if phy not in HCI_LE_PHY_TYPE_TO_BIT:
+ raise ValueError('invalid PHY')
+ phy_bits |= 1 << HCI_LE_PHY_TYPE_TO_BIT[phy]
+ return phy_bits
# -----------------------------------------------------------------------------
# Constants
# -----------------------------------------------------------------------------
+# fmt: off
+# pylint: disable=line-too-long
# HCI Version
HCI_VERSION_BLUETOOTH_CORE_1_0B = 0
@@ -81,6 +116,25 @@ HCI_VERSION_BLUETOOTH_CORE_5_1 = 10
HCI_VERSION_BLUETOOTH_CORE_5_2 = 11
HCI_VERSION_BLUETOOTH_CORE_5_3 = 12
+HCI_VERSION_NAMES = {
+ HCI_VERSION_BLUETOOTH_CORE_1_0B: 'HCI_VERSION_BLUETOOTH_CORE_1_0B',
+ HCI_VERSION_BLUETOOTH_CORE_1_1: 'HCI_VERSION_BLUETOOTH_CORE_1_1',
+ HCI_VERSION_BLUETOOTH_CORE_1_2: 'HCI_VERSION_BLUETOOTH_CORE_1_2',
+ HCI_VERSION_BLUETOOTH_CORE_2_0_EDR: 'HCI_VERSION_BLUETOOTH_CORE_2_0_EDR',
+ HCI_VERSION_BLUETOOTH_CORE_2_1_EDR: 'HCI_VERSION_BLUETOOTH_CORE_2_1_EDR',
+ HCI_VERSION_BLUETOOTH_CORE_3_0_HS: 'HCI_VERSION_BLUETOOTH_CORE_3_0_HS',
+ HCI_VERSION_BLUETOOTH_CORE_4_0: 'HCI_VERSION_BLUETOOTH_CORE_4_0',
+ HCI_VERSION_BLUETOOTH_CORE_4_1: 'HCI_VERSION_BLUETOOTH_CORE_4_1',
+ HCI_VERSION_BLUETOOTH_CORE_4_2: 'HCI_VERSION_BLUETOOTH_CORE_4_2',
+ HCI_VERSION_BLUETOOTH_CORE_5_0: 'HCI_VERSION_BLUETOOTH_CORE_5_0',
+ HCI_VERSION_BLUETOOTH_CORE_5_1: 'HCI_VERSION_BLUETOOTH_CORE_5_1',
+ HCI_VERSION_BLUETOOTH_CORE_5_2: 'HCI_VERSION_BLUETOOTH_CORE_5_2',
+ HCI_VERSION_BLUETOOTH_CORE_5_3: 'HCI_VERSION_BLUETOOTH_CORE_5_3'
+}
+
+# LMP Version
+LMP_VERSION_NAMES = HCI_VERSION_NAMES
+
# HCI Packet types
HCI_COMMAND_PACKET = 0x01
HCI_ACL_DATA_PACKET = 0x02
@@ -88,544 +142,546 @@ HCI_SYNCHRONOUS_DATA_PACKET = 0x03
HCI_EVENT_PACKET = 0x04
# HCI Event Codes
-HCI_INQUIRY_COMPLETE_EVENT = 0x01
-HCI_INQUIRY_RESULT_EVENT = 0x02
-HCI_CONNECTION_COMPLETE_EVENT = 0x03
-HCI_CONNECTION_REQUEST_EVENT = 0x04
-HCI_DISCONNECTION_COMPLETE_EVENT = 0x05
-HCI_AUTHENTICATION_COMPLETE_EVENT = 0x06
-HCI_REMOTE_NAME_REQUEST_COMPLETE_EVENT = 0x07
-HCI_ENCRYPTION_CHANGE_EVENT = 0x08
-HCI_CHANGE_CONNECTION_LINK_KEY_COMPLETE_EVENT = 0x09
-HCI_LINK_KEY_TYPE_CHANGED_EVENT = 0x0A
-HCI_READ_REMOTE_SUPPORTED_FEATURES_COMPLETE_EVENT = 0x0B
-HCI_READ_REMOTE_VERSION_INFORMATION_COMPLETE_EVENT = 0x0C
-HCI_QOS_SETUP_COMPLETE_EVENT = 0x0D
-HCI_COMMAND_COMPLETE_EVENT = 0x0E
-HCI_COMMAND_STATUS_EVENT = 0x0F
-HCI_HARDWARE_ERROR_EVENT = 0x10
-HCI_FLUSH_OCCURRED_EVENT = 0x11
-HCI_ROLE_CHANGE_EVENT = 0x12
-HCI_NUMBER_OF_COMPLETED_PACKETS_EVENT = 0x13
-HCI_MODE_CHANGE_EVENT = 0x14
-HCI_RETURN_LINK_KEYS_EVENT = 0x15
-HCI_PIN_CODE_REQUEST_EVENT = 0x16
-HCI_LINK_KEY_REQUEST_EVENT = 0x17
-HCI_LINK_KEY_NOTIFICATION_EVENT = 0x18
-HCI_LOOPBACK_COMMAND_EVENT = 0x19
-HCI_DATA_BUFFER_OVERFLOW_EVENT = 0x1A
-HCI_MAX_SLOTS_CHANGE_EVENT = 0x1B
-HCI_READ_CLOCK_OFFSET_COMPLETE_EVENT = 0x1C
-HCI_CONNECTION_PACKET_TYPE_CHANGED_EVENT = 0x1D
-HCI_QOS_VIOLATION_EVENT = 0x1E
-HCI_PAGE_SCAN_REPETITION_MODE_CHANGE_EVENT = 0x20
-HCI_FLOW_SPECIFICATION_COMPLETE_EVENT = 0x21
-HCI_INQUIRY_RESULT_WITH_RSSI_EVENT = 0x22
-HCI_READ_REMOTE_EXTENDED_FEATURES_COMPLETE_EVENT = 0x23
-HCI_SYNCHRONOUS_CONNECTION_COMPLETE_EVENT = 0x2C
-HCI_SYNCHRONOUS_CONNECTION_CHANGED_EVENT = 0x2D
-HCI_SNIFF_SUBRATING_EVENT = 0x2E
-HCI_EXTENDED_INQUIRY_RESULT_EVENT = 0x2F
-HCI_ENCRYPTION_KEY_REFRESH_COMPLETE_EVENT = 0x30
-HCI_IO_CAPABILITY_REQUEST_EVENT = 0x31
-HCI_IO_CAPABILITY_RESPONSE_EVENT = 0x32
-HCI_USER_CONFIRMATION_REQUEST_EVENT = 0x33
-HCI_USER_PASSKEY_REQUEST_EVENT = 0x34
-HCI_REMOTE_OOB_DATA_REQUEST = 0x35
-HCI_SIMPLE_PAIRING_COMPLETE_EVENT = 0x36
-HCI_LINK_SUPERVISION_TIMEOUT_CHANGED_EVENT = 0x38
-HCI_ENHANCED_FLUSH_COMPLETE_EVENT = 0x39
-HCI_USER_PASSKEY_NOTIFICATION_EVENT = 0x3B
-HCI_KEYPRESS_NOTIFICATION_EVENT = 0x3C
-HCI_REMOTE_HOST_SUPPORTED_FEATURES_NOTIFICATION_EVENT = 0x3D
-HCI_LE_META_EVENT = 0x3E
-HCI_NUMBER_OF_COMPLETED_DATA_BLOCKS_EVENT = 0x48
+HCI_INQUIRY_COMPLETE_EVENT = 0x01
+HCI_INQUIRY_RESULT_EVENT = 0x02
+HCI_CONNECTION_COMPLETE_EVENT = 0x03
+HCI_CONNECTION_REQUEST_EVENT = 0x04
+HCI_DISCONNECTION_COMPLETE_EVENT = 0x05
+HCI_AUTHENTICATION_COMPLETE_EVENT = 0x06
+HCI_REMOTE_NAME_REQUEST_COMPLETE_EVENT = 0x07
+HCI_ENCRYPTION_CHANGE_EVENT = 0x08
+HCI_CHANGE_CONNECTION_LINK_KEY_COMPLETE_EVENT = 0x09
+HCI_LINK_KEY_TYPE_CHANGED_EVENT = 0x0A
+HCI_READ_REMOTE_SUPPORTED_FEATURES_COMPLETE_EVENT = 0x0B
+HCI_READ_REMOTE_VERSION_INFORMATION_COMPLETE_EVENT = 0x0C
+HCI_QOS_SETUP_COMPLETE_EVENT = 0x0D
+HCI_COMMAND_COMPLETE_EVENT = 0x0E
+HCI_COMMAND_STATUS_EVENT = 0x0F
+HCI_HARDWARE_ERROR_EVENT = 0x10
+HCI_FLUSH_OCCURRED_EVENT = 0x11
+HCI_ROLE_CHANGE_EVENT = 0x12
+HCI_NUMBER_OF_COMPLETED_PACKETS_EVENT = 0x13
+HCI_MODE_CHANGE_EVENT = 0x14
+HCI_RETURN_LINK_KEYS_EVENT = 0x15
+HCI_PIN_CODE_REQUEST_EVENT = 0x16
+HCI_LINK_KEY_REQUEST_EVENT = 0x17
+HCI_LINK_KEY_NOTIFICATION_EVENT = 0x18
+HCI_LOOPBACK_COMMAND_EVENT = 0x19
+HCI_DATA_BUFFER_OVERFLOW_EVENT = 0x1A
+HCI_MAX_SLOTS_CHANGE_EVENT = 0x1B
+HCI_READ_CLOCK_OFFSET_COMPLETE_EVENT = 0x1C
+HCI_CONNECTION_PACKET_TYPE_CHANGED_EVENT = 0x1D
+HCI_QOS_VIOLATION_EVENT = 0x1E
+HCI_PAGE_SCAN_REPETITION_MODE_CHANGE_EVENT = 0x20
+HCI_FLOW_SPECIFICATION_COMPLETE_EVENT = 0x21
+HCI_INQUIRY_RESULT_WITH_RSSI_EVENT = 0x22
+HCI_READ_REMOTE_EXTENDED_FEATURES_COMPLETE_EVENT = 0x23
+HCI_SYNCHRONOUS_CONNECTION_COMPLETE_EVENT = 0x2C
+HCI_SYNCHRONOUS_CONNECTION_CHANGED_EVENT = 0x2D
+HCI_SNIFF_SUBRATING_EVENT = 0x2E
+HCI_EXTENDED_INQUIRY_RESULT_EVENT = 0x2F
+HCI_ENCRYPTION_KEY_REFRESH_COMPLETE_EVENT = 0x30
+HCI_IO_CAPABILITY_REQUEST_EVENT = 0x31
+HCI_IO_CAPABILITY_RESPONSE_EVENT = 0x32
+HCI_USER_CONFIRMATION_REQUEST_EVENT = 0x33
+HCI_USER_PASSKEY_REQUEST_EVENT = 0x34
+HCI_REMOTE_OOB_DATA_REQUEST = 0x35
+HCI_SIMPLE_PAIRING_COMPLETE_EVENT = 0x36
+HCI_LINK_SUPERVISION_TIMEOUT_CHANGED_EVENT = 0x38
+HCI_ENHANCED_FLUSH_COMPLETE_EVENT = 0x39
+HCI_USER_PASSKEY_NOTIFICATION_EVENT = 0x3B
+HCI_KEYPRESS_NOTIFICATION_EVENT = 0x3C
+HCI_REMOTE_HOST_SUPPORTED_FEATURES_NOTIFICATION_EVENT = 0x3D
+HCI_LE_META_EVENT = 0x3E
+HCI_NUMBER_OF_COMPLETED_DATA_BLOCKS_EVENT = 0x48
+HCI_TRIGGERED_CLOCK_CAPTURE_EVENT = 0X4E
+HCI_SYNCHRONIZATION_TRAIN_COMPLETE_EVENT = 0X4F
+HCI_SYNCHRONIZATION_TRAIN_RECEIVED_EVENT = 0X50
+HCI_CONNECTIONLESS_PERIPHERAL_BROADCAST_RECEIVE_EVENT = 0X51
+HCI_CONNECTIONLESS_PERIPHERAL_BROADCAST_TIMEOUT_EVENT = 0X52
+HCI_TRUNCATED_PAGE_COMPLETE_EVENT = 0X53
+HCI_PERIPHERAL_PAGE_RESPONSE_TIMEOUT_EVENT = 0X54
+HCI_CONNECTIONLESS_PERIPHERAL_BROADCAST_CHANNEL_MAP_CHANGE_EVENT = 0X55
+HCI_INQUIRY_RESPONSE_NOTIFICATION_EVENT = 0X56
+HCI_AUTHENTICATED_PAYLOAD_TIMEOUT_EXPIRED_EVENT = 0X57
+HCI_SAM_STATUS_CHANGE_EVENT = 0X58
HCI_EVENT_NAMES = {
- HCI_INQUIRY_COMPLETE_EVENT: 'HCI_INQUIRY_COMPLETE_EVENT',
- HCI_INQUIRY_RESULT_EVENT: 'HCI_INQUIRY_RESULT_EVENT',
- HCI_CONNECTION_COMPLETE_EVENT: 'HCI_CONNECTION_COMPLETE_EVENT',
- HCI_CONNECTION_REQUEST_EVENT: 'HCI_CONNECTION_REQUEST_EVENT',
- HCI_DISCONNECTION_COMPLETE_EVENT: 'HCI_DISCONNECTION_COMPLETE_EVENT',
- HCI_AUTHENTICATION_COMPLETE_EVENT: 'HCI_AUTHENTICATION_COMPLETE_EVENT',
- HCI_REMOTE_NAME_REQUEST_COMPLETE_EVENT: 'HCI_REMOTE_NAME_REQUEST_COMPLETE_EVENT',
- HCI_ENCRYPTION_CHANGE_EVENT: 'HCI_ENCRYPTION_CHANGE_EVENT',
- HCI_CHANGE_CONNECTION_LINK_KEY_COMPLETE_EVENT: 'HCI_CHANGE_CONNECTION_LINK_KEY_COMPLETE_EVENT',
- HCI_LINK_KEY_TYPE_CHANGED_EVENT: 'HCI_LINK_KEY_TYPE_CHANGED_EVENT',
- HCI_INQUIRY_RESULT_WITH_RSSI_EVENT: 'HCI_INQUIRY_RESULT_WITH_RSSI_EVENT',
- HCI_READ_REMOTE_SUPPORTED_FEATURES_COMPLETE_EVENT: 'HCI_READ_REMOTE_SUPPORTED_FEATURES_COMPLETE_EVENT',
- HCI_READ_REMOTE_VERSION_INFORMATION_COMPLETE_EVENT: 'HCI_READ_REMOTE_VERSION_INFORMATION_COMPLETE_EVENT',
- HCI_QOS_SETUP_COMPLETE_EVENT: 'HCI_QOS_SETUP_COMPLETE_EVENT',
- HCI_SYNCHRONOUS_CONNECTION_COMPLETE_EVENT: 'HCI_SYNCHRONOUS_CONNECTION_COMPLETE_EVENT',
- HCI_SYNCHRONOUS_CONNECTION_CHANGED_EVENT: 'HCI_SYNCHRONOUS_CONNECTION_CHANGED_EVENT',
- HCI_SNIFF_SUBRATING_EVENT: 'HCI_SNIFF_SUBRATING_EVENT',
- HCI_COMMAND_COMPLETE_EVENT: 'HCI_COMMAND_COMPLETE_EVENT',
- HCI_COMMAND_STATUS_EVENT: 'HCI_COMMAND_STATUS_EVENT',
- HCI_HARDWARE_ERROR_EVENT: 'HCI_HARDWARE_ERROR_EVENT',
- HCI_FLUSH_OCCURRED_EVENT: 'HCI_FLUSH_OCCURRED_EVENT',
- HCI_ROLE_CHANGE_EVENT: 'HCI_ROLE_CHANGE_EVENT',
- HCI_NUMBER_OF_COMPLETED_PACKETS_EVENT: 'HCI_NUMBER_OF_COMPLETED_PACKETS_EVENT',
- HCI_MODE_CHANGE_EVENT: 'HCI_MODE_CHANGE_EVENT',
- HCI_RETURN_LINK_KEYS_EVENT: 'HCI_RETURN_LINK_KEYS_EVENT',
- HCI_PIN_CODE_REQUEST_EVENT: 'HCI_PIN_CODE_REQUEST_EVENT',
- HCI_LINK_KEY_REQUEST_EVENT: 'HCI_LINK_KEY_REQUEST_EVENT',
- HCI_LINK_KEY_NOTIFICATION_EVENT: 'HCI_LINK_KEY_NOTIFICATION_EVENT',
- HCI_LOOPBACK_COMMAND_EVENT: 'HCI_LOOPBACK_COMMAND_EVENT',
- HCI_DATA_BUFFER_OVERFLOW_EVENT: 'HCI_DATA_BUFFER_OVERFLOW_EVENT',
- HCI_MAX_SLOTS_CHANGE_EVENT: 'HCI_MAX_SLOTS_CHANGE_EVENT',
- HCI_READ_CLOCK_OFFSET_COMPLETE_EVENT: 'HCI_READ_CLOCK_OFFSET_COMPLETE_EVENT',
- HCI_CONNECTION_PACKET_TYPE_CHANGED_EVENT: 'HCI_CONNECTION_PACKET_TYPE_CHANGED_EVENT',
- HCI_QOS_VIOLATION_EVENT: 'HCI_QOS_VIOLATION_EVENT',
- HCI_PAGE_SCAN_REPETITION_MODE_CHANGE_EVENT: 'HCI_PAGE_SCAN_REPETITION_MODE_CHANGE_EVENT',
- HCI_FLOW_SPECIFICATION_COMPLETE_EVENT: 'HCI_FLOW_SPECIFICATION_COMPLETE_EVENT',
- HCI_READ_REMOTE_EXTENDED_FEATURES_COMPLETE_EVENT: 'HCI_READ_REMOTE_EXTENDED_FEATURES_COMPLETE_EVENT',
- HCI_EXTENDED_INQUIRY_RESULT_EVENT: 'HCI_EXTENDED_INQUIRY_RESULT_EVENT',
- HCI_ENCRYPTION_KEY_REFRESH_COMPLETE_EVENT: 'HCI_ENCRYPTION_KEY_REFRESH_COMPLETE_EVENT',
- HCI_IO_CAPABILITY_REQUEST_EVENT: 'HCI_IO_CAPABILITY_REQUEST_EVENT',
- HCI_IO_CAPABILITY_RESPONSE_EVENT: 'HCI_IO_CAPABILITY_RESPONSE_EVENT',
- HCI_USER_CONFIRMATION_REQUEST_EVENT: 'HCI_USER_CONFIRMATION_REQUEST_EVENT',
- HCI_USER_PASSKEY_REQUEST_EVENT: 'HCI_USER_PASSKEY_REQUEST_EVENT',
- HCI_REMOTE_OOB_DATA_REQUEST: 'HCI_REMOTE_OOB_DATA_REQUEST',
- HCI_SIMPLE_PAIRING_COMPLETE_EVENT: 'HCI_SIMPLE_PAIRING_COMPLETE_EVENT',
- HCI_LINK_SUPERVISION_TIMEOUT_CHANGED_EVENT: 'HCI_LINK_SUPERVISION_TIMEOUT_CHANGED_EVENT',
- HCI_ENHANCED_FLUSH_COMPLETE_EVENT: 'HCI_ENHANCED_FLUSH_COMPLETE_EVENT',
- HCI_USER_PASSKEY_NOTIFICATION_EVENT: 'HCI_USER_PASSKEY_NOTIFICATION_EVENT',
- HCI_KEYPRESS_NOTIFICATION_EVENT: 'HCI_KEYPRESS_NOTIFICATION_EVENT',
- HCI_REMOTE_HOST_SUPPORTED_FEATURES_NOTIFICATION_EVENT: 'HCI_REMOTE_HOST_SUPPORTED_FEATURES_NOTIFICATION_EVENT',
- HCI_LE_META_EVENT: 'HCI_LE_META_EVENT'
+ event_code: event_name for (event_name, event_code) in globals().items()
+ if event_name.startswith('HCI_') and event_name.endswith('_EVENT')
}
# HCI Subevent Codes
-HCI_LE_CONNECTION_COMPLETE_EVENT = 0x01
-HCI_LE_ADVERTISING_REPORT_EVENT = 0x02
-HCI_LE_CONNECTION_UPDATE_COMPLETE_EVENT = 0x03
-HCI_LE_READ_REMOTE_FEATURES_COMPLETE_EVENT = 0x04
-HCI_LE_LONG_TERM_KEY_REQUEST_EVENT = 0x05
-HCI_LE_REMOTE_CONNECTION_PARAMETER_REQUEST_EVENT = 0x06
-HCI_LE_DATA_LENGTH_CHANGE_EVENT = 0x07
-HCI_LE_READ_LOCAL_P_256_PUBLIC_KEY_COMPLETE_EVENT = 0x08
-HCI_LE_GENERATE_DHKEY_COMPLETE_EVENT = 0x09
-HCI_LE_ENHANCED_CONNECTION_COMPLETE_EVENT = 0x0A
-HCI_LE_DIRECTED_ADVERTISING_REPORT_EVENT = 0x0B
-HCI_LE_PHY_UPDATE_COMPLETE_EVENT = 0x0C
-HCI_LE_EXTENDED_ADVERTISING_REPORT_EVENT = 0x0D
-HCI_LE_PERIODIC_ADVERTISING_SYNC_ESTABLISHED_EVENT = 0x0E
-HCI_LE_PERIODIC_ADVERTISING_REPORT_EVENT = 0x0F
-HCI_LE_PERIODIC_ADVERTISING_SYNC_LOST_EVENT = 0x10
-HCI_LE_SCAN_TIMEOUT_EVENT = 0x11
-HCI_LE_ADVERTISING_SET_TERMINATED_EVENT = 0x12
-HCI_LE_SCAN_REQUEST_RECEIVED_EVENT = 0x13
-HCI_LE_CHANNEL_SELECTION_ALGORITHM_EVENT = 0x14
+HCI_LE_CONNECTION_COMPLETE_EVENT = 0x01
+HCI_LE_ADVERTISING_REPORT_EVENT = 0x02
+HCI_LE_CONNECTION_UPDATE_COMPLETE_EVENT = 0x03
+HCI_LE_READ_REMOTE_FEATURES_COMPLETE_EVENT = 0x04
+HCI_LE_LONG_TERM_KEY_REQUEST_EVENT = 0x05
+HCI_LE_REMOTE_CONNECTION_PARAMETER_REQUEST_EVENT = 0x06
+HCI_LE_DATA_LENGTH_CHANGE_EVENT = 0x07
+HCI_LE_READ_LOCAL_P_256_PUBLIC_KEY_COMPLETE_EVENT = 0x08
+HCI_LE_GENERATE_DHKEY_COMPLETE_EVENT = 0x09
+HCI_LE_ENHANCED_CONNECTION_COMPLETE_EVENT = 0x0A
+HCI_LE_DIRECTED_ADVERTISING_REPORT_EVENT = 0x0B
+HCI_LE_PHY_UPDATE_COMPLETE_EVENT = 0x0C
+HCI_LE_EXTENDED_ADVERTISING_REPORT_EVENT = 0x0D
+HCI_LE_PERIODIC_ADVERTISING_SYNC_ESTABLISHED_EVENT = 0x0E
+HCI_LE_PERIODIC_ADVERTISING_REPORT_EVENT = 0x0F
+HCI_LE_PERIODIC_ADVERTISING_SYNC_LOST_EVENT = 0x10
+HCI_LE_SCAN_TIMEOUT_EVENT = 0x11
+HCI_LE_ADVERTISING_SET_TERMINATED_EVENT = 0x12
+HCI_LE_SCAN_REQUEST_RECEIVED_EVENT = 0x13
+HCI_LE_CHANNEL_SELECTION_ALGORITHM_EVENT = 0x14
+HCI_LE_CONNECTIONLESS_IQ_REPORT_EVENT = 0X15
+HCI_LE_CONNECTION_IQ_REPORT_EVENT = 0X16
+HCI_LE_CTE_REQUEST_FAILED_EVENT = 0X17
+HCI_LE_PERIODIC_ADVERTISING_SYNC_TRANSFER_RECEIVED_EVENT = 0X18
+HCI_LE_CIS_ESTABLISHED_EVENT = 0X19
+HCI_LE_CIS_REQUEST_EVENT = 0X1A
+HCI_LE_CREATE_BIG_COMPLETE_EVENT = 0X1B
+HCI_LE_TERMINATE_BIG_COMPLETE_EVENT = 0X1C
+HCI_LE_BIG_SYNC_ESTABLISHED_EVENT = 0X1D
+HCI_LE_BIG_SYNC_LOST_EVENT = 0X1E
+HCI_LE_REQUEST_PEER_SCA_COMPLETE_EVENT = 0X1F
+HCI_LE_PATH_LOSS_THRESHOLD_EVENT = 0X20
+HCI_LE_TRANSMIT_POWER_REPORTING_EVENT = 0X21
+HCI_LE_BIGINFO_ADVERTISING_REPORT_EVENT = 0X22
+HCI_LE_SUBRATE_CHANGE_EVENT = 0X23
HCI_SUBEVENT_NAMES = {
- HCI_LE_CONNECTION_COMPLETE_EVENT: 'HCI_LE_CONNECTION_COMPLETE_EVENT',
- HCI_LE_ADVERTISING_REPORT_EVENT: 'HCI_LE_ADVERTISING_REPORT_EVENT',
- HCI_LE_CONNECTION_UPDATE_COMPLETE_EVENT: 'HCI_LE_CONNECTION_UPDATE_COMPLETE_EVENT',
- HCI_LE_READ_REMOTE_FEATURES_COMPLETE_EVENT: 'HCI_LE_READ_REMOTE_FEATURES_COMPLETE_EVENT',
- HCI_LE_LONG_TERM_KEY_REQUEST_EVENT: 'HCI_LE_LONG_TERM_KEY_REQUEST_EVENT',
- HCI_LE_REMOTE_CONNECTION_PARAMETER_REQUEST_EVENT: 'HCI_LE_REMOTE_CONNECTION_PARAMETER_REQUEST_EVENT',
- HCI_LE_DATA_LENGTH_CHANGE_EVENT: 'HCI_LE_DATA_LENGTH_CHANGE_EVENT',
- HCI_LE_READ_LOCAL_P_256_PUBLIC_KEY_COMPLETE_EVENT: 'HCI_LE_READ_LOCAL_P_256_PUBLIC_KEY_COMPLETE_EVENT',
- HCI_LE_GENERATE_DHKEY_COMPLETE_EVENT: 'HCI_LE_GENERATE_DHKEY_COMPLETE_EVENT',
- HCI_LE_ENHANCED_CONNECTION_COMPLETE_EVENT: 'HCI_LE_ENHANCED_CONNECTION_COMPLETE_EVENT',
- HCI_LE_DIRECTED_ADVERTISING_REPORT_EVENT: 'HCI_LE_DIRECTED_ADVERTISING_REPORT_EVENT',
- HCI_LE_PHY_UPDATE_COMPLETE_EVENT: 'HCI_LE_PHY_UPDATE_COMPLETE_EVENT',
- HCI_LE_EXTENDED_ADVERTISING_REPORT_EVENT: 'HCI_LE_EXTENDED_ADVERTISING_REPORT_EVENT',
- HCI_LE_PERIODIC_ADVERTISING_SYNC_ESTABLISHED_EVENT: 'HCI_LE_PERIODIC_ADVERTISING_SYNC_ESTABLISHED_EVENT',
- HCI_LE_PERIODIC_ADVERTISING_REPORT_EVENT: 'HCI_LE_PERIODIC_ADVERTISING_REPORT_EVENT',
- HCI_LE_PERIODIC_ADVERTISING_SYNC_LOST_EVENT: 'HCI_LE_PERIODIC_ADVERTISING_SYNC_LOST_EVENT',
- HCI_LE_SCAN_TIMEOUT_EVENT: 'HCI_LE_SCAN_TIMEOUT_EVENT',
- HCI_LE_ADVERTISING_SET_TERMINATED_EVENT: 'HCI_LE_ADVERTISING_SET_TERMINATED_EVENT',
- HCI_LE_SCAN_REQUEST_RECEIVED_EVENT: 'HCI_LE_SCAN_REQUEST_RECEIVED_EVENT',
- HCI_LE_CHANNEL_SELECTION_ALGORITHM_EVENT: 'HCI_LE_CHANNEL_SELECTION_ALGORITHM_EVENT'
+ event_code: event_name for (event_name, event_code) in globals().items()
+ if event_name.startswith('HCI_LE_') and event_name.endswith('_EVENT') and event_code != HCI_LE_META_EVENT
}
# HCI Command
-HCI_INQUIRY_COMMAND = hci_command_op_code(0x01, 0x0001)
-HCI_INQUIRY_CANCEL_COMMAND = hci_command_op_code(0x01, 0x0002)
-HCI_CREATE_CONNECTION_COMMAND = hci_command_op_code(0x01, 0x0005)
-HCI_DISCONNECT_COMMAND = hci_command_op_code(0x01, 0x0006)
-HCI_ACCEPT_CONNECTION_REQUEST_COMMAND = hci_command_op_code(0x01, 0x0009)
-HCI_LINK_KEY_REQUEST_REPLY_COMMAND = hci_command_op_code(0x01, 0x000B)
-HCI_LINK_KEY_REQUEST_NEGATIVE_REPLY_COMMAND = hci_command_op_code(0x01, 0x000C)
-HCI_PIN_CODE_REQUEST_NEGATIVE_REPLY_COMMAND = hci_command_op_code(0x01, 0x000E)
-HCI_CHANGE_CONNECTION_PACKET_TYPE_COMMAND = hci_command_op_code(0x01, 0x000F)
-HCI_AUTHENTICATION_REQUESTED_COMMAND = hci_command_op_code(0x01, 0x0011)
-HCI_SET_CONNECTION_ENCRYPTION_COMMAND = hci_command_op_code(0x01, 0x0013)
-HCI_REMOTE_NAME_REQUEST_COMMAND = hci_command_op_code(0x01, 0x0019)
-HCI_READ_REMOTE_SUPPORTED_FEATURES_COMMAND = hci_command_op_code(0x01, 0x001B)
-HCI_READ_REMOTE_EXTENDED_FEATURES_COMMAND = hci_command_op_code(0x01, 0x001C)
-HCI_READ_REMOTE_VERSION_INFORMATION_COMMAND = hci_command_op_code(0x01, 0x001D)
-HCI_READ_CLOCK_OFFSET_COMMAND = hci_command_op_code(0x01, 0x001F)
-HCI_IO_CAPABILITY_REQUEST_REPLY_COMMAND = hci_command_op_code(0x01, 0x002B)
-HCI_USER_CONFIRMATION_REQUEST_REPLY_COMMAND = hci_command_op_code(0x01, 0x002C)
-HCI_USER_CONFIRMATION_REQUEST_NEGATIVE_REPLY_COMMAND = hci_command_op_code(0x01, 0x002D)
-HCI_USER_PASSKEY_REQUEST_REPLY_COMMAND = hci_command_op_code(0x01, 0x002E)
-HCI_USER_PASSKEY_REQUEST_NEGATIVE_REPLY_COMMAND = hci_command_op_code(0x01, 0x002F)
-HCI_ENHANCED_SETUP_SYNCHRONOUS_CONNECTION_COMMAND = hci_command_op_code(0x01, 0x003D)
-HCI_SNIFF_MODE_COMMAND = hci_command_op_code(0x02, 0x0003)
-HCI_EXIT_SNIFF_MODE_COMMAND = hci_command_op_code(0x02, 0x0004)
-HCI_SWITCH_ROLE_COMMAND = hci_command_op_code(0x02, 0x000B)
-HCI_WRITE_LINK_POLICY_SETTINGS_COMMAND = hci_command_op_code(0x02, 0x000D)
-HCI_WRITE_DEFAULT_LINK_POLICY_SETTINGS_COMMAND = hci_command_op_code(0x02, 0x000F)
-HCI_SNIFF_SUBRATING_COMMAND = hci_command_op_code(0x02, 0x0011)
-HCI_SET_EVENT_MASK_COMMAND = hci_command_op_code(0x03, 0x0001)
-HCI_RESET_COMMAND = hci_command_op_code(0x03, 0x0003)
-HCI_SET_EVENT_FILTER_COMMAND = hci_command_op_code(0x03, 0x0005)
-HCI_READ_STORED_LINK_KEY_COMMAND = hci_command_op_code(0x03, 0x000D)
-HCI_DELETE_STORED_LINK_KEY_COMMAND = hci_command_op_code(0x03, 0x0012)
-HCI_WRITE_LOCAL_NAME_COMMAND = hci_command_op_code(0x03, 0x0013)
-HCI_READ_LOCAL_NAME_COMMAND = hci_command_op_code(0x03, 0x0014)
-HCI_WRITE_CONNECTION_ACCEPT_TIMEOUT_COMMAND = hci_command_op_code(0x03, 0x0016)
-HCI_WRITE_PAGE_TIMEOUT_COMMAND = hci_command_op_code(0x03, 0x0018)
-HCI_WRITE_SCAN_ENABLE_COMMAND = hci_command_op_code(0x03, 0x001A)
-HCI_READ_PAGE_SCAN_ACTIVITY_COMMAND = hci_command_op_code(0x03, 0x001B)
-HCI_WRITE_PAGE_SCAN_ACTIVITY_COMMAND = hci_command_op_code(0x03, 0x001C)
-HCI_WRITE_INQUIRY_SCAN_ACTIVITY_COMMAND = hci_command_op_code(0x03, 0x001E)
-HCI_READ_CLASS_OF_DEVICE_COMMAND = hci_command_op_code(0x03, 0x0023)
-HCI_WRITE_CLASS_OF_DEVICE_COMMAND = hci_command_op_code(0x03, 0x0024)
-HCI_READ_VOICE_SETTING_COMMAND = hci_command_op_code(0x03, 0x0025)
-HCI_WRITE_VOICE_SETTING_COMMAND = hci_command_op_code(0x03, 0x0026)
-HCI_READ_SYNCHRONOUS_FLOW_CONTROL_ENABLE_COMMAND = hci_command_op_code(0x03, 0x002E)
-HCI_WRITE_SYNCHRONOUS_FLOW_CONTROL_ENABLE_COMMAND = hci_command_op_code(0x03, 0x002F)
-HCI_HOST_BUFFER_SIZE_COMMAND = hci_command_op_code(0x03, 0x0033)
-HCI_WRITE_LINK_SUPERVISION_TIMEOUT_COMMAND = hci_command_op_code(0x03, 0x0037)
-HCI_READ_NUMBER_OF_SUPPORTED_IAC_COMMAND = hci_command_op_code(0x03, 0x0038)
-HCI_READ_CURRENT_IAC_LAP_COMMAND = hci_command_op_code(0x03, 0x0039)
-HCI_WRITE_INQUIRY_SCAN_TYPE_COMMAND = hci_command_op_code(0x03, 0x0043)
-HCI_WRITE_INQUIRY_MODE_COMMAND = hci_command_op_code(0x03, 0x0045)
-HCI_READ_PAGE_SCAN_TYPE_COMMAND = hci_command_op_code(0x03, 0x0046)
-HCI_WRITE_PAGE_SCAN_TYPE_COMMAND = hci_command_op_code(0x03, 0x0047)
-HCI_WRITE_EXTENDED_INQUIRY_RESPONSE_COMMAND = hci_command_op_code(0x03, 0x0052)
-HCI_WRITE_SIMPLE_PAIRING_MODE_COMMAND = hci_command_op_code(0x03, 0x0056)
-HCI_READ_INQUIRY_RESPONSE_TRANSMIT_POWER_LEVEL_COMMAND = hci_command_op_code(0x03, 0x0058)
-HCI_SET_EVENT_MASK_PAGE_2_COMMAND = hci_command_op_code(0x03, 0x0063)
-HCI_READ_DEFAULT_ERRONEOUS_DATA_REPORTING_COMMAND = hci_command_op_code(0x03, 0x005A)
-HCI_READ_LE_HOST_SUPPORT_COMMAND = hci_command_op_code(0x03, 0x006C)
-HCI_WRITE_LE_HOST_SUPPORT_COMMAND = hci_command_op_code(0x03, 0x006D)
-HCI_WRITE_SECURE_CONNECTIONS_HOST_SUPPORT_COMMAND = hci_command_op_code(0x03, 0x007A)
-HCI_WRITE_AUTHENTICATED_PAYLOAD_TIMEOUT_COMMAND = hci_command_op_code(0x03, 0x007C)
-HCI_READ_LOCAL_VERSION_INFORMATION_COMMAND = hci_command_op_code(0x04, 0x0001)
-HCI_READ_LOCAL_SUPPORTED_COMMANDS_COMMAND = hci_command_op_code(0x04, 0x0002)
-HCI_READ_LOCAL_SUPPORTED_FEATURES_COMMAND = hci_command_op_code(0x04, 0x0003)
-HCI_READ_LOCAL_EXTENDED_FEATURES_COMMAND = hci_command_op_code(0x04, 0x0004)
-HCI_READ_BUFFER_SIZE_COMMAND = hci_command_op_code(0x04, 0x0005)
-HCI_READ_BD_ADDR_COMMAND = hci_command_op_code(0x04, 0x0009)
-HCI_READ_LOCAL_SUPPORTED_CODECS_COMMAND = hci_command_op_code(0x04, 0x000B)
-HCI_READ_ENCRYPTION_KEY_SIZE_COMMAND = hci_command_op_code(0x05, 0x0008)
-HCI_LE_SET_EVENT_MASK_COMMAND = hci_command_op_code(0x08, 0x0001)
-HCI_LE_READ_BUFFER_SIZE_COMMAND = hci_command_op_code(0x08, 0x0002)
-HCI_LE_READ_LOCAL_SUPPORTED_FEATURES_COMMAND = hci_command_op_code(0x08, 0x0003)
-HCI_LE_SET_RANDOM_ADDRESS_COMMAND = hci_command_op_code(0x08, 0x0005)
-HCI_LE_SET_ADVERTISING_PARAMETERS_COMMAND = hci_command_op_code(0x08, 0x0006)
-HCI_LE_READ_ADVERTISING_CHANNEL_TX_POWER_COMMAND = hci_command_op_code(0x08, 0x0007)
-HCI_LE_SET_ADVERTISING_DATA_COMMAND = hci_command_op_code(0x08, 0x0008)
-HCI_LE_SET_SCAN_RESPONSE_DATA_COMMAND = hci_command_op_code(0x08, 0x0009)
-HCI_LE_SET_ADVERTISING_ENABLE_COMMAND = hci_command_op_code(0x08, 0x000A)
-HCI_LE_SET_SCAN_PARAMETERS_COMMAND = hci_command_op_code(0x08, 0x000B)
-HCI_LE_SET_SCAN_ENABLE_COMMAND = hci_command_op_code(0x08, 0x000C)
-HCI_LE_CREATE_CONNECTION_COMMAND = hci_command_op_code(0x08, 0x000D)
-HCI_LE_CREATE_CONNECTION_CANCEL_COMMAND = hci_command_op_code(0x08, 0x000E)
-HCI_LE_READ_WHITE_LIST_SIZE_COMMAND = hci_command_op_code(0x08, 0x000F)
-HCI_LE_CLEAR_WHITE_LIST_COMMAND = hci_command_op_code(0x08, 0x0010)
-HCI_LE_ADD_DEVICE_TO_WHITE_LIST_COMMAND = hci_command_op_code(0x08, 0x0011)
-HCI_LE_REMOVE_DEVICE_FROM_WHITE_LIST_COMMAND = hci_command_op_code(0x08, 0x0012)
-HCI_LE_CONNECTION_UPDATE_COMMAND = hci_command_op_code(0x08, 0x0013)
-HCI_LE_SET_HOST_CHANNEL_CLASSIFICATION_COMMAND = hci_command_op_code(0x08, 0x0014)
-HCI_LE_READ_CHANNEL_MAP_COMMAND = hci_command_op_code(0x08, 0x0015)
-HCI_LE_READ_REMOTE_FEATURES_COMMAND = hci_command_op_code(0x08, 0x0016)
-HCI_LE_ENCRYPT_COMMAND = hci_command_op_code(0x08, 0x0017)
-HCI_LE_RAND_COMMAND = hci_command_op_code(0x08, 0x0018)
-HCI_LE_START_ENCRYPTION_COMMAND = hci_command_op_code(0x08, 0x0019)
-HCI_LE_LONG_TERM_KEY_REQUEST_REPLY_COMMAND = hci_command_op_code(0x08, 0x001A)
-HCI_LE_LONG_TERM_KEY_REQUEST_NEGATIVE_REPLY_COMMAND = hci_command_op_code(0x08, 0x001B)
-HCI_LE_READ_SUPPORTED_STATES_COMMAND = hci_command_op_code(0x08, 0x001C)
-HCI_LE_RECEIVER_TEST_COMMAND = hci_command_op_code(0x08, 0x001D)
-HCI_LE_TRANSMITTER_TEST_COMMAND = hci_command_op_code(0x08, 0x001E)
-HCI_LE_TEST_END_COMMAND = hci_command_op_code(0x08, 0x001F)
-HCI_LE_REMOTE_CONNECTION_PARAMETER_REQUEST_REPLY_COMMAND = hci_command_op_code(0x08, 0x0020)
-HCI_LE_REMOTE_CONNECTION_PARAMETER_REQUEST_NEGATIVE_REPLY_COMMAND = hci_command_op_code(0x08, 0x0021)
-HCI_LE_SET_DATA_LENGTH_COMMAND = hci_command_op_code(0x08, 0x0022)
-HCI_LE_READ_SUGGESTED_DEFAULT_DATA_LENGTH_COMMAND = hci_command_op_code(0x08, 0x0023)
-HCI_LE_WRITE_SUGGESTED_DEFAULT_DATA_LENGTH_COMMAND = hci_command_op_code(0x08, 0x0024)
-HCI_LE_READ_LOCAL_P_256_PUBLIC_KEY_COMMAND = hci_command_op_code(0x08, 0x0025)
-HCI_LE_GENERATE_DHKEY_COMMAND = hci_command_op_code(0x08, 0x0026)
-HCI_LE_ADD_DEVICE_TO_RESOLVING_LIST_COMMAND = hci_command_op_code(0x08, 0x0027)
-HCI_LE_REMOVE_DEVICE_FROM_RESOLVING_LIST_COMMAND = hci_command_op_code(0x08, 0x0028)
-HCI_LE_CLEAR_RESOLVING_LIST_COMMAND = hci_command_op_code(0x08, 0x0029)
-HCI_LE_READ_RESOLVING_LIST_SIZE_COMMAND = hci_command_op_code(0x08, 0x002A)
-HCI_LE_READ_PEER_RESOLVABLE_ADDRESS_COMMAND = hci_command_op_code(0x08, 0x002B)
-HCI_LE_READ_LOCAL_RESOLVABLE_ADDRESS_COMMAND = hci_command_op_code(0x08, 0x002C)
-HCI_LE_SET_ADDRESS_RESOLUTION_ENABLE_COMMAND = hci_command_op_code(0x08, 0x002D)
-HCI_LE_SET_RESOLVABLE_PRIVATE_ADDRESS_TIMEOUT_COMMAND = hci_command_op_code(0x08, 0x002E)
-HCI_LE_READ_MAXIMUM_DATA_LENGTH_COMMAND = hci_command_op_code(0x08, 0x002F)
-HCI_LE_READ_PHY_COMMAND = hci_command_op_code(0x08, 0x0030)
-HCI_LE_SET_DEFAULT_PHY_COMMAND = hci_command_op_code(0x08, 0x0031)
-HCI_LE_SET_PHY_COMMAND = hci_command_op_code(0x08, 0x0032)
-HCI_LE_ENHANCED_RECEIVER_TEST_COMMAND = hci_command_op_code(0x08, 0x0033)
-HCI_LE_ENHANCED_TRANSMITTER_TEST_COMMAND = hci_command_op_code(0x08, 0x0034)
-HCI_LE_SET_ADVERTISING_SET_RANDOM_ADDRESS_COMMAND = hci_command_op_code(0x08, 0x0035)
-HCI_LE_SET_EXTENDED_ADVERTISING_PARAMETERS_COMMAND = hci_command_op_code(0x08, 0x0036)
-HCI_LE_SET_EXTENDED_ADVERTISING_DATA_COMMAND = hci_command_op_code(0x08, 0x0037)
-HCI_LE_SET_EXTENDED_SCAN_RESPONSE_DATA_COMMAND = hci_command_op_code(0x08, 0x0038)
-HCI_LE_SET_EXTENDED_ADVERTISING_ENABLE_COMMAND = hci_command_op_code(0x08, 0x0039)
-HCI_LE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH_COMMAND = hci_command_op_code(0x08, 0x003A)
-HCI_LE_READ_NUMBER_OF_SUPPORTED_ADVERETISING_SETS_COMMAND = hci_command_op_code(0x08, 0x003B)
-HCI_LE_REMOVE_ADVERTISING_SET_COMMAND = hci_command_op_code(0x08, 0x003C)
-HCI_LE_CLEAR_ADVERTISING_SETS_COMMAND = hci_command_op_code(0x08, 0x003D)
-HCI_LE_SET_PERIODIC_ADVERTISING_PARAMETERS_COMMAND = hci_command_op_code(0x08, 0x003E)
-HCI_LE_SET_PERIODIC_ADVERTISING_DATA_COMMAND = hci_command_op_code(0x08, 0x003F)
-HCI_LE_SET_PERIODIC_ADVERTISING_ENABLE_COMMAND = hci_command_op_code(0x08, 0x0040)
-HCI_LE_SET_EXTENDED_SCAN_PARAMETERS_COMMAND = hci_command_op_code(0x08, 0x0041)
-HCI_LE_SET_EXTENDED_SCAN_ENABLE_COMMAND = hci_command_op_code(0x08, 0x0042)
-HCI_LE_SET_EXTENDED_CREATE_CONNECTION_COMMAND = hci_command_op_code(0x08, 0x0043)
-HCI_LE_PERIODIC_ADVERTISING_CREATE_SYNC_COMMAND = hci_command_op_code(0x08, 0x0044)
-HCI_LE_PERIODIC_ADVERTISING_CREATE_SYNC_CANCEL_COMMAND = hci_command_op_code(0x08, 0x0045)
-HCI_LE_PERIODIC_ADVERTISING_TERMINATE_SYNC_COMMAND = hci_command_op_code(0x08, 0x0046)
-HCI_LE_ADD_DEVICE_TO_PERIODIC_ADVERTISER_LIST_COMMAND = hci_command_op_code(0x08, 0x0047)
-HCI_LE_REMOVE_DEVICE_FROM_PERIODIC_ADVERTISER_LIST_COMMAND = hci_command_op_code(0x08, 0x0048)
-HCI_LE_CLEAR_PERIODIC_ADVERTISER_LIST_COMMAND = hci_command_op_code(0x08, 0x0049)
-HCI_LE_READ_PERIODIC_ADVERTISER_LIST_SIZE_COMMAND = hci_command_op_code(0x08, 0x004A)
-HCI_LE_READ_TRANSMIT_POWER_COMMAND = hci_command_op_code(0x08, 0x004B)
-HCI_LE_READ_RF_PATH_COMPENSATION_COMMAND = hci_command_op_code(0x08, 0x004C)
-HCI_LE_WRITE_RF_PATH_COMPENSATION_COMMAND = hci_command_op_code(0x08, 0x004D)
-HCI_LE_SET_PRIVACY_MODE_COMMAND = hci_command_op_code(0x08, 0x004E)
-
+HCI_INQUIRY_COMMAND = hci_command_op_code(0x01, 0x0001)
+HCI_INQUIRY_CANCEL_COMMAND = hci_command_op_code(0x01, 0x0002)
+HCI_PERIODIC_INQUIRY_MODE_COMMAND = hci_command_op_code(0x01, 0x0003)
+HCI_EXIT_PERIODIC_INQUIRY_MODE_COMMAND = hci_command_op_code(0x01, 0x0004)
+HCI_CREATE_CONNECTION_COMMAND = hci_command_op_code(0x01, 0x0005)
+HCI_DISCONNECT_COMMAND = hci_command_op_code(0x01, 0x0006)
+HCI_CREATE_CONNECTION_CANCEL_COMMAND = hci_command_op_code(0x01, 0x0008)
+HCI_ACCEPT_CONNECTION_REQUEST_COMMAND = hci_command_op_code(0x01, 0x0009)
+HCI_REJECT_CONNECTION_REQUEST_COMMAND = hci_command_op_code(0x01, 0x000A)
+HCI_LINK_KEY_REQUEST_REPLY_COMMAND = hci_command_op_code(0x01, 0x000B)
+HCI_LINK_KEY_REQUEST_NEGATIVE_REPLY_COMMAND = hci_command_op_code(0x01, 0x000C)
+HCI_PIN_CODE_REQUEST_REPLY_COMMAND = hci_command_op_code(0x01, 0x000D)
+HCI_PIN_CODE_REQUEST_NEGATIVE_REPLY_COMMAND = hci_command_op_code(0x01, 0x000E)
+HCI_CHANGE_CONNECTION_PACKET_TYPE_COMMAND = hci_command_op_code(0x01, 0x000F)
+HCI_AUTHENTICATION_REQUESTED_COMMAND = hci_command_op_code(0x01, 0x0011)
+HCI_SET_CONNECTION_ENCRYPTION_COMMAND = hci_command_op_code(0x01, 0x0013)
+HCI_CHANGE_CONNECTION_LINK_KEY_COMMAND = hci_command_op_code(0x01, 0x0015)
+HCI_LINK_KEY_SELECTION_COMMAND = hci_command_op_code(0x01, 0x0017)
+HCI_REMOTE_NAME_REQUEST_COMMAND = hci_command_op_code(0x01, 0x0019)
+HCI_REMOTE_NAME_REQUEST_CANCEL_COMMAND = hci_command_op_code(0x01, 0x001A)
+HCI_READ_REMOTE_SUPPORTED_FEATURES_COMMAND = hci_command_op_code(0x01, 0x001B)
+HCI_READ_REMOTE_EXTENDED_FEATURES_COMMAND = hci_command_op_code(0x01, 0x001C)
+HCI_READ_REMOTE_VERSION_INFORMATION_COMMAND = hci_command_op_code(0x01, 0x001D)
+HCI_READ_CLOCK_OFFSET_COMMAND = hci_command_op_code(0x01, 0x001F)
+HCI_READ_LMP_HANDLE_COMMAND = hci_command_op_code(0x01, 0x0020)
+HCI_SETUP_SYNCHRONOUS_CONNECTION_COMMAND = hci_command_op_code(0x01, 0x0028)
+HCI_ACCEPT_SYNCHRONOUS_CONNECTION_REQUEST_COMMAND = hci_command_op_code(0x01, 0x0029)
+HCI_REJECT_SYNCHRONOUS_CONNECTION_REQUEST_COMMAND = hci_command_op_code(0x01, 0x002A)
+HCI_IO_CAPABILITY_REQUEST_REPLY_COMMAND = hci_command_op_code(0x01, 0x002B)
+HCI_USER_CONFIRMATION_REQUEST_REPLY_COMMAND = hci_command_op_code(0x01, 0x002C)
+HCI_USER_CONFIRMATION_REQUEST_NEGATIVE_REPLY_COMMAND = hci_command_op_code(0x01, 0x002D)
+HCI_USER_PASSKEY_REQUEST_REPLY_COMMAND = hci_command_op_code(0x01, 0x002E)
+HCI_USER_PASSKEY_REQUEST_NEGATIVE_REPLY_COMMAND = hci_command_op_code(0x01, 0x002F)
+HCI_REMOTE_OOB_DATA_REQUEST_REPLY_COMMAND = hci_command_op_code(0x01, 0x0030)
+HCI_REMOTE_OOB_DATA_REQUEST_NEGATIVE_REPLY_COMMAND = hci_command_op_code(0x01, 0x0033)
+HCI_IO_CAPABILITY_REQUEST_NEGATIVE_REPLY_COMMAND = hci_command_op_code(0x01, 0x0034)
+HCI_ENHANCED_SETUP_SYNCHRONOUS_CONNECTION_COMMAND = hci_command_op_code(0x01, 0x003D)
+HCI_ENHANCED_ACCEPT_SYNCHRONOUS_CONNECTION_REQUEST_COMMAND = hci_command_op_code(0x01, 0x003E)
+HCI_TRUNCATED_PAGE_COMMAND = hci_command_op_code(0x01, 0x003F)
+HCI_TRUNCATED_PAGE_CANCEL_COMMAND = hci_command_op_code(0x01, 0x0040)
+HCI_SET_CONNECTIONLESS_PERIPHERAL_BROADCAST_COMMAND = hci_command_op_code(0x01, 0x0041)
+HCI_SET_CONNECTIONLESS_PERIPHERAL_BROADCAST_RECEIVE_COMMAND = hci_command_op_code(0x01, 0x0042)
+HCI_START_SYNCHRONIZATION_TRAIN_COMMAND = hci_command_op_code(0x01, 0x0043)
+HCI_RECEIVE_SYNCHRONIZATION_TRAIN_COMMAND = hci_command_op_code(0x01, 0x0044)
+HCI_REMOTE_OOB_EXTENDED_DATA_REQUEST_REPLY_COMMAND = hci_command_op_code(0x01, 0x0045)
+HCI_HOLD_MODE_COMMAND = hci_command_op_code(0x02, 0x0001)
+HCI_SNIFF_MODE_COMMAND = hci_command_op_code(0x02, 0x0003)
+HCI_EXIT_SNIFF_MODE_COMMAND = hci_command_op_code(0x02, 0x0004)
+HCI_QOS_SETUP_COMMAND = hci_command_op_code(0x02, 0x0007)
+HCI_ROLE_DISCOVERY_COMMAND = hci_command_op_code(0x02, 0x0009)
+HCI_SWITCH_ROLE_COMMAND = hci_command_op_code(0x02, 0x000B)
+HCI_READ_LINK_POLICY_SETTINGS_COMMAND = hci_command_op_code(0x02, 0x000C)
+HCI_WRITE_LINK_POLICY_SETTINGS_COMMAND = hci_command_op_code(0x02, 0x000D)
+HCI_READ_DEFAULT_LINK_POLICY_SETTINGS_COMMAND = hci_command_op_code(0x02, 0x000E)
+HCI_WRITE_DEFAULT_LINK_POLICY_SETTINGS_COMMAND = hci_command_op_code(0x02, 0x000F)
+HCI_FLOW_SPECIFICATION_COMMAND = hci_command_op_code(0x02, 0x0010)
+HCI_SNIFF_SUBRATING_COMMAND = hci_command_op_code(0x02, 0x0011)
+HCI_SET_EVENT_MASK_COMMAND = hci_command_op_code(0x03, 0x0001)
+HCI_RESET_COMMAND = hci_command_op_code(0x03, 0x0003)
+HCI_SET_EVENT_FILTER_COMMAND = hci_command_op_code(0x03, 0x0005)
+HCI_FLUSH_COMMAND = hci_command_op_code(0x03, 0x0008)
+HCI_READ_PIN_TYPE_COMMAND = hci_command_op_code(0x03, 0x0009)
+HCI_WRITE_PIN_TYPE_COMMAND = hci_command_op_code(0x03, 0x000A)
+HCI_READ_STORED_LINK_KEY_COMMAND = hci_command_op_code(0x03, 0x000D)
+HCI_WRITE_STORED_LINK_KEY_COMMAND = hci_command_op_code(0x03, 0x0011)
+HCI_DELETE_STORED_LINK_KEY_COMMAND = hci_command_op_code(0x03, 0x0012)
+HCI_WRITE_LOCAL_NAME_COMMAND = hci_command_op_code(0x03, 0x0013)
+HCI_READ_LOCAL_NAME_COMMAND = hci_command_op_code(0x03, 0x0014)
+HCI_READ_CONNECTION_ACCEPT_TIMEOUT_COMMAND = hci_command_op_code(0x03, 0x0015)
+HCI_WRITE_CONNECTION_ACCEPT_TIMEOUT_COMMAND = hci_command_op_code(0x03, 0x0016)
+HCI_READ_PAGE_TIMEOUT_COMMAND = hci_command_op_code(0x03, 0x0017)
+HCI_WRITE_PAGE_TIMEOUT_COMMAND = hci_command_op_code(0x03, 0x0018)
+HCI_READ_SCAN_ENABLE_COMMAND = hci_command_op_code(0x03, 0x0019)
+HCI_WRITE_SCAN_ENABLE_COMMAND = hci_command_op_code(0x03, 0x001A)
+HCI_READ_PAGE_SCAN_ACTIVITY_COMMAND = hci_command_op_code(0x03, 0x001B)
+HCI_WRITE_PAGE_SCAN_ACTIVITY_COMMAND = hci_command_op_code(0x03, 0x001C)
+HCI_READ_INQUIRY_SCAN_ACTIVITY_COMMAND = hci_command_op_code(0x03, 0x001D)
+HCI_WRITE_INQUIRY_SCAN_ACTIVITY_COMMAND = hci_command_op_code(0x03, 0x001E)
+HCI_READ_AUTHENTICATION_ENABLE_COMMAND = hci_command_op_code(0x03, 0x001F)
+HCI_WRITE_AUTHENTICATION_ENABLE_COMMAND = hci_command_op_code(0x03, 0x0020)
+HCI_READ_CLASS_OF_DEVICE_COMMAND = hci_command_op_code(0x03, 0x0023)
+HCI_WRITE_CLASS_OF_DEVICE_COMMAND = hci_command_op_code(0x03, 0x0024)
+HCI_READ_VOICE_SETTING_COMMAND = hci_command_op_code(0x03, 0x0025)
+HCI_WRITE_VOICE_SETTING_COMMAND = hci_command_op_code(0x03, 0x0026)
+HCI_READ_AUTOMATIC_FLUSH_TIMEOUT_COMMAND = hci_command_op_code(0x03, 0x0027)
+HCI_WRITE_AUTOMATIC_FLUSH_TIMEOUT_COMMAND = hci_command_op_code(0x03, 0x0028)
+HCI_READ_NUM_BROADCAST_RETRANSMISSIONS_COMMAND = hci_command_op_code(0x03, 0x0029)
+HCI_WRITE_NUM_BROADCAST_RETRANSMISSIONS_COMMAND = hci_command_op_code(0x03, 0x002A)
+HCI_READ_HOLD_MODE_ACTIVITY_COMMAND = hci_command_op_code(0x03, 0x002B)
+HCI_WRITE_HOLD_MODE_ACTIVITY_COMMAND = hci_command_op_code(0x03, 0x002C)
+HCI_READ_TRANSMIT_POWER_LEVEL_COMMAND = hci_command_op_code(0x03, 0x002D)
+HCI_READ_SYNCHRONOUS_FLOW_CONTROL_ENABLE_COMMAND = hci_command_op_code(0x03, 0x002E)
+HCI_WRITE_SYNCHRONOUS_FLOW_CONTROL_ENABLE_COMMAND = hci_command_op_code(0x03, 0x002F)
+HCI_SET_CONTROLLER_TO_HOST_FLOW_CONTROL_COMMAND = hci_command_op_code(0x03, 0x0031)
+HCI_HOST_BUFFER_SIZE_COMMAND = hci_command_op_code(0x03, 0x0033)
+HCI_HOST_NUMBER_OF_COMPLETED_PACKETS_COMMAND = hci_command_op_code(0x03, 0x0035)
+HCI_READ_LINK_SUPERVISION_TIMEOUT_COMMAND = hci_command_op_code(0x03, 0x0036)
+HCI_WRITE_LINK_SUPERVISION_TIMEOUT_COMMAND = hci_command_op_code(0x03, 0x0037)
+HCI_READ_NUMBER_OF_SUPPORTED_IAC_COMMAND = hci_command_op_code(0x03, 0x0038)
+HCI_READ_CURRENT_IAC_LAP_COMMAND = hci_command_op_code(0x03, 0x0039)
+HCI_WRITE_CURRENT_IAC_LAP_COMMAND = hci_command_op_code(0x03, 0x003A)
+HCI_SET_AFH_HOST_CHANNEL_CLASSIFICATION_COMMAND = hci_command_op_code(0x03, 0x003F)
+HCI_READ_INQUIRY_SCAN_TYPE_COMMAND = hci_command_op_code(0x03, 0x0042)
+HCI_WRITE_INQUIRY_SCAN_TYPE_COMMAND = hci_command_op_code(0x03, 0x0043)
+HCI_READ_INQUIRY_MODE_COMMAND = hci_command_op_code(0x03, 0x0044)
+HCI_WRITE_INQUIRY_MODE_COMMAND = hci_command_op_code(0x03, 0x0045)
+HCI_READ_PAGE_SCAN_TYPE_COMMAND = hci_command_op_code(0x03, 0x0046)
+HCI_WRITE_PAGE_SCAN_TYPE_COMMAND = hci_command_op_code(0x03, 0x0047)
+HCI_READ_AFH_CHANNEL_ASSESSMENT_MODE_COMMAND = hci_command_op_code(0x03, 0x0048)
+HCI_WRITE_AFH_CHANNEL_ASSESSMENT_MODE_COMMAND = hci_command_op_code(0x03, 0x0049)
+HCI_READ_EXTENDED_INQUIRY_RESPONSE_COMMAND = hci_command_op_code(0x03, 0x0051)
+HCI_WRITE_EXTENDED_INQUIRY_RESPONSE_COMMAND = hci_command_op_code(0x03, 0x0052)
+HCI_REFRESH_ENCRYPTION_KEY_COMMAND = hci_command_op_code(0x03, 0x0053)
+HCI_READ_SIMPLE_PAIRING_MODE_COMMAND = hci_command_op_code(0x03, 0x0055)
+HCI_WRITE_SIMPLE_PAIRING_MODE_COMMAND = hci_command_op_code(0x03, 0x0056)
+HCI_READ_LOCAL_OOB_DATA_COMMAND = hci_command_op_code(0x03, 0x0057)
+HCI_READ_INQUIRY_RESPONSE_TRANSMIT_POWER_LEVEL_COMMAND = hci_command_op_code(0x03, 0x0058)
+HCI_WRITE_INQUIRY_TRANSMIT_POWER_LEVEL_COMMAND = hci_command_op_code(0x03, 0x0059)
+HCI_READ_DEFAULT_ERRONEOUS_DATA_REPORTING_COMMAND = hci_command_op_code(0x03, 0x005A)
+HCI_WRITE_DEFAULT_ERRONEOUS_DATA_REPORTING_COMMAND = hci_command_op_code(0x03, 0x005B)
+HCI_ENHANCED_FLUSH_COMMAND = hci_command_op_code(0x03, 0x005F)
+HCI_SEND_KEYPRESS_NOTIFICATION_COMMAND = hci_command_op_code(0x03, 0x0060)
+HCI_SET_EVENT_MASK_PAGE_2_COMMAND = hci_command_op_code(0x03, 0x0063)
+HCI_READ_FLOW_CONTROL_MODE_COMMAND = hci_command_op_code(0x03, 0x0066)
+HCI_WRITE_FLOW_CONTROL_MODE_COMMAND = hci_command_op_code(0x03, 0x0067)
+HCI_READ_ENHANCED_TRANSMIT_POWER_LEVEL_COMMAND = hci_command_op_code(0x03, 0x0068)
+HCI_READ_LE_HOST_SUPPORT_COMMAND = hci_command_op_code(0x03, 0x006C)
+HCI_WRITE_LE_HOST_SUPPORT_COMMAND = hci_command_op_code(0x03, 0x006D)
+HCI_SET_MWS_CHANNEL_PARAMETERS_COMMAND = hci_command_op_code(0x03, 0x006E)
+HCI_SET_EXTERNAL_FRAME_CONFIGURATION_COMMAND = hci_command_op_code(0x03, 0x006F)
+HCI_SET_MWS_SIGNALING_COMMAND = hci_command_op_code(0x03, 0x0070)
+HCI_SET_MWS_TRANSPORT_LAYER_COMMAND = hci_command_op_code(0x03, 0x0071)
+HCI_SET_MWS_SCAN_FREQUENCY_TABLE_COMMAND = hci_command_op_code(0x03, 0x0072)
+HCI_SET_MWS_PATTERN_CONFIGURATION_COMMAND = hci_command_op_code(0x03, 0x0073)
+HCI_SET_RESERVED_LT_ADDR_COMMAND = hci_command_op_code(0x03, 0x0074)
+HCI_DELETE_RESERVED_LT_ADDR_COMMAND = hci_command_op_code(0x03, 0x0075)
+HCI_SET_CONNECTIONLESS_PERIPHERAL_BROADCAST_DATA_COMMAND = hci_command_op_code(0x03, 0x0076)
+HCI_READ_SYNCHRONIZATION_TRAIN_PARAMETERS_COMMAND = hci_command_op_code(0x03, 0x0077)
+HCI_WRITE_SYNCHRONIZATION_TRAIN_PARAMETERS_COMMAND = hci_command_op_code(0x03, 0x0078)
+HCI_READ_SECURE_CONNECTIONS_HOST_SUPPORT_COMMAND = hci_command_op_code(0x03, 0x0079)
+HCI_WRITE_SECURE_CONNECTIONS_HOST_SUPPORT_COMMAND = hci_command_op_code(0x03, 0x007A)
+HCI_READ_AUTHENTICATED_PAYLOAD_TIMEOUT_COMMAND = hci_command_op_code(0x03, 0x007B)
+HCI_WRITE_AUTHENTICATED_PAYLOAD_TIMEOUT_COMMAND = hci_command_op_code(0x03, 0x007C)
+HCI_READ_LOCAL_OOB_EXTENDED_DATA_COMMAND = hci_command_op_code(0x03, 0x007D)
+HCI_READ_EXTENDED_PAGE_TIMEOUT_COMMAND = hci_command_op_code(0x03, 0x007E)
+HCI_WRITE_EXTENDED_PAGE_TIMEOUT_COMMAND = hci_command_op_code(0x03, 0x007F)
+HCI_READ_EXTENDED_INQUIRY_LENGTH_COMMAND = hci_command_op_code(0x03, 0x0080)
+HCI_WRITE_EXTENDED_INQUIRY_LENGTH_COMMAND = hci_command_op_code(0x03, 0x0081)
+HCI_SET_ECOSYSTEM_BASE_INTERVAL_COMMAND = hci_command_op_code(0x03, 0x0082)
+HCI_CONFIGURE_DATA_PATH_COMMAND = hci_command_op_code(0x03, 0x0083)
+HCI_SET_MIN_ENCRYPTION_KEY_SIZE_COMMAND = hci_command_op_code(0x03, 0x0084)
+HCI_READ_LOCAL_VERSION_INFORMATION_COMMAND = hci_command_op_code(0x04, 0x0001)
+HCI_READ_LOCAL_SUPPORTED_COMMANDS_COMMAND = hci_command_op_code(0x04, 0x0002)
+HCI_READ_LOCAL_SUPPORTED_FEATURES_COMMAND = hci_command_op_code(0x04, 0x0003)
+HCI_READ_LOCAL_EXTENDED_FEATURES_COMMAND = hci_command_op_code(0x04, 0x0004)
+HCI_READ_BUFFER_SIZE_COMMAND = hci_command_op_code(0x04, 0x0005)
+HCI_READ_BD_ADDR_COMMAND = hci_command_op_code(0x04, 0x0009)
+HCI_READ_DATA_BLOCK_SIZE_COMMAND = hci_command_op_code(0x04, 0x000A)
+HCI_READ_LOCAL_SUPPORTED_CODECS_COMMAND = hci_command_op_code(0x04, 0x000B)
+HCI_READ_LOCAL_SIMPLE_PAIRING_OPTIONS_COMMAND = hci_command_op_code(0x04, 0x000C)
+HCI_READ_LOCAL_SUPPORTED_CODECS_V2_COMMAND = hci_command_op_code(0x04, 0x000D)
+HCI_READ_LOCAL_SUPPORTED_CODEC_CAPABILITIES_COMMAND = hci_command_op_code(0x04, 0x000E)
+HCI_READ_LOCAL_SUPPORTED_CONTROLLER_DELAY_COMMAND = hci_command_op_code(0x04, 0x000F)
+HCI_READ_FAILED_CONTACT_COUNTER_COMMAND = hci_command_op_code(0x05, 0x0001)
+HCI_RESET_FAILED_CONTACT_COUNTER_COMMAND = hci_command_op_code(0x05, 0x0002)
+HCI_READ_LINK_QUALITY_COMMAND = hci_command_op_code(0x05, 0x0003)
+HCI_READ_RSSI_COMMAND = hci_command_op_code(0x05, 0x0005)
+HCI_READ_AFH_CHANNEL_MAP_COMMAND = hci_command_op_code(0x05, 0x0006)
+HCI_READ_CLOCK_COMMAND = hci_command_op_code(0x05, 0x0007)
+HCI_READ_ENCRYPTION_KEY_SIZE_COMMAND = hci_command_op_code(0x05, 0x0008)
+HCI_GET_MWS_TRANSPORT_LAYER_CONFIGURATION_COMMAND = hci_command_op_code(0x05, 0x000C)
+HCI_SET_TRIGGERED_CLOCK_CAPTURE_COMMAND = hci_command_op_code(0x05, 0x000D)
+HCI_READ_LOOPBACK_MODE_COMMAND = hci_command_op_code(0x06, 0x0001)
+HCI_WRITE_LOOPBACK_MODE_COMMAND = hci_command_op_code(0x06, 0x0002)
+HCI_ENABLE_DEVICE_UNDER_TEST_MODE_COMMAND = hci_command_op_code(0x06, 0x0003)
+HCI_WRITE_SIMPLE_PAIRING_DEBUG_MODE_COMMAND = hci_command_op_code(0x06, 0x0004)
+HCI_WRITE_SECURE_CONNECTIONS_TEST_MODE_COMMAND = hci_command_op_code(0x06, 0x000A)
+HCI_LE_SET_EVENT_MASK_COMMAND = hci_command_op_code(0x08, 0x0001)
+HCI_LE_READ_BUFFER_SIZE_COMMAND = hci_command_op_code(0x08, 0x0002)
+HCI_LE_READ_LOCAL_SUPPORTED_FEATURES_COMMAND = hci_command_op_code(0x08, 0x0003)
+HCI_LE_SET_RANDOM_ADDRESS_COMMAND = hci_command_op_code(0x08, 0x0005)
+HCI_LE_SET_ADVERTISING_PARAMETERS_COMMAND = hci_command_op_code(0x08, 0x0006)
+HCI_LE_READ_ADVERTISING_PHYSICAL_CHANNEL_TX_POWER_COMMAND = hci_command_op_code(0x08, 0x0007)
+HCI_LE_SET_ADVERTISING_DATA_COMMAND = hci_command_op_code(0x08, 0x0008)
+HCI_LE_SET_SCAN_RESPONSE_DATA_COMMAND = hci_command_op_code(0x08, 0x0009)
+HCI_LE_SET_ADVERTISING_ENABLE_COMMAND = hci_command_op_code(0x08, 0x000A)
+HCI_LE_SET_SCAN_PARAMETERS_COMMAND = hci_command_op_code(0x08, 0x000B)
+HCI_LE_SET_SCAN_ENABLE_COMMAND = hci_command_op_code(0x08, 0x000C)
+HCI_LE_CREATE_CONNECTION_COMMAND = hci_command_op_code(0x08, 0x000D)
+HCI_LE_CREATE_CONNECTION_CANCEL_COMMAND = hci_command_op_code(0x08, 0x000E)
+HCI_LE_READ_FILTER_ACCEPT_LIST_SIZE_COMMAND = hci_command_op_code(0x08, 0x000F)
+HCI_LE_CLEAR_FILTER_ACCEPT_LIST_COMMAND = hci_command_op_code(0x08, 0x0010)
+HCI_LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST_COMMAND = hci_command_op_code(0x08, 0x0011)
+HCI_LE_REMOVE_DEVICE_FROM_FILTER_ACCEPT_LIST_COMMAND = hci_command_op_code(0x08, 0x0012)
+HCI_LE_CONNECTION_UPDATE_COMMAND = hci_command_op_code(0x08, 0x0013)
+HCI_LE_SET_HOST_CHANNEL_CLASSIFICATION_COMMAND = hci_command_op_code(0x08, 0x0014)
+HCI_LE_READ_CHANNEL_MAP_COMMAND = hci_command_op_code(0x08, 0x0015)
+HCI_LE_READ_REMOTE_FEATURES_COMMAND = hci_command_op_code(0x08, 0x0016)
+HCI_LE_ENCRYPT_COMMAND = hci_command_op_code(0x08, 0x0017)
+HCI_LE_RAND_COMMAND = hci_command_op_code(0x08, 0x0018)
+HCI_LE_ENABLE_ENCRYPTION_COMMAND = hci_command_op_code(0x08, 0x0019)
+HCI_LE_LONG_TERM_KEY_REQUEST_REPLY_COMMAND = hci_command_op_code(0x08, 0x001A)
+HCI_LE_LONG_TERM_KEY_REQUEST_NEGATIVE_REPLY_COMMAND = hci_command_op_code(0x08, 0x001B)
+HCI_LE_READ_SUPPORTED_STATES_COMMAND = hci_command_op_code(0x08, 0x001C)
+HCI_LE_RECEIVER_TEST_COMMAND = hci_command_op_code(0x08, 0x001D)
+HCI_LE_TRANSMITTER_TEST_COMMAND = hci_command_op_code(0x08, 0x001E)
+HCI_LE_TEST_END_COMMAND = hci_command_op_code(0x08, 0x001F)
+HCI_LE_REMOTE_CONNECTION_PARAMETER_REQUEST_REPLY_COMMAND = hci_command_op_code(0x08, 0x0020)
+HCI_LE_REMOTE_CONNECTION_PARAMETER_REQUEST_NEGATIVE_REPLY_COMMAND = hci_command_op_code(0x08, 0x0021)
+HCI_LE_SET_DATA_LENGTH_COMMAND = hci_command_op_code(0x08, 0x0022)
+HCI_LE_READ_SUGGESTED_DEFAULT_DATA_LENGTH_COMMAND = hci_command_op_code(0x08, 0x0023)
+HCI_LE_WRITE_SUGGESTED_DEFAULT_DATA_LENGTH_COMMAND = hci_command_op_code(0x08, 0x0024)
+HCI_LE_READ_LOCAL_P_256_PUBLIC_KEY_COMMAND = hci_command_op_code(0x08, 0x0025)
+HCI_LE_GENERATE_DHKEY_COMMAND = hci_command_op_code(0x08, 0x0026)
+HCI_LE_ADD_DEVICE_TO_RESOLVING_LIST_COMMAND = hci_command_op_code(0x08, 0x0027)
+HCI_LE_REMOVE_DEVICE_FROM_RESOLVING_LIST_COMMAND = hci_command_op_code(0x08, 0x0028)
+HCI_LE_CLEAR_RESOLVING_LIST_COMMAND = hci_command_op_code(0x08, 0x0029)
+HCI_LE_READ_RESOLVING_LIST_SIZE_COMMAND = hci_command_op_code(0x08, 0x002A)
+HCI_LE_READ_PEER_RESOLVABLE_ADDRESS_COMMAND = hci_command_op_code(0x08, 0x002B)
+HCI_LE_READ_LOCAL_RESOLVABLE_ADDRESS_COMMAND = hci_command_op_code(0x08, 0x002C)
+HCI_LE_SET_ADDRESS_RESOLUTION_ENABLE_COMMAND = hci_command_op_code(0x08, 0x002D)
+HCI_LE_SET_RESOLVABLE_PRIVATE_ADDRESS_TIMEOUT_COMMAND = hci_command_op_code(0x08, 0x002E)
+HCI_LE_READ_MAXIMUM_DATA_LENGTH_COMMAND = hci_command_op_code(0x08, 0x002F)
+HCI_LE_READ_PHY_COMMAND = hci_command_op_code(0x08, 0x0030)
+HCI_LE_SET_DEFAULT_PHY_COMMAND = hci_command_op_code(0x08, 0x0031)
+HCI_LE_SET_PHY_COMMAND = hci_command_op_code(0x08, 0x0032)
+HCI_LE_RECEIVER_TEST_V2_COMMAND = hci_command_op_code(0x08, 0x0033)
+HCI_LE_TRANSMITTER_TEST_V2_COMMAND = hci_command_op_code(0x08, 0x0034)
+HCI_LE_SET_ADVERTISING_SET_RANDOM_ADDRESS_COMMAND = hci_command_op_code(0x08, 0x0035)
+HCI_LE_SET_EXTENDED_ADVERTISING_PARAMETERS_COMMAND = hci_command_op_code(0x08, 0x0036)
+HCI_LE_SET_EXTENDED_ADVERTISING_DATA_COMMAND = hci_command_op_code(0x08, 0x0037)
+HCI_LE_SET_EXTENDED_SCAN_RESPONSE_DATA_COMMAND = hci_command_op_code(0x08, 0x0038)
+HCI_LE_SET_EXTENDED_ADVERTISING_ENABLE_COMMAND = hci_command_op_code(0x08, 0x0039)
+HCI_LE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH_COMMAND = hci_command_op_code(0x08, 0x003A)
+HCI_LE_READ_NUMBER_OF_SUPPORTED_ADVERTISING_SETS_COMMAND = hci_command_op_code(0x08, 0x003B)
+HCI_LE_REMOVE_ADVERTISING_SET_COMMAND = hci_command_op_code(0x08, 0x003C)
+HCI_LE_CLEAR_ADVERTISING_SETS_COMMAND = hci_command_op_code(0x08, 0x003D)
+HCI_LE_SET_PERIODIC_ADVERTISING_PARAMETERS_COMMAND = hci_command_op_code(0x08, 0x003E)
+HCI_LE_SET_PERIODIC_ADVERTISING_DATA_COMMAND = hci_command_op_code(0x08, 0x003F)
+HCI_LE_SET_PERIODIC_ADVERTISING_ENABLE_COMMAND = hci_command_op_code(0x08, 0x0040)
+HCI_LE_SET_EXTENDED_SCAN_PARAMETERS_COMMAND = hci_command_op_code(0x08, 0x0041)
+HCI_LE_SET_EXTENDED_SCAN_ENABLE_COMMAND = hci_command_op_code(0x08, 0x0042)
+HCI_LE_EXTENDED_CREATE_CONNECTION_COMMAND = hci_command_op_code(0x08, 0x0043)
+HCI_LE_PERIODIC_ADVERTISING_CREATE_SYNC_COMMAND = hci_command_op_code(0x08, 0x0044)
+HCI_LE_PERIODIC_ADVERTISING_CREATE_SYNC_CANCEL_COMMAND = hci_command_op_code(0x08, 0x0045)
+HCI_LE_PERIODIC_ADVERTISING_TERMINATE_SYNC_COMMAND = hci_command_op_code(0x08, 0x0046)
+HCI_LE_ADD_DEVICE_TO_PERIODIC_ADVERTISER_LIST_COMMAND = hci_command_op_code(0x08, 0x0047)
+HCI_LE_REMOVE_DEVICE_FROM_PERIODIC_ADVERTISER_LIST_COMMAND = hci_command_op_code(0x08, 0x0048)
+HCI_LE_CLEAR_PERIODIC_ADVERTISER_LIST_COMMAND = hci_command_op_code(0x08, 0x0049)
+HCI_LE_READ_PERIODIC_ADVERTISER_LIST_SIZE_COMMAND = hci_command_op_code(0x08, 0x004A)
+HCI_LE_READ_TRANSMIT_POWER_COMMAND = hci_command_op_code(0x08, 0x004B)
+HCI_LE_READ_RF_PATH_COMPENSATION_COMMAND = hci_command_op_code(0x08, 0x004C)
+HCI_LE_WRITE_RF_PATH_COMPENSATION_COMMAND = hci_command_op_code(0x08, 0x004D)
+HCI_LE_SET_PRIVACY_MODE_COMMAND = hci_command_op_code(0x08, 0x004E)
+HCI_LE_RECEIVER_TEST_V3_COMMAND = hci_command_op_code(0x08, 0x004F)
+HCI_LE_TRANSMITTER_TEST_V3_COMMAND = hci_command_op_code(0x08, 0x0050)
+HCI_LE_SET_CONNECTIONLESS_CTE_TRANSMIT_PARAMETERS_COMMAND = hci_command_op_code(0x08, 0x0051)
+HCI_LE_SET_CONNECTIONLESS_CTE_TRANSMIT_ENABLE_COMMAND = hci_command_op_code(0x08, 0x0052)
+HCI_LE_SET_CONNECTIONLESS_IQ_SAMPLING_ENABLE_COMMAND = hci_command_op_code(0x08, 0x0053)
+HCI_LE_SET_CONNECTION_CTE_RECEIVE_PARAMETERS_COMMAND = hci_command_op_code(0x08, 0x0054)
+HCI_LE_SET_CONNECTION_CTE_TRANSMIT_PARAMETERS_COMMAND = hci_command_op_code(0x08, 0x0055)
+HCI_LE_CONNECTION_CTE_REQUEST_ENABLE_COMMAND = hci_command_op_code(0x08, 0x0056)
+HCI_LE_CONNECTION_CTE_RESPONSE_ENABLE_COMMAND = hci_command_op_code(0x08, 0x0057)
+HCI_LE_READ_ANTENNA_INFORMATION_COMMAND = hci_command_op_code(0x08, 0x0058)
+HCI_LE_SET_PERIODIC_ADVERTISING_RECEIVE_ENABLE_COMMAND = hci_command_op_code(0x08, 0x0059)
+HCI_LE_PERIODIC_ADVERTISING_SYNC_TRANSFER_COMMAND = hci_command_op_code(0x08, 0x005A)
+HCI_LE_PERIODIC_ADVERTISING_SET_INFO_TRANSFER_COMMAND = hci_command_op_code(0x08, 0x005B)
+HCI_LE_SET_PERIODIC_ADVERTISING_SYNC_TRANSFER_PARAMETERS_COMMAND = hci_command_op_code(0x08, 0x005C)
+HCI_LE_SET_DEFAULT_PERIODIC_ADVERTISING_SYNC_TRANSFER_PARAMETERS_COMMAND = hci_command_op_code(0x08, 0x005D)
+HCI_LE_GENERATE_DHKEY_V2_COMMAND = hci_command_op_code(0x08, 0x005E)
+HCI_LE_MODIFY_SLEEP_CLOCK_ACCURACY_COMMAND = hci_command_op_code(0x08, 0x005F)
+HCI_LE_READ_BUFFER_SIZE_V2_COMMAND = hci_command_op_code(0x08, 0x0060)
+HCI_LE_READ_ISO_TX_SYNC_COMMAND = hci_command_op_code(0x08, 0x0061)
+HCI_LE_SET_CIG_PARAMETERS_COMMAND = hci_command_op_code(0x08, 0x0062)
+HCI_LE_SET_CIG_PARAMETERS_TEST_COMMAND = hci_command_op_code(0x08, 0x0063)
+HCI_LE_CREATE_CIS_COMMAND = hci_command_op_code(0x08, 0x0064)
+HCI_LE_REMOVE_CIG_COMMAND = hci_command_op_code(0x08, 0x0065)
+HCI_LE_ACCEPT_CIS_REQUEST_COMMAND = hci_command_op_code(0x08, 0x0066)
+HCI_LE_REJECT_CIS_REQUEST_COMMAND = hci_command_op_code(0x08, 0x0067)
+HCI_LE_CREATE_BIG_COMMAND = hci_command_op_code(0x08, 0x0068)
+HCI_LE_CREATE_BIG_TEST_COMMAND = hci_command_op_code(0x08, 0x0069)
+HCI_LE_TERMINATE_BIG_COMMAND = hci_command_op_code(0x08, 0x006A)
+HCI_LE_BIG_CREATE_SYNC_COMMAND = hci_command_op_code(0x08, 0x006B)
+HCI_LE_BIG_TERMINATE_SYNC_COMMAND = hci_command_op_code(0x08, 0x006C)
+HCI_LE_REQUEST_PEER_SCA_COMMAND = hci_command_op_code(0x08, 0x006D)
+HCI_LE_SETUP_ISO_DATA_PATH_COMMAND = hci_command_op_code(0x08, 0x006E)
+HCI_LE_REMOVE_ISO_DATA_PATH_COMMAND = hci_command_op_code(0x08, 0x006F)
+HCI_LE_ISO_TRANSMIT_TEST_COMMAND = hci_command_op_code(0x08, 0x0070)
+HCI_LE_ISO_RECEIVE_TEST_COMMAND = hci_command_op_code(0x08, 0x0071)
+HCI_LE_ISO_READ_TEST_COUNTERS_COMMAND = hci_command_op_code(0x08, 0x0072)
+HCI_LE_ISO_TEST_END_COMMAND = hci_command_op_code(0x08, 0x0073)
+HCI_LE_SET_HOST_FEATURE_COMMAND = hci_command_op_code(0x08, 0x0074)
+HCI_LE_READ_ISO_LINK_QUALITY_COMMAND = hci_command_op_code(0x08, 0x0075)
+HCI_LE_ENHANCED_READ_TRANSMIT_POWER_LEVEL_COMMAND = hci_command_op_code(0x08, 0x0076)
+HCI_LE_READ_REMOTE_TRANSMIT_POWER_LEVEL_COMMAND = hci_command_op_code(0x08, 0x0077)
+HCI_LE_SET_PATH_LOSS_REPORTING_PARAMETERS_COMMAND = hci_command_op_code(0x08, 0x0078)
+HCI_LE_SET_PATH_LOSS_REPORTING_ENABLE_COMMAND = hci_command_op_code(0x08, 0x0079)
+HCI_LE_SET_TRANSMIT_POWER_REPORTING_ENABLE_COMMAND = hci_command_op_code(0x08, 0x007A)
+HCI_LE_TRANSMITTER_TEST_V4_COMMAND = hci_command_op_code(0x08, 0x007B)
+HCI_LE_SET_DATA_RELATED_ADDRESS_CHANGES_COMMAND = hci_command_op_code(0x08, 0x007C)
+HCI_LE_SET_DEFAULT_SUBRATE_COMMAND = hci_command_op_code(0x08, 0x007D)
+HCI_LE_SUBRATE_REQUEST_COMMAND = hci_command_op_code(0x08, 0x007E)
HCI_COMMAND_NAMES = {
- HCI_INQUIRY_COMMAND: 'HCI_INQUIRY_COMMAND',
- HCI_INQUIRY_CANCEL_COMMAND: 'HCI_INQUIRY_CANCEL_COMMAND',
- HCI_CREATE_CONNECTION_COMMAND: 'HCI_CREATE_CONNECTION_COMMAND',
- HCI_DISCONNECT_COMMAND: 'HCI_DISCONNECT_COMMAND',
- HCI_ACCEPT_CONNECTION_REQUEST_COMMAND: 'HCI_ACCEPT_CONNECTION_REQUEST_COMMAND',
- HCI_LINK_KEY_REQUEST_REPLY_COMMAND: 'HCI_LINK_KEY_REQUEST_REPLY_COMMAND',
- HCI_LINK_KEY_REQUEST_NEGATIVE_REPLY_COMMAND: 'HCI_LINK_KEY_REQUEST_NEGATIVE_REPLY_COMMAND',
- HCI_PIN_CODE_REQUEST_NEGATIVE_REPLY_COMMAND: 'HCI_PIN_CODE_REQUEST_NEGATIVE_REPLY_COMMAND',
- HCI_CHANGE_CONNECTION_PACKET_TYPE_COMMAND: 'HCI_CHANGE_CONNECTION_PACKET_TYPE_COMMAND',
- HCI_AUTHENTICATION_REQUESTED_COMMAND: 'HCI_AUTHENTICATION_REQUESTED_COMMAND',
- HCI_SET_CONNECTION_ENCRYPTION_COMMAND: 'HCI_SET_CONNECTION_ENCRYPTION_COMMAND',
- HCI_REMOTE_NAME_REQUEST_COMMAND: 'HCI_REMOTE_NAME_REQUEST_COMMAND',
- HCI_READ_REMOTE_SUPPORTED_FEATURES_COMMAND: 'HCI_READ_REMOTE_SUPPORTED_FEATURES_COMMAND',
- HCI_READ_REMOTE_EXTENDED_FEATURES_COMMAND: 'HCI_READ_REMOTE_EXTENDED_FEATURES_COMMAND',
- HCI_READ_REMOTE_VERSION_INFORMATION_COMMAND: 'HCI_READ_REMOTE_VERSION_INFORMATION_COMMAND',
- HCI_READ_CLOCK_OFFSET_COMMAND: 'HCI_READ_CLOCK_OFFSET_COMMAND',
- HCI_IO_CAPABILITY_REQUEST_REPLY_COMMAND: 'HCI_IO_CAPABILITY_REQUEST_REPLY_COMMAND',
- HCI_USER_CONFIRMATION_REQUEST_REPLY_COMMAND: 'HCI_USER_CONFIRMATION_REQUEST_REPLY_COMMAND',
- HCI_USER_CONFIRMATION_REQUEST_NEGATIVE_REPLY_COMMAND: 'HCI_USER_CONFIRMATION_REQUEST_NEGATIVE_REPLY_COMMAND',
- HCI_USER_PASSKEY_REQUEST_REPLY_COMMAND: 'HCI_USER_PASSKEY_REQUEST_REPLY_COMMAND',
- HCI_USER_PASSKEY_REQUEST_NEGATIVE_REPLY_COMMAND: 'HCI_USER_PASSKEY_REQUEST_NEGATIVE_REPLY_COMMAND',
- HCI_ENHANCED_SETUP_SYNCHRONOUS_CONNECTION_COMMAND: 'HCI_ENHANCED_SETUP_SYNCHRONOUS_CONNECTION_COMMAND',
- HCI_SNIFF_MODE_COMMAND: 'HCI_SNIFF_MODE_COMMAND',
- HCI_EXIT_SNIFF_MODE_COMMAND: 'HCI_EXIT_SNIFF_MODE_COMMAND',
- HCI_SWITCH_ROLE_COMMAND: 'HCI_SWITCH_ROLE_COMMAND',
- HCI_WRITE_LINK_POLICY_SETTINGS_COMMAND: 'HCI_WRITE_LINK_POLICY_SETTINGS_COMMAND',
- HCI_WRITE_DEFAULT_LINK_POLICY_SETTINGS_COMMAND: 'HCI_WRITE_DEFAULT_LINK_POLICY_SETTINGS_COMMAND',
- HCI_SNIFF_SUBRATING_COMMAND: 'HCI_SNIFF_SUBRATING_COMMAND',
- HCI_SET_EVENT_MASK_COMMAND: 'HCI_SET_EVENT_MASK_COMMAND',
- HCI_RESET_COMMAND: 'HCI_RESET_COMMAND',
- HCI_SET_EVENT_FILTER_COMMAND: 'HCI_SET_EVENT_FILTER_COMMAND',
- HCI_READ_STORED_LINK_KEY_COMMAND: 'HCI_READ_STORED_LINK_KEY_COMMAND',
- HCI_DELETE_STORED_LINK_KEY_COMMAND: 'HCI_DELETE_STORED_LINK_KEY_COMMAND',
- HCI_WRITE_LOCAL_NAME_COMMAND: 'HCI_WRITE_LOCAL_NAME_COMMAND',
- HCI_READ_LOCAL_NAME_COMMAND: 'HCI_READ_LOCAL_NAME_COMMAND',
- HCI_WRITE_CONNECTION_ACCEPT_TIMEOUT_COMMAND: 'HCI_WRITE_CONNECTION_ACCEPT_TIMEOUT_COMMAND',
- HCI_WRITE_PAGE_TIMEOUT_COMMAND: 'HCI_WRITE_PAGE_TIMEOUT_COMMAND',
- HCI_WRITE_SCAN_ENABLE_COMMAND: 'HCI_WRITE_SCAN_ENABLE_COMMAND',
- HCI_READ_PAGE_SCAN_ACTIVITY_COMMAND: 'HCI_READ_PAGE_SCAN_ACTIVITY_COMMAND',
- HCI_WRITE_PAGE_SCAN_ACTIVITY_COMMAND: 'HCI_WRITE_PAGE_SCAN_ACTIVITY_COMMAND',
- HCI_WRITE_INQUIRY_SCAN_ACTIVITY_COMMAND: 'HCI_WRITE_INQUIRY_SCAN_ACTIVITY_COMMAND',
- HCI_READ_CLASS_OF_DEVICE_COMMAND: 'HCI_READ_CLASS_OF_DEVICE_COMMAND',
- HCI_WRITE_CLASS_OF_DEVICE_COMMAND: 'HCI_WRITE_CLASS_OF_DEVICE_COMMAND',
- HCI_READ_VOICE_SETTING_COMMAND: 'HCI_READ_VOICE_SETTING_COMMAND',
- HCI_WRITE_VOICE_SETTING_COMMAND: 'HCI_WRITE_VOICE_SETTING_COMMAND',
- HCI_READ_SYNCHRONOUS_FLOW_CONTROL_ENABLE_COMMAND: 'HCI_READ_SYNCHRONOUS_FLOW_CONTROL_ENABLE_COMMAND',
- HCI_WRITE_SYNCHRONOUS_FLOW_CONTROL_ENABLE_COMMAND: 'HCI_WRITE_SYNCHRONOUS_FLOW_CONTROL_ENABLE_COMMAND',
- HCI_HOST_BUFFER_SIZE_COMMAND: 'HCI_HOST_BUFFER_SIZE_COMMAND',
- HCI_WRITE_LINK_SUPERVISION_TIMEOUT_COMMAND: 'HCI_WRITE_LINK_SUPERVISION_TIMEOUT_COMMAND',
- HCI_READ_NUMBER_OF_SUPPORTED_IAC_COMMAND: 'HCI_READ_NUMBER_OF_SUPPORTED_IAC_COMMAND',
- HCI_READ_CURRENT_IAC_LAP_COMMAND: 'HCI_READ_CURRENT_IAC_LAP_COMMAND',
- HCI_WRITE_INQUIRY_SCAN_TYPE_COMMAND: 'HCI_WRITE_INQUIRY_SCAN_TYPE_COMMAND',
- HCI_WRITE_INQUIRY_MODE_COMMAND: 'HCI_WRITE_INQUIRY_MODE_COMMAND',
- HCI_READ_PAGE_SCAN_TYPE_COMMAND: 'HCI_READ_PAGE_SCAN_TYPE_COMMAND',
- HCI_WRITE_PAGE_SCAN_TYPE_COMMAND: 'HCI_WRITE_PAGE_SCAN_TYPE_COMMAND',
- HCI_WRITE_EXTENDED_INQUIRY_RESPONSE_COMMAND: 'HCI_WRITE_EXTENDED_INQUIRY_RESPONSE_COMMAND',
- HCI_WRITE_SIMPLE_PAIRING_MODE_COMMAND: 'HCI_WRITE_SIMPLE_PAIRING_MODE_COMMAND',
- HCI_READ_INQUIRY_RESPONSE_TRANSMIT_POWER_LEVEL_COMMAND: 'HCI_READ_INQUIRY_RESPONSE_TRANSMIT_POWER_LEVEL_COMMAND',
- HCI_SET_EVENT_MASK_PAGE_2_COMMAND: 'HCI_SET_EVENT_MASK_PAGE_2_COMMAND',
- HCI_READ_DEFAULT_ERRONEOUS_DATA_REPORTING_COMMAND: 'HCI_READ_DEFAULT_ERRONEOUS_DATA_REPORTING_COMMAND',
- HCI_READ_LOCAL_VERSION_INFORMATION_COMMAND: 'HCI_READ_LOCAL_VERSION_INFORMATION_COMMAND',
- HCI_READ_LOCAL_SUPPORTED_COMMANDS_COMMAND: 'HCI_READ_LOCAL_SUPPORTED_COMMANDS_COMMAND',
- HCI_READ_LOCAL_SUPPORTED_FEATURES_COMMAND: 'HCI_READ_LOCAL_SUPPORTED_FEATURES_COMMAND',
- HCI_READ_LOCAL_EXTENDED_FEATURES_COMMAND: 'HCI_READ_LOCAL_EXTENDED_FEATURES_COMMAND',
- HCI_READ_BUFFER_SIZE_COMMAND: 'HCI_READ_BUFFER_SIZE_COMMAND',
- HCI_READ_LE_HOST_SUPPORT_COMMAND: 'HCI_READ_LE_HOST_SUPPORT_COMMAND',
- HCI_WRITE_LE_HOST_SUPPORT_COMMAND: 'HCI_WRITE_LE_HOST_SUPPORT_COMMAND',
- HCI_WRITE_SECURE_CONNECTIONS_HOST_SUPPORT_COMMAND: 'HCI_WRITE_SECURE_CONNECTIONS_HOST_SUPPORT_COMMAND',
- HCI_WRITE_AUTHENTICATED_PAYLOAD_TIMEOUT_COMMAND: 'HCI_WRITE_AUTHENTICATED_PAYLOAD_TIMEOUT_COMMAND',
- HCI_READ_BD_ADDR_COMMAND: 'HCI_READ_BD_ADDR_COMMAND',
- HCI_READ_LOCAL_SUPPORTED_CODECS_COMMAND: 'HCI_READ_LOCAL_SUPPORTED_CODECS_COMMAND',
- HCI_READ_ENCRYPTION_KEY_SIZE_COMMAND: 'HCI_READ_ENCRYPTION_KEY_SIZE_COMMAND',
- HCI_LE_SET_EVENT_MASK_COMMAND: 'HCI_LE_SET_EVENT_MASK_COMMAND',
- HCI_LE_READ_BUFFER_SIZE_COMMAND: 'HCI_LE_READ_BUFFER_SIZE_COMMAND',
- HCI_LE_READ_LOCAL_SUPPORTED_FEATURES_COMMAND: 'HCI_LE_READ_LOCAL_SUPPORTED_FEATURES_COMMAND',
- HCI_LE_SET_RANDOM_ADDRESS_COMMAND: 'HCI_LE_SET_RANDOM_ADDRESS_COMMAND',
- HCI_LE_SET_ADVERTISING_PARAMETERS_COMMAND: 'HCI_LE_SET_ADVERTISING_PARAMETERS_COMMAND',
- HCI_LE_READ_ADVERTISING_CHANNEL_TX_POWER_COMMAND: 'HCI_LE_READ_ADVERTISING_CHANNEL_TX_POWER_COMMAND',
- HCI_LE_SET_ADVERTISING_DATA_COMMAND: 'HCI_LE_SET_ADVERTISING_DATA_COMMAND',
- HCI_LE_SET_SCAN_RESPONSE_DATA_COMMAND: 'HCI_LE_SET_SCAN_RESPONSE_DATA_COMMAND',
- HCI_LE_SET_ADVERTISING_ENABLE_COMMAND: 'HCI_LE_SET_ADVERTISING_ENABLE_COMMAND',
- HCI_LE_SET_SCAN_PARAMETERS_COMMAND: 'HCI_LE_SET_SCAN_PARAMETERS_COMMAND',
- HCI_LE_SET_SCAN_ENABLE_COMMAND: 'HCI_LE_SET_SCAN_ENABLE_COMMAND',
- HCI_LE_CREATE_CONNECTION_COMMAND: 'HCI_LE_CREATE_CONNECTION_COMMAND',
- HCI_LE_CREATE_CONNECTION_CANCEL_COMMAND: 'HCI_LE_CREATE_CONNECTION_CANCEL_COMMAND',
- HCI_LE_READ_WHITE_LIST_SIZE_COMMAND: 'HCI_LE_READ_WHITE_LIST_SIZE_COMMAND',
- HCI_LE_CLEAR_WHITE_LIST_COMMAND: 'HCI_LE_CLEAR_WHITE_LIST_COMMAND',
- HCI_LE_ADD_DEVICE_TO_WHITE_LIST_COMMAND: 'HCI_LE_ADD_DEVICE_TO_WHITE_LIST_COMMAND',
- HCI_LE_REMOVE_DEVICE_FROM_WHITE_LIST_COMMAND: 'HCI_LE_REMOVE_DEVICE_FROM_WHITE_LIST_COMMAND',
- HCI_LE_CONNECTION_UPDATE_COMMAND: 'HCI_LE_CONNECTION_UPDATE_COMMAND',
- HCI_LE_SET_HOST_CHANNEL_CLASSIFICATION_COMMAND: 'HCI_LE_SET_HOST_CHANNEL_CLASSIFICATION_COMMAND',
- HCI_LE_READ_CHANNEL_MAP_COMMAND: 'HCI_LE_READ_CHANNEL_MAP_COMMAND',
- HCI_LE_READ_REMOTE_FEATURES_COMMAND: 'HCI_LE_READ_REMOTE_FEATURES_COMMAND',
- HCI_LE_ENCRYPT_COMMAND: 'HCI_LE_ENCRYPT_COMMAND',
- HCI_LE_RAND_COMMAND: 'HCI_LE_RAND_COMMAND',
- HCI_LE_START_ENCRYPTION_COMMAND: 'HCI_LE_START_ENCRYPTION_COMMAND',
- HCI_LE_LONG_TERM_KEY_REQUEST_REPLY_COMMAND: 'HCI_LE_LONG_TERM_KEY_REQUEST_REPLY_COMMAND',
- HCI_LE_LONG_TERM_KEY_REQUEST_NEGATIVE_REPLY_COMMAND: 'HCI_LE_LONG_TERM_KEY_REQUEST_NEGATIVE_REPLY_COMMAND',
- HCI_LE_READ_SUPPORTED_STATES_COMMAND: 'HCI_LE_READ_SUPPORTED_STATES_COMMAND',
- HCI_LE_RECEIVER_TEST_COMMAND: 'HCI_LE_RECEIVER_TEST_COMMAND',
- HCI_LE_TRANSMITTER_TEST_COMMAND: 'HCI_LE_TRANSMITTER_TEST_COMMAND',
- HCI_LE_TEST_END_COMMAND: 'HCI_LE_TEST_END_COMMAND',
- HCI_LE_REMOTE_CONNECTION_PARAMETER_REQUEST_REPLY_COMMAND: 'HCI_LE_REMOTE_CONNECTION_PARAMETER_REQUEST_REPLY_COMMAND',
- HCI_LE_REMOTE_CONNECTION_PARAMETER_REQUEST_NEGATIVE_REPLY_COMMAND: 'HCI_LE_REMOTE_CONNECTION_PARAMETER_REQUEST_NEGATIVE_REPLY_COMMAND',
- HCI_LE_SET_DATA_LENGTH_COMMAND: 'HCI_LE_SET_DATA_LENGTH_COMMAND',
- HCI_LE_READ_SUGGESTED_DEFAULT_DATA_LENGTH_COMMAND: 'HCI_LE_READ_SUGGESTED_DEFAULT_DATA_LENGTH_COMMAND',
- HCI_LE_WRITE_SUGGESTED_DEFAULT_DATA_LENGTH_COMMAND: 'HCI_LE_WRITE_SUGGESTED_DEFAULT_DATA_LENGTH_COMMAND',
- HCI_LE_READ_LOCAL_P_256_PUBLIC_KEY_COMMAND: 'HCI_LE_READ_LOCAL_P_256_PUBLIC_KEY_COMMAND',
- HCI_LE_GENERATE_DHKEY_COMMAND: 'HCI_LE_GENERATE_DHKEY_COMMAND',
- HCI_LE_ADD_DEVICE_TO_RESOLVING_LIST_COMMAND: 'HCI_LE_ADD_DEVICE_TO_RESOLVING_LIST_COMMAND',
- HCI_LE_REMOVE_DEVICE_FROM_RESOLVING_LIST_COMMAND: 'HCI_LE_REMOVE_DEVICE_FROM_RESOLVING_LIST_COMMAND',
- HCI_LE_CLEAR_RESOLVING_LIST_COMMAND: 'HCI_LE_CLEAR_RESOLVING_LIST_COMMAND',
- HCI_LE_READ_RESOLVING_LIST_SIZE_COMMAND: 'HCI_LE_READ_RESOLVING_LIST_SIZE_COMMAND',
- HCI_LE_READ_PEER_RESOLVABLE_ADDRESS_COMMAND: 'HCI_LE_READ_PEER_RESOLVABLE_ADDRESS_COMMAND',
- HCI_LE_READ_LOCAL_RESOLVABLE_ADDRESS_COMMAND: 'HCI_LE_READ_LOCAL_RESOLVABLE_ADDRESS_COMMAND',
- HCI_LE_SET_ADDRESS_RESOLUTION_ENABLE_COMMAND: 'HCI_LE_SET_ADDRESS_RESOLUTION_ENABLE_COMMAND',
- HCI_LE_SET_RESOLVABLE_PRIVATE_ADDRESS_TIMEOUT_COMMAND: 'HCI_LE_SET_RESOLVABLE_PRIVATE_ADDRESS_TIMEOUT_COMMAND',
- HCI_LE_READ_MAXIMUM_DATA_LENGTH_COMMAND: 'HCI_LE_READ_MAXIMUM_DATA_LENGTH_COMMAND',
- HCI_LE_READ_PHY_COMMAND: 'HCI_LE_READ_PHY_COMMAND',
- HCI_LE_SET_DEFAULT_PHY_COMMAND: 'HCI_LE_SET_DEFAULT_PHY_COMMAND',
- HCI_LE_SET_PHY_COMMAND: 'HCI_LE_SET_PHY_COMMAND',
- HCI_LE_ENHANCED_RECEIVER_TEST_COMMAND: 'HCI_LE_ENHANCED_RECEIVER_TEST_COMMAND',
- HCI_LE_ENHANCED_TRANSMITTER_TEST_COMMAND: 'HCI_LE_ENHANCED_TRANSMITTER_TEST_COMMAND',
- HCI_LE_SET_ADVERTISING_SET_RANDOM_ADDRESS_COMMAND: 'HCI_LE_SET_ADVERTISING_SET_RANDOM_ADDRESS_COMMAND',
- HCI_LE_SET_EXTENDED_ADVERTISING_PARAMETERS_COMMAND: 'HCI_LE_SET_EXTENDED_ADVERTISING_PARAMETERS_COMMAND',
- HCI_LE_SET_EXTENDED_ADVERTISING_DATA_COMMAND: 'HCI_LE_SET_EXTENDED_ADVERTISING_DATA_COMMAND',
- HCI_LE_SET_EXTENDED_SCAN_RESPONSE_DATA_COMMAND: 'HCI_LE_SET_EXTENDED_SCAN_RESPONSE_DATA_COMMAND',
- HCI_LE_SET_EXTENDED_ADVERTISING_ENABLE_COMMAND: 'HCI_LE_SET_EXTENDED_ADVERTISING_ENABLE_COMMAND',
- HCI_LE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH_COMMAND: 'HCI_LE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH_COMMAND',
- HCI_LE_READ_NUMBER_OF_SUPPORTED_ADVERETISING_SETS_COMMAND: 'HCI_LE_READ_NUMBER_OF_SUPPORTED_ADVERETISING_SETS_COMMAND',
- HCI_LE_REMOVE_ADVERTISING_SET_COMMAND: 'HCI_LE_REMOVE_ADVERTISING_SET_COMMAND',
- HCI_LE_CLEAR_ADVERTISING_SETS_COMMAND: 'HCI_LE_CLEAR_ADVERTISING_SETS_COMMAND',
- HCI_LE_SET_PERIODIC_ADVERTISING_PARAMETERS_COMMAND: 'HCI_LE_SET_PERIODIC_ADVERTISING_PARAMETERS_COMMAND',
- HCI_LE_SET_PERIODIC_ADVERTISING_DATA_COMMAND: 'HCI_LE_SET_PERIODIC_ADVERTISING_DATA_COMMAND',
- HCI_LE_SET_PERIODIC_ADVERTISING_ENABLE_COMMAND: 'HCI_LE_SET_PERIODIC_ADVERTISING_ENABLE_COMMAND',
- HCI_LE_SET_EXTENDED_SCAN_PARAMETERS_COMMAND: 'HCI_LE_SET_EXTENDED_SCAN_PARAMETERS_COMMAND',
- HCI_LE_SET_EXTENDED_SCAN_ENABLE_COMMAND: 'HCI_LE_SET_EXTENDED_SCAN_ENABLE_COMMAND',
- HCI_LE_SET_EXTENDED_CREATE_CONNECTION_COMMAND: 'HCI_LE_SET_EXTENDED_CREATE_CONNECTION_COMMAND',
- HCI_LE_PERIODIC_ADVERTISING_CREATE_SYNC_COMMAND: 'HCI_LE_PERIODIC_ADVERTISING_CREATE_SYNC_COMMAND',
- HCI_LE_PERIODIC_ADVERTISING_CREATE_SYNC_CANCEL_COMMAND: 'HCI_LE_PERIODIC_ADVERTISING_CREATE_SYNC_CANCEL_COMMAND',
- HCI_LE_PERIODIC_ADVERTISING_TERMINATE_SYNC_COMMAND: 'HCI_LE_PERIODIC_ADVERTISING_TERMINATE_SYNC_COMMAND',
- HCI_LE_ADD_DEVICE_TO_PERIODIC_ADVERTISER_LIST_COMMAND: 'HCI_LE_ADD_DEVICE_TO_PERIODIC_ADVERTISER_LIST_COMMAND',
- HCI_LE_REMOVE_DEVICE_FROM_PERIODIC_ADVERTISER_LIST_COMMAND: 'HCI_LE_REMOVE_DEVICE_FROM_PERIODIC_ADVERTISER_LIST_COMMAND',
- HCI_LE_CLEAR_PERIODIC_ADVERTISER_LIST_COMMAND: 'HCI_LE_CLEAR_PERIODIC_ADVERTISER_LIST_COMMAND',
- HCI_LE_READ_PERIODIC_ADVERTISER_LIST_SIZE_COMMAND: 'HCI_LE_READ_PERIODIC_ADVERTISER_LIST_SIZE_COMMAND',
- HCI_LE_READ_TRANSMIT_POWER_COMMAND: 'HCI_LE_READ_TRANSMIT_POWER_COMMAND',
- HCI_LE_READ_RF_PATH_COMPENSATION_COMMAND: 'HCI_LE_READ_RF_PATH_COMPENSATION_COMMAND',
- HCI_LE_WRITE_RF_PATH_COMPENSATION_COMMAND: 'HCI_LE_WRITE_RF_PATH_COMPENSATION_COMMAND',
- HCI_LE_SET_PRIVACY_MODE_COMMAND: 'HCI_LE_SET_PRIVACY_MODE_COMMAND'
+ command_code: command_name for (command_name, command_code) in globals().items()
+ if command_name.startswith('HCI_') and command_name.endswith('_COMMAND')
}
-
# HCI Error Codes
# See Bluetooth spec Vol 2, Part D - 1.3 LIST OF ERROR CODES
-HCI_SUCCESS = 0x00
-HCI_UNKNOWN_HCI_COMMAND_ERROR = 0x01
-HCI_UNKNOWN_CONNECTION_IDENTIFIER_ERROR = 0x02
-HCI_HARDWARE_FAILURE_ERROR = 0x03
-HCI_PAGE_TIMEOUT_ERROR = 0x04
-HCI_AUTHENTICATION_FAILURE_ERROR = 0x05
-HCI_PIN_OR_KEY_MISSING_ERROR = 0x06
-HCI_MEMORY_CAPACITY_EXCEEDED_ERROR = 0x07
-HCI_CONNECTION_TIMEOUT_ERROR = 0x08
-HCI_CONNECTION_LIMIT_EXCEEDED_ERROR = 0x09
-HCI_SYNCHRONOUS_CONNECTION_LIMIT_TO_A_DEVICE_EXCEEDED_ERROR = 0x0A
-HCI_CONNECTION_ALREADY_EXISTS_ERROR = 0x0B
-HCI_COMMAND_DISALLOWED_ERROR = 0x0C
-HCI_CONNECTION_REJECTED_DUE_TO_LIMITED_RESOURCES_ERROR = 0x0D
-HCI_CONNECTION_REJECTED_DUE_TO_SECURITY_REASONS_ERROR = 0x0E
-HCI_CONNECTION_REJECTED_DUE_TO_UNACCEPTABLE_BD_ADDR_ERROR = 0x0F
-HCI_CONNECTION_ACCEPT_TIMEOUT_ERROR = 0x10
-HCI_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE_ERROR = 0x11
-HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR = 0x12
-HCI_REMOTE_USER_TERMINATED_CONNECTION_ERROR = 0x13
-HCI_REMOTE_DEVICE_TERMINATED_CONNECTION_DUE_TO_LOW_RESOURCES_ERROR = 0x14
-HCI_REMOTE_DEVICE_TERMINATED_CONNECTION_DUE_TO_POWER_OFF_ERROR = 0x15
-HCI_CONNECTION_TERMINATED_BY_LOCAL_HOST_ERROR = 0x16
-HCI_UNACCEPTABLE_CONNECTION_PARAMETERS_ERROR = 0x3B
-HCI_CONNECTION_FAILED_TO_BE_ESTABLISHED_ERROR = 0x3E
-# TODO: more error codes
+HCI_SUCCESS = 0x00
+HCI_UNKNOWN_HCI_COMMAND_ERROR = 0x01
+HCI_UNKNOWN_CONNECTION_IDENTIFIER_ERROR = 0x02
+HCI_HARDWARE_FAILURE_ERROR = 0x03
+HCI_PAGE_TIMEOUT_ERROR = 0x04
+HCI_AUTHENTICATION_FAILURE_ERROR = 0x05
+HCI_PIN_OR_KEY_MISSING_ERROR = 0x06
+HCI_MEMORY_CAPACITY_EXCEEDED_ERROR = 0x07
+HCI_CONNECTION_TIMEOUT_ERROR = 0x08
+HCI_CONNECTION_LIMIT_EXCEEDED_ERROR = 0x09
+HCI_SYNCHRONOUS_CONNECTION_LIMIT_TO_A_DEVICE_EXCEEDED_ERROR = 0x0A
+HCI_CONNECTION_ALREADY_EXISTS_ERROR = 0x0B
+HCI_COMMAND_DISALLOWED_ERROR = 0x0C
+HCI_CONNECTION_REJECTED_DUE_TO_LIMITED_RESOURCES_ERROR = 0x0D
+HCI_CONNECTION_REJECTED_DUE_TO_SECURITY_REASONS_ERROR = 0x0E
+HCI_CONNECTION_REJECTED_DUE_TO_UNACCEPTABLE_BD_ADDR_ERROR = 0x0F
+HCI_CONNECTION_ACCEPT_TIMEOUT_ERROR = 0x10
+HCI_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE_ERROR = 0x11
+HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR = 0x12
+HCI_REMOTE_USER_TERMINATED_CONNECTION_ERROR = 0x13
+HCI_REMOTE_DEVICE_TERMINATED_CONNECTION_DUE_TO_LOW_RESOURCES_ERROR = 0x14
+HCI_REMOTE_DEVICE_TERMINATED_CONNECTION_DUE_TO_POWER_OFF_ERROR = 0x15
+HCI_CONNECTION_TERMINATED_BY_LOCAL_HOST_ERROR = 0x16
+HCI_REPEATED_ATTEMPTS_ERROR = 0X17
+HCI_PAIRING_NOT_ALLOWED_ERROR = 0X18
+HCI_UNKNOWN_LMP_PDU_ERROR = 0X19
+HCI_UNSUPPORTED_REMOTE_FEATURE_ERROR = 0X1A
+HCI_SCO_OFFSET_REJECTED_ERROR = 0X1B
+HCI_SCO_INTERVAL_REJECTED_ERROR = 0X1C
+HCI_SCO_AIR_MODE_REJECTED_ERROR = 0X1D
+HCI_INVALID_LMP_OR_LL_PARAMETERS_ERROR = 0X1E
+HCI_UNSPECIFIED_ERROR_ERROR = 0X1F
+HCI_UNSUPPORTED_LMP_OR_LL_PARAMETER_VALUE_ERROR = 0X20
+HCI_ROLE_CHANGE_NOT_ALLOWED_ERROR = 0X21
+HCI_LMP_OR_LL_RESPONSE_TIMEOUT_ERROR = 0X22
+HCI_LMP_ERROR_TRANSACTION_COLLISION_OR_LL_PROCEDURE_COLLISION_ERROR = 0X23
+HCI_LMP_PDU_NOT_ALLOWED_ERROR = 0X24
+HCI_ENCRYPTION_MODE_NOT_ACCEPTABLE_ERROR = 0X25
+HCI_LINK_KEY_CANNOT_BE_CHANGED_ERROR = 0X26
+HCI_REQUESTED_QOS_NOT_SUPPORTED_ERROR = 0X27
+HCI_INSTANT_PASSED_ERROR = 0X28
+HCI_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED_ERROR = 0X29
+HCI_DIFFERENT_TRANSACTION_COLLISION_ERROR = 0X2A
+HCI_RESERVED_FOR_FUTURE_USE = 0X2B
+HCI_QOS_UNACCEPTABLE_PARAMETER_ERROR = 0X2C
+HCI_QOS_REJECTED_ERROR = 0X2D
+HCI_CHANNEL_CLASSIFICATION_NOT_SUPPORTED_ERROR = 0X2E
+HCI_INSUFFICIENT_SECURITY_ERROR = 0X2F
+HCI_PARAMETER_OUT_OF_MANDATORY_RANGE_ERROR = 0X30
+HCI_ROLE_SWITCH_PENDING_ERROR = 0X32
+HCI_RESERVED_SLOT_VIOLATION_ERROR = 0X34
+HCI_ROLE_SWITCH_FAILED_ERROR = 0X35
+HCI_EXTENDED_INQUIRY_RESPONSE_TOO_LARGE_ERROR = 0X36
+HCI_SECURE_SIMPLE_PAIRING_NOT_SUPPORTED_BY_HOST_ERROR = 0X37
+HCI_HOST_BUSY_PAIRING_ERROR = 0X38
+HCI_CONNECTION_REJECTED_DUE_TO_NO_SUITABLE_CHANNEL_FOUND_ERROR = 0X39
+HCI_CONTROLLER_BUSY_ERROR = 0X3A
+HCI_UNACCEPTABLE_CONNECTION_PARAMETERS_ERROR = 0X3B
+HCI_ADVERTISING_TIMEOUT_ERROR = 0X3C
+HCI_CONNECTION_TERMINATED_DUE_TO_MIC_FAILURE_ERROR = 0X3D
+HCI_CONNECTION_FAILED_TO_BE_ESTABLISHED_ERROR = 0X3E
+HCI_COARSE_CLOCK_ADJUSTMENT_REJECTED_BUT_WILL_TRY_TO_ADJUST_USING_CLOCK_DRAGGING_ERROR = 0X40
+HCI_TYPE0_SUBMAP_NOT_DEFINED_ERROR = 0X41
+HCI_UNKNOWN_ADVERTISING_IDENTIFIER_ERROR = 0X42
+HCI_LIMIT_REACHED_ERROR = 0X43
+HCI_OPERATION_CANCELLED_BY_HOST_ERROR = 0X44
+HCI_PACKET_TOO_LONG_ERROR = 0X45
HCI_ERROR_NAMES = {
- HCI_SUCCESS: 'HCI_SUCCESS',
- HCI_UNKNOWN_HCI_COMMAND_ERROR: 'HCI_UNKNOWN_HCI_COMMAND_ERROR',
- HCI_UNKNOWN_CONNECTION_IDENTIFIER_ERROR: 'HCI_UNKNOWN_CONNECTION_IDENTIFIER_ERROR',
- HCI_HARDWARE_FAILURE_ERROR: 'HCI_HARDWARE_FAILURE_ERROR',
- HCI_PAGE_TIMEOUT_ERROR: 'HCI_PAGE_TIMEOUT_ERROR',
- HCI_AUTHENTICATION_FAILURE_ERROR: 'HCI_AUTHENTICATION_FAILURE_ERROR',
- HCI_PIN_OR_KEY_MISSING_ERROR: 'HCI_PIN_OR_KEY_MISSING_ERROR',
- HCI_MEMORY_CAPACITY_EXCEEDED_ERROR: 'HCI_MEMORY_CAPACITY_EXCEEDED_ERROR',
- HCI_CONNECTION_TIMEOUT_ERROR: 'HCI_CONNECTION_TIMEOUT_ERROR',
- HCI_CONNECTION_LIMIT_EXCEEDED_ERROR: 'HCI_CONNECTION_LIMIT_EXCEEDED_ERROR',
- HCI_SYNCHRONOUS_CONNECTION_LIMIT_TO_A_DEVICE_EXCEEDED_ERROR: 'HCI_SYNCHRONOUS_CONNECTION_LIMIT_TO_A_DEVICE_EXCEEDED_ERROR',
- HCI_CONNECTION_ALREADY_EXISTS_ERROR: 'HCI_CONNECTION_ALREADY_EXISTS_ERROR',
- HCI_COMMAND_DISALLOWED_ERROR: 'HCI_COMMAND_DISALLOWED_ERROR',
- HCI_CONNECTION_REJECTED_DUE_TO_LIMITED_RESOURCES_ERROR: 'HCI_CONNECTION_REJECTED_DUE_TO_LIMITED_RESOURCES_ERROR',
- HCI_CONNECTION_REJECTED_DUE_TO_SECURITY_REASONS_ERROR: 'HCI_CONNECTION_REJECTED_DUE_TO_SECURITY_REASONS_ERROR',
- HCI_CONNECTION_REJECTED_DUE_TO_UNACCEPTABLE_BD_ADDR_ERROR: 'HCI_CONNECTION_REJECTED_DUE_TO_UNACCEPTABLE_BD_ADDR_ERROR',
- HCI_CONNECTION_ACCEPT_TIMEOUT_ERROR: 'HCI_CONNECTION_ACCEPT_TIMEOUT_ERROR',
- HCI_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE_ERROR: 'HCI_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE_ERROR',
- HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR: 'HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR',
- HCI_REMOTE_USER_TERMINATED_CONNECTION_ERROR: 'HCI_REMOTE_USER_TERMINATED_CONNECTION_ERROR',
- HCI_REMOTE_DEVICE_TERMINATED_CONNECTION_DUE_TO_LOW_RESOURCES_ERROR: 'HCI_REMOTE_DEVICE_TERMINATED_CONNECTION_DUE_TO_LOW_RESOURCES_ERROR',
- HCI_REMOTE_DEVICE_TERMINATED_CONNECTION_DUE_TO_POWER_OFF_ERROR: 'HCI_REMOTE_DEVICE_TERMINATED_CONNECTION_DUE_TO_POWER_OFF_ERROR',
- HCI_CONNECTION_TERMINATED_BY_LOCAL_HOST_ERROR: 'HCI_CONNECTION_TERMINATED_BY_LOCAL_HOST_ERROR',
- HCI_UNACCEPTABLE_CONNECTION_PARAMETERS_ERROR: 'HCI_UNACCEPTABLE_CONNECTION_PARAMETERS_ERROR',
- HCI_CONNECTION_FAILED_TO_BE_ESTABLISHED_ERROR: 'HCI_CONNECTION_FAILED_TO_BE_ESTABLISHED_ERROR'
+ error_code: error_name for (error_name, error_code) in globals().items()
+ if error_name.startswith('HCI_') and error_name.endswith('_ERROR')
}
+HCI_ERROR_NAMES[HCI_SUCCESS] = 'HCI_SUCCESS'
# Command Status codes
HCI_COMMAND_STATUS_PENDING = 0
# LE Event Masks
-LE_CONNECTION_COMPLETE_EVENT_MASK = (1 << 0)
-LE_ADVERTISING_REPORT_EVENT_MASK = (1 << 1)
-LE_CONNECTION_UPDATE_COMPLETE_EVENT_MASK = (1 << 2)
-LE_READ_REMOTE_FEATURES_COMPLETE_EVENT_MASK = (1 << 3)
-LE_LONG_TERM_KEY_REQUEST_EVENT_MASK = (1 << 4)
-LE_REMOTE_CONNECTION_PARAMETER_REQUEST_EVENT_MASK = (1 << 5)
-LE_DATA_LENGTH_CHANGE_EVENT_MASK = (1 << 6)
-LE_READ_LOCAL_P_256_PUBLIC_KEY_COMPLETE_EVENT_MASK = (1 << 7)
-LE_GENERATE_DHKEY_COMPLETE_EVENT_MASK = (1 << 8)
-LE_ENHANCED_CONNECTION_COMPLETE_EVENT_MASK = (1 << 9)
-LE_DIRECTED_ADVERTISING_REPORT_EVENT_MASK = (1 << 10)
-LE_PHY_UPDATE_COMPLETE_EVENT_MASK = (1 << 11)
-LE_EXTENDED_ADVERTISING_REPORT_EVENT_MASK = (1 << 12)
-LE_PERIODIC_ADVERTISING_SYNC_ESTABLISHED_EVENT_MASK = (1 << 13)
-LE_PERIODIC_ADVERTISING_REPORT_EVENT_MASK = (1 << 14)
-LE_PERIODIC_ADVERTISING_SYNC_LOST_EVENT_MASK = (1 << 15)
-LE_EXTENDED_SCAN_TIMEOUT_EVENT_MASK = (1 << 16)
-LE_EXTENDED_ADVERTISING_SET_TERMINATED_EVENT_MASK = (1 << 17)
-LE_SCAN_REQUEST_RECEIVED_EVENT_MASK = (1 << 18)
-LE_CHANNEL_SELECTION_ALGORITHM_EVENT_MASK = (1 << 19)
+HCI_LE_CONNECTION_COMPLETE_EVENT_MASK = (1 << 0)
+HCI_LE_ADVERTISING_REPORT_EVENT_MASK = (1 << 1)
+HCI_LE_CONNECTION_UPDATE_COMPLETE_EVENT_MASK = (1 << 2)
+HCI_LE_READ_REMOTE_FEATURES_COMPLETE_EVENT_MASK = (1 << 3)
+HCI_LE_LONG_TERM_KEY_REQUEST_EVENT_MASK = (1 << 4)
+HCI_LE_REMOTE_CONNECTION_PARAMETER_REQUEST_EVENT_MASK = (1 << 5)
+HCI_LE_DATA_LENGTH_CHANGE_EVENT_MASK = (1 << 6)
+HCI_LE_READ_LOCAL_P_256_PUBLIC_KEY_COMPLETE_EVENT_MASK = (1 << 7)
+HCI_LE_GENERATE_DHKEY_COMPLETE_EVENT_MASK = (1 << 8)
+HCI_LE_ENHANCED_CONNECTION_COMPLETE_EVENT_MASK = (1 << 9)
+HCI_LE_DIRECTED_ADVERTISING_REPORT_EVENT_MASK = (1 << 10)
+HCI_LE_PHY_UPDATE_COMPLETE_EVENT_MASK = (1 << 11)
+HCI_LE_EXTENDED_ADVERTISING_REPORT_EVENT_MASK = (1 << 12)
+HCI_LE_PERIODIC_ADVERTISING_SYNC_ESTABLISHED_EVENT_MASK = (1 << 13)
+HCI_LE_PERIODIC_ADVERTISING_REPORT_EVENT_MASK = (1 << 14)
+HCI_LE_PERIODIC_ADVERTISING_SYNC_LOST_EVENT_MASK = (1 << 15)
+HCI_LE_EXTENDED_SCAN_TIMEOUT_EVENT_MASK = (1 << 16)
+HCI_LE_EXTENDED_ADVERTISING_SET_TERMINATED_EVENT_MASK = (1 << 17)
+HCI_LE_SCAN_REQUEST_RECEIVED_EVENT_MASK = (1 << 18)
+HCI_LE_CHANNEL_SELECTION_ALGORITHM_EVENT_MASK = (1 << 19)
+HCI_LE_CONNECTIONLESS_IQ_REPORT_EVENT_MASK = (1 << 20)
+HCI_LE_CONNECTION_IQ_REPORT_EVENT_MASK = (1 << 21)
+HCI_LE_CTE_REQUEST_FAILED_EVENT_MASK = (1 << 22)
+HCI_LE_PERIODIC_ADVERTISING_SYNC_TRANSFER_RECEIVED_EVENT_MASK = (1 << 23)
+HCI_LE_CIS_ESTABLISHED_EVENT_MASK = (1 << 24)
+HCI_LE_CIS_REQUEST_EVENT_MASK = (1 << 25)
+HCI_LE_CREATE_BIG_COMPLETE_EVENT_MASK = (1 << 26)
+HCI_LE_TERMINATE_BIG_COMPLETE_EVENT_MASK = (1 << 27)
+HCI_LE_BIG_SYNC_ESTABLISHED_EVENT_MASK = (1 << 28)
+HCI_LE_BIG_SYNC_LOST_EVENT_MASK = (1 << 29)
+HCI_LE_REQUEST_PEER_SCA_COMPLETE_EVENT_MASK = (1 << 30)
+HCI_LE_PATH_LOSS_THRESHOLD_EVENT_MASK = (1 << 31)
+HCI_LE_TRANSMIT_POWER_REPORTING_EVENT_MASK = (1 << 32)
+HCI_LE_BIGINFO_ADVERTISING_REPORT_EVENT_MASK = (1 << 33)
+HCI_LE_SUBRATE_CHANGE_EVENT_MASK = (1 << 34)
+
+HCI_LE_EVENT_MASK_NAMES = {
+ mask: mask_name for (mask_name, mask) in globals().items()
+ if mask_name.startswith('HCI_LE_') and mask_name.endswith('_EVENT_MASK')
+}
# ACL
HCI_ACL_PB_FIRST_NON_FLUSHABLE = 0
@@ -649,10 +705,22 @@ HCI_LE_CODED_PHY = 3
HCI_LE_PHY_NAMES = {
HCI_LE_1M_PHY: 'LE 1M',
- HCI_LE_2M_PHY: 'L2 2M',
+ HCI_LE_2M_PHY: 'LE 2M',
HCI_LE_CODED_PHY: 'LE Coded'
}
+HCI_LE_1M_PHY_BIT = 0
+HCI_LE_2M_PHY_BIT = 1
+HCI_LE_CODED_PHY_BIT = 2
+
+HCI_LE_PHY_BIT_NAMES = ['LE_1M_PHY', 'LE_2M_PHY', 'LE_CODED_PHY']
+
+HCI_LE_PHY_TYPE_TO_BIT = {
+ HCI_LE_1M_PHY: HCI_LE_1M_PHY_BIT,
+ HCI_LE_2M_PHY: HCI_LE_2M_PHY_BIT,
+ HCI_LE_CODED_PHY: HCI_LE_CODED_PHY_BIT
+}
+
# Connection Parameters
HCI_CONNECTION_INTERVAL_MS_PER_UNIT = 1.25
HCI_CONNECTION_LATENCY_MS_PER_UNIT = 1.25
@@ -735,7 +803,581 @@ HCI_RANDOM_DEVICE_ADDRESS_TYPE = 0x01
HCI_PUBLIC_IDENTITY_ADDRESS_TYPE = 0x02
HCI_RANDOM_IDENTITY_ADDRESS_TYPE = 0x03
+# Supported Commands Flags
+# See Bluetooth spec @ 6.27 SUPPORTED COMMANDS
+HCI_SUPPORTED_COMMANDS_FLAGS = (
+ # Octet 0
+ (
+ HCI_INQUIRY_COMMAND,
+ HCI_INQUIRY_CANCEL_COMMAND,
+ HCI_PERIODIC_INQUIRY_MODE_COMMAND,
+ HCI_EXIT_PERIODIC_INQUIRY_MODE_COMMAND,
+ HCI_CREATE_CONNECTION_COMMAND,
+ HCI_DISCONNECT_COMMAND,
+ None,
+ HCI_CREATE_CONNECTION_CANCEL_COMMAND
+ ),
+ # Octet 1
+ (
+ HCI_ACCEPT_CONNECTION_REQUEST_COMMAND,
+ HCI_REJECT_CONNECTION_REQUEST_COMMAND,
+ HCI_LINK_KEY_REQUEST_REPLY_COMMAND,
+ HCI_LINK_KEY_REQUEST_NEGATIVE_REPLY_COMMAND,
+ HCI_PIN_CODE_REQUEST_REPLY_COMMAND,
+ HCI_PIN_CODE_REQUEST_NEGATIVE_REPLY_COMMAND,
+ HCI_CHANGE_CONNECTION_PACKET_TYPE_COMMAND,
+ HCI_AUTHENTICATION_REQUESTED_COMMAND
+ ),
+ # Octet 2
+ (
+ HCI_SET_CONNECTION_ENCRYPTION_COMMAND,
+ HCI_CHANGE_CONNECTION_LINK_KEY_COMMAND,
+ HCI_LINK_KEY_SELECTION_COMMAND,
+ HCI_REMOTE_NAME_REQUEST_COMMAND,
+ HCI_REMOTE_NAME_REQUEST_CANCEL_COMMAND,
+ HCI_READ_REMOTE_SUPPORTED_FEATURES_COMMAND,
+ HCI_READ_REMOTE_EXTENDED_FEATURES_COMMAND,
+ HCI_READ_REMOTE_VERSION_INFORMATION_COMMAND
+ ),
+ # Octet 3
+ (
+ HCI_READ_CLOCK_OFFSET_COMMAND,
+ HCI_READ_LMP_HANDLE_COMMAND,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None
+ ),
+ # Octet 4
+ (
+ None,
+ HCI_HOLD_MODE_COMMAND,
+ HCI_SNIFF_MODE_COMMAND,
+ HCI_EXIT_SNIFF_MODE_COMMAND,
+ None,
+ None,
+ HCI_QOS_SETUP_COMMAND,
+ HCI_ROLE_DISCOVERY_COMMAND
+ ),
+ # Octet 5
+ (
+ HCI_SWITCH_ROLE_COMMAND,
+ HCI_READ_LINK_POLICY_SETTINGS_COMMAND,
+ HCI_WRITE_LINK_POLICY_SETTINGS_COMMAND,
+ HCI_READ_DEFAULT_LINK_POLICY_SETTINGS_COMMAND,
+ HCI_WRITE_DEFAULT_LINK_POLICY_SETTINGS_COMMAND,
+ HCI_FLOW_SPECIFICATION_COMMAND,
+ HCI_SET_EVENT_MASK_COMMAND,
+ HCI_RESET_COMMAND
+ ),
+ # Octet 6
+ (
+ HCI_SET_EVENT_FILTER_COMMAND,
+ HCI_FLUSH_COMMAND,
+ HCI_READ_PIN_TYPE_COMMAND,
+ HCI_WRITE_PIN_TYPE_COMMAND,
+ None,
+ HCI_READ_STORED_LINK_KEY_COMMAND,
+ HCI_WRITE_STORED_LINK_KEY_COMMAND,
+ HCI_DELETE_STORED_LINK_KEY_COMMAND
+ ),
+ # Octet 7
+ (
+ HCI_WRITE_LOCAL_NAME_COMMAND,
+ HCI_READ_LOCAL_NAME_COMMAND,
+ HCI_READ_CONNECTION_ACCEPT_TIMEOUT_COMMAND,
+ HCI_WRITE_CONNECTION_ACCEPT_TIMEOUT_COMMAND,
+ HCI_READ_PAGE_TIMEOUT_COMMAND,
+ HCI_WRITE_PAGE_TIMEOUT_COMMAND,
+ HCI_READ_SCAN_ENABLE_COMMAND,
+ HCI_WRITE_SCAN_ENABLE_COMMAND
+ ),
+ # Octet 8
+ (
+ HCI_READ_PAGE_SCAN_ACTIVITY_COMMAND,
+ HCI_WRITE_PAGE_SCAN_ACTIVITY_COMMAND,
+ HCI_READ_INQUIRY_SCAN_ACTIVITY_COMMAND,
+ HCI_WRITE_INQUIRY_SCAN_ACTIVITY_COMMAND,
+ HCI_READ_AUTHENTICATION_ENABLE_COMMAND,
+ HCI_WRITE_AUTHENTICATION_ENABLE_COMMAND,
+ None,
+ None
+ ),
+ # Octet 9
+ (
+ HCI_READ_CLASS_OF_DEVICE_COMMAND,
+ HCI_WRITE_CLASS_OF_DEVICE_COMMAND,
+ HCI_READ_VOICE_SETTING_COMMAND,
+ HCI_WRITE_VOICE_SETTING_COMMAND,
+ HCI_READ_AUTOMATIC_FLUSH_TIMEOUT_COMMAND,
+ HCI_WRITE_AUTOMATIC_FLUSH_TIMEOUT_COMMAND,
+ HCI_READ_NUM_BROADCAST_RETRANSMISSIONS_COMMAND,
+ HCI_WRITE_NUM_BROADCAST_RETRANSMISSIONS_COMMAND
+ ),
+ # Octet 10
+ (
+ HCI_READ_HOLD_MODE_ACTIVITY_COMMAND,
+ HCI_WRITE_HOLD_MODE_ACTIVITY_COMMAND,
+ HCI_READ_TRANSMIT_POWER_LEVEL_COMMAND,
+ HCI_READ_SYNCHRONOUS_FLOW_CONTROL_ENABLE_COMMAND,
+ HCI_WRITE_SYNCHRONOUS_FLOW_CONTROL_ENABLE_COMMAND,
+ HCI_SET_CONTROLLER_TO_HOST_FLOW_CONTROL_COMMAND,
+ HCI_HOST_BUFFER_SIZE_COMMAND,
+ HCI_HOST_NUMBER_OF_COMPLETED_PACKETS_COMMAND
+ ),
+ # Octet 11
+ (
+ HCI_READ_LINK_SUPERVISION_TIMEOUT_COMMAND,
+ HCI_WRITE_LINK_SUPERVISION_TIMEOUT_COMMAND,
+ HCI_READ_NUMBER_OF_SUPPORTED_IAC_COMMAND,
+ HCI_READ_CURRENT_IAC_LAP_COMMAND,
+ HCI_WRITE_CURRENT_IAC_LAP_COMMAND,
+ None,
+ None,
+ None
+ ),
+ # Octet 12
+ (
+ None,
+ HCI_SET_AFH_HOST_CHANNEL_CLASSIFICATION_COMMAND,
+ None,
+ None,
+ HCI_READ_INQUIRY_SCAN_TYPE_COMMAND,
+ HCI_WRITE_INQUIRY_SCAN_TYPE_COMMAND,
+ HCI_READ_INQUIRY_MODE_COMMAND,
+ HCI_WRITE_INQUIRY_MODE_COMMAND
+ ),
+ # Octet 13
+ (
+ HCI_READ_PAGE_SCAN_TYPE_COMMAND,
+ HCI_WRITE_PAGE_SCAN_TYPE_COMMAND,
+ HCI_READ_AFH_CHANNEL_ASSESSMENT_MODE_COMMAND,
+ HCI_WRITE_AFH_CHANNEL_ASSESSMENT_MODE_COMMAND,
+ None,
+ None,
+ None,
+ None,
+ ),
+ # Octet 14
+ (
+ None,
+ None,
+ None,
+ HCI_READ_LOCAL_VERSION_INFORMATION_COMMAND,
+ None,
+ HCI_READ_LOCAL_SUPPORTED_FEATURES_COMMAND,
+ HCI_READ_LOCAL_EXTENDED_FEATURES_COMMAND,
+ HCI_READ_BUFFER_SIZE_COMMAND
+ ),
+ # Octet 15
+ (
+ None,
+ HCI_READ_BD_ADDR_COMMAND,
+ HCI_READ_FAILED_CONTACT_COUNTER_COMMAND,
+ HCI_RESET_FAILED_CONTACT_COUNTER_COMMAND,
+ HCI_READ_LINK_QUALITY_COMMAND,
+ HCI_READ_RSSI_COMMAND,
+ HCI_READ_AFH_CHANNEL_MAP_COMMAND,
+ HCI_READ_CLOCK_COMMAND
+ ),
+ # Octet 16
+ (
+ HCI_READ_LOOPBACK_MODE_COMMAND,
+ HCI_WRITE_LOOPBACK_MODE_COMMAND,
+ HCI_ENABLE_DEVICE_UNDER_TEST_MODE_COMMAND,
+ HCI_SETUP_SYNCHRONOUS_CONNECTION_COMMAND,
+ HCI_ACCEPT_SYNCHRONOUS_CONNECTION_REQUEST_COMMAND,
+ HCI_REJECT_SYNCHRONOUS_CONNECTION_REQUEST_COMMAND,
+ None,
+ None,
+ ),
+ # Octet 17
+ (
+ HCI_READ_EXTENDED_INQUIRY_RESPONSE_COMMAND,
+ HCI_WRITE_EXTENDED_INQUIRY_RESPONSE_COMMAND,
+ HCI_REFRESH_ENCRYPTION_KEY_COMMAND,
+ None,
+ HCI_SNIFF_SUBRATING_COMMAND,
+ HCI_READ_SIMPLE_PAIRING_MODE_COMMAND,
+ HCI_WRITE_SIMPLE_PAIRING_MODE_COMMAND,
+ HCI_READ_LOCAL_OOB_DATA_COMMAND
+ ),
+ # Octet 18
+ (
+ HCI_READ_INQUIRY_RESPONSE_TRANSMIT_POWER_LEVEL_COMMAND,
+ HCI_WRITE_INQUIRY_TRANSMIT_POWER_LEVEL_COMMAND,
+ HCI_READ_DEFAULT_ERRONEOUS_DATA_REPORTING_COMMAND,
+ HCI_WRITE_DEFAULT_ERRONEOUS_DATA_REPORTING_COMMAND,
+ None,
+ None,
+ None,
+ HCI_IO_CAPABILITY_REQUEST_REPLY_COMMAND
+ ),
+ # Octet 19
+ (
+ HCI_USER_CONFIRMATION_REQUEST_REPLY_COMMAND,
+ HCI_USER_CONFIRMATION_REQUEST_NEGATIVE_REPLY_COMMAND,
+ HCI_USER_PASSKEY_REQUEST_REPLY_COMMAND,
+ HCI_USER_PASSKEY_REQUEST_NEGATIVE_REPLY_COMMAND,
+ HCI_REMOTE_OOB_DATA_REQUEST_REPLY_COMMAND,
+ HCI_WRITE_SIMPLE_PAIRING_DEBUG_MODE_COMMAND,
+ HCI_ENHANCED_FLUSH_COMMAND,
+ HCI_REMOTE_OOB_DATA_REQUEST_NEGATIVE_REPLY_COMMAND
+ ),
+ # Octet 20
+ (
+ None,
+ None,
+ HCI_SEND_KEYPRESS_NOTIFICATION_COMMAND,
+ HCI_IO_CAPABILITY_REQUEST_NEGATIVE_REPLY_COMMAND,
+ HCI_READ_ENCRYPTION_KEY_SIZE_COMMAND,
+ None,
+ None,
+ None,
+ ),
+ # Octet 21
+ (
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ ),
+ # Octet 22
+ (
+ None,
+ None,
+ HCI_SET_EVENT_MASK_PAGE_2_COMMAND,
+ None,
+ None,
+ None,
+ None,
+ None,
+ ),
+ # Octet 23
+ (
+ HCI_READ_FLOW_CONTROL_MODE_COMMAND,
+ HCI_WRITE_FLOW_CONTROL_MODE_COMMAND,
+ HCI_READ_DATA_BLOCK_SIZE_COMMAND,
+ None,
+ None,
+ None,
+ None,
+ None,
+ ),
+ # Octet 24
+ (
+ HCI_READ_ENHANCED_TRANSMIT_POWER_LEVEL_COMMAND,
+ None,
+ None,
+ None,
+ None,
+ HCI_READ_LE_HOST_SUPPORT_COMMAND,
+ HCI_WRITE_LE_HOST_SUPPORT_COMMAND,
+ None,
+ ),
+ # Octet 25
+ (
+ HCI_LE_SET_EVENT_MASK_COMMAND,
+ HCI_LE_READ_BUFFER_SIZE_COMMAND,
+ HCI_LE_READ_LOCAL_SUPPORTED_FEATURES_COMMAND,
+ None,
+ HCI_LE_SET_RANDOM_ADDRESS_COMMAND,
+ HCI_LE_SET_ADVERTISING_PARAMETERS_COMMAND,
+ HCI_LE_READ_ADVERTISING_PHYSICAL_CHANNEL_TX_POWER_COMMAND,
+ HCI_LE_SET_ADVERTISING_DATA_COMMAND,
+ ),
+ # Octet 26
+ (
+ HCI_LE_SET_SCAN_RESPONSE_DATA_COMMAND,
+ HCI_LE_SET_ADVERTISING_ENABLE_COMMAND,
+ HCI_LE_SET_SCAN_PARAMETERS_COMMAND,
+ HCI_LE_SET_SCAN_ENABLE_COMMAND,
+ HCI_LE_CREATE_CONNECTION_COMMAND,
+ HCI_LE_CREATE_CONNECTION_CANCEL_COMMAND,
+ HCI_LE_READ_FILTER_ACCEPT_LIST_SIZE_COMMAND,
+ HCI_LE_CLEAR_FILTER_ACCEPT_LIST_COMMAND
+ ),
+ # Octet 27
+ (
+ HCI_LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST_COMMAND,
+ HCI_LE_REMOVE_DEVICE_FROM_FILTER_ACCEPT_LIST_COMMAND,
+ HCI_LE_CONNECTION_UPDATE_COMMAND,
+ HCI_LE_SET_HOST_CHANNEL_CLASSIFICATION_COMMAND,
+ HCI_LE_READ_CHANNEL_MAP_COMMAND,
+ HCI_LE_READ_REMOTE_FEATURES_COMMAND,
+ HCI_LE_ENCRYPT_COMMAND,
+ HCI_LE_RAND_COMMAND
+ ),
+ # Octet 28
+ (
+ HCI_LE_ENABLE_ENCRYPTION_COMMAND,
+ HCI_LE_LONG_TERM_KEY_REQUEST_REPLY_COMMAND,
+ HCI_LE_LONG_TERM_KEY_REQUEST_NEGATIVE_REPLY_COMMAND,
+ HCI_LE_READ_SUPPORTED_STATES_COMMAND,
+ HCI_LE_RECEIVER_TEST_COMMAND,
+ HCI_LE_TRANSMITTER_TEST_COMMAND,
+ HCI_LE_TEST_END_COMMAND,
+ None,
+ ),
+ # Octet 29
+ (
+ None,
+ None,
+ None,
+ HCI_ENHANCED_SETUP_SYNCHRONOUS_CONNECTION_COMMAND,
+ HCI_ENHANCED_ACCEPT_SYNCHRONOUS_CONNECTION_REQUEST_COMMAND,
+ HCI_READ_LOCAL_SUPPORTED_CODECS_COMMAND,
+ HCI_SET_MWS_CHANNEL_PARAMETERS_COMMAND,
+ HCI_SET_EXTERNAL_FRAME_CONFIGURATION_COMMAND
+ ),
+ # Octet 30
+ (
+ HCI_SET_MWS_SIGNALING_COMMAND,
+ HCI_SET_MWS_TRANSPORT_LAYER_COMMAND,
+ HCI_SET_MWS_SCAN_FREQUENCY_TABLE_COMMAND,
+ HCI_GET_MWS_TRANSPORT_LAYER_CONFIGURATION_COMMAND,
+ HCI_SET_MWS_PATTERN_CONFIGURATION_COMMAND,
+ HCI_SET_TRIGGERED_CLOCK_CAPTURE_COMMAND,
+ HCI_TRUNCATED_PAGE_COMMAND,
+ HCI_TRUNCATED_PAGE_CANCEL_COMMAND
+ ),
+ # Octet 31
+ (
+ HCI_SET_CONNECTIONLESS_PERIPHERAL_BROADCAST_COMMAND,
+ HCI_SET_CONNECTIONLESS_PERIPHERAL_BROADCAST_RECEIVE_COMMAND,
+ HCI_START_SYNCHRONIZATION_TRAIN_COMMAND,
+ HCI_RECEIVE_SYNCHRONIZATION_TRAIN_COMMAND,
+ HCI_SET_RESERVED_LT_ADDR_COMMAND,
+ HCI_DELETE_RESERVED_LT_ADDR_COMMAND,
+ HCI_SET_CONNECTIONLESS_PERIPHERAL_BROADCAST_DATA_COMMAND,
+ HCI_READ_SYNCHRONIZATION_TRAIN_PARAMETERS_COMMAND
+ ),
+ # Octet 32
+ (
+ HCI_WRITE_SYNCHRONIZATION_TRAIN_PARAMETERS_COMMAND,
+ HCI_REMOTE_OOB_EXTENDED_DATA_REQUEST_REPLY_COMMAND,
+ HCI_READ_SECURE_CONNECTIONS_HOST_SUPPORT_COMMAND,
+ HCI_WRITE_SECURE_CONNECTIONS_HOST_SUPPORT_COMMAND,
+ HCI_READ_AUTHENTICATED_PAYLOAD_TIMEOUT_COMMAND,
+ HCI_WRITE_AUTHENTICATED_PAYLOAD_TIMEOUT_COMMAND,
+ HCI_READ_LOCAL_OOB_EXTENDED_DATA_COMMAND,
+ HCI_WRITE_SECURE_CONNECTIONS_TEST_MODE_COMMAND
+ ),
+ # Octet 33
+ (
+ HCI_READ_EXTENDED_PAGE_TIMEOUT_COMMAND,
+ HCI_WRITE_EXTENDED_PAGE_TIMEOUT_COMMAND,
+ HCI_READ_EXTENDED_INQUIRY_LENGTH_COMMAND,
+ HCI_WRITE_EXTENDED_INQUIRY_LENGTH_COMMAND,
+ HCI_LE_REMOTE_CONNECTION_PARAMETER_REQUEST_REPLY_COMMAND,
+ HCI_LE_REMOTE_CONNECTION_PARAMETER_REQUEST_NEGATIVE_REPLY_COMMAND,
+ HCI_LE_SET_DATA_LENGTH_COMMAND,
+ HCI_LE_READ_SUGGESTED_DEFAULT_DATA_LENGTH_COMMAND
+ ),
+ # Octet 34
+ (
+ HCI_LE_WRITE_SUGGESTED_DEFAULT_DATA_LENGTH_COMMAND,
+ HCI_LE_READ_LOCAL_P_256_PUBLIC_KEY_COMMAND,
+ HCI_LE_GENERATE_DHKEY_COMMAND,
+ HCI_LE_ADD_DEVICE_TO_RESOLVING_LIST_COMMAND,
+ HCI_LE_REMOVE_DEVICE_FROM_RESOLVING_LIST_COMMAND,
+ HCI_LE_CLEAR_RESOLVING_LIST_COMMAND,
+ HCI_LE_READ_RESOLVING_LIST_SIZE_COMMAND,
+ HCI_LE_READ_PEER_RESOLVABLE_ADDRESS_COMMAND
+ ),
+ # Octet 35
+ (
+ HCI_LE_READ_LOCAL_RESOLVABLE_ADDRESS_COMMAND,
+ HCI_LE_SET_ADDRESS_RESOLUTION_ENABLE_COMMAND,
+ HCI_LE_SET_RESOLVABLE_PRIVATE_ADDRESS_TIMEOUT_COMMAND,
+ HCI_LE_READ_MAXIMUM_DATA_LENGTH_COMMAND,
+ HCI_LE_READ_PHY_COMMAND,
+ HCI_LE_SET_DEFAULT_PHY_COMMAND,
+ HCI_LE_SET_PHY_COMMAND,
+ HCI_LE_RECEIVER_TEST_V2_COMMAND
+ ),
+ # Octet 36
+ (
+ HCI_LE_TRANSMITTER_TEST_V2_COMMAND,
+ HCI_LE_SET_ADVERTISING_SET_RANDOM_ADDRESS_COMMAND,
+ HCI_LE_SET_EXTENDED_ADVERTISING_PARAMETERS_COMMAND,
+ HCI_LE_SET_EXTENDED_ADVERTISING_DATA_COMMAND,
+ HCI_LE_SET_EXTENDED_SCAN_RESPONSE_DATA_COMMAND,
+ HCI_LE_SET_EXTENDED_ADVERTISING_ENABLE_COMMAND,
+ HCI_LE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH_COMMAND,
+ HCI_LE_READ_NUMBER_OF_SUPPORTED_ADVERTISING_SETS_COMMAND,
+ ),
+ # Octet 37
+ (
+ HCI_LE_REMOVE_ADVERTISING_SET_COMMAND,
+ HCI_LE_CLEAR_ADVERTISING_SETS_COMMAND,
+ HCI_LE_SET_PERIODIC_ADVERTISING_PARAMETERS_COMMAND,
+ HCI_LE_SET_PERIODIC_ADVERTISING_DATA_COMMAND,
+ HCI_LE_SET_PERIODIC_ADVERTISING_ENABLE_COMMAND,
+ HCI_LE_SET_EXTENDED_SCAN_PARAMETERS_COMMAND,
+ HCI_LE_SET_EXTENDED_SCAN_ENABLE_COMMAND,
+ HCI_LE_EXTENDED_CREATE_CONNECTION_COMMAND
+ ),
+ # Octet 38
+ (
+ HCI_LE_PERIODIC_ADVERTISING_CREATE_SYNC_COMMAND,
+ HCI_LE_PERIODIC_ADVERTISING_CREATE_SYNC_CANCEL_COMMAND,
+ HCI_LE_PERIODIC_ADVERTISING_TERMINATE_SYNC_COMMAND,
+ HCI_LE_ADD_DEVICE_TO_PERIODIC_ADVERTISER_LIST_COMMAND,
+ HCI_LE_REMOVE_DEVICE_FROM_PERIODIC_ADVERTISER_LIST_COMMAND,
+ HCI_LE_CLEAR_PERIODIC_ADVERTISER_LIST_COMMAND,
+ HCI_LE_READ_PERIODIC_ADVERTISER_LIST_SIZE_COMMAND,
+ HCI_LE_READ_TRANSMIT_POWER_COMMAND
+ ),
+ # Octet 39
+ (
+ HCI_LE_READ_RF_PATH_COMPENSATION_COMMAND,
+ HCI_LE_WRITE_RF_PATH_COMPENSATION_COMMAND,
+ HCI_LE_SET_PRIVACY_MODE_COMMAND,
+ HCI_LE_RECEIVER_TEST_V3_COMMAND,
+ HCI_LE_TRANSMITTER_TEST_V3_COMMAND,
+ HCI_LE_SET_CONNECTIONLESS_CTE_TRANSMIT_PARAMETERS_COMMAND,
+ HCI_LE_SET_CONNECTIONLESS_CTE_TRANSMIT_ENABLE_COMMAND,
+ HCI_LE_SET_CONNECTIONLESS_IQ_SAMPLING_ENABLE_COMMAND,
+ ),
+ # Octet 40
+ (
+ HCI_LE_SET_CONNECTION_CTE_RECEIVE_PARAMETERS_COMMAND,
+ HCI_LE_SET_CONNECTION_CTE_TRANSMIT_PARAMETERS_COMMAND,
+ HCI_LE_CONNECTION_CTE_REQUEST_ENABLE_COMMAND,
+ HCI_LE_CONNECTION_CTE_RESPONSE_ENABLE_COMMAND,
+ HCI_LE_READ_ANTENNA_INFORMATION_COMMAND,
+ HCI_LE_SET_PERIODIC_ADVERTISING_RECEIVE_ENABLE_COMMAND,
+ HCI_LE_PERIODIC_ADVERTISING_SYNC_TRANSFER_COMMAND,
+ HCI_LE_PERIODIC_ADVERTISING_SET_INFO_TRANSFER_COMMAND
+ ),
+ # Octet 41
+ (
+ HCI_LE_SET_PERIODIC_ADVERTISING_SYNC_TRANSFER_PARAMETERS_COMMAND,
+ HCI_LE_SET_DEFAULT_PERIODIC_ADVERTISING_SYNC_TRANSFER_PARAMETERS_COMMAND,
+ HCI_LE_GENERATE_DHKEY_V2_COMMAND,
+ HCI_READ_LOCAL_SIMPLE_PAIRING_OPTIONS_COMMAND,
+ HCI_LE_MODIFY_SLEEP_CLOCK_ACCURACY_COMMAND,
+ HCI_LE_READ_BUFFER_SIZE_V2_COMMAND,
+ HCI_LE_READ_ISO_TX_SYNC_COMMAND,
+ HCI_LE_SET_CIG_PARAMETERS_COMMAND
+ ),
+ # Octet 42
+ (
+ HCI_LE_SET_CIG_PARAMETERS_TEST_COMMAND,
+ HCI_LE_CREATE_CIS_COMMAND,
+ HCI_LE_REMOVE_CIG_COMMAND,
+ HCI_LE_ACCEPT_CIS_REQUEST_COMMAND,
+ HCI_LE_REJECT_CIS_REQUEST_COMMAND,
+ HCI_LE_CREATE_BIG_COMMAND,
+ HCI_LE_CREATE_BIG_TEST_COMMAND,
+ HCI_LE_TERMINATE_BIG_COMMAND,
+ ),
+ # Octet 43
+ (
+ HCI_LE_BIG_CREATE_SYNC_COMMAND,
+ HCI_LE_BIG_TERMINATE_SYNC_COMMAND,
+ HCI_LE_REQUEST_PEER_SCA_COMMAND,
+ HCI_LE_SETUP_ISO_DATA_PATH_COMMAND,
+ HCI_LE_REMOVE_ISO_DATA_PATH_COMMAND,
+ HCI_LE_ISO_TRANSMIT_TEST_COMMAND,
+ HCI_LE_ISO_RECEIVE_TEST_COMMAND,
+ HCI_LE_ISO_READ_TEST_COUNTERS_COMMAND
+ ),
+ # Octet 44
+ (
+ HCI_LE_ISO_TEST_END_COMMAND,
+ HCI_LE_SET_HOST_FEATURE_COMMAND,
+ HCI_LE_READ_ISO_LINK_QUALITY_COMMAND,
+ HCI_LE_ENHANCED_READ_TRANSMIT_POWER_LEVEL_COMMAND,
+ HCI_LE_READ_REMOTE_TRANSMIT_POWER_LEVEL_COMMAND,
+ HCI_LE_SET_PATH_LOSS_REPORTING_PARAMETERS_COMMAND,
+ HCI_LE_SET_PATH_LOSS_REPORTING_ENABLE_COMMAND,
+ HCI_LE_SET_TRANSMIT_POWER_REPORTING_ENABLE_COMMAND
+ ),
+ # Octet 45
+ (
+ HCI_LE_TRANSMITTER_TEST_V4_COMMAND,
+ HCI_SET_ECOSYSTEM_BASE_INTERVAL_COMMAND,
+ HCI_READ_LOCAL_SUPPORTED_CODECS_V2_COMMAND,
+ HCI_READ_LOCAL_SUPPORTED_CODEC_CAPABILITIES_COMMAND,
+ HCI_READ_LOCAL_SUPPORTED_CONTROLLER_DELAY_COMMAND,
+ HCI_CONFIGURE_DATA_PATH_COMMAND,
+ HCI_LE_SET_DATA_RELATED_ADDRESS_CHANGES_COMMAND,
+ HCI_SET_MIN_ENCRYPTION_KEY_SIZE_COMMAND
+ ),
+ # Octet 46
+ (
+ HCI_LE_SET_DEFAULT_SUBRATE_COMMAND,
+ HCI_LE_SUBRATE_REQUEST_COMMAND,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None
+ )
+)
+
+# LE Supported Features
+HCI_LE_ENCRYPTION_LE_SUPPORTED_FEATURE = 0
+HCI_CONNECTION_PARAMETERS_REQUEST_PROCEDURE_LE_SUPPORTED_FEATURE = 1
+HCI_EXTENDED_REJECT_INDICATION_LE_SUPPORTED_FEATURE = 2
+HCI_PERIPHERAL_INITIATED_FEATURE_EXCHANGE_LE_SUPPORTED_FEATURE = 3
+HCI_LE_PING_LE_SUPPORTED_FEATURE = 4
+HCI_LE_DATA_PACKET_LENGTH_EXTENSION_LE_SUPPORTED_FEATURE = 5
+HCI_LL_PRIVACY_LE_SUPPORTED_FEATURE = 6
+HCI_EXTENDED_SCANNER_FILTER_POLICIES_LE_SUPPORTED_FEATURE = 7
+HCI_LE_2M_PHY_LE_SUPPORTED_FEATURE = 8
+HCI_STABLE_MODULATION_INDEX_TRANSMITTER_LE_SUPPORTED_FEATURE = 9
+HCI_STABLE_MODULATION_INDEX_RECEIVER_LE_SUPPORTED_FEATURE = 10
+HCI_LE_CODED_PHY_LE_SUPPORTED_FEATURE = 11
+HCI_LE_EXTENDED_ADVERTISING_LE_SUPPORTED_FEATURE = 12
+HCI_LE_PERIODIC_ADVERTISING_LE_SUPPORTED_FEATURE = 13
+HCI_CHANNEL_SELECTION_ALGORITHM_2_LE_SUPPORTED_FEATURE = 14
+HCI_LE_POWER_CLASS_1_LE_SUPPORTED_FEATURE = 15
+HCI_MINIMUM_NUMBER_OF_USED_CHANNELS_PROCEDURE_LE_SUPPORTED_FEATURE = 16
+HCI_CONNECTION_CTE_REQUEST_LE_SUPPORTED_FEATURE = 17
+HCI_CONNECTION_CTE_RESPONSE_LE_SUPPORTED_FEATURE = 18
+HCI_CONNECTIONLESS_CTE_TRANSMITTER_LE_SUPPORTED_FEATURE = 19
+HCI_CONNECTIONLESS_CTR_RECEIVER_LE_SUPPORTED_FEATURE = 20
+HCI_ANTENNA_SWITCHING_DURING_CTE_TRANSMISSION_LE_SUPPORTED_FEATURE = 21
+HCI_ANTENNA_SWITCHING_DURING_CTE_RECEPTION_LE_SUPPORTED_FEATURE = 22
+HCI_RECEIVING_CONSTANT_TONE_EXTENSIONS_LE_SUPPORTED_FEATURE = 23
+HCI_PERIODIC_ADVERTISING_SYNC_TRANSFER_SENDER_LE_SUPPORTED_FEATURE = 24
+HCI_PERIODIC_ADVERTISING_SYNC_TRANSFER_RECIPIENT_LE_SUPPORTED_FEATURE = 25
+HCI_SLEEP_CLOCK_ACCURACY_UPDATES_LE_SUPPORTED_FEATURE = 26
+HCI_REMOTE_PUBLIC_KEY_VALIDATION_LE_SUPPORTED_FEATURE = 27
+HCI_CONNECTED_ISOCHRONOUS_STREAM_CENTRAL_LE_SUPPORTED_FEATURE = 28
+HCI_CONNECTED_ISOCHRONOUS_STREAM_PERIPHERAL_LE_SUPPORTED_FEATURE = 29
+HCI_ISOCHRONOUS_BROADCASTER_LE_SUPPORTED_FEATURE = 30
+HCI_SYNCHRONIZED_RECEIVER_LE_SUPPORTED_FEATURE = 31
+HCI_CONNECTED_ISOCHRONOUS_STREAM_LE_SUPPORTED_FEATURE = 32
+HCI_LE_POWER_CONTROL_REQUEST_LE_SUPPORTED_FEATURE = 33
+HCI_LE_POWER_CONTROL_REQUEST_DUP_LE_SUPPORTED_FEATURE = 34
+HCI_LE_PATH_LOSS_MONITORING_LE_SUPPORTED_FEATURE = 35
+HCI_PERIODIC_ADVERTISING_ADI_SUPPORT_LE_SUPPORTED_FEATURE = 36
+HCI_CONNECTION_SUBRATING_LE_SUPPORTED_FEATURE = 37
+HCI_CONNECTION_SUBRATING_HOST_SUPPORT_LE_SUPPORTED_FEATURE = 38
+HCI_CHANNEL_CLASSIFICATION_LE_SUPPORTED_FEATURE = 39
+
+HCI_LE_SUPPORTED_FEATURES_NAMES = {
+ flag: feature_name for (feature_name, flag) in globals().items()
+ if feature_name.startswith('HCI_') and feature_name.endswith('_LE_SUPPORTED_FEATURE')
+}
+
+# fmt: on
+# pylint: enable=line-too-long
+# pylint: disable=invalid-name
+
# -----------------------------------------------------------------------------
+# pylint: disable-next=unnecessary-lambda
STATUS_SPEC = {'size': 1, 'mapper': lambda x: HCI_Constant.status_name(x)}
@@ -768,8 +1410,7 @@ class HCI_Constant:
@staticmethod
def authentication_requirements_name(authentication_requirements):
return HCI_AUTHENTICATION_REQUIREMENTS_NAMES.get(
- authentication_requirements,
- f'0x{authentication_requirements:02X}'
+ authentication_requirements, f'0x{authentication_requirements:02X}'
)
@staticmethod
@@ -780,7 +1421,21 @@ class HCI_Constant:
# -----------------------------------------------------------------------------
class HCI_Error(ProtocolError):
def __init__(self, error_code):
- super().__init__(error_code, 'hci', HCI_Constant.error_name(error_code))
+ super().__init__(
+ error_code,
+ error_namespace='hci',
+ error_name=HCI_Constant.error_name(error_code),
+ )
+
+
+# -----------------------------------------------------------------------------
+class HCI_StatusError(ProtocolError):
+ def __init__(self, response):
+ super().__init__(
+ response.status,
+ error_namespace=HCI_Command.command_name(response.command_opcode),
+ error_name=HCI_Constant.status_name(response.status),
+ )
# -----------------------------------------------------------------------------
@@ -788,25 +1443,25 @@ class HCI_Error(ProtocolError):
# -----------------------------------------------------------------------------
class HCI_Object:
@staticmethod
- def init_from_fields(object, fields, values):
- if type(values) is dict:
+ def init_from_fields(hci_object, fields, values):
+ if isinstance(values, dict):
for field_name, _ in fields:
- setattr(object, field_name, values[field_name])
+ setattr(hci_object, field_name, values[field_name])
else:
for field_name, field_value in zip(fields, values):
- setattr(object, field_name, field_value)
+ setattr(hci_object, field_name, field_value)
@staticmethod
- def init_from_bytes(object, data, offset, fields):
+ def init_from_bytes(hci_object, data, offset, fields):
parsed = HCI_Object.dict_from_bytes(data, offset, fields)
- HCI_Object.init_from_fields(object, parsed.keys(), parsed.values())
+ HCI_Object.init_from_fields(hci_object, parsed.keys(), parsed.values())
@staticmethod
def dict_from_bytes(data, offset, fields):
result = collections.OrderedDict()
for (field_name, field_type) in fields:
- # The field_type may be a dictionnary with a mapper, parser, and/or size
- if type(field_type) is dict:
+ # The field_type may be a dictionary with a mapper, parser, and/or size
+ if isinstance(field_type, dict):
if 'size' in field_type:
field_type = field_type['size']
elif 'parser' in field_type:
@@ -836,10 +1491,10 @@ class HCI_Object:
elif field_type == -2:
# 16-bit signed
field_value = struct.unpack_from('<h', data, offset)[0]
- offset += 1
+ offset += 2
elif field_type == 3:
# 24-bit unsigned
- padded = data[offset:offset + 3] + bytes([0])
+ padded = data[offset : offset + 3] + bytes([0])
field_value = struct.unpack('<I', padded)[0]
offset += 3
elif field_type == 4:
@@ -850,9 +1505,9 @@ class HCI_Object:
# 32-bit unsigned big-endian
field_value = struct.unpack_from('>I', data, offset)[0]
offset += 4
- elif type(field_type) is int and field_type > 4 and field_type <= 256:
+ elif isinstance(field_type, int) and 4 < field_type <= 256:
# Byte array (from 5 up to 256 bytes)
- field_value = data[offset:offset + field_type]
+ field_value = data[offset : offset + field_type]
offset += field_type
elif callable(field_type):
offset, field_value = field_type(data, offset)
@@ -864,19 +1519,20 @@ class HCI_Object:
return result
@staticmethod
- def dict_to_bytes(object, fields):
+ def dict_to_bytes(hci_object, fields):
result = bytearray()
for (field_name, field_type) in fields:
- # The field_type may be a dictionnary with a mapper, parser, serializer, and/or size
+ # The field_type may be a dictionary with a mapper, parser, serializer,
+ # and/or size
serializer = None
- if type(field_type) is dict:
+ if isinstance(field_type, dict):
if 'serializer' in field_type:
serializer = field_type['serializer']
if 'size' in field_type:
field_type = field_type['size']
# Serialize the field
- field_value = object[field_name]
+ field_value = hci_object[field_name]
if serializer:
field_bytes = serializer(field_value)
elif field_type == 1:
@@ -904,31 +1560,35 @@ class HCI_Object:
# 32-bit unsigned big-endian
field_bytes = struct.pack('>I', field_value)
elif field_type == '*':
- if type(field_value) is int:
- if field_value >= 0 and field_value <= 255:
+ if isinstance(field_value, int):
+ if 0 <= field_value <= 255:
field_bytes = bytes([field_value])
else:
raise ValueError('value too large for *-typed field')
else:
field_bytes = bytes(field_value)
- elif type(field_value) is bytes or type(field_value) is bytearray or hasattr(field_value, 'to_bytes'):
+ elif isinstance(field_value, (bytes, bytearray)) or hasattr(
+ field_value, 'to_bytes'
+ ):
field_bytes = bytes(field_value)
- if type(field_type) is int and field_type > 4 and field_type <= 256:
+ if isinstance(field_type, int) and 4 < field_type <= 256:
# Truncate or Pad with zeros if the field is too long or too short
if len(field_bytes) < field_type:
field_bytes += bytes(field_type - len(field_bytes))
elif len(field_bytes) > field_type:
field_bytes = field_bytes[:field_type]
else:
- raise ValueError(f"don't know how to serialize type {type(field_value)}")
+ raise ValueError(
+ f"don't know how to serialize type {type(field_value)}"
+ )
result += field_bytes
return bytes(result)
- @staticmethod
- def from_bytes(data, offset, fields):
- return HCI_Object(fields, **HCI_Object.dict_from_bytes(data, offset, fields))
+ @classmethod
+ def from_bytes(cls, data, offset, fields):
+ return cls(fields, **cls.dict_from_bytes(data, offset, fields))
def to_bytes(self):
return HCI_Object.dict_to_bytes(self.__dict__, self.fields)
@@ -936,53 +1596,61 @@ class HCI_Object:
@staticmethod
def parse_length_prefixed_bytes(data, offset):
length = data[offset]
- return offset + 1 + length, data[offset + 1:offset + 1 + length]
+ return offset + 1 + length, data[offset + 1 : offset + 1 + length]
@staticmethod
def serialize_length_prefixed_bytes(data, padded_size=0):
prefixed_size = 1 + len(data)
- padding = bytes(padded_size - prefixed_size) if prefixed_size < padded_size else b''
+ padding = (
+ bytes(padded_size - prefixed_size) if prefixed_size < padded_size else b''
+ )
return bytes([len(data)]) + data + padding
@staticmethod
def format_field_value(value, indentation):
- if type(value) is bytes:
+ if isinstance(value, bytes):
return value.hex()
- elif isinstance(value, HCI_Object):
+
+ if isinstance(value, HCI_Object):
return '\n' + value.to_string(indentation)
- else:
- return str(value)
+
+ return str(value)
@staticmethod
- def format_fields(object, keys, indentation='', value_mappers={}):
+ def format_fields(hci_object, keys, indentation='', value_mappers=None):
if not keys:
return ''
# Measure the widest field name
- max_field_name_length = max([len(key[0] if type(key) is tuple else key) for key in keys])
+ max_field_name_length = max(
+ (len(key[0] if isinstance(key, tuple) else key) for key in keys)
+ )
# Build array of formatted key:value pairs
fields = []
for key in keys:
value_mapper = None
- if type(key) is tuple:
+ if isinstance(key, tuple):
# The key has an associated specifier
key, specifier = key
# Get the value mapper from the specifier
- if type(specifier) is dict:
+ if isinstance(specifier, dict):
value_mapper = specifier.get('mapper')
# Get the value for the field
- value = object[key]
+ value = hci_object[key]
# Map the value if needed
- value_mapper = value_mappers.get(key, value_mapper)
+ if value_mappers:
+ value_mapper = value_mappers.get(key, value_mapper)
if value_mapper is not None:
value = value_mapper(value)
# Get the string representation of the value
- value_str = HCI_Object.format_field_value(value, indentation = indentation + ' ')
+ value_str = HCI_Object.format_field_value(
+ value, indentation=indentation + ' '
+ )
# Add the field to the formatted result
key_str = color(f'{key + ":":{1 + max_field_name_length}}', 'cyan')
@@ -997,8 +1665,10 @@ class HCI_Object:
self.fields = fields
self.init_from_fields(self, fields, kwargs)
- def to_string(self, indentation='', value_mappers={}):
- return HCI_Object.format_fields(self.__dict__, self.fields, indentation, value_mappers)
+ def to_string(self, indentation='', value_mappers=None):
+ return HCI_Object.format_fields(
+ self.__dict__, self.fields, indentation, value_mappers
+ )
def __str__(self):
return self.to_string()
@@ -1014,18 +1684,24 @@ class Address:
address[0] is the LSB of the address, address[5] is the MSB.
'''
- PUBLIC_DEVICE_ADDRESS = 0x00
- RANDOM_DEVICE_ADDRESS = 0x01
+ PUBLIC_DEVICE_ADDRESS = 0x00
+ RANDOM_DEVICE_ADDRESS = 0x01
PUBLIC_IDENTITY_ADDRESS = 0x02
RANDOM_IDENTITY_ADDRESS = 0x03
ADDRESS_TYPE_NAMES = {
- PUBLIC_DEVICE_ADDRESS: 'PUBLIC_DEVICE_ADDRESS',
- RANDOM_DEVICE_ADDRESS: 'RANDOM_DEVICE_ADDRESS',
+ PUBLIC_DEVICE_ADDRESS: 'PUBLIC_DEVICE_ADDRESS',
+ RANDOM_DEVICE_ADDRESS: 'RANDOM_DEVICE_ADDRESS',
PUBLIC_IDENTITY_ADDRESS: 'PUBLIC_IDENTITY_ADDRESS',
- RANDOM_IDENTITY_ADDRESS: 'RANDOM_IDENTITY_ADDRESS'
+ RANDOM_IDENTITY_ADDRESS: 'RANDOM_IDENTITY_ADDRESS',
}
+ # Type declarations
+ NIL: Address
+ ANY: Address
+ ANY_RANDOM: Address
+
+ # pylint: disable-next=unnecessary-lambda
ADDRESS_TYPE_SPEC = {'size': 1, 'mapper': lambda x: Address.address_type_name(x)}
@staticmethod
@@ -1033,28 +1709,41 @@ class Address:
return name_or_number(Address.ADDRESS_TYPE_NAMES, address_type)
@staticmethod
+ def from_string_for_transport(string, transport):
+ if transport == BT_BR_EDR_TRANSPORT:
+ address_type = Address.PUBLIC_DEVICE_ADDRESS
+ else:
+ address_type = Address.RANDOM_DEVICE_ADDRESS
+ return Address(string, address_type)
+
+ @staticmethod
def parse_address(data, offset):
- # Fix the type to a default value. This is used for parsing type-less Classic addresses
- return Address.parse_address_with_type(data, offset, Address.PUBLIC_DEVICE_ADDRESS)
+ # Fix the type to a default value. This is used for parsing type-less Classic
+ # addresses
+ return Address.parse_address_with_type(
+ data, offset, Address.PUBLIC_DEVICE_ADDRESS
+ )
@staticmethod
def parse_address_with_type(data, offset, address_type):
- return offset + 6, Address(data[offset:offset + 6], address_type)
+ return offset + 6, Address(data[offset : offset + 6], address_type)
@staticmethod
def parse_address_preceded_by_type(data, offset):
address_type = data[offset - 1]
return Address.parse_address_with_type(data, offset, address_type)
- def __init__(self, address, address_type = RANDOM_DEVICE_ADDRESS):
+ def __init__(
+ self, address: Union[bytes, str], address_type: int = RANDOM_DEVICE_ADDRESS
+ ):
'''
Initialize an instance. `address` may be a byte array in little-endian
format, or a hex string in big-endian format (with optional ':'
separators between the bytes).
- If the address is a string suffixed with '/P', `address_type` is ignored and the type
- is set to PUBLIC_DEVICE_ADDRESS.
+ If the address is a string suffixed with '/P', `address_type` is ignored and
+ the type is set to PUBLIC_DEVICE_ADDRESS.
'''
- if type(address) is bytes:
+ if isinstance(address, bytes):
self.address_bytes = address
else:
# Check if there's a '/P' type specifier
@@ -1072,9 +1761,15 @@ class Address:
self.address_type = address_type
+ def clone(self):
+ return Address(self.address_bytes, self.address_type)
+
@property
def is_public(self):
- return self.address_type == self.PUBLIC_DEVICE_ADDRESS or self.address_type == self.PUBLIC_IDENTITY_ADDRESS
+ return self.address_type in (
+ self.PUBLIC_DEVICE_ADDRESS,
+ self.PUBLIC_IDENTITY_ADDRESS,
+ )
@property
def is_random(self):
@@ -1082,11 +1777,16 @@ class Address:
@property
def is_resolved(self):
- return self.address_type == self.PUBLIC_IDENTITY_ADDRESS or self.address_type == self.RANDOM_IDENTITY_ADDRESS
+ return self.address_type in (
+ self.PUBLIC_IDENTITY_ADDRESS,
+ self.RANDOM_IDENTITY_ADDRESS,
+ )
@property
def is_resolvable(self):
- return self.address_type == self.RANDOM_DEVICE_ADDRESS and (self.address_bytes[5] >> 6 == 1)
+ return self.address_type == self.RANDOM_DEVICE_ADDRESS and (
+ self.address_bytes[5] >> 6 == 1
+ )
@property
def is_static(self):
@@ -1102,13 +1802,46 @@ class Address:
return hash(self.address_bytes)
def __eq__(self, other):
- return self.address_bytes == other.address_bytes and self.is_public == other.is_public
+ return (
+ self.address_bytes == other.address_bytes
+ and self.is_public == other.is_public
+ )
def __str__(self):
'''
String representation of the address, MSB first
'''
- return ':'.join([f'{x:02X}' for x in reversed(self.address_bytes)])
+ result = ':'.join([f'{x:02X}' for x in reversed(self.address_bytes)])
+ if not self.is_public:
+ return result
+ return result + '/P'
+
+
+# Predefined address values
+Address.NIL = Address(b"\xff\xff\xff\xff\xff\xff", Address.PUBLIC_DEVICE_ADDRESS)
+Address.ANY = Address(b"\x00\x00\x00\x00\x00\x00", Address.PUBLIC_DEVICE_ADDRESS)
+Address.ANY_RANDOM = Address(b"\x00\x00\x00\x00\x00\x00", Address.RANDOM_DEVICE_ADDRESS)
+
+# -----------------------------------------------------------------------------
+class OwnAddressType:
+ PUBLIC = 0
+ RANDOM = 1
+ RESOLVABLE_OR_PUBLIC = 2
+ RESOLVABLE_OR_RANDOM = 3
+
+ TYPE_NAMES = {
+ PUBLIC: 'PUBLIC',
+ RANDOM: 'RANDOM',
+ RESOLVABLE_OR_PUBLIC: 'RESOLVABLE_OR_PUBLIC',
+ RESOLVABLE_OR_RANDOM: 'RESOLVABLE_OR_RANDOM',
+ }
+
+ @staticmethod
+ def type_name(type_id):
+ return name_or_number(OwnAddressType.TYPE_NAMES, type_id)
+
+ # pylint: disable-next=unnecessary-lambda
+ TYPE_SPEC = {'size': 1, 'mapper': lambda x: OwnAddressType.type_name(x)}
# -----------------------------------------------------------------------------
@@ -1117,21 +1850,29 @@ class HCI_Packet:
Abstract Base class for HCI packets
'''
+ hci_packet_type: int
+
@staticmethod
def from_bytes(packet):
packet_type = packet[0]
+
if packet_type == HCI_COMMAND_PACKET:
return HCI_Command.from_bytes(packet)
- elif packet_type == HCI_ACL_DATA_PACKET:
+
+ if packet_type == HCI_ACL_DATA_PACKET:
return HCI_AclDataPacket.from_bytes(packet)
- elif packet_type == HCI_EVENT_PACKET:
+
+ if packet_type == HCI_EVENT_PACKET:
return HCI_Event.from_bytes(packet)
- else:
- return HCI_CustomPacket(packet)
+
+ return HCI_CustomPacket(packet)
def __init__(self, name):
self.name = name
+ def __bytes__(self) -> bytes:
+ raise NotImplementedError
+
def __repr__(self) -> str:
return self.name
@@ -1141,7 +1882,10 @@ class HCI_CustomPacket(HCI_Packet):
def __init__(self, payload):
super().__init__('HCI_CUSTOM_PACKET')
self.hci_packet_type = payload[0]
- self.payload = payload
+ self.payload = payload
+
+ def __bytes__(self) -> bytes:
+ return self.payload
# -----------------------------------------------------------------------------
@@ -1149,11 +1893,12 @@ class HCI_Command(HCI_Packet):
'''
See Bluetooth spec @ Vol 2, Part E - 5.4.1 HCI Command Packet
'''
+
hci_packet_type = HCI_COMMAND_PACKET
- command_classes = {}
+ command_classes: Dict[int, Type[HCI_Command]] = {}
@staticmethod
- def command(fields=[], return_parameters_fields=[]):
+ def command(fields=(), return_parameters_fields=()):
'''
Decorator used to declare and register subclasses
'''
@@ -1162,14 +1907,17 @@ class HCI_Command(HCI_Packet):
cls.name = cls.__name__.upper()
cls.op_code = key_with_value(HCI_COMMAND_NAMES, cls.name)
if cls.op_code is None:
- raise KeyError('command not found in HCI_COMMAND_NAMES')
+ raise KeyError(f'command {cls.name} not found in HCI_COMMAND_NAMES')
cls.fields = fields
cls.return_parameters_fields = return_parameters_fields
# Patch the __init__ method to fix the op_code
- def init(self, parameters=None, **kwargs):
- return HCI_Command.__init__(self, cls.op_code, parameters, **kwargs)
- cls.__init__ = init
+ if fields is not None:
+
+ def init(self, parameters=None, **kwargs):
+ return HCI_Command.__init__(self, cls.op_code, parameters, **kwargs)
+
+ cls.__init__ = init
# Register a factory for this class
HCI_Command.command_classes[cls.op_code] = cls
@@ -1192,11 +1940,13 @@ class HCI_Command(HCI_Packet):
return HCI_Command(op_code, parameters)
# Create a new instance
- self = cls.__new__(cls)
- HCI_Command.__init__(self, op_code, parameters)
- if fields := getattr(self, 'fields', None):
+ if (fields := getattr(cls, 'fields', None)) is not None:
+ self = cls.__new__(cls)
+ HCI_Command.__init__(self, op_code, parameters)
HCI_Object.init_from_bytes(self, parameters, 0, fields)
- return self
+ return self
+
+ return cls.from_parameters(parameters)
@staticmethod
def command_name(op_code):
@@ -1215,12 +1965,15 @@ class HCI_Command(HCI_Packet):
HCI_Object.init_from_fields(self, fields, kwargs)
if parameters is None:
parameters = HCI_Object.dict_to_bytes(kwargs, fields)
- self.op_code = op_code
+ self.op_code = op_code
self.parameters = parameters
def to_bytes(self):
parameters = b'' if self.parameters is None else self.parameters
- return struct.pack('<BHB', HCI_COMMAND_PACKET, self.op_code, len(parameters)) + parameters
+ return (
+ struct.pack('<BHB', HCI_COMMAND_PACKET, self.op_code, len(parameters))
+ + parameters
+ )
def __bytes__(self):
return self.to_bytes()
@@ -1236,11 +1989,13 @@ class HCI_Command(HCI_Packet):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('lap', {'size': 3, 'mapper': HCI_Constant.inquiry_lap_name}),
- ('inquiry_length', 1),
- ('num_responses', 1)
-])
+@HCI_Command.command(
+ [
+ ('lap', {'size': 3, 'mapper': HCI_Constant.inquiry_lap_name}),
+ ('inquiry_length', 1),
+ ('num_responses', 1),
+ ]
+)
class HCI_Inquiry_Command(HCI_Command):
'''
See Bluetooth spec @ 7.1.1 Inquiry Command
@@ -1256,14 +2011,16 @@ class HCI_Inquiry_Cancel_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('bd_addr', Address.parse_address),
- ('packet_type', 2),
- ('page_scan_repetition_mode', 1),
- ('reserved', 1),
- ('clock_offset', 2),
- ('allow_role_switch', 1)
-])
+@HCI_Command.command(
+ [
+ ('bd_addr', Address.parse_address),
+ ('packet_type', 2),
+ ('page_scan_repetition_mode', 1),
+ ('reserved', 1),
+ ('clock_offset', 2),
+ ('allow_role_switch', 1),
+ ]
+)
class HCI_Create_Connection_Command(HCI_Command):
'''
See Bluetooth spec @ 7.1.5 Create Connection Command
@@ -1271,10 +2028,12 @@ class HCI_Create_Connection_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('connection_handle', 2),
- ('reason', {'size': 1, 'mapper': HCI_Constant.error_name})
-])
+@HCI_Command.command(
+ [
+ ('connection_handle', 2),
+ ('reason', {'size': 1, 'mapper': HCI_Constant.error_name}),
+ ]
+)
class HCI_Disconnect_Command(HCI_Command):
'''
See Bluetooth spec @ 7.1.6 Disconnect Command
@@ -1282,10 +2041,21 @@ class HCI_Disconnect_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('bd_addr', Address.parse_address),
- ('role', 1)
-])
+@HCI_Command.command(
+ fields=[('bd_addr', Address.parse_address)],
+ return_parameters_fields=[
+ ('status', STATUS_SPEC),
+ ('bd_addr', Address.parse_address),
+ ],
+)
+class HCI_Create_Connection_Cancel_Command(HCI_Command):
+ '''
+ See Bluetooth spec @ 7.1.7 Create Connection Cancel Command
+ '''
+
+
+# -----------------------------------------------------------------------------
+@HCI_Command.command([('bd_addr', Address.parse_address), ('role', 1)])
class HCI_Accept_Connection_Request_Command(HCI_Command):
'''
See Bluetooth spec @ 7.1.8 Accept Connection Request Command
@@ -1293,10 +2063,20 @@ class HCI_Accept_Connection_Request_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('bd_addr', Address.parse_address),
- ('link_key', 16)
-])
+@HCI_Command.command(
+ [
+ ('bd_addr', Address.parse_address),
+ ('reason', {'size': 1, 'mapper': HCI_Constant.error_name}),
+ ]
+)
+class HCI_Reject_Connection_Request_Command(HCI_Command):
+ '''
+ See Bluetooth spec @ 7.1.9 Reject Connection Request Command
+ '''
+
+
+# -----------------------------------------------------------------------------
+@HCI_Command.command([('bd_addr', Address.parse_address), ('link_key', 16)])
class HCI_Link_Key_Request_Reply_Command(HCI_Command):
'''
See Bluetooth spec @ 7.1.10 Link Key Request Reply Command
@@ -1305,13 +2085,11 @@ class HCI_Link_Key_Request_Reply_Command(HCI_Command):
# -----------------------------------------------------------------------------
@HCI_Command.command(
- fields=[
- ('bd_addr', Address.parse_address)
- ],
+ fields=[('bd_addr', Address.parse_address)],
return_parameters_fields=[
- ('status', STATUS_SPEC),
- ('bd_addr', Address.parse_address)
- ]
+ ('status', STATUS_SPEC),
+ ('bd_addr', Address.parse_address),
+ ],
)
class HCI_Link_Key_Request_Negative_Reply_Command(HCI_Command):
'''
@@ -1322,12 +2100,28 @@ class HCI_Link_Key_Request_Negative_Reply_Command(HCI_Command):
# -----------------------------------------------------------------------------
@HCI_Command.command(
fields=[
- ('bd_addr', Address.parse_address)
+ ('bd_addr', Address.parse_address),
+ ('pin_code_length', 1),
+ ('pin_code', 16),
],
return_parameters_fields=[
- ('status', STATUS_SPEC),
- ('bd_addr', Address.parse_address)
- ]
+ ('status', STATUS_SPEC),
+ ('bd_addr', Address.parse_address),
+ ],
+)
+class HCI_PIN_Code_Request_Reply_Command(HCI_Command):
+ '''
+ See Bluetooth spec @ 7.1.12 PIN Code Request Reply Command
+ '''
+
+
+# -----------------------------------------------------------------------------
+@HCI_Command.command(
+ fields=[('bd_addr', Address.parse_address)],
+ return_parameters_fields=[
+ ('status', STATUS_SPEC),
+ ('bd_addr', Address.parse_address),
+ ],
)
class HCI_PIN_Code_Request_Negative_Reply_Command(HCI_Command):
'''
@@ -1336,10 +2130,7 @@ class HCI_PIN_Code_Request_Negative_Reply_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('connection_handle', 2),
- ('packet_type', 2)
-])
+@HCI_Command.command([('connection_handle', 2), ('packet_type', 2)])
class HCI_Change_Connection_Packet_Type_Command(HCI_Command):
'''
See Bluetooth spec @ 7.1.14 Change Connection Packet Type Command
@@ -1347,9 +2138,7 @@ class HCI_Change_Connection_Packet_Type_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('connection_handle', 2)
-])
+@HCI_Command.command([('connection_handle', 2)])
class HCI_Authentication_Requested_Command(HCI_Command):
'''
See Bluetooth spec @ 7.1.15 Authentication Requested Command
@@ -1357,10 +2146,7 @@ class HCI_Authentication_Requested_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('connection_handle', 2),
- ('encryption_enable', 1)
-])
+@HCI_Command.command([('connection_handle', 2), ('encryption_enable', 1)])
class HCI_Set_Connection_Encryption_Command(HCI_Command):
'''
See Bluetooth spec @ 7.1.16 Set Connection Encryption Command
@@ -1368,25 +2154,26 @@ class HCI_Set_Connection_Encryption_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('bd_addr', Address.parse_address),
- ('page_scan_repetition_mode', 1),
- ('reserved', 1),
- ('clock_offset', 2)
-])
+@HCI_Command.command(
+ [
+ ('bd_addr', Address.parse_address),
+ ('page_scan_repetition_mode', 1),
+ ('reserved', 1),
+ ('clock_offset', 2),
+ ]
+)
class HCI_Remote_Name_Request_Command(HCI_Command):
'''
See Bluetooth spec @ 7.1.19 Remote Name Request Command
'''
+
R0 = 0x00
R1 = 0x01
R2 = 0x02
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('connection_handle', 2)
-])
+@HCI_Command.command([('connection_handle', 2)])
class HCI_Read_Remote_Supported_Features_Command(HCI_Command):
'''
See Bluetooth spec @ 7.1.21 Read Remote Supported Features Command
@@ -1394,10 +2181,7 @@ class HCI_Read_Remote_Supported_Features_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('connection_handle', 2),
- ('page_number', 1)
-])
+@HCI_Command.command([('connection_handle', 2), ('page_number', 1)])
class HCI_Read_Remote_Extended_Features_Command(HCI_Command):
'''
See Bluetooth spec @ 7.1.22 Read Remote Extended Features Command
@@ -1405,9 +2189,7 @@ class HCI_Read_Remote_Extended_Features_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('connection_handle', 2)
-])
+@HCI_Command.command([('connection_handle', 2)])
class HCI_Read_Remote_Version_Information_Command(HCI_Command):
'''
See Bluetooth spec @ 7.1.23 Read Remote Version Information Command
@@ -1415,9 +2197,7 @@ class HCI_Read_Remote_Version_Information_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('connection_handle', 2)
-])
+@HCI_Command.command([('connection_handle', 2)])
class HCI_Read_Clock_Offset_Command(HCI_Command):
'''
See Bluetooth spec @ 7.1.23 Read Clock Offset Command
@@ -1427,15 +2207,18 @@ class HCI_Read_Clock_Offset_Command(HCI_Command):
# -----------------------------------------------------------------------------
@HCI_Command.command(
fields=[
- ('bd_addr', Address.parse_address),
- ('io_capability', {'size': 1, 'mapper': HCI_Constant.io_capability_name}),
- ('oob_data_present', 1),
- ('authentication_requirements', {'size': 1, 'mapper': HCI_Constant.authentication_requirements_name})
+ ('bd_addr', Address.parse_address),
+ ('io_capability', {'size': 1, 'mapper': HCI_Constant.io_capability_name}),
+ ('oob_data_present', 1),
+ (
+ 'authentication_requirements',
+ {'size': 1, 'mapper': HCI_Constant.authentication_requirements_name},
+ ),
],
return_parameters_fields=[
- ('status', STATUS_SPEC),
- ('bd_addr', Address.parse_address)
- ]
+ ('status', STATUS_SPEC),
+ ('bd_addr', Address.parse_address),
+ ],
)
class HCI_IO_Capability_Request_Reply_Command(HCI_Command):
'''
@@ -1445,13 +2228,11 @@ class HCI_IO_Capability_Request_Reply_Command(HCI_Command):
# -----------------------------------------------------------------------------
@HCI_Command.command(
- fields=[
- ('bd_addr', Address.parse_address)
- ],
+ fields=[('bd_addr', Address.parse_address)],
return_parameters_fields=[
- ('status', STATUS_SPEC),
- ('bd_addr', Address.parse_address)
- ]
+ ('status', STATUS_SPEC),
+ ('bd_addr', Address.parse_address),
+ ],
)
class HCI_User_Confirmation_Request_Reply_Command(HCI_Command):
'''
@@ -1461,13 +2242,11 @@ class HCI_User_Confirmation_Request_Reply_Command(HCI_Command):
# -----------------------------------------------------------------------------
@HCI_Command.command(
- fields=[
- ('bd_addr', Address.parse_address)
- ],
+ fields=[('bd_addr', Address.parse_address)],
return_parameters_fields=[
- ('status', STATUS_SPEC),
- ('bd_addr', Address.parse_address)
- ]
+ ('status', STATUS_SPEC),
+ ('bd_addr', Address.parse_address),
+ ],
)
class HCI_User_Confirmation_Request_Negative_Reply_Command(HCI_Command):
'''
@@ -1477,14 +2256,11 @@ class HCI_User_Confirmation_Request_Negative_Reply_Command(HCI_Command):
# -----------------------------------------------------------------------------
@HCI_Command.command(
- fields=[
+ fields=[('bd_addr', Address.parse_address), ('numeric_value', 4)],
+ return_parameters_fields=[
+ ('status', STATUS_SPEC),
('bd_addr', Address.parse_address),
- ('numeric_value', 4)
],
- return_parameters_fields=[
- ('status', STATUS_SPEC),
- ('bd_addr', Address.parse_address)
- ]
)
class HCI_User_Passkey_Request_Reply_Command(HCI_Command):
'''
@@ -1494,13 +2270,11 @@ class HCI_User_Passkey_Request_Reply_Command(HCI_Command):
# -----------------------------------------------------------------------------
@HCI_Command.command(
- fields=[
- ('bd_addr', Address.parse_address)
- ],
+ fields=[('bd_addr', Address.parse_address)],
return_parameters_fields=[
- ('status', STATUS_SPEC),
- ('bd_addr', Address.parse_address)
- ]
+ ('status', STATUS_SPEC),
+ ('bd_addr', Address.parse_address),
+ ],
)
class HCI_User_Passkey_Request_Negative_Reply_Command(HCI_Command):
'''
@@ -1509,32 +2283,34 @@ class HCI_User_Passkey_Request_Negative_Reply_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('connection_handle', 2),
- ('transmit_bandwidth', 4),
- ('receive_bandwidth', 4),
- ('transmit_coding_format', 5),
- ('receive_coding_format', 5),
- ('transmit_codec_frame_size', 2),
- ('receive_codec_frame_size', 2),
- ('input_bandwidth', 4),
- ('output_bandwidth', 4),
- ('input_coding_format', 5),
- ('output_coding_format', 5),
- ('input_coded_data_size', 2),
- ('output_coded_data_size', 2),
- ('input_pcm_data_format', 1),
- ('output_pcm_data_format', 1),
- ('input_pcm_sample_payload_msb_position', 1),
- ('output_pcm_sample_payload_msb_position', 1),
- ('input_data_path', 1),
- ('output_data_path', 1),
- ('input_transport_unit_size', 1),
- ('output_transport_unit_size', 1),
- ('max_latency', 2),
- ('packet_type', 2),
- ('retransmission_effort', 1)
-])
+@HCI_Command.command(
+ [
+ ('connection_handle', 2),
+ ('transmit_bandwidth', 4),
+ ('receive_bandwidth', 4),
+ ('transmit_coding_format', 5),
+ ('receive_coding_format', 5),
+ ('transmit_codec_frame_size', 2),
+ ('receive_codec_frame_size', 2),
+ ('input_bandwidth', 4),
+ ('output_bandwidth', 4),
+ ('input_coding_format', 5),
+ ('output_coding_format', 5),
+ ('input_coded_data_size', 2),
+ ('output_coded_data_size', 2),
+ ('input_pcm_data_format', 1),
+ ('output_pcm_data_format', 1),
+ ('input_pcm_sample_payload_msb_position', 1),
+ ('output_pcm_sample_payload_msb_position', 1),
+ ('input_data_path', 1),
+ ('output_data_path', 1),
+ ('input_transport_unit_size', 1),
+ ('output_transport_unit_size', 1),
+ ('max_latency', 2),
+ ('packet_type', 2),
+ ('retransmission_effort', 1),
+ ]
+)
class HCI_Enhanced_Setup_Synchronous_Connection_Command(HCI_Command):
'''
See Bluetooth spec @ 7.1.45 Enhanced Setup Synchronous Connection Command
@@ -1542,13 +2318,15 @@ class HCI_Enhanced_Setup_Synchronous_Connection_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('connection_handle', 2),
- ('sniff_max_interval', 2),
- ('sniff_min_interval', 2),
- ('sniff_attempt', 2),
- ('sniff_timeout', 2)
-])
+@HCI_Command.command(
+ [
+ ('connection_handle', 2),
+ ('sniff_max_interval', 2),
+ ('sniff_min_interval', 2),
+ ('sniff_attempt', 2),
+ ('sniff_timeout', 2),
+ ]
+)
class HCI_Sniff_Mode_Command(HCI_Command):
'''
See Bluetooth spec @ 7.2.2 Sniff Mode Command
@@ -1556,9 +2334,7 @@ class HCI_Sniff_Mode_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('connection_handle', 2)
-])
+@HCI_Command.command([('connection_handle', 2)])
class HCI_Exit_Sniff_Mode_Command(HCI_Command):
'''
See Bluetooth spec @ 7.2.3 Exit Sniff Mode Command
@@ -1566,10 +2342,12 @@ class HCI_Exit_Sniff_Mode_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('bd_addr', Address.parse_address),
- ('role', {'size': 1, 'mapper': HCI_Constant.role_name})
-])
+@HCI_Command.command(
+ [
+ ('bd_addr', Address.parse_address),
+ ('role', {'size': 1, 'mapper': HCI_Constant.role_name}),
+ ]
+)
class HCI_Switch_Role_Command(HCI_Command):
'''
See Bluetooth spec @ 7.2.8 Switch Role Command
@@ -1577,10 +2355,7 @@ class HCI_Switch_Role_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('connection_handle', 2),
- ('link_policy_settings', 2)
-])
+@HCI_Command.command([('connection_handle', 2), ('link_policy_settings', 2)])
class HCI_Write_Link_Policy_Settings_Command(HCI_Command):
'''
See Bluetooth spec @ 7.2.10 Write Link Policy Settings Command
@@ -1588,9 +2363,7 @@ class HCI_Write_Link_Policy_Settings_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('default_link_policy_settings', 2)
-])
+@HCI_Command.command([('default_link_policy_settings', 2)])
class HCI_Write_Default_Link_Policy_Settings_Command(HCI_Command):
'''
See Bluetooth spec @ 7.2.12 Write Default Link Policy Settings Command
@@ -1598,12 +2371,14 @@ class HCI_Write_Default_Link_Policy_Settings_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('connection_handle', 2),
- ('maximum_latency', 2),
- ('minimum_remote_timeout', 2),
- ('minimum_local_timeout', 2)
-])
+@HCI_Command.command(
+ [
+ ('connection_handle', 2),
+ ('maximum_latency', 2),
+ ('minimum_remote_timeout', 2),
+ ('minimum_local_timeout', 2),
+ ]
+)
class HCI_Sniff_Subrating_Command(HCI_Command):
'''
See Bluetooth spec @ 7.2.14 Sniff Subrating Command
@@ -1611,9 +2386,7 @@ class HCI_Sniff_Subrating_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('event_mask', 8)
-])
+@HCI_Command.command([('event_mask', 8)])
class HCI_Set_Event_Mask_Command(HCI_Command):
'''
See Bluetooth spec @ 7.3.1 Set Event Mask Command
@@ -1629,10 +2402,12 @@ class HCI_Reset_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('filter_type', 1),
- ('filter_condition', '*'),
-])
+@HCI_Command.command(
+ [
+ ('filter_type', 1),
+ ('filter_condition', '*'),
+ ]
+)
class HCI_Set_Event_Filter_Command(HCI_Command):
'''
See Bluetooth spec @ 7.3.3 Set Event Filter Command
@@ -1641,15 +2416,12 @@ class HCI_Set_Event_Filter_Command(HCI_Command):
# -----------------------------------------------------------------------------
@HCI_Command.command(
- fields=[
- ('bd_addr', Address.parse_address),
- ('read_all_flag', 1)
- ],
+ fields=[('bd_addr', Address.parse_address), ('read_all_flag', 1)],
return_parameters_fields=[
- ('status', STATUS_SPEC),
- ('max_num_keys', 2),
- ('num_keys_read', 2)
- ]
+ ('status', STATUS_SPEC),
+ ('max_num_keys', 2),
+ ('num_keys_read', 2),
+ ],
)
class HCI_Read_Stored_Link_Key_Command(HCI_Command):
'''
@@ -1659,14 +2431,8 @@ class HCI_Read_Stored_Link_Key_Command(HCI_Command):
# -----------------------------------------------------------------------------
@HCI_Command.command(
- fields=[
- ('bd_addr', Address.parse_address),
- ('delete_all_flag', 1)
- ],
- return_parameters_fields=[
- ('status', STATUS_SPEC),
- ('num_keys_deleted', 2)
- ]
+ fields=[('bd_addr', Address.parse_address), ('delete_all_flag', 1)],
+ return_parameters_fields=[('status', STATUS_SPEC), ('num_keys_deleted', 2)],
)
class HCI_Delete_Stored_Link_Key_Command(HCI_Command):
'''
@@ -1675,9 +2441,9 @@ class HCI_Delete_Stored_Link_Key_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('local_name', {'size': 248, 'mapper': map_null_terminated_utf8_string})
-])
+@HCI_Command.command(
+ [('local_name', {'size': 248, 'mapper': map_null_terminated_utf8_string})]
+)
class HCI_Write_Local_Name_Command(HCI_Command):
'''
See Bluetooth spec @ 7.3.11 Write Local Name Command
@@ -1685,10 +2451,12 @@ class HCI_Write_Local_Name_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command(return_parameters_fields=[
- ('status', STATUS_SPEC),
- ('local_name', {'size': 248, 'mapper': map_null_terminated_utf8_string})
-])
+@HCI_Command.command(
+ return_parameters_fields=[
+ ('status', STATUS_SPEC),
+ ('local_name', {'size': 248, 'mapper': map_null_terminated_utf8_string}),
+ ]
+)
class HCI_Read_Local_Name_Command(HCI_Command):
'''
See Bluetooth spec @ 7.3.12 Read Local Name Command
@@ -1696,9 +2464,7 @@ class HCI_Read_Local_Name_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('conn_accept_timeout', 2)
-])
+@HCI_Command.command([('connection_accept_timeout', 2)])
class HCI_Write_Connection_Accept_Timeout_Command(HCI_Command):
'''
See Bluetooth spec @ 7.3.14 Write Connection Accept Timeout Command
@@ -1706,9 +2472,7 @@ class HCI_Write_Connection_Accept_Timeout_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('page_timeout', 2)
-])
+@HCI_Command.command([('page_timeout', 2)])
class HCI_Write_Page_Timeout_Command(HCI_Command):
'''
See Bluetooth spec @ 7.3.16 Write Page Timeout Command
@@ -1716,9 +2480,7 @@ class HCI_Write_Page_Timeout_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('scan_enable', 1)
-])
+@HCI_Command.command([('scan_enable', 1)])
class HCI_Write_Scan_Enable_Command(HCI_Command):
'''
See Bluetooth spec @ 7.3.18 Write Scan Enable Command
@@ -1726,11 +2488,13 @@ class HCI_Write_Scan_Enable_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command(return_parameters_fields=[
- ('status', STATUS_SPEC),
- ('page_scan_interval', 2),
- ('page_scan_window', 2)
-])
+@HCI_Command.command(
+ return_parameters_fields=[
+ ('status', STATUS_SPEC),
+ ('page_scan_interval', 2),
+ ('page_scan_window', 2),
+ ]
+)
class HCI_Read_Page_Scan_Activity_Command(HCI_Command):
'''
See Bluetooth spec @ 7.3.19 Read Page Scan Activity Command
@@ -1738,10 +2502,7 @@ class HCI_Read_Page_Scan_Activity_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('page_scan_interval', 2),
- ('page_scan_window', 2)
-])
+@HCI_Command.command([('page_scan_interval', 2), ('page_scan_window', 2)])
class HCI_Write_Page_Scan_Activity_Command(HCI_Command):
'''
See Bluetooth spec @ 7.3.20 Write Page Scan Activity Command
@@ -1749,10 +2510,7 @@ class HCI_Write_Page_Scan_Activity_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('inquiry_scan_interval', 2),
- ('inquiry_scan_window', 2)
-])
+@HCI_Command.command([('inquiry_scan_interval', 2), ('inquiry_scan_window', 2)])
class HCI_Write_Inquiry_Scan_Activity_Command(HCI_Command):
'''
See Bluetooth spec @ 7.3.22 Write Inquiry Scan Activity Command
@@ -1760,10 +2518,12 @@ class HCI_Write_Inquiry_Scan_Activity_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command(return_parameters_fields=[
- ('status', STATUS_SPEC),
- ('class_of_device', {'size': 3, 'mapper': map_class_of_device})
-])
+@HCI_Command.command(
+ return_parameters_fields=[
+ ('status', STATUS_SPEC),
+ ('class_of_device', {'size': 3, 'mapper': map_class_of_device}),
+ ]
+)
class HCI_Read_Class_Of_Device_Command(HCI_Command):
'''
See Bluetooth spec @ 7.3.25 Read Class of Device Command
@@ -1771,9 +2531,7 @@ class HCI_Read_Class_Of_Device_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('class_of_device', {'size': 3, 'mapper': map_class_of_device})
-])
+@HCI_Command.command([('class_of_device', {'size': 3, 'mapper': map_class_of_device})])
class HCI_Write_Class_Of_Device_Command(HCI_Command):
'''
See Bluetooth spec @ 7.3.26 Write Class of Device Command
@@ -1781,10 +2539,9 @@ class HCI_Write_Class_Of_Device_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command(return_parameters_fields=[
- ('status', STATUS_SPEC),
- ('voice_setting', 2)
-])
+@HCI_Command.command(
+ return_parameters_fields=[('status', STATUS_SPEC), ('voice_setting', 2)]
+)
class HCI_Read_Voice_Setting_Command(HCI_Command):
'''
See Bluetooth spec @ 7.3.27 Read Voice Setting Command
@@ -1792,9 +2549,7 @@ class HCI_Read_Voice_Setting_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('voice_setting', 2)
-])
+@HCI_Command.command([('voice_setting', 2)])
class HCI_Write_Voice_Setting_Command(HCI_Command):
'''
See Bluetooth spec @ 7.3.28 Write Voice Setting Command
@@ -1802,16 +2557,15 @@ class HCI_Write_Voice_Setting_Command(HCI_Command):
# -----------------------------------------------------------------------------
+@HCI_Command.command()
class HCI_Read_Synchronous_Flow_Control_Enable_Command(HCI_Command):
'''
- See Bluetooth spec @ 7.3.36 Write Synchronous Flow Control Enable Command
+ See Bluetooth spec @ 7.3.36 Read Synchronous Flow Control Enable Command
'''
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('synchronous_flow_control_enable', 1)
-])
+@HCI_Command.command([('synchronous_flow_control_enable', 1)])
class HCI_Write_Synchronous_Flow_Control_Enable_Command(HCI_Command):
'''
See Bluetooth spec @ 7.3.37 Write Synchronous Flow Control Enable Command
@@ -1819,12 +2573,14 @@ class HCI_Write_Synchronous_Flow_Control_Enable_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('host_acl_data_packet_length', 2),
- ('host_synchronous_data_packet_length', 1),
- ('host_total_num_acl_data_packets', 2),
- ('host_total_num_synchronous_data_packets', 2)
-])
+@HCI_Command.command(
+ [
+ ('host_acl_data_packet_length', 2),
+ ('host_synchronous_data_packet_length', 1),
+ ('host_total_num_acl_data_packets', 2),
+ ('host_total_num_synchronous_data_packets', 2),
+ ]
+)
class HCI_Host_Buffer_Size_Command(HCI_Command):
'''
See Bluetooth spec @ 7.3.39 Host Buffer Size Command
@@ -1833,14 +2589,11 @@ class HCI_Host_Buffer_Size_Command(HCI_Command):
# -----------------------------------------------------------------------------
@HCI_Command.command(
- fields=[
- ('handle', 2),
- ('link_supervision_timeout', 2)
- ],
+ fields=[('handle', 2), ('link_supervision_timeout', 2)],
return_parameters_fields=[
('status', STATUS_SPEC),
('handle', 2),
- ]
+ ],
)
class HCI_Write_Link_Supervision_Timeout_Command(HCI_Command):
'''
@@ -1849,10 +2602,9 @@ class HCI_Write_Link_Supervision_Timeout_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command(return_parameters_fields=[
- ('status', STATUS_SPEC),
- ('num_support_iac', 1)
-])
+@HCI_Command.command(
+ return_parameters_fields=[('status', STATUS_SPEC), ('num_support_iac', 1)]
+)
class HCI_Read_Number_Of_Supported_IAC_Command(HCI_Command):
'''
See Bluetooth spec @ 7.3.43 Read Number Of Supported IAC Command
@@ -1860,11 +2612,13 @@ class HCI_Read_Number_Of_Supported_IAC_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command(return_parameters_fields=[
- ('status', STATUS_SPEC),
- ('num_current_iac', 1),
- ('iac_lap', '*') # TODO: this should be parsed as an array
-])
+@HCI_Command.command(
+ return_parameters_fields=[
+ ('status', STATUS_SPEC),
+ ('num_current_iac', 1),
+ ('iac_lap', '*'), # TODO: this should be parsed as an array
+ ]
+)
class HCI_Read_Current_IAC_LAP_Command(HCI_Command):
'''
See Bluetooth spec @ 7.3.44 Read Current IAC LAP Command
@@ -1872,9 +2626,7 @@ class HCI_Read_Current_IAC_LAP_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('scan_type', 1)
-])
+@HCI_Command.command([('scan_type', 1)])
class HCI_Write_Inquiry_Scan_Type_Command(HCI_Command):
'''
See Bluetooth spec @ 7.3.48 Write Inquiry Scan Type Command
@@ -1882,9 +2634,7 @@ class HCI_Write_Inquiry_Scan_Type_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('inquiry_mode', 1)
-])
+@HCI_Command.command([('inquiry_mode', 1)])
class HCI_Write_Inquiry_Mode_Command(HCI_Command):
'''
See Bluetooth spec @ 7.3.50 Write Inquiry Mode Command
@@ -1892,10 +2642,9 @@ class HCI_Write_Inquiry_Mode_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command(return_parameters_fields=[
- ('status', STATUS_SPEC),
- ('page_scan_type', 1)
-])
+@HCI_Command.command(
+ return_parameters_fields=[('status', STATUS_SPEC), ('page_scan_type', 1)]
+)
class HCI_Read_Page_Scan_Type_Command(HCI_Command):
'''
See Bluetooth spec @ 7.3.51 Read Page Scan Type Command
@@ -1903,9 +2652,7 @@ class HCI_Read_Page_Scan_Type_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('page_scan_type', 1)
-])
+@HCI_Command.command([('page_scan_type', 1)])
class HCI_Write_Page_Scan_Type_Command(HCI_Command):
'''
See Bluetooth spec @ 7.3.52 Write Page Scan Type Command
@@ -1913,10 +2660,15 @@ class HCI_Write_Page_Scan_Type_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('fec_required', 1),
- ('extended_inquiry_response', {'size': 240, 'serializer': lambda x: padded_bytes(x, 240)})
-])
+@HCI_Command.command(
+ [
+ ('fec_required', 1),
+ (
+ 'extended_inquiry_response',
+ {'size': 240, 'serializer': lambda x: padded_bytes(x, 240)},
+ ),
+ ]
+)
class HCI_Write_Extended_Inquiry_Response_Command(HCI_Command):
'''
See Bluetooth spec @ 7.3.56 Write Extended Inquiry Response Command
@@ -1924,9 +2676,7 @@ class HCI_Write_Extended_Inquiry_Response_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('simple_pairing_mode', 1)
-])
+@HCI_Command.command([('simple_pairing_mode', 1)])
class HCI_Write_Simple_Pairing_Mode_Command(HCI_Command):
'''
See Bluetooth spec @ 7.3.59 Write Simple Pairing Mode Command
@@ -1934,10 +2684,9 @@ class HCI_Write_Simple_Pairing_Mode_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command(return_parameters_fields=[
- ('status', STATUS_SPEC),
- ('tx_power', -1)
-])
+@HCI_Command.command(
+ return_parameters_fields=[('status', STATUS_SPEC), ('tx_power', -1)]
+)
class HCI_Read_Inquiry_Response_Transmit_Power_Level_Command(HCI_Command):
'''
See Bluetooth spec @ 7.3.61 Read Inquiry Response Transmit Power Level Command
@@ -1945,10 +2694,9 @@ class HCI_Read_Inquiry_Response_Transmit_Power_Level_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command(return_parameters_fields=[
- ('status', STATUS_SPEC),
- ('erroneous_data_reporting', 1)
-])
+@HCI_Command.command(
+ return_parameters_fields=[('status', STATUS_SPEC), ('erroneous_data_reporting', 1)]
+)
class HCI_Read_Default_Erroneous_Data_Reporting_Command(HCI_Command):
'''
See Bluetooth spec @ 7.3.64 Read Default Erroneous Data Reporting Command
@@ -1956,9 +2704,7 @@ class HCI_Read_Default_Erroneous_Data_Reporting_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('event_mask_page_2', 8)
-])
+@HCI_Command.command([('event_mask_page_2', 8)])
class HCI_Set_Event_Mask_Page_2_Command(HCI_Command):
'''
See Bluetooth spec @ 7.3.69 Set Event Mask Page 2 Command
@@ -1974,10 +2720,7 @@ class HCI_Read_LE_Host_Support_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('le_supported_host', 1),
- ('simultaneous_le_host', 1)
-])
+@HCI_Command.command([('le_supported_host', 1), ('simultaneous_le_host', 1)])
class HCI_Write_LE_Host_Support_Command(HCI_Command):
'''
See Bluetooth spec @ 7.3.79 Write LE Host Support Command
@@ -1985,9 +2728,7 @@ class HCI_Write_LE_Host_Support_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('secure_connections_host_support', 1)
-])
+@HCI_Command.command([('secure_connections_host_support', 1)])
class HCI_Write_Secure_Connections_Host_Support_Command(HCI_Command):
'''
See Bluetooth spec @ 7.3.92 Write Secure Connections Host Support Command
@@ -1995,10 +2736,7 @@ class HCI_Write_Secure_Connections_Host_Support_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('connection_handle', 2),
- ('authenticated_payload_timeout', 2)
-])
+@HCI_Command.command([('connection_handle', 2), ('authenticated_payload_timeout', 2)])
class HCI_Write_Authenticated_Payload_Timeout_Command(HCI_Command):
'''
See Bluetooth spec @ 7.3.94 Write Authenticated Payload Timeout Command
@@ -2006,14 +2744,16 @@ class HCI_Write_Authenticated_Payload_Timeout_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command(return_parameters_fields=[
- ('status', STATUS_SPEC),
- ('hci_version', 1),
- ('hci_revsion', 2),
- ('lmp_pal_version', 1),
- ('manufacturer_name', 2),
- ('lmp_pal_subversion', 2)
-])
+@HCI_Command.command(
+ return_parameters_fields=[
+ ('status', STATUS_SPEC),
+ ('hci_version', 1),
+ ('hci_subversion', 2),
+ ('lmp_version', 1),
+ ('company_identifier', 2),
+ ('lmp_subversion', 2),
+ ]
+)
class HCI_Read_Local_Version_Information_Command(HCI_Command):
'''
See Bluetooth spec @ 7.4.1 Read Local Version Information Command
@@ -2021,10 +2761,9 @@ class HCI_Read_Local_Version_Information_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command(return_parameters_fields=[
- ('status', STATUS_SPEC),
- ('supported_commands', 64)
-])
+@HCI_Command.command(
+ return_parameters_fields=[('status', STATUS_SPEC), ('supported_commands', 64)]
+)
class HCI_Read_Local_Supported_Commands_Command(HCI_Command):
'''
See Bluetooth spec @ 7.4.2 Read Local Supported Commands Command
@@ -2041,15 +2780,13 @@ class HCI_Read_Local_Supported_Features_Command(HCI_Command):
# -----------------------------------------------------------------------------
@HCI_Command.command(
- fields=[
- ('page_number', 1)
- ],
+ fields=[('page_number', 1)],
return_parameters_fields=[
- ('status', STATUS_SPEC),
- ('page_number', 1),
- ('maximum_page_number', 1),
- ('extended_lmp_features', 8)
- ]
+ ('status', STATUS_SPEC),
+ ('page_number', 1),
+ ('maximum_page_number', 1),
+ ('extended_lmp_features', 8),
+ ],
)
class HCI_Read_Local_Extended_Features_Command(HCI_Command):
'''
@@ -2058,13 +2795,15 @@ class HCI_Read_Local_Extended_Features_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command(return_parameters_fields=[
- ('status', STATUS_SPEC),
- ('hc_acl_data_packet_length', 2),
- ('hc_synchronous_data_packet_length', 1),
- ('hc_total_num_acl_data_packets', 2),
- ('hc_total_num_synchronous_data_packets', 2)
-])
+@HCI_Command.command(
+ return_parameters_fields=[
+ ('status', STATUS_SPEC),
+ ('hc_acl_data_packet_length', 2),
+ ('hc_synchronous_data_packet_length', 1),
+ ('hc_total_num_acl_data_packets', 2),
+ ('hc_total_num_synchronous_data_packets', 2),
+ ]
+)
class HCI_Read_Buffer_Size_Command(HCI_Command):
'''
See Bluetooth spec @ 7.4.5 Read Buffer Size Command
@@ -2072,10 +2811,12 @@ class HCI_Read_Buffer_Size_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command(return_parameters_fields=[
- ('status', STATUS_SPEC),
- ('bd_addr', Address.parse_address)
-])
+@HCI_Command.command(
+ return_parameters_fields=[
+ ('status', STATUS_SPEC),
+ ('bd_addr', Address.parse_address),
+ ]
+)
class HCI_Read_BD_ADDR_Command(HCI_Command):
'''
See Bluetooth spec @ 7.4.6 Read BD_ADDR Command
@@ -2092,14 +2833,23 @@ class HCI_Read_Local_Supported_Codecs_Command(HCI_Command):
# -----------------------------------------------------------------------------
@HCI_Command.command(
- fields=[
- ('connection_handle', 2)
- ],
+ fields=[('handle', 2)],
+ return_parameters_fields=[('status', STATUS_SPEC), ('handle', 2), ('rssi', -1)],
+)
+class HCI_Read_RSSI_Command(HCI_Command):
+ '''
+ See Bluetooth spec @ 7.5.4 Read RSSI Command
+ '''
+
+
+# -----------------------------------------------------------------------------
+@HCI_Command.command(
+ fields=[('connection_handle', 2)],
return_parameters_fields=[
- ('status', STATUS_SPEC),
+ ('status', STATUS_SPEC),
('connection_handle', 2),
- ('key_size', 1)
- ]
+ ('key_size', 1),
+ ],
)
class HCI_Read_Encryption_Key_Size_Command(HCI_Command):
'''
@@ -2108,9 +2858,7 @@ class HCI_Read_Encryption_Key_Size_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('le_event_mask', 8)
-])
+@HCI_Command.command([('le_event_mask', 8)])
class HCI_LE_Set_Event_Mask_Command(HCI_Command):
'''
See Bluetooth spec @ 7.8.1 LE Set Event Mask Command
@@ -2118,11 +2866,13 @@ class HCI_LE_Set_Event_Mask_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command(return_parameters_fields=[
- ('status', STATUS_SPEC),
- ('hc_le_acl_data_packet_length', 2),
- ('hc_total_num_le_acl_data_packets', 1)
-])
+@HCI_Command.command(
+ return_parameters_fields=[
+ ('status', STATUS_SPEC),
+ ('hc_le_acl_data_packet_length', 2),
+ ('hc_total_num_le_acl_data_packets', 1),
+ ]
+)
class HCI_LE_Read_Buffer_Size_Command(HCI_Command):
'''
See Bluetooth spec @ 7.8.2 LE Read Buffer Size Command
@@ -2130,9 +2880,26 @@ class HCI_LE_Read_Buffer_Size_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('random_address', lambda data, offset: Address.parse_address_with_type(data, offset, Address.RANDOM_DEVICE_ADDRESS))
-])
+@HCI_Command.command(
+ return_parameters_fields=[('status', STATUS_SPEC), ('le_features', 8)]
+)
+class HCI_LE_Read_Local_Supported_Features_Command(HCI_Command):
+ '''
+ See Bluetooth spec @ 7.8.3 LE Read Local Supported Features Command
+ '''
+
+
+# -----------------------------------------------------------------------------
+@HCI_Command.command(
+ [
+ (
+ 'random_address',
+ lambda data, offset: Address.parse_address_with_type(
+ data, offset, Address.RANDOM_DEVICE_ADDRESS
+ ),
+ )
+ ]
+)
class HCI_LE_Set_Random_Address_Command(HCI_Command):
'''
See Bluetooth spec @ 7.8.4 LE Set Random Address Command
@@ -2140,33 +2907,44 @@ class HCI_LE_Set_Random_Address_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('advertising_interval_min', 2),
- ('advertising_interval_max', 2),
- ('advertising_type', {'size': 1, 'mapper': lambda x: HCI_LE_Set_Advertising_Parameters_Command.advertising_type_name(x)}),
- ('own_address_type', Address.ADDRESS_TYPE_SPEC),
- ('peer_address_type', Address.ADDRESS_TYPE_SPEC),
- ('peer_address', Address.parse_address_preceded_by_type),
- ('advertising_channel_map', 1),
- ('advertising_filter_policy', 1),
-])
+@HCI_Command.command(
+ # pylint: disable=line-too-long,unnecessary-lambda
+ [
+ ('advertising_interval_min', 2),
+ ('advertising_interval_max', 2),
+ (
+ 'advertising_type',
+ {
+ 'size': 1,
+ 'mapper': lambda x: HCI_LE_Set_Advertising_Parameters_Command.advertising_type_name(
+ x
+ ),
+ },
+ ),
+ ('own_address_type', OwnAddressType.TYPE_SPEC),
+ ('peer_address_type', Address.ADDRESS_TYPE_SPEC),
+ ('peer_address', Address.parse_address_preceded_by_type),
+ ('advertising_channel_map', 1),
+ ('advertising_filter_policy', 1),
+ ]
+)
class HCI_LE_Set_Advertising_Parameters_Command(HCI_Command):
'''
See Bluetooth spec @ 7.8.5 LE Set Advertising Parameters Command
'''
- ADV_IND = 0x00
- ADV_DIRECT_IND = 0x01
- ADV_SCAN_IND = 0x02
+ ADV_IND = 0x00
+ ADV_DIRECT_IND = 0x01
+ ADV_SCAN_IND = 0x02
ADV_NONCONN_IND = 0x03
- ADV_DIRECT_IND = 0x04
+ ADV_DIRECT_IND_LOW_DUTY = 0x04
ADVERTISING_TYPE_NAMES = {
- ADV_IND: 'ADV_IND',
- ADV_DIRECT_IND: 'ADV_DIRECT_IND',
- ADV_SCAN_IND: 'ADV_SCAN_IND',
+ ADV_IND: 'ADV_IND',
+ ADV_DIRECT_IND: 'ADV_DIRECT_IND',
+ ADV_SCAN_IND: 'ADV_SCAN_IND',
ADV_NONCONN_IND: 'ADV_NONCONN_IND',
- ADV_DIRECT_IND: 'ADV_DIRECT_IND'
+ ADV_DIRECT_IND_LOW_DUTY: 'ADV_DIRECT_IND_LOW_DUTY',
}
@classmethod
@@ -2176,19 +2954,26 @@ class HCI_LE_Set_Advertising_Parameters_Command(HCI_Command):
# -----------------------------------------------------------------------------
@HCI_Command.command()
-class HCI_LE_Read_Advertising_Channel_Tx_Power_Command(HCI_Command):
+class HCI_LE_Read_Advertising_Physical_Channel_Tx_Power_Command(HCI_Command):
'''
- See Bluetooth spec @ 7.8.6 LE Read Advertising Channel Tx Power Command
+ See Bluetooth spec @ 7.8.6 LE Read Advertising Physical Channel Tx Power Command
'''
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('advertising_data', {
- 'parser': HCI_Object.parse_length_prefixed_bytes,
- 'serializer': functools.partial(HCI_Object.serialize_length_prefixed_bytes, padded_size=32)
- })
-])
+@HCI_Command.command(
+ [
+ (
+ 'advertising_data',
+ {
+ 'parser': HCI_Object.parse_length_prefixed_bytes,
+ 'serializer': functools.partial(
+ HCI_Object.serialize_length_prefixed_bytes, padded_size=32
+ ),
+ },
+ )
+ ]
+)
class HCI_LE_Set_Advertising_Data_Command(HCI_Command):
'''
See Bluetooth spec @ 7.8.7 LE Set Advertising Data Command
@@ -2196,12 +2981,19 @@ class HCI_LE_Set_Advertising_Data_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('scan_response_data', {
- 'parser': HCI_Object.parse_length_prefixed_bytes,
- 'serializer': functools.partial(HCI_Object.serialize_length_prefixed_bytes, padded_size=32)
- })
-])
+@HCI_Command.command(
+ [
+ (
+ 'scan_response_data',
+ {
+ 'parser': HCI_Object.parse_length_prefixed_bytes,
+ 'serializer': functools.partial(
+ HCI_Object.serialize_length_prefixed_bytes, padded_size=32
+ ),
+ },
+ )
+ ]
+)
class HCI_LE_Set_Scan_Response_Data_Command(HCI_Command):
'''
See Bluetooth spec @ 7.8.8 LE Set Scan Response Data Command
@@ -2209,9 +3001,7 @@ class HCI_LE_Set_Scan_Response_Data_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('advertising_enable', 1)
-])
+@HCI_Command.command([('advertising_enable', 1)])
class HCI_LE_Set_Advertising_Enable_Command(HCI_Command):
'''
See Bluetooth spec @ 7.8.9 LE Set Advertising Enable Command
@@ -2219,31 +3009,36 @@ class HCI_LE_Set_Advertising_Enable_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('le_scan_type', 1),
- ('le_scan_interval', 2),
- ('le_scan_window', 2),
- ('own_address_type', Address.ADDRESS_TYPE_SPEC),
- ('scanning_filter_policy', 1)
-])
+@HCI_Command.command(
+ [
+ ('le_scan_type', 1),
+ ('le_scan_interval', 2),
+ ('le_scan_window', 2),
+ ('own_address_type', OwnAddressType.TYPE_SPEC),
+ ('scanning_filter_policy', 1),
+ ]
+)
class HCI_LE_Set_Scan_Parameters_Command(HCI_Command):
'''
See Bluetooth spec @ 7.8.10 LE Set Scan Parameters Command
'''
+
PASSIVE_SCANNING = 0
- ACTIVE_SCANNING = 1
+ ACTIVE_SCANNING = 1
- BASIC_UNFILTERED_POLICY = 0x00
- BASIC_FILTERED_POLICY = 0x01
+ BASIC_UNFILTERED_POLICY = 0x00
+ BASIC_FILTERED_POLICY = 0x01
EXTENDED_UNFILTERED_POLICY = 0x02
- EXTENDED_FILTERED_POLICY = 0x03
+ EXTENDED_FILTERED_POLICY = 0x03
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('le_scan_enable', 1),
- ('filter_duplicates', 1),
-])
+@HCI_Command.command(
+ [
+ ('le_scan_enable', 1),
+ ('filter_duplicates', 1),
+ ]
+)
class HCI_LE_Set_Scan_Enable_Command(HCI_Command):
'''
See Bluetooth spec @ 7.8.11 LE Set Scan Enable Command
@@ -2251,20 +3046,22 @@ class HCI_LE_Set_Scan_Enable_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('le_scan_interval', 2),
- ('le_scan_window', 2),
- ('initiator_filter_policy', 1),
- ('peer_address_type', Address.ADDRESS_TYPE_SPEC),
- ('peer_address', Address.parse_address_preceded_by_type),
- ('own_address_type', Address.ADDRESS_TYPE_SPEC),
- ('conn_interval_min', 2),
- ('conn_interval_max', 2),
- ('conn_latency', 2),
- ('supervision_timeout', 2),
- ('minimum_ce_length', 2),
- ('maximum_ce_length', 2)
-])
+@HCI_Command.command(
+ [
+ ('le_scan_interval', 2),
+ ('le_scan_window', 2),
+ ('initiator_filter_policy', 1),
+ ('peer_address_type', Address.ADDRESS_TYPE_SPEC),
+ ('peer_address', Address.parse_address_preceded_by_type),
+ ('own_address_type', OwnAddressType.TYPE_SPEC),
+ ('connection_interval_min', 2),
+ ('connection_interval_max', 2),
+ ('max_latency', 2),
+ ('supervision_timeout', 2),
+ ('min_ce_length', 2),
+ ('max_ce_length', 2),
+ ]
+)
class HCI_LE_Create_Connection_Command(HCI_Command):
'''
See Bluetooth spec @ 7.8.12 LE Create Connection Command
@@ -2281,52 +3078,58 @@ class HCI_LE_Create_Connection_Cancel_Command(HCI_Command):
# -----------------------------------------------------------------------------
@HCI_Command.command()
-class HCI_LE_Read_White_List_Size_Command(HCI_Command):
+class HCI_LE_Read_Filter_Accept_List_Size_Command(HCI_Command):
'''
- See Bluetooth spec @ 7.8.14 LE Read White List Size Command
+ See Bluetooth spec @ 7.8.14 LE Read Filter Accept List Size Command
'''
# -----------------------------------------------------------------------------
@HCI_Command.command()
-class HCI_LE_Clear_White_List_Command(HCI_Command):
+class HCI_LE_Clear_Filter_Accept_List_Command(HCI_Command):
'''
- See Bluetooth spec @ 7.8.15 LE Clear White List Command
+ See Bluetooth spec @ 7.8.15 LE Clear Filter Accept List Command
'''
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('address_type', Address.ADDRESS_TYPE_SPEC),
- ('address', Address.parse_address_preceded_by_type)
-])
-class HCI_LE_Add_Device_To_White_List_Command(HCI_Command):
+@HCI_Command.command(
+ [
+ ('address_type', Address.ADDRESS_TYPE_SPEC),
+ ('address', Address.parse_address_preceded_by_type),
+ ]
+)
+class HCI_LE_Add_Device_To_Filter_Accept_List_Command(HCI_Command):
'''
- See Bluetooth spec @ 7.8.16 LE Add Device To White List Command
+ See Bluetooth spec @ 7.8.16 LE Add Device To Filter Accept List Command
'''
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('address_type', Address.ADDRESS_TYPE_SPEC),
- ('address', Address.parse_address_preceded_by_type)
-])
-class HCI_LE_Remove_Device_From_White_List_Command(HCI_Command):
+@HCI_Command.command(
+ [
+ ('address_type', Address.ADDRESS_TYPE_SPEC),
+ ('address', Address.parse_address_preceded_by_type),
+ ]
+)
+class HCI_LE_Remove_Device_From_Filter_Accept_List_Command(HCI_Command):
'''
- See Bluetooth spec @ 7.8.17 LE Remove Device From White List Command
+ See Bluetooth spec @ 7.8.17 LE Remove Device From Filter Accept List Command
'''
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('connection_handle', 2),
- ('conn_interval_min', 2),
- ('conn_interval_max', 2),
- ('conn_latency', 2),
- ('supervision_timeout', 2),
- ('minimum_ce_length', 2),
- ('maximum_ce_length', 2)
-])
+@HCI_Command.command(
+ [
+ ('connection_handle', 2),
+ ('connection_interval_min', 2),
+ ('connection_interval_max', 2),
+ ('max_latency', 2),
+ ('supervision_timeout', 2),
+ ('min_ce_length', 2),
+ ('max_ce_length', 2),
+ ]
+)
class HCI_LE_Connection_Update_Command(HCI_Command):
'''
See Bluetooth spec @ 7.8.18 LE Connection Update Command
@@ -2334,9 +3137,7 @@ class HCI_LE_Connection_Update_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('connection_handle', 2)
-])
+@HCI_Command.command([('connection_handle', 2)])
class HCI_LE_Read_Remote_Features_Command(HCI_Command):
'''
See Bluetooth spec @ 7.8.21 LE Read Remote Features Command
@@ -2344,24 +3145,34 @@ class HCI_LE_Read_Remote_Features_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('connection_handle', 2),
- ('random_number', 8),
- ('encrypted_diversifier', 2),
- ('long_term_key', 16)
-])
-class HCI_LE_Start_Encryption_Command(HCI_Command):
+@HCI_Command.command(
+ return_parameters_fields=[("status", STATUS_SPEC), ("random_number", 8)]
+)
+class HCI_LE_Rand_Command(HCI_Command):
+ """
+ See Bluetooth spec @ 7.8.23 LE Rand Command
+ """
+
+
+# -----------------------------------------------------------------------------
+@HCI_Command.command(
+ [
+ ('connection_handle', 2),
+ ('random_number', 8),
+ ('encrypted_diversifier', 2),
+ ('long_term_key', 16),
+ ]
+)
+class HCI_LE_Enable_Encryption_Command(HCI_Command):
'''
- See Bluetooth spec @ 7.8.24 LE Start Encryption Command
- (renamed to "LE Enable Encryption Command" in version 5.2 of the specification)
+ See Bluetooth spec @ 7.8.24 LE Enable Encryption Command
+ (renamed from "LE Start Encryption Command" in version prior to 5.2 of the
+ specification)
'''
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('connection_handle', 2),
- ('long_term_key', 16)
-])
+@HCI_Command.command([('connection_handle', 2), ('long_term_key', 16)])
class HCI_LE_Long_Term_Key_Request_Reply_Command(HCI_Command):
'''
See Bluetooth spec @ 7.8.25 LE Long Term Key Request Reply Command
@@ -2369,9 +3180,7 @@ class HCI_LE_Long_Term_Key_Request_Reply_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('connection_handle', 2)
-])
+@HCI_Command.command([('connection_handle', 2)])
class HCI_LE_Long_Term_Key_Request_Negative_Reply_Command(HCI_Command):
'''
See Bluetooth spec @ 7.8.26 LE Long Term Key Request Negative Reply Command
@@ -2387,15 +3196,17 @@ class HCI_LE_Read_Supported_States_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('connection_handle', 2),
- ('interval_min', 2),
- ('interval_max', 2),
- ('latency', 2),
- ('timeout', 2),
- ('minimum_ce_length', 2),
- ('maximum_ce_length', 2)
-])
+@HCI_Command.command(
+ [
+ ('connection_handle', 2),
+ ('interval_min', 2),
+ ('interval_max', 2),
+ ('max_latency', 2),
+ ('timeout', 2),
+ ('min_ce_length', 2),
+ ('max_ce_length', 2),
+ ]
+)
class HCI_LE_Remote_Connection_Parameter_Request_Reply_Command(HCI_Command):
'''
See Bluetooth spec @ 7.8.31 LE Remote Connection Parameter Request Reply Command
@@ -2403,21 +3214,50 @@ class HCI_LE_Remote_Connection_Parameter_Request_Reply_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('connection_handle', 2),
- ('reason', {'size': 1, 'mapper': HCI_Constant.error_name})
-])
+@HCI_Command.command(
+ [
+ ('connection_handle', 2),
+ ('reason', {'size': 1, 'mapper': HCI_Constant.error_name}),
+ ]
+)
class HCI_LE_Remote_Connection_Parameter_Request_Negative_Reply_Command(HCI_Command):
'''
- See Bluetooth spec @ 7.8.32 LE Remote Connection Parameter Request Negative Reply Command
+ See Bluetooth spec @ 7.8.32 LE Remote Connection Parameter Request Negative Reply
+ Command
+ '''
+
+
+# -----------------------------------------------------------------------------
+@HCI_Command.command(
+ fields=[
+ ('connection_handle', 2),
+ ('tx_octets', 2),
+ ('tx_time', 2),
+ ],
+ return_parameters_fields=[('status', STATUS_SPEC), ('connection_handle', 2)],
+)
+class HCI_LE_Set_Data_Length_Command(HCI_Command):
+ '''
+ See Bluetooth spec @ 7.8.33 LE Set Data Length Command
+ '''
+
+
+# -----------------------------------------------------------------------------
+@HCI_Command.command(
+ return_parameters_fields=[
+ ('status', STATUS_SPEC),
+ ('suggested_max_tx_octets', 2),
+ ('suggested_max_tx_time', 2),
+ ]
+)
+class HCI_LE_Read_Suggested_Default_Data_Length_Command(HCI_Command):
+ '''
+ See Bluetooth spec @ 7.8.34 LE Read Suggested Default Data Length Command
'''
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('suggested_max_tx_octets', 2),
- ('suggested_max_tx_time', 2)
-])
+@HCI_Command.command([('suggested_max_tx_octets', 2), ('suggested_max_tx_time', 2)])
class HCI_LE_Write_Suggested_Default_Data_Length_Command(HCI_Command):
'''
See Bluetooth spec @ 7.8.35 LE Write Suggested Default Data Length Command
@@ -2425,12 +3265,14 @@ class HCI_LE_Write_Suggested_Default_Data_Length_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('peer_identity_address_type', Address.ADDRESS_TYPE_SPEC),
- ('peer_identity_address', Address.parse_address_preceded_by_type),
- ('peer_irk', 16),
- ('local_irk', 16),
-])
+@HCI_Command.command(
+ [
+ ('peer_identity_address_type', Address.ADDRESS_TYPE_SPEC),
+ ('peer_identity_address', Address.parse_address_preceded_by_type),
+ ('peer_irk', 16),
+ ('local_irk', 16),
+ ]
+)
class HCI_LE_Add_Device_To_Resolving_List_Command(HCI_Command):
'''
See Bluetooth spec @ 7.8.38 LE Add Device To Resolving List Command
@@ -2446,34 +3288,765 @@ class HCI_LE_Clear_Resolving_List_Command(HCI_Command):
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('all_phys', 1),
- ('tx_phys', 1),
- ('rx_phys', 1)
-])
+@HCI_Command.command([('address_resolution_enable', 1)])
+class HCI_LE_Set_Address_Resolution_Enable_Command(HCI_Command):
+ '''
+ See Bluetooth spec @ 7.8.44 LE Set Address Resolution Enable Command
+ '''
+
+
+# -----------------------------------------------------------------------------
+@HCI_Command.command([('rpa_timeout', 2)])
+class HCI_LE_Set_Resolvable_Private_Address_Timeout_Command(HCI_Command):
+ '''
+ See Bluetooth spec @ 7.8.45 LE Set Resolvable Private Address Timeout Command
+ '''
+
+
+# -----------------------------------------------------------------------------
+@HCI_Command.command(
+ return_parameters_fields=[
+ ('status', STATUS_SPEC),
+ ('supported_max_tx_octets', 2),
+ ('supported_max_tx_time', 2),
+ ('supported_max_rx_octets', 2),
+ ('supported_max_rx_time', 2),
+ ]
+)
+class HCI_LE_Read_Maximum_Data_Length_Command(HCI_Command):
+ '''
+ See Bluetooth spec @ 7.8.46 LE Read Maximum Data Length Command
+ '''
+
+
+# -----------------------------------------------------------------------------
+@HCI_Command.command(
+ fields=[('connection_handle', 2)],
+ return_parameters_fields=[
+ ('status', STATUS_SPEC),
+ ('connection_handle', 2),
+ ('tx_phy', {'size': 1, 'mapper': HCI_Constant.le_phy_name}),
+ ('rx_phy', {'size': 1, 'mapper': HCI_Constant.le_phy_name}),
+ ],
+)
+class HCI_LE_Read_PHY_Command(HCI_Command):
+ '''
+ See Bluetooth spec @ 7.8.47 LE Read PHY Command
+ '''
+
+
+# -----------------------------------------------------------------------------
+@HCI_Command.command(
+ [
+ (
+ 'all_phys',
+ {
+ 'size': 1,
+ 'mapper': lambda x: bit_flags_to_strings(
+ x, HCI_LE_Set_Default_PHY_Command.ANY_PHY_BIT_NAMES
+ ),
+ },
+ ),
+ (
+ 'tx_phys',
+ {
+ 'size': 1,
+ 'mapper': lambda x: bit_flags_to_strings(x, HCI_LE_PHY_BIT_NAMES),
+ },
+ ),
+ (
+ 'rx_phys',
+ {
+ 'size': 1,
+ 'mapper': lambda x: bit_flags_to_strings(x, HCI_LE_PHY_BIT_NAMES),
+ },
+ ),
+ ]
+)
class HCI_LE_Set_Default_PHY_Command(HCI_Command):
'''
See Bluetooth spec @ 7.8.48 LE Set Default PHY Command
'''
+ ANY_TX_PHY_BIT = 0
+ ANY_RX_PHY_BIT = 1
+
+ ANY_PHY_BIT_NAMES = ['Any TX', 'Any RX']
+
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('address_resolution_enable', 1)
-])
-class HCI_LE_Set_Address_Resolution_Enable_Command(HCI_Command):
+@HCI_Command.command(
+ [
+ ('connection_handle', 2),
+ (
+ 'all_phys',
+ {
+ 'size': 1,
+ 'mapper': lambda x: bit_flags_to_strings(
+ x, HCI_LE_Set_PHY_Command.ANY_PHY_BIT_NAMES
+ ),
+ },
+ ),
+ (
+ 'tx_phys',
+ {
+ 'size': 1,
+ 'mapper': lambda x: bit_flags_to_strings(x, HCI_LE_PHY_BIT_NAMES),
+ },
+ ),
+ (
+ 'rx_phys',
+ {
+ 'size': 1,
+ 'mapper': lambda x: bit_flags_to_strings(x, HCI_LE_PHY_BIT_NAMES),
+ },
+ ),
+ ('phy_options', 2),
+ ]
+)
+class HCI_LE_Set_PHY_Command(HCI_Command):
'''
- See Bluetooth spec @ 7.8.44 LE Set Address Resolution Enable Command
+ See Bluetooth spec @ 7.8.49 LE Set PHY Command
'''
+ ANY_TX_PHY_BIT = 0
+ ANY_RX_PHY_BIT = 1
+
+ ANY_PHY_BIT_NAMES = ['Any TX', 'Any RX']
+
# -----------------------------------------------------------------------------
-@HCI_Command.command([
- ('rpa_timeout', 2)
-])
-class HCI_LE_Set_Resolvable_Private_Address_Timeout_Command(HCI_Command):
+@HCI_Command.command(
+ [
+ ('advertising_handle', 1),
+ (
+ 'random_address',
+ lambda data, offset: Address.parse_address_with_type(
+ data, offset, Address.RANDOM_DEVICE_ADDRESS
+ ),
+ ),
+ ]
+)
+class HCI_LE_Set_Advertising_Set_Random_Address_Command(HCI_Command):
'''
- See Bluetooth spec @ 7.8.45 LE Set Resolvable Private Address Timeout Command
+ See Bluetooth spec @ 7.8.52 LE Set Advertising Set Random Address Command
+ '''
+
+
+# -----------------------------------------------------------------------------
+@HCI_Command.command(
+ # pylint: disable=line-too-long,unnecessary-lambda
+ fields=[
+ ('advertising_handle', 1),
+ (
+ 'advertising_event_properties',
+ {
+ 'size': 2,
+ 'mapper': lambda x: HCI_LE_Set_Extended_Advertising_Parameters_Command.advertising_properties_string(
+ x
+ ),
+ },
+ ),
+ ('primary_advertising_interval_min', 3),
+ ('primary_advertising_interval_max', 3),
+ (
+ 'primary_advertising_channel_map',
+ {
+ 'size': 1,
+ 'mapper': lambda x: HCI_LE_Set_Extended_Advertising_Parameters_Command.channel_map_string(
+ x
+ ),
+ },
+ ),
+ ('own_address_type', OwnAddressType.TYPE_SPEC),
+ ('peer_address_type', Address.ADDRESS_TYPE_SPEC),
+ ('peer_address', Address.parse_address_preceded_by_type),
+ ('advertising_filter_policy', 1),
+ ('advertising_tx_power', 1),
+ ('primary_advertising_phy', {'size': 1, 'mapper': HCI_Constant.le_phy_name}),
+ ('secondary_advertising_max_skip', 1),
+ ('secondary_advertising_phy', {'size': 1, 'mapper': HCI_Constant.le_phy_name}),
+ ('advertising_sid', 1),
+ ('scan_request_notification_enable', 1),
+ ],
+ return_parameters_fields=[('status', STATUS_SPEC), ('selected_tx__power', 1)],
+)
+class HCI_LE_Set_Extended_Advertising_Parameters_Command(HCI_Command):
+ '''
+ See Bluetooth spec @ 7.8.53 LE Set Extended Advertising Parameters Command
+ '''
+
+ CONNECTABLE_ADVERTISING = 0
+ SCANNABLE_ADVERTISING = 1
+ DIRECTED_ADVERTISING = 2
+ HIGH_DUTY_CYCLE_DIRECTED_CONNECTABLE_ADVERTISING = 3
+ USE_LEGACY_ADVERTISING_PDUS = 4
+ ANONYMOUS_ADVERTISING = 5
+ INCLUDE_TX_POWER = 6
+
+ ADVERTISING_PROPERTIES_NAMES = (
+ 'CONNECTABLE_ADVERTISING',
+ 'SCANNABLE_ADVERTISING',
+ 'DIRECTED_ADVERTISING',
+ 'HIGH_DUTY_CYCLE_DIRECTED_CONNECTABLE_ADVERTISING',
+ 'USE_LEGACY_ADVERTISING_PDUS',
+ 'ANONYMOUS_ADVERTISING',
+ 'INCLUDE_TX_POWER',
+ )
+
+ CHANNEL_37 = 0
+ CHANNEL_38 = 1
+ CHANNEL_39 = 2
+
+ CHANNEL_NAMES = ('37', '38', '39')
+
+ @classmethod
+ def advertising_properties_string(cls, properties):
+ # pylint: disable=line-too-long
+ return f'[{",".join(bit_flags_to_strings(properties, cls.ADVERTISING_PROPERTIES_NAMES))}]'
+
+ @classmethod
+ def channel_map_string(cls, channel_map):
+ return f'[{",".join(bit_flags_to_strings(channel_map, cls.CHANNEL_NAMES))}]'
+
+
+# -----------------------------------------------------------------------------
+@HCI_Command.command(
+ # pylint: disable=line-too-long,unnecessary-lambda
+ [
+ ('advertising_handle', 1),
+ (
+ 'operation',
+ {
+ 'size': 1,
+ 'mapper': lambda x: HCI_LE_Set_Extended_Advertising_Data_Command.operation_name(
+ x
+ ),
+ },
+ ),
+ ('fragment_preference', 1),
+ (
+ 'advertising_data',
+ {
+ 'parser': HCI_Object.parse_length_prefixed_bytes,
+ 'serializer': functools.partial(
+ HCI_Object.serialize_length_prefixed_bytes
+ ),
+ },
+ ),
+ ]
+)
+class HCI_LE_Set_Extended_Advertising_Data_Command(HCI_Command):
+ '''
+ See Bluetooth spec @ 7.8.54 LE Set Extended Advertising Data Command
+ '''
+
+ INTERMEDIATE_FRAGMENT = 0x00
+ FIRST_FRAGMENT = 0x01
+ LAST_FRAGMENT = 0x02
+ COMPLETE_DATA = 0x03
+ UNCHANGED_DATA = 0x04
+
+ OPERATION_NAMES = {
+ INTERMEDIATE_FRAGMENT: 'INTERMEDIATE_FRAGMENT',
+ FIRST_FRAGMENT: 'FIRST_FRAGMENT',
+ LAST_FRAGMENT: 'LAST_FRAGMENT',
+ COMPLETE_DATA: 'COMPLETE_DATA',
+ UNCHANGED_DATA: 'UNCHANGED_DATA',
+ }
+
+ @classmethod
+ def operation_name(cls, operation):
+ return name_or_number(cls.OPERATION_NAMES, operation)
+
+
+# -----------------------------------------------------------------------------
+@HCI_Command.command(
+ # pylint: disable=line-too-long,unnecessary-lambda
+ [
+ ('advertising_handle', 1),
+ (
+ 'operation',
+ {
+ 'size': 1,
+ 'mapper': lambda x: HCI_LE_Set_Extended_Advertising_Data_Command.operation_name(
+ x
+ ),
+ },
+ ),
+ ('fragment_preference', 1),
+ (
+ 'scan_response_data',
+ {
+ 'parser': HCI_Object.parse_length_prefixed_bytes,
+ 'serializer': functools.partial(
+ HCI_Object.serialize_length_prefixed_bytes
+ ),
+ },
+ ),
+ ]
+)
+class HCI_LE_Set_Extended_Scan_Response_Data_Command(HCI_Command):
+ '''
+ See Bluetooth spec @ 7.8.55 LE Set Extended Scan Response Data Command
+ '''
+
+ INTERMEDIATE_FRAGMENT = 0x00
+ FIRST_FRAGMENT = 0x01
+ LAST_FRAGMENT = 0x02
+ COMPLETE_DATA = 0x03
+
+ OPERATION_NAMES = {
+ INTERMEDIATE_FRAGMENT: 'INTERMEDIATE_FRAGMENT',
+ FIRST_FRAGMENT: 'FIRST_FRAGMENT',
+ LAST_FRAGMENT: 'LAST_FRAGMENT',
+ COMPLETE_DATA: 'COMPLETE_DATA',
+ }
+
+ @classmethod
+ def operation_name(cls, operation):
+ return name_or_number(cls.OPERATION_NAMES, operation)
+
+
+# -----------------------------------------------------------------------------
+@HCI_Command.command(fields=None)
+class HCI_LE_Set_Extended_Advertising_Enable_Command(HCI_Command):
+ '''
+ See Bluetooth spec @ 7.8.56 LE Set Extended Advertising Enable Command
+ '''
+
+ @classmethod
+ def from_parameters(cls, parameters):
+ enable = parameters[0]
+ num_sets = parameters[1]
+ advertising_handles = []
+ durations = []
+ max_extended_advertising_events = []
+ offset = 2
+ for _ in range(num_sets):
+ advertising_handles.append(parameters[offset])
+ durations.append(struct.unpack_from('<H', parameters, offset + 1)[0])
+ max_extended_advertising_events.append(parameters[offset + 3])
+ offset += 4
+
+ return cls(
+ enable, advertising_handles, durations, max_extended_advertising_events
+ )
+
+ def __init__(
+ self, enable, advertising_handles, durations, max_extended_advertising_events
+ ):
+ super().__init__(HCI_LE_SET_EXTENDED_ADVERTISING_ENABLE_COMMAND)
+ self.enable = enable
+ self.advertising_handles = advertising_handles
+ self.durations = durations
+ self.max_extended_advertising_events = max_extended_advertising_events
+
+ self.parameters = bytes([enable, len(advertising_handles)]) + b''.join(
+ [
+ struct.pack(
+ '<BHB',
+ advertising_handles[i],
+ durations[i],
+ max_extended_advertising_events[i],
+ )
+ for i in range(len(advertising_handles))
+ ]
+ )
+
+ def __str__(self):
+ fields = [('enable:', self.enable)]
+ for i, advertising_handle in enumerate(self.advertising_handles):
+ fields.append(
+ (f'advertising_handle[{i}]: ', advertising_handle)
+ )
+ fields.append((f'duration[{i}]: ', self.durations[i]))
+ fields.append(
+ (
+ f'max_extended_advertising_events[{i}]:',
+ self.max_extended_advertising_events[i],
+ )
+ )
+
+ return (
+ color(self.name, 'green')
+ + ':\n'
+ + '\n'.join(
+ [color(field[0], 'cyan') + ' ' + str(field[1]) for field in fields]
+ )
+ )
+
+
+# -----------------------------------------------------------------------------
+@HCI_Command.command(
+ return_parameters_fields=[
+ ('status', STATUS_SPEC),
+ ('max_advertising_data_length', 2),
+ ]
+)
+class HCI_LE_Read_Maximum_Advertising_Data_Length_Command(HCI_Command):
+ '''
+ See Bluetooth spec @ 7.8.57 LE Read Maximum Advertising Data Length Command
+ '''
+
+
+# -----------------------------------------------------------------------------
+@HCI_Command.command(
+ return_parameters_fields=[
+ ('status', STATUS_SPEC),
+ ('num_supported_advertising_sets', 1),
+ ]
+)
+class HCI_LE_Read_Number_Of_Supported_Advertising_Sets_Command(HCI_Command):
+ '''
+ See Bluetooth spec @ 7.8.58 LE Read Number of Supported Advertising Sets Command
+ '''
+
+
+# -----------------------------------------------------------------------------
+@HCI_Command.command([('advertising_handle', 1)])
+class HCI_LE_Remove_Advertising_Set_Command(HCI_Command):
+ '''
+ See Bluetooth spec @ 7.8.59 LE Remove Advertising Set Command
+ '''
+
+
+# -----------------------------------------------------------------------------
+@HCI_Command.command()
+class HCI_LE_Clear_Advertising_Sets_Command(HCI_Command):
+ '''
+ See Bluetooth spec @ 7.8.60 LE Clear Advertising Sets Command
+ '''
+
+
+# -----------------------------------------------------------------------------
+@HCI_Command.command([('enable', 1), ('advertising_handle', 1)])
+class HCI_LE_Set_Periodic_Advertising_Enable_Command(HCI_Command):
+ '''
+ See Bluetooth spec @ 7.8.63 LE Set Periodic Advertising Enable Command
+ '''
+
+
+# -----------------------------------------------------------------------------
+@HCI_Command.command(fields=None)
+class HCI_LE_Set_Extended_Scan_Parameters_Command(HCI_Command):
+ '''
+ See Bluetooth spec @ 7.8.64 LE Set Extended Scan Parameters Command
+ '''
+
+ PASSIVE_SCANNING = 0
+ ACTIVE_SCANNING = 1
+
+ BASIC_UNFILTERED_POLICY = 0x00
+ BASIC_FILTERED_POLICY = 0x01
+ EXTENDED_UNFILTERED_POLICY = 0x02
+ EXTENDED_FILTERED_POLICY = 0x03
+
+ @classmethod
+ def from_parameters(cls, parameters):
+ own_address_type = parameters[0]
+ scanning_filter_policy = parameters[1]
+ scanning_phys = parameters[2]
+
+ phy_bits_set = bin(scanning_phys).count('1')
+ scan_types = []
+ scan_intervals = []
+ scan_windows = []
+ for i in range(phy_bits_set):
+ scan_types.append(parameters[3 + (5 * i)])
+ scan_intervals.append(
+ struct.unpack_from('<H', parameters, 3 + (5 * i) + 1)[0]
+ )
+ scan_windows.append(
+ struct.unpack_from('<H', parameters, 3 + (5 * i) + 3)[0]
+ )
+
+ return cls(
+ own_address_type=own_address_type,
+ scanning_filter_policy=scanning_filter_policy,
+ scanning_phys=scanning_phys,
+ scan_types=scan_types,
+ scan_intervals=scan_intervals,
+ scan_windows=scan_windows,
+ )
+
+ def __init__(
+ self,
+ own_address_type,
+ scanning_filter_policy,
+ scanning_phys,
+ scan_types,
+ scan_intervals,
+ scan_windows,
+ ):
+ super().__init__(HCI_LE_SET_EXTENDED_SCAN_PARAMETERS_COMMAND)
+ self.own_address_type = own_address_type
+ self.scanning_filter_policy = scanning_filter_policy
+ self.scanning_phys = scanning_phys
+ self.scan_types = scan_types
+ self.scan_intervals = scan_intervals
+ self.scan_windows = scan_windows
+
+ self.parameters = bytes(
+ [own_address_type, scanning_filter_policy, scanning_phys]
+ )
+ phy_bits_set = bin(scanning_phys).count('1')
+ for i in range(phy_bits_set):
+ self.parameters += struct.pack(
+ '<BHH', scan_types[i], scan_intervals[i], scan_windows[i]
+ )
+
+ def __str__(self):
+ scanning_phys_strs = bit_flags_to_strings(
+ self.scanning_phys, HCI_LE_PHY_BIT_NAMES
+ )
+ fields = [
+ (
+ 'own_address_type: ',
+ Address.address_type_name(self.own_address_type),
+ ),
+ ('scanning_filter_policy:', self.scanning_filter_policy),
+ ('scanning_phys: ', ','.join(scanning_phys_strs)),
+ ]
+ for (i, scanning_phy_str) in enumerate(scanning_phys_strs):
+ fields.append(
+ (
+ f'{scanning_phy_str}.scan_type: ',
+ 'PASSIVE'
+ if self.scan_types[i] == self.PASSIVE_SCANNING
+ else 'ACTIVE',
+ )
+ )
+ fields.append(
+ (f'{scanning_phy_str}.scan_interval:', self.scan_intervals[i])
+ )
+ fields.append((f'{scanning_phy_str}.scan_window: ', self.scan_windows[i]))
+
+ return (
+ color(self.name, 'green')
+ + ':\n'
+ + '\n'.join(
+ [color(field[0], 'cyan') + ' ' + str(field[1]) for field in fields]
+ )
+ )
+
+
+# -----------------------------------------------------------------------------
+@HCI_Command.command(
+ [('enable', 1), ('filter_duplicates', 1), ('duration', 2), ('period', 2)]
+)
+class HCI_LE_Set_Extended_Scan_Enable_Command(HCI_Command):
+ '''
+ See Bluetooth spec @ 7.8.65 LE Set Extended Scan Enable Command
+ '''
+
+
+# -----------------------------------------------------------------------------
+@HCI_Command.command(fields=None)
+class HCI_LE_Extended_Create_Connection_Command(HCI_Command):
+ '''
+ See Bluetooth spec @ 7.8.66 LE Extended Create Connection Command
+ '''
+
+ @classmethod
+ def from_parameters(cls, parameters):
+ initiator_filter_policy = parameters[0]
+ own_address_type = parameters[1]
+ peer_address_type = parameters[2]
+ peer_address = Address.parse_address_preceded_by_type(parameters, 3)[1]
+ initiating_phys = parameters[9]
+
+ phy_bits_set = bin(initiating_phys).count('1')
+
+ def read_parameter_list(offset):
+ return [
+ struct.unpack_from('<H', parameters, offset + 16 * i)[0]
+ for i in range(phy_bits_set)
+ ]
+
+ return cls(
+ initiator_filter_policy=initiator_filter_policy,
+ own_address_type=own_address_type,
+ peer_address_type=peer_address_type,
+ peer_address=peer_address,
+ initiating_phys=initiating_phys,
+ scan_intervals=read_parameter_list(10),
+ scan_windows=read_parameter_list(12),
+ connection_interval_mins=read_parameter_list(14),
+ connection_interval_maxs=read_parameter_list(16),
+ max_latencies=read_parameter_list(18),
+ supervision_timeouts=read_parameter_list(20),
+ min_ce_lengths=read_parameter_list(22),
+ max_ce_lengths=read_parameter_list(24),
+ )
+
+ def __init__(
+ self,
+ initiator_filter_policy,
+ own_address_type,
+ peer_address_type,
+ peer_address,
+ initiating_phys,
+ scan_intervals,
+ scan_windows,
+ connection_interval_mins,
+ connection_interval_maxs,
+ max_latencies,
+ supervision_timeouts,
+ min_ce_lengths,
+ max_ce_lengths,
+ ):
+ super().__init__(HCI_LE_EXTENDED_CREATE_CONNECTION_COMMAND)
+ self.initiator_filter_policy = initiator_filter_policy
+ self.own_address_type = own_address_type
+ self.peer_address_type = peer_address_type
+ self.peer_address = peer_address
+ self.initiating_phys = initiating_phys
+ self.scan_intervals = scan_intervals
+ self.scan_windows = scan_windows
+ self.connection_interval_mins = connection_interval_mins
+ self.connection_interval_maxs = connection_interval_maxs
+ self.max_latencies = max_latencies
+ self.supervision_timeouts = supervision_timeouts
+ self.min_ce_lengths = min_ce_lengths
+ self.max_ce_lengths = max_ce_lengths
+
+ self.parameters = (
+ bytes([initiator_filter_policy, own_address_type, peer_address_type])
+ + bytes(peer_address)
+ + bytes([initiating_phys])
+ )
+
+ phy_bits_set = bin(initiating_phys).count('1')
+ for i in range(phy_bits_set):
+ self.parameters += struct.pack(
+ '<HHHHHHHH',
+ scan_intervals[i],
+ scan_windows[i],
+ connection_interval_mins[i],
+ connection_interval_maxs[i],
+ max_latencies[i],
+ supervision_timeouts[i],
+ min_ce_lengths[i],
+ max_ce_lengths[i],
+ )
+
+ def __str__(self):
+ initiating_phys_strs = bit_flags_to_strings(
+ self.initiating_phys, HCI_LE_PHY_BIT_NAMES
+ )
+ fields = [
+ ('initiator_filter_policy:', self.initiator_filter_policy),
+ (
+ 'own_address_type: ',
+ OwnAddressType.type_name(self.own_address_type),
+ ),
+ (
+ 'peer_address_type: ',
+ Address.address_type_name(self.peer_address_type),
+ ),
+ ('peer_address: ', str(self.peer_address)),
+ ('initiating_phys: ', ','.join(initiating_phys_strs)),
+ ]
+ for (i, initiating_phys_str) in enumerate(initiating_phys_strs):
+ fields.append(
+ (
+ f'{initiating_phys_str}.scan_interval: ',
+ self.scan_intervals[i],
+ )
+ )
+ fields.append(
+ (
+ f'{initiating_phys_str}.scan_window: ',
+ self.scan_windows[i],
+ )
+ )
+ fields.append(
+ (
+ f'{initiating_phys_str}.connection_interval_min:',
+ self.connection_interval_mins[i],
+ )
+ )
+ fields.append(
+ (
+ f'{initiating_phys_str}.connection_interval_max:',
+ self.connection_interval_maxs[i],
+ )
+ )
+ fields.append(
+ (
+ f'{initiating_phys_str}.max_latency: ',
+ self.max_latencies[i],
+ )
+ )
+ fields.append(
+ (
+ f'{initiating_phys_str}.supervision_timeout: ',
+ self.supervision_timeouts[i],
+ )
+ )
+ fields.append(
+ (
+ f'{initiating_phys_str}.min_ce_length: ',
+ self.min_ce_lengths[i],
+ )
+ )
+ fields.append(
+ (
+ f'{initiating_phys_str}.max_ce_length: ',
+ self.max_ce_lengths[i],
+ )
+ )
+
+ return (
+ color(self.name, 'green')
+ + ':\n'
+ + '\n'.join(
+ [color(field[0], 'cyan') + ' ' + str(field[1]) for field in fields]
+ )
+ )
+
+
+# -----------------------------------------------------------------------------
+@HCI_Command.command(
+ [
+ ('peer_identity_address_type', Address.ADDRESS_TYPE_SPEC),
+ ('peer_identity_address', Address.parse_address_preceded_by_type),
+ (
+ 'privacy_mode',
+ {
+ 'size': 1,
+ # pylint: disable-next=unnecessary-lambda
+ 'mapper': lambda x: HCI_LE_Set_Privacy_Mode_Command.privacy_mode_name(
+ x
+ ),
+ },
+ ),
+ ]
+)
+class HCI_LE_Set_Privacy_Mode_Command(HCI_Command):
+ '''
+ See Bluetooth spec @ 7.8.77 LE Set Privacy Mode Command
+ '''
+
+ NETWORK_PRIVACY_MODE = 0x00
+ DEVICE_PRIVACY_MODE = 0x01
+
+ PRIVACY_MODE_NAMES = {
+ NETWORK_PRIVACY_MODE: 'NETWORK_PRIVACY_MODE',
+ DEVICE_PRIVACY_MODE: 'DEVICE_PRIVACY_MODE',
+ }
+
+ @classmethod
+ def privacy_mode_name(cls, privacy_mode):
+ return name_or_number(cls.PRIVACY_MODE_NAMES, privacy_mode)
+
+
+# -----------------------------------------------------------------------------
+@HCI_Command.command([('bit_number', 1), ('bit_value', 1)])
+class HCI_LE_Set_Host_Feature_Command(HCI_Command):
+ '''
+ See Bluetooth spec @ 7.8.115 LE Set Host Feature Command
'''
@@ -2484,12 +4057,13 @@ class HCI_Event(HCI_Packet):
'''
See Bluetooth spec @ Vol 2, Part E - 5.4.4 HCI Event Packet
'''
- hci_packet_type = HCI_EVENT_PACKET
- event_classes = {}
- meta_event_classes = {}
+
+ hci_packet_type = HCI_EVENT_PACKET
+ event_classes: Dict[int, Type[HCI_Event]] = {}
+ meta_event_classes: Dict[int, Type[HCI_LE_Meta_Event]] = {}
@staticmethod
- def event(fields=[]):
+ def event(fields=()):
'''
Decorator used to declare and register subclasses
'''
@@ -2504,6 +4078,7 @@ class HCI_Event(HCI_Packet):
# Patch the __init__ method to fix the event_code
def init(self, parameters=None, **kwargs):
return HCI_Event.__init__(self, cls.event_code, parameters, **kwargs)
+
cls.__init__ = init
# Register a factory for this class
@@ -2514,27 +4089,28 @@ class HCI_Event(HCI_Packet):
return inner
@staticmethod
- def registered(cls):
- cls.name = cls.__name__.upper()
- cls.event_code = key_with_value(HCI_EVENT_NAMES, cls.name)
- if cls.event_code is None:
+ def registered(event_class):
+ event_class.name = event_class.__name__.upper()
+ event_class.event_code = key_with_value(HCI_EVENT_NAMES, event_class.name)
+ if event_class.event_code is None:
raise KeyError('event not found in HCI_EVENT_NAMES')
# Register a factory for this class
- HCI_Event.event_classes[cls.event_code] = cls
+ HCI_Event.event_classes[event_class.event_code] = event_class
- return cls
+ return event_class
@staticmethod
def from_bytes(packet):
event_code = packet[1]
- length = packet[2]
+ length = packet[2]
parameters = packet[3:]
if len(parameters) != length:
raise ValueError('invalid packet length')
if event_code == HCI_LE_META_EVENT:
- # We do this dispatch here and not in the subclass in order to avoid call loops
+ # We do this dispatch here and not in the subclass in order to avoid call
+ # loops
subevent_code = parameters[0]
cls = HCI_Event.meta_event_classes.get(subevent_code)
if cls is None:
@@ -2575,6 +4151,9 @@ class HCI_Event(HCI_Packet):
parameters = b'' if self.parameters is None else self.parameters
return bytes([HCI_EVENT_PACKET, self.event_code, len(parameters)]) + parameters
+ def __bytes__(self):
+ return self.to_bytes()
+
def __str__(self):
result = color(self.name, 'magenta')
if fields := getattr(self, 'fields', None):
@@ -2592,7 +4171,7 @@ class HCI_LE_Meta_Event(HCI_Event):
'''
@staticmethod
- def event(fields=[]):
+ def event(fields=()):
'''
Decorator used to declare and register subclasses
'''
@@ -2606,7 +4185,10 @@ class HCI_LE_Meta_Event(HCI_Event):
# Patch the __init__ method to fix the subevent_code
def init(self, parameters=None, **kwargs):
- return HCI_LE_Meta_Event.__init__(self, cls.subevent_code, parameters, **kwargs)
+ return HCI_LE_Meta_Event.__init__(
+ self, cls.subevent_code, parameters, **kwargs
+ )
+
cls.__init__ = init
# Register a factory for this class
@@ -2631,7 +4213,9 @@ class HCI_LE_Meta_Event(HCI_Event):
def __init__(self, subevent_code, parameters, **kwargs):
self.subevent_code = subevent_code
if parameters is None and (fields := getattr(self, 'fields', None)) and kwargs:
- parameters = bytes([subevent_code]) + HCI_Object.dict_to_bytes(kwargs, fields)
+ parameters = bytes([subevent_code]) + HCI_Object.dict_to_bytes(
+ kwargs, fields
+ )
super().__init__(HCI_LE_META_EVENT, parameters, **kwargs)
# Override the name in order to adopt the subevent name instead
@@ -2648,17 +4232,22 @@ class HCI_LE_Meta_Event(HCI_Event):
# -----------------------------------------------------------------------------
-@HCI_LE_Meta_Event.event([
- ('status', STATUS_SPEC),
- ('connection_handle', 2),
- ('role', {'size': 1, 'mapper': lambda x: 'CENTRAL' if x == 0 else 'PERIPHERAL'}),
- ('peer_address_type', Address.ADDRESS_TYPE_SPEC),
- ('peer_address', Address.parse_address_preceded_by_type),
- ('conn_interval', 2),
- ('conn_latency', 2),
- ('supervision_timeout', 2),
- ('master_clock_accuracy', 1)
-])
+@HCI_LE_Meta_Event.event(
+ [
+ ('status', STATUS_SPEC),
+ ('connection_handle', 2),
+ (
+ 'role',
+ {'size': 1, 'mapper': lambda x: 'CENTRAL' if x == 0 else 'PERIPHERAL'},
+ ),
+ ('peer_address_type', Address.ADDRESS_TYPE_SPEC),
+ ('peer_address', Address.parse_address_preceded_by_type),
+ ('connection_interval', 2),
+ ('peripheral_latency', 2),
+ ('supervision_timeout', 2),
+ ('central_clock_accuracy', 1),
+ ]
+)
class HCI_LE_Connection_Complete_Event(HCI_LE_Meta_Event):
'''
See Bluetooth spec @ 7.7.65.1 LE Connection Complete Event
@@ -2670,75 +4259,104 @@ class HCI_LE_Advertising_Report_Event(HCI_LE_Meta_Event):
'''
See Bluetooth spec @ 7.7.65.2 LE Advertising Report Event
'''
+
subevent_code = HCI_LE_ADVERTISING_REPORT_EVENT
# Event Types
- ADV_IND = 0x00
- ADV_DIRECT_IND = 0x01
- ADV_SCAN_IND = 0x02
+ ADV_IND = 0x00
+ ADV_DIRECT_IND = 0x01
+ ADV_SCAN_IND = 0x02
ADV_NONCONN_IND = 0x03
- SCAN_RSP = 0x04
+ SCAN_RSP = 0x04
EVENT_TYPE_NAMES = {
- ADV_IND: 'ADV_IND', # Connectable and scannable undirected advertising
- ADV_DIRECT_IND: 'ADV_DIRECT_IND', # Connectable directed advertising
- ADV_SCAN_IND: 'ADV_SCAN_IND', # Scannable undirected advertising
+ ADV_IND: 'ADV_IND', # Connectable and scannable undirected advertising
+ ADV_DIRECT_IND: 'ADV_DIRECT_IND', # Connectable directed advertising
+ ADV_SCAN_IND: 'ADV_SCAN_IND', # Scannable undirected advertising
ADV_NONCONN_IND: 'ADV_NONCONN_IND', # Non connectable undirected advertising
- SCAN_RSP: 'SCAN_RSP' # Scan Response
+ SCAN_RSP: 'SCAN_RSP', # Scan Response
}
- REPORT_FIELDS = [
- ('event_type', 1),
- ('address_type', Address.ADDRESS_TYPE_SPEC),
- ('address', Address.parse_address_preceded_by_type),
- ('data', {'parser': HCI_Object.parse_length_prefixed_bytes, 'serializer': HCI_Object.serialize_length_prefixed_bytes}),
- ('rssi', -1)
- ]
+ class Report(HCI_Object):
+ FIELDS = [
+ ('event_type', 1),
+ ('address_type', Address.ADDRESS_TYPE_SPEC),
+ ('address', Address.parse_address_preceded_by_type),
+ (
+ 'data',
+ {
+ 'parser': HCI_Object.parse_length_prefixed_bytes,
+ 'serializer': HCI_Object.serialize_length_prefixed_bytes,
+ },
+ ),
+ ('rssi', -1),
+ ]
+
+ @classmethod
+ def from_parameters(cls, parameters, offset):
+ return cls.from_bytes(parameters, offset, cls.FIELDS)
+
+ def event_type_string(self):
+ return HCI_LE_Advertising_Report_Event.event_type_name(self.event_type)
+
+ def to_string(self, indentation='', _=None):
+ return super().to_string(
+ indentation,
+ {
+ 'event_type': HCI_LE_Advertising_Report_Event.event_type_name,
+ 'address_type': Address.address_type_name,
+ 'data': lambda x: str(AdvertisingData.from_bytes(x)),
+ },
+ )
@classmethod
def event_type_name(cls, event_type):
return name_or_number(cls.EVENT_TYPE_NAMES, event_type)
- @staticmethod
- def from_parameters(parameters):
+ @classmethod
+ def from_parameters(cls, parameters):
num_reports = parameters[1]
reports = []
offset = 2
for _ in range(num_reports):
- report = HCI_Object.from_bytes(parameters, offset, HCI_LE_Advertising_Report_Event.REPORT_FIELDS)
+ report = cls.Report.from_parameters(parameters, offset)
offset += 10 + len(report.data)
reports.append(report)
- return HCI_LE_Advertising_Report_Event(reports)
+ return cls(reports)
def __init__(self, reports):
self.reports = reports[:]
# Serialize the fields
- parameters = bytes([HCI_LE_ADVERTISING_REPORT_EVENT, len(reports)]) + b''.join([bytes(report) for report in reports])
+ parameters = bytes([HCI_LE_ADVERTISING_REPORT_EVENT, len(reports)]) + b''.join(
+ [bytes(report) for report in reports]
+ )
super().__init__(self.subevent_code, parameters)
def __str__(self):
- reports = '\n'.join([report.to_string(' ', {
- 'event_type': self.event_type_name,
- 'address_type': Address.address_type_name,
- 'data': lambda x: str(AdvertisingData.from_bytes(x))
- }) for report in self.reports])
+ reports = '\n'.join(
+ [f'{i}:\n{report.to_string(" ")}' for i, report in enumerate(self.reports)]
+ )
return f'{color(self.subevent_name(self.subevent_code), "magenta")}:\n{reports}'
-HCI_Event.meta_event_classes[HCI_LE_ADVERTISING_REPORT_EVENT] = HCI_LE_Advertising_Report_Event
+HCI_Event.meta_event_classes[
+ HCI_LE_ADVERTISING_REPORT_EVENT
+] = HCI_LE_Advertising_Report_Event
# -----------------------------------------------------------------------------
-@HCI_LE_Meta_Event.event([
- ('status', STATUS_SPEC),
- ('connection_handle', 2),
- ('conn_interval', 2),
- ('conn_latency', 2),
- ('supervision_timeout', 2)
-])
+@HCI_LE_Meta_Event.event(
+ [
+ ('status', STATUS_SPEC),
+ ('connection_handle', 2),
+ ('connection_interval', 2),
+ ('peripheral_latency', 2),
+ ('supervision_timeout', 2),
+ ]
+)
class HCI_LE_Connection_Update_Complete_Event(HCI_LE_Meta_Event):
'''
See Bluetooth spec @ 7.7.65.3 LE Connection Update Complete Event
@@ -2746,11 +4364,9 @@ class HCI_LE_Connection_Update_Complete_Event(HCI_LE_Meta_Event):
# -----------------------------------------------------------------------------
-@HCI_LE_Meta_Event.event([
- ('status', STATUS_SPEC),
- ('connection_handle', 2),
- ('le_features', 8)
-])
+@HCI_LE_Meta_Event.event(
+ [('status', STATUS_SPEC), ('connection_handle', 2), ('le_features', 8)]
+)
class HCI_LE_Read_Remote_Features_Complete_Event(HCI_LE_Meta_Event):
'''
See Bluetooth spec @ 7.7.65.4 LE Read Remote Features Complete Event
@@ -2758,11 +4374,9 @@ class HCI_LE_Read_Remote_Features_Complete_Event(HCI_LE_Meta_Event):
# -----------------------------------------------------------------------------
-@HCI_LE_Meta_Event.event([
- ('connection_handle', 2),
- ('random_number', 8),
- ('encryption_diversifier', 2)
-])
+@HCI_LE_Meta_Event.event(
+ [('connection_handle', 2), ('random_number', 8), ('encryption_diversifier', 2)]
+)
class HCI_LE_Long_Term_Key_Request_Event(HCI_LE_Meta_Event):
'''
See Bluetooth spec @ 7.7.65.5 LE Long Term Key Request Event
@@ -2770,13 +4384,15 @@ class HCI_LE_Long_Term_Key_Request_Event(HCI_LE_Meta_Event):
# -----------------------------------------------------------------------------
-@HCI_LE_Meta_Event.event([
- ('connection_handle', 2),
- ('interval_min', 2),
- ('interval_max', 2),
- ('latency', 2),
- ('timeout', 2)
-])
+@HCI_LE_Meta_Event.event(
+ [
+ ('connection_handle', 2),
+ ('interval_min', 2),
+ ('interval_max', 2),
+ ('max_latency', 2),
+ ('timeout', 2),
+ ]
+)
class HCI_LE_Remote_Connection_Parameter_Request_Event(HCI_LE_Meta_Event):
'''
See Bluetooth spec @ 7.7.65.6 LE Remote Connection Parameter Request Event
@@ -2784,13 +4400,15 @@ class HCI_LE_Remote_Connection_Parameter_Request_Event(HCI_LE_Meta_Event):
# -----------------------------------------------------------------------------
-@HCI_LE_Meta_Event.event([
- ('connection_handle', 2),
- ('max_tx_octets', 2),
- ('max_tx_time', 2),
- ('max_rx_octets', 2),
- ('max_rx_time', 2),
-])
+@HCI_LE_Meta_Event.event(
+ [
+ ('connection_handle', 2),
+ ('max_tx_octets', 2),
+ ('max_tx_time', 2),
+ ('max_rx_octets', 2),
+ ('max_rx_time', 2),
+ ]
+)
class HCI_LE_Data_Length_Change_Event(HCI_LE_Meta_Event):
'''
See Bluetooth spec @ 7.7.65.7 LE Data Length Change Event
@@ -2798,19 +4416,24 @@ class HCI_LE_Data_Length_Change_Event(HCI_LE_Meta_Event):
# -----------------------------------------------------------------------------
-@HCI_LE_Meta_Event.event([
- ('status', STATUS_SPEC),
- ('connection_handle', 2),
- ('role', {'size': 1, 'mapper': lambda x: 'CENTRAL' if x == 0 else 'PERIPHERAL'}),
- ('peer_address_type', Address.ADDRESS_TYPE_SPEC),
- ('peer_address', Address.parse_address_preceded_by_type),
- ('local_resolvable_private_address', Address.parse_address),
- ('peer_resolvable_private_address', Address.parse_address),
- ('conn_interval', 2),
- ('conn_latency', 2),
- ('supervision_timeout', 2),
- ('master_clock_accuracy', 1)
-])
+@HCI_LE_Meta_Event.event(
+ [
+ ('status', STATUS_SPEC),
+ ('connection_handle', 2),
+ (
+ 'role',
+ {'size': 1, 'mapper': lambda x: 'CENTRAL' if x == 0 else 'PERIPHERAL'},
+ ),
+ ('peer_address_type', Address.ADDRESS_TYPE_SPEC),
+ ('peer_address', Address.parse_address_preceded_by_type),
+ ('local_resolvable_private_address', Address.parse_address),
+ ('peer_resolvable_private_address', Address.parse_address),
+ ('connection_interval', 2),
+ ('peripheral_latency', 2),
+ ('supervision_timeout', 2),
+ ('central_clock_accuracy', 1),
+ ]
+)
class HCI_LE_Enhanced_Connection_Complete_Event(HCI_LE_Meta_Event):
'''
See Bluetooth spec @ 7.7.65.10 LE Enhanced Connection Complete Event
@@ -2818,12 +4441,14 @@ class HCI_LE_Enhanced_Connection_Complete_Event(HCI_LE_Meta_Event):
# -----------------------------------------------------------------------------
-@HCI_LE_Meta_Event.event([
- ('status', STATUS_SPEC),
- ('connection_handle', 2),
- ('tx_phy', {'size': 1, 'mapper': HCI_Constant.le_phy_name}),
- ('rx_phy', {'size': 1, 'mapper': HCI_Constant.le_phy_name})
-])
+@HCI_LE_Meta_Event.event(
+ [
+ ('status', STATUS_SPEC),
+ ('connection_handle', 2),
+ ('tx_phy', {'size': 1, 'mapper': HCI_Constant.le_phy_name}),
+ ('rx_phy', {'size': 1, 'mapper': HCI_Constant.le_phy_name}),
+ ]
+)
class HCI_LE_PHY_Update_Complete_Event(HCI_LE_Meta_Event):
'''
See Bluetooth spec @ 7.7.65.12 LE PHY Update Complete Event
@@ -2831,10 +4456,153 @@ class HCI_LE_PHY_Update_Complete_Event(HCI_LE_Meta_Event):
# -----------------------------------------------------------------------------
-@HCI_LE_Meta_Event.event([
- ('connection_handle', 2),
- ('channel_selection_algorithm', 1)
-])
+class HCI_LE_Extended_Advertising_Report_Event(HCI_LE_Meta_Event):
+ '''
+ See Bluetooth spec @ 7.7.65.13 LE Extended Advertising Report Event
+ '''
+
+ subevent_code = HCI_LE_EXTENDED_ADVERTISING_REPORT_EVENT
+
+ # Event types flags
+ CONNECTABLE_ADVERTISING = 0
+ SCANNABLE_ADVERTISING = 1
+ DIRECTED_ADVERTISING = 2
+ SCAN_RESPONSE = 3
+ LEGACY_ADVERTISING_PDU_USED = 4
+
+ DATA_COMPLETE = 0x00
+ DATA_INCOMPLETE_MORE_TO_COME = 0x01
+ DATA_INCOMPLETE_TRUNCATED_NO_MORE_TO_COME = 0x02
+
+ EVENT_TYPE_FLAG_NAMES = (
+ 'CONNECTABLE_ADVERTISING',
+ 'SCANNABLE_ADVERTISING',
+ 'DIRECTED_ADVERTISING',
+ 'SCAN_RESPONSE',
+ 'LEGACY_ADVERTISING_PDU_USED',
+ )
+
+ LEGACY_PDU_TYPE_MAP = {
+ 0b0011: HCI_LE_Advertising_Report_Event.ADV_IND,
+ 0b0101: HCI_LE_Advertising_Report_Event.ADV_DIRECT_IND,
+ 0b0010: HCI_LE_Advertising_Report_Event.ADV_SCAN_IND,
+ 0b0000: HCI_LE_Advertising_Report_Event.ADV_NONCONN_IND,
+ 0b1011: HCI_LE_Advertising_Report_Event.SCAN_RSP,
+ 0b1010: HCI_LE_Advertising_Report_Event.SCAN_RSP,
+ }
+
+ NO_ADI_FIELD_PROVIDED = 0xFF
+ TX_POWER_INFORMATION_NOT_AVAILABLE = 0x7F
+ RSSI_NOT_AVAILABLE = 0x7F
+ ANONYMOUS_ADDRESS_TYPE = 0xFF
+ UNRESOLVED_RESOLVABLE_ADDRESS_TYPE = 0xFE
+
+ class Report(HCI_Object):
+ FIELDS = [
+ ('event_type', 2),
+ ('address_type', Address.ADDRESS_TYPE_SPEC),
+ ('address', Address.parse_address_preceded_by_type),
+ ('primary_phy', {'size': 1, 'mapper': HCI_Constant.le_phy_name}),
+ ('secondary_phy', {'size': 1, 'mapper': HCI_Constant.le_phy_name}),
+ ('advertising_sid', 1),
+ ('tx_power', 1),
+ ('rssi', -1),
+ ('periodic_advertising_interval', 2),
+ ('direct_address_type', Address.ADDRESS_TYPE_SPEC),
+ ('direct_address', Address.parse_address_preceded_by_type),
+ (
+ 'data',
+ {
+ 'parser': HCI_Object.parse_length_prefixed_bytes,
+ 'serializer': HCI_Object.serialize_length_prefixed_bytes,
+ },
+ ),
+ ]
+
+ @classmethod
+ def from_parameters(cls, parameters, offset):
+ return cls.from_bytes(parameters, offset, cls.FIELDS)
+
+ def event_type_string(self):
+ return HCI_LE_Extended_Advertising_Report_Event.event_type_string(
+ self.event_type
+ )
+
+ def to_string(self, indentation='', _=None):
+ # pylint: disable=line-too-long
+ return super().to_string(
+ indentation,
+ {
+ 'event_type': HCI_LE_Extended_Advertising_Report_Event.event_type_string,
+ 'address_type': Address.address_type_name,
+ 'data': lambda x: str(AdvertisingData.from_bytes(x)),
+ },
+ )
+
+ @staticmethod
+ def event_type_string(event_type):
+ event_type_flags = bit_flags_to_strings(
+ event_type & 0x1F,
+ HCI_LE_Extended_Advertising_Report_Event.EVENT_TYPE_FLAG_NAMES,
+ )
+ event_type_flags.append(
+ ('COMPLETE', 'INCOMPLETE+', 'INCOMPLETE#', '?')[(event_type >> 5) & 3]
+ )
+
+ if event_type & (
+ 1 << HCI_LE_Extended_Advertising_Report_Event.LEGACY_ADVERTISING_PDU_USED
+ ):
+ legacy_pdu_type = (
+ HCI_LE_Extended_Advertising_Report_Event.LEGACY_PDU_TYPE_MAP.get(
+ event_type & 0x0F
+ )
+ )
+ if legacy_pdu_type is not None:
+ # pylint: disable=line-too-long
+ legacy_info_string = f'({HCI_LE_Advertising_Report_Event.event_type_name(legacy_pdu_type)})'
+ else:
+ legacy_info_string = ''
+ else:
+ legacy_info_string = ''
+
+ return f'0x{event_type:04X} [{",".join(event_type_flags)}]{legacy_info_string}'
+
+ @classmethod
+ def from_parameters(cls, parameters):
+ num_reports = parameters[1]
+ reports = []
+ offset = 2
+ for _ in range(num_reports):
+ report = cls.Report.from_parameters(parameters, offset)
+ offset += 24 + len(report.data)
+ reports.append(report)
+
+ return cls(reports)
+
+ def __init__(self, reports):
+ self.reports = reports[:]
+
+ # Serialize the fields
+ parameters = bytes(
+ [HCI_LE_EXTENDED_ADVERTISING_REPORT_EVENT, len(reports)]
+ ) + b''.join([bytes(report) for report in reports])
+
+ super().__init__(self.subevent_code, parameters)
+
+ def __str__(self):
+ reports = '\n'.join(
+ [f'{i}:\n{report.to_string(" ")}' for i, report in enumerate(self.reports)]
+ )
+ return f'{color(self.subevent_name(self.subevent_code), "magenta")}:\n{reports}'
+
+
+HCI_Event.meta_event_classes[
+ HCI_LE_EXTENDED_ADVERTISING_REPORT_EVENT
+] = HCI_LE_Extended_Advertising_Report_Event
+
+
+# -----------------------------------------------------------------------------
+@HCI_LE_Meta_Event.event([('connection_handle', 2), ('channel_selection_algorithm', 1)])
class HCI_LE_Channel_Selection_Algorithm_Event(HCI_LE_Meta_Event):
'''
See Bluetooth spec @ 7.7.65.20 LE Channel Selection Algorithm Event
@@ -2842,9 +4610,7 @@ class HCI_LE_Channel_Selection_Algorithm_Event(HCI_LE_Meta_Event):
# -----------------------------------------------------------------------------
-@HCI_Event.event([
- ('status', STATUS_SPEC)
-])
+@HCI_Event.event([('status', STATUS_SPEC)])
class HCI_Inquiry_Complete_Event(HCI_Event):
'''
See Bluetooth spec @ 7.7.1 Inquiry Complete Event
@@ -2859,12 +4625,12 @@ class HCI_Inquiry_Result_Event(HCI_Event):
'''
RESPONSE_FIELDS = [
- ('bd_addr', Address.parse_address),
+ ('bd_addr', Address.parse_address),
('page_scan_repetition_mode', 1),
- ('reserved', 1),
- ('reserved', 1),
- ('class_of_device', {'size': 3, 'mapper': map_class_of_device}),
- ('clock_offset', 2)
+ ('reserved', 1),
+ ('reserved', 1),
+ ('class_of_device', {'size': 3, 'mapper': map_class_of_device}),
+ ('clock_offset', 2),
]
@staticmethod
@@ -2873,7 +4639,9 @@ class HCI_Inquiry_Result_Event(HCI_Event):
responses = []
offset = 1
for _ in range(num_responses):
- response = HCI_Object.from_bytes(parameters, offset, HCI_Inquiry_Result_Event.RESPONSE_FIELDS)
+ response = HCI_Object.from_bytes(
+ parameters, offset, HCI_Inquiry_Result_Event.RESPONSE_FIELDS
+ )
offset += 14
responses.append(response)
@@ -2883,36 +4651,49 @@ class HCI_Inquiry_Result_Event(HCI_Event):
self.responses = responses[:]
# Serialize the fields
- parameters = bytes([HCI_INQUIRY_RESULT_EVENT, len(responses)]) + b''.join([bytes(response) for response in responses])
+ parameters = bytes([HCI_INQUIRY_RESULT_EVENT, len(responses)]) + b''.join(
+ [bytes(response) for response in responses]
+ )
super().__init__(HCI_INQUIRY_RESULT_EVENT, parameters)
def __str__(self):
- responses = '\n'.join([response.to_string(indentation=' ') for response in self.responses])
+ responses = '\n'.join(
+ [response.to_string(indentation=' ') for response in self.responses]
+ )
return f'{color("HCI_INQUIRY_RESULT_EVENT", "magenta")}:\n{responses}'
# -----------------------------------------------------------------------------
-@HCI_Event.event([
- ('status', STATUS_SPEC),
- ('connection_handle', 2),
- ('bd_addr', Address.parse_address),
- ('link_type', {'size': 1, 'mapper': lambda x: HCI_Connection_Complete_Event.link_type_name(x)}),
- ('encryption_enabled', 1)
-])
+@HCI_Event.event(
+ [
+ ('status', STATUS_SPEC),
+ ('connection_handle', 2),
+ ('bd_addr', Address.parse_address),
+ (
+ 'link_type',
+ {
+ 'size': 1,
+ # pylint: disable-next=unnecessary-lambda
+ 'mapper': lambda x: HCI_Connection_Complete_Event.link_type_name(x),
+ },
+ ),
+ ('encryption_enabled', 1),
+ ]
+)
class HCI_Connection_Complete_Event(HCI_Event):
'''
See Bluetooth spec @ 7.7.3 Connection Complete Event
'''
- SCO_LINK_TYPE = 0x00
- ACL_LINK_TYPE = 0x01
+ SCO_LINK_TYPE = 0x00
+ ACL_LINK_TYPE = 0x01
ESCO_LINK_TYPE = 0x02
LINK_TYPE_NAMES = {
- SCO_LINK_TYPE: 'SCO',
- ACL_LINK_TYPE: 'ACL',
- ESCO_LINK_TYPE: 'eSCO'
+ SCO_LINK_TYPE: 'SCO',
+ ACL_LINK_TYPE: 'ACL',
+ ESCO_LINK_TYPE: 'eSCO',
}
@staticmethod
@@ -2921,11 +4702,20 @@ class HCI_Connection_Complete_Event(HCI_Event):
# -----------------------------------------------------------------------------
-@HCI_Event.event([
- ('bd_addr', Address.parse_address),
- ('class_of_device', 3),
- ('link_type', {'size': 1, 'mapper': lambda x: HCI_Connection_Complete_Event.link_type_name(x)})
-])
+@HCI_Event.event(
+ [
+ ('bd_addr', Address.parse_address),
+ ('class_of_device', 3),
+ (
+ 'link_type',
+ {
+ 'size': 1,
+ # pylint: disable-next=unnecessary-lambda
+ 'mapper': lambda x: HCI_Connection_Complete_Event.link_type_name(x),
+ },
+ ),
+ ]
+)
class HCI_Connection_Request_Event(HCI_Event):
'''
See Bluetooth spec @ 7.7.4 Connection Request Event
@@ -2933,11 +4723,13 @@ class HCI_Connection_Request_Event(HCI_Event):
# -----------------------------------------------------------------------------
-@HCI_Event.event([
- ('status', STATUS_SPEC),
- ('connection_handle', 2),
- ('reason', {'size': 1, 'mapper': HCI_Constant.error_name})
-])
+@HCI_Event.event(
+ [
+ ('status', STATUS_SPEC),
+ ('connection_handle', 2),
+ ('reason', {'size': 1, 'mapper': HCI_Constant.error_name}),
+ ]
+)
class HCI_Disconnection_Complete_Event(HCI_Event):
'''
See Bluetooth spec @ 7.7.5 Disconnection Complete Event
@@ -2945,10 +4737,7 @@ class HCI_Disconnection_Complete_Event(HCI_Event):
# -----------------------------------------------------------------------------
-@HCI_Event.event([
- ('status', STATUS_SPEC),
- ('connection_handle', 2)
-])
+@HCI_Event.event([('status', STATUS_SPEC), ('connection_handle', 2)])
class HCI_Authentication_Complete_Event(HCI_Event):
'''
See Bluetooth spec @ 7.7.6 Authentication Complete Event
@@ -2956,11 +4745,13 @@ class HCI_Authentication_Complete_Event(HCI_Event):
# -----------------------------------------------------------------------------
-@HCI_Event.event([
- ('status', STATUS_SPEC),
- ('bd_addr', Address.parse_address),
- ('remote_name', {'size': 248, 'mapper': map_null_terminated_utf8_string})
-])
+@HCI_Event.event(
+ [
+ ('status', STATUS_SPEC),
+ ('bd_addr', Address.parse_address),
+ ('remote_name', {'size': 248, 'mapper': map_null_terminated_utf8_string}),
+ ]
+)
class HCI_Remote_Name_Request_Complete_Event(HCI_Event):
'''
See Bluetooth spec @ 7.7.7 Remote Name Request Complete Event
@@ -2968,37 +4759,48 @@ class HCI_Remote_Name_Request_Complete_Event(HCI_Event):
# -----------------------------------------------------------------------------
-@HCI_Event.event([
- ('status', STATUS_SPEC),
- ('connection_handle', 2),
- ('encryption_enabled', {'size': 1, 'mapper': lambda x: HCI_Encryption_Change_Event.encryption_enabled_name(x)})
-])
+@HCI_Event.event(
+ [
+ ('status', STATUS_SPEC),
+ ('connection_handle', 2),
+ (
+ 'encryption_enabled',
+ {
+ 'size': 1,
+ # pylint: disable-next=unnecessary-lambda
+ 'mapper': lambda x: HCI_Encryption_Change_Event.encryption_enabled_name(
+ x
+ ),
+ },
+ ),
+ ]
+)
class HCI_Encryption_Change_Event(HCI_Event):
'''
See Bluetooth spec @ 7.7.8 Encryption Change Event
'''
- OFF = 0x00
+ OFF = 0x00
E0_OR_AES_CCM = 0x01
- AES_CCM = 0x02
+ AES_CCM = 0x02
- ENCYRPTION_ENABLED_NAMES = {
- OFF: 'OFF',
+ ENCRYPTION_ENABLED_NAMES = {
+ OFF: 'OFF',
E0_OR_AES_CCM: 'E0_OR_AES_CCM',
- AES_CCM: 'AES_CCM'
+ AES_CCM: 'AES_CCM',
}
@staticmethod
def encryption_enabled_name(encryption_enabled):
- return name_or_number(HCI_Encryption_Change_Event.ENCYRPTION_ENABLED_NAMES, encryption_enabled)
+ return name_or_number(
+ HCI_Encryption_Change_Event.ENCRYPTION_ENABLED_NAMES, encryption_enabled
+ )
# -----------------------------------------------------------------------------
-@HCI_Event.event([
- ('status', STATUS_SPEC),
- ('connection_handle', 2),
- ('lmp_features', 8)
-])
+@HCI_Event.event(
+ [('status', STATUS_SPEC), ('connection_handle', 2), ('lmp_features', 8)]
+)
class HCI_Read_Remote_Supported_Features_Complete_Event(HCI_Event):
'''
See Bluetooth spec @ 7.7.11 Read Remote Supported Features Complete Event
@@ -3006,13 +4808,15 @@ class HCI_Read_Remote_Supported_Features_Complete_Event(HCI_Event):
# -----------------------------------------------------------------------------
-@HCI_Event.event([
- ('status', STATUS_SPEC),
- ('connection_handle', 2),
- ('version', 1),
- ('manufacturer_name', 2),
- ('subversion', 2)
-])
+@HCI_Event.event(
+ [
+ ('status', STATUS_SPEC),
+ ('connection_handle', 2),
+ ('version', 1),
+ ('manufacturer_name', 2),
+ ('subversion', 2),
+ ]
+)
class HCI_Read_Remote_Version_Information_Complete_Event(HCI_Event):
'''
See Bluetooth spec @ 7.7.12 Read Remote Version Information Complete Event
@@ -3020,77 +4824,103 @@ class HCI_Read_Remote_Version_Information_Complete_Event(HCI_Event):
# -----------------------------------------------------------------------------
-@HCI_Event.event([
- ('num_hci_command_packets', 1),
- ('command_opcode', {'size': 2, 'mapper': HCI_Command.command_name}),
- ('return_parameters', '*')
-])
+@HCI_Event.event(
+ [
+ ('num_hci_command_packets', 1),
+ ('command_opcode', {'size': 2, 'mapper': HCI_Command.command_name}),
+ ('return_parameters', '*'),
+ ]
+)
class HCI_Command_Complete_Event(HCI_Event):
'''
See Bluetooth spec @ 7.7.14 Command Complete Event
'''
+ return_parameters = b''
+
def map_return_parameters(self, return_parameters):
- # Map simple 'status' return parameters to their named constant form
- if type(return_parameters) is bytes and len(return_parameters) == 1:
+ '''Map simple 'status' return parameters to their named constant form'''
+
+ if isinstance(return_parameters, bytes) and len(return_parameters) == 1:
# Byte-array form
return HCI_Constant.status_name(return_parameters[0])
- elif type(return_parameters) is int:
+
+ if isinstance(return_parameters, int):
# Already converted to an integer status code
return HCI_Constant.status_name(return_parameters)
- else:
- return return_parameters
+
+ return return_parameters
@staticmethod
def from_parameters(parameters):
self = HCI_Command_Complete_Event.__new__(HCI_Command_Complete_Event)
HCI_Event.__init__(self, self.event_code, parameters)
- HCI_Object.init_from_bytes(self, parameters, 0, HCI_Command_Complete_Event.fields)
+ HCI_Object.init_from_bytes(
+ self, parameters, 0, HCI_Command_Complete_Event.fields
+ )
# Parse the return parameters
- if type(self.return_parameters) is bytes and len(self.return_parameters) == 1:
- # All commands with 1-byte return parameters return a 'status' field, convert it to an integer
+ if (
+ isinstance(self.return_parameters, bytes)
+ and len(self.return_parameters) == 1
+ ):
+ # All commands with 1-byte return parameters return a 'status' field,
+ # convert it to an integer
self.return_parameters = self.return_parameters[0]
else:
cls = HCI_Command.command_classes.get(self.command_opcode)
if cls and cls.return_parameters_fields:
- self.return_parameters = HCI_Object.from_bytes(self.return_parameters, 0, cls.return_parameters_fields)
+ self.return_parameters = HCI_Object.from_bytes(
+ self.return_parameters, 0, cls.return_parameters_fields
+ )
self.return_parameters.fields = cls.return_parameters_fields
return self
def __str__(self):
- return f'{color(self.name, "magenta")}:\n' + HCI_Object.format_fields(self.__dict__, self.fields, ' ', {
- 'return_parameters': self.map_return_parameters
- })
+ return f'{color(self.name, "magenta")}:\n' + HCI_Object.format_fields(
+ self.__dict__,
+ self.fields,
+ ' ',
+ {'return_parameters': self.map_return_parameters},
+ )
# -----------------------------------------------------------------------------
-@HCI_Event.event([
- ('status', {'size': 1, 'mapper': lambda x: HCI_Command_Status_Event.status_name(x)}),
- ('num_hci_command_packets', 1),
- ('command_opcode', {'size': 2, 'mapper': HCI_Command.command_name})
-])
+@HCI_Event.event(
+ [
+ (
+ 'status',
+ # pylint: disable-next=unnecessary-lambda
+ {'size': 1, 'mapper': lambda x: HCI_Command_Status_Event.status_name(x)},
+ ),
+ ('num_hci_command_packets', 1),
+ ('command_opcode', {'size': 2, 'mapper': HCI_Command.command_name}),
+ ]
+)
class HCI_Command_Status_Event(HCI_Event):
'''
See Bluetooth spec @ 7.7.15 Command Complete Event
'''
+
PENDING = 0
@staticmethod
def status_name(status):
if status == HCI_Command_Status_Event.PENDING:
return 'PENDING'
- else:
- return HCI_Constant.error_name(status)
+
+ return HCI_Constant.error_name(status)
# -----------------------------------------------------------------------------
-@HCI_Event.event([
- ('status', STATUS_SPEC),
- ('bd_addr', Address.parse_address),
- ('new_role', {'size': 1, 'mapper': HCI_Constant.role_name})
-])
+@HCI_Event.event(
+ [
+ ('status', STATUS_SPEC),
+ ('bd_addr', Address.parse_address),
+ ('new_role', {'size': 1, 'mapper': HCI_Constant.role_name}),
+ ]
+)
class HCI_Role_Change_Event(HCI_Event):
'''
See Bluetooth spec @ 7.7.18 Role Change Event
@@ -3135,34 +4965,47 @@ class HCI_Number_Of_Completed_Packets_Event(HCI_Event):
def __str__(self):
lines = [
color(self.name, 'magenta') + ':',
- color(' number_of_handles: ', 'cyan') + f'{len(self.connection_handles)}'
+ color(' number_of_handles: ', 'cyan')
+ + f'{len(self.connection_handles)}',
]
- for i in range(len(self.connection_handles)):
- lines.append(color(f' connection_handle[{i}]: ', 'cyan') + f'{self.connection_handles[i]}')
- lines.append(color(f' num_completed_packets[{i}]: ', 'cyan') + f'{self.num_completed_packets[i]}')
+ for i, connection_handle in enumerate(self.connection_handles):
+ lines.append(
+ color(f' connection_handle[{i}]: ', 'cyan')
+ + f'{connection_handle}'
+ )
+ lines.append(
+ color(f' num_completed_packets[{i}]: ', 'cyan')
+ + f'{self.num_completed_packets[i]}'
+ )
return '\n'.join(lines)
# -----------------------------------------------------------------------------
-@HCI_Event.event([
- ('status', STATUS_SPEC),
- ('connection_handle', 2),
- ('current_mode', {'size': 1, 'mapper': lambda x: HCI_Mode_Change_Event.mode_name(x)}),
- ('interval', 2)
-])
+@HCI_Event.event(
+ [
+ ('status', STATUS_SPEC),
+ ('connection_handle', 2),
+ (
+ 'current_mode',
+ # pylint: disable-next=unnecessary-lambda
+ {'size': 1, 'mapper': lambda x: HCI_Mode_Change_Event.mode_name(x)},
+ ),
+ ('interval', 2),
+ ]
+)
class HCI_Mode_Change_Event(HCI_Event):
'''
See Bluetooth spec @ 7.7.20 Mode Change Event
'''
ACTIVE_MODE = 0x00
- HOLD_MODE = 0x01
- SNIFF_MODE = 0x02
+ HOLD_MODE = 0x01
+ SNIFF_MODE = 0x02
MODE_NAMES = {
ACTIVE_MODE: 'ACTIVE_MODE',
- HOLD_MODE: 'HOLD_MODE',
- SNIFF_MODE: 'SNIFF_MODE'
+ HOLD_MODE: 'HOLD_MODE',
+ SNIFF_MODE: 'SNIFF_MODE',
}
@staticmethod
@@ -3171,9 +5014,7 @@ class HCI_Mode_Change_Event(HCI_Event):
# -----------------------------------------------------------------------------
-@HCI_Event.event([
- ('bd_addr', Address.parse_address)
-])
+@HCI_Event.event([('bd_addr', Address.parse_address)])
class HCI_PIN_Code_Request_Event(HCI_Event):
'''
See Bluetooth spec @ 7.7.22 PIN Code Request Event
@@ -3181,9 +5022,7 @@ class HCI_PIN_Code_Request_Event(HCI_Event):
# -----------------------------------------------------------------------------
-@HCI_Event.event([
- ('bd_addr', Address.parse_address)
-])
+@HCI_Event.event([('bd_addr', Address.parse_address)])
class HCI_Link_Key_Request_Event(HCI_Event):
'''
See Bluetooth spec @ 7.7.24 7.7.23 Link Key Request Event
@@ -3191,11 +5030,13 @@ class HCI_Link_Key_Request_Event(HCI_Event):
# -----------------------------------------------------------------------------
-@HCI_Event.event([
- ('bd_addr', Address.parse_address),
- ('link_key', 16),
- ('key_type', {'size': 1, 'mapper': HCI_Constant.link_key_type_name})
-])
+@HCI_Event.event(
+ [
+ ('bd_addr', Address.parse_address),
+ ('link_key', 16),
+ ('key_type', {'size': 1, 'mapper': HCI_Constant.link_key_type_name}),
+ ]
+)
class HCI_Link_Key_Notification_Event(HCI_Event):
'''
See Bluetooth spec @ 7.7.24 Link Key Notification Event
@@ -3203,10 +5044,7 @@ class HCI_Link_Key_Notification_Event(HCI_Event):
# -----------------------------------------------------------------------------
-@HCI_Event.event([
- ('connection_handle', 2),
- ('lmp_max_slots', 1)
-])
+@HCI_Event.event([('connection_handle', 2), ('lmp_max_slots', 1)])
class HCI_Max_Slots_Change_Event(HCI_Event):
'''
See Bluetooth spec @ 7.7.27 Max Slots Change Event
@@ -3214,11 +5052,9 @@ class HCI_Max_Slots_Change_Event(HCI_Event):
# -----------------------------------------------------------------------------
-@HCI_Event.event([
- ('status', STATUS_SPEC),
- ('connection_handle', 2),
- ('clock_offset', 2)
-])
+@HCI_Event.event(
+ [('status', STATUS_SPEC), ('connection_handle', 2), ('clock_offset', 2)]
+)
class HCI_Read_Clock_Offset_Complete_Event(HCI_Event):
'''
See Bluetooth spec @ 7.7.28 Read Clock Offset Complete Event
@@ -3226,11 +5062,9 @@ class HCI_Read_Clock_Offset_Complete_Event(HCI_Event):
# -----------------------------------------------------------------------------
-@HCI_Event.event([
- ('status', STATUS_SPEC),
- ('connection_handle', 2),
- ('packet_type', 2)
-])
+@HCI_Event.event(
+ [('status', STATUS_SPEC), ('connection_handle', 2), ('packet_type', 2)]
+)
class HCI_Connection_Packet_Type_Changed_Event(HCI_Event):
'''
See Bluetooth spec @ 7.7.29 Connection Packet Type Changed Event
@@ -3238,10 +5072,7 @@ class HCI_Connection_Packet_Type_Changed_Event(HCI_Event):
# -----------------------------------------------------------------------------
-@HCI_Event.event([
- ('bd_addr', Address.parse_address),
- ('page_scan_repetition_mode', 1)
-])
+@HCI_Event.event([('bd_addr', Address.parse_address), ('page_scan_repetition_mode', 1)])
class HCI_Page_Scan_Repetition_Mode_Change_Event(HCI_Event):
'''
See Bluetooth spec @ 7.7.31 Page Scan Repetition Mode Change Event
@@ -3250,18 +5081,18 @@ class HCI_Page_Scan_Repetition_Mode_Change_Event(HCI_Event):
# -----------------------------------------------------------------------------
@HCI_Event.registered
-class HCI_Inquiry_Result_With_Rssi_Event(HCI_Event):
+class HCI_Inquiry_Result_With_RSSI_Event(HCI_Event):
'''
See Bluetooth spec @ 7.7.33 Inquiry Result with RSSI Event
'''
RESPONSE_FIELDS = [
- ('bd_addr', Address.parse_address),
+ ('bd_addr', Address.parse_address),
('page_scan_repetition_mode', 1),
- ('reserved', 1),
- ('class_of_device', {'size': 3, 'mapper': map_class_of_device}),
- ('clock_offset', 2),
- ('rssi', -1)
+ ('reserved', 1),
+ ('class_of_device', {'size': 3, 'mapper': map_class_of_device}),
+ ('clock_offset', 2),
+ ('rssi', -1),
]
@staticmethod
@@ -3270,33 +5101,41 @@ class HCI_Inquiry_Result_With_Rssi_Event(HCI_Event):
responses = []
offset = 1
for _ in range(num_responses):
- response = HCI_Object.from_bytes(parameters, offset, HCI_Inquiry_Result_With_Rssi_Event.RESPONSE_FIELDS)
+ response = HCI_Object.from_bytes(
+ parameters, offset, HCI_Inquiry_Result_With_RSSI_Event.RESPONSE_FIELDS
+ )
offset += 14
responses.append(response)
- return HCI_Inquiry_Result_With_Rssi_Event(responses)
+ return HCI_Inquiry_Result_With_RSSI_Event(responses)
def __init__(self, responses):
self.responses = responses[:]
# Serialize the fields
- parameters = bytes([HCI_INQUIRY_RESULT_WITH_RSSI_EVENT, len(responses)]) + b''.join([bytes(response) for response in responses])
+ parameters = bytes(
+ [HCI_INQUIRY_RESULT_WITH_RSSI_EVENT, len(responses)]
+ ) + b''.join([bytes(response) for response in responses])
super().__init__(HCI_INQUIRY_RESULT_WITH_RSSI_EVENT, parameters)
def __str__(self):
- responses = '\n'.join([response.to_string(indentation=' ') for response in self.responses])
+ responses = '\n'.join(
+ [response.to_string(indentation=' ') for response in self.responses]
+ )
return f'{color("HCI_INQUIRY_RESULT_WITH_RSSI_EVENT", "magenta")}:\n{responses}'
# -----------------------------------------------------------------------------
-@HCI_Event.event([
- ('status', STATUS_SPEC),
- ('connection_handle', 2),
- ('page_number', 1),
- ('maximum_page_number', 1),
- ('extended_lmp_features', 8)
-])
+@HCI_Event.event(
+ [
+ ('status', STATUS_SPEC),
+ ('connection_handle', 2),
+ ('page_number', 1),
+ ('maximum_page_number', 1),
+ ('extended_lmp_features', 8),
+ ]
+)
class HCI_Read_Remote_Extended_Features_Complete_Event(HCI_Event):
'''
See Bluetooth spec @ 7.7.34 Read Remote Extended Features Complete Event
@@ -3304,17 +5143,38 @@ class HCI_Read_Remote_Extended_Features_Complete_Event(HCI_Event):
# -----------------------------------------------------------------------------
-@HCI_Event.event([
- ('status', STATUS_SPEC),
- ('connection_handle', 2),
- ('bd_addr', Address.parse_address),
- ('link_type', {'size': 1, 'mapper': lambda x: HCI_Synchronous_Connection_Complete_Event.link_type_name(x)}),
- ('transmission_interval', 1),
- ('retransmission_window', 1),
- ('rx_packet_length', 2),
- ('tx_packet_length', 2),
- ('air_mode', {'size': 1, 'mapper': lambda x: HCI_Synchronous_Connection_Complete_Event.air_mode_name(x)}),
-])
+@HCI_Event.event(
+ # pylint: disable=line-too-long
+ [
+ ('status', STATUS_SPEC),
+ ('connection_handle', 2),
+ ('bd_addr', Address.parse_address),
+ (
+ 'link_type',
+ {
+ 'size': 1,
+ # pylint: disable-next=unnecessary-lambda
+ 'mapper': lambda x: HCI_Synchronous_Connection_Complete_Event.link_type_name(
+ x
+ ),
+ },
+ ),
+ ('transmission_interval', 1),
+ ('retransmission_window', 1),
+ ('rx_packet_length', 2),
+ ('tx_packet_length', 2),
+ (
+ 'air_mode',
+ {
+ 'size': 1,
+ # pylint: disable-next=unnecessary-lambda
+ 'mapper': lambda x: HCI_Synchronous_Connection_Complete_Event.air_mode_name(
+ x
+ ),
+ },
+ ),
+ ]
+)
class HCI_Synchronous_Connection_Complete_Event(HCI_Event):
'''
See Bluetooth spec @ 7.7.35 Synchronous Connection Complete Event
@@ -3324,40 +5184,46 @@ class HCI_Synchronous_Connection_Complete_Event(HCI_Event):
ESCO_CONNECTION_LINK_TYPE = 0x02
LINK_TYPE_NAMES = {
- SCO_CONNECTION_LINK_TYPE: 'SCO',
- ESCO_CONNECTION_LINK_TYPE: 'eSCO'
+ SCO_CONNECTION_LINK_TYPE: 'SCO',
+ ESCO_CONNECTION_LINK_TYPE: 'eSCO',
}
- U_LAW_LOG_AIR_MODE = 0x00
- A_LAW_LOG_AIR_MORE = 0x01
- CVSD_AIR_MODE = 0x02
+ U_LAW_LOG_AIR_MODE = 0x00
+ A_LAW_LOG_AIR_MORE = 0x01
+ CVSD_AIR_MODE = 0x02
TRANSPARENT_DATA_AIR_MODE = 0x03
AIR_MODE_NAMES = {
- U_LAW_LOG_AIR_MODE: 'u-law log',
- A_LAW_LOG_AIR_MORE: 'A-law log',
- CVSD_AIR_MODE: 'CVSD',
- TRANSPARENT_DATA_AIR_MODE: 'Transparend Data'
+ U_LAW_LOG_AIR_MODE: 'u-law log',
+ A_LAW_LOG_AIR_MORE: 'A-law log',
+ CVSD_AIR_MODE: 'CVSD',
+ TRANSPARENT_DATA_AIR_MODE: 'Transparent Data',
}
@staticmethod
def link_type_name(link_type):
- return name_or_number(HCI_Synchronous_Connection_Complete_Event.LINK_TYPE_NAMES, link_type)
+ return name_or_number(
+ HCI_Synchronous_Connection_Complete_Event.LINK_TYPE_NAMES, link_type
+ )
@staticmethod
def air_mode_name(air_mode):
- return name_or_number(HCI_Synchronous_Connection_Complete_Event.AIR_MODE_NAMES, air_mode)
+ return name_or_number(
+ HCI_Synchronous_Connection_Complete_Event.AIR_MODE_NAMES, air_mode
+ )
# -----------------------------------------------------------------------------
-@HCI_Event.event([
- ('status', STATUS_SPEC),
- ('connection_handle', 2),
- ('transmission_interval', 1),
- ('retransmission_window', 1),
- ('rx_packet_length', 2),
- ('tx_packet_length', 2)
-])
+@HCI_Event.event(
+ [
+ ('status', STATUS_SPEC),
+ ('connection_handle', 2),
+ ('transmission_interval', 1),
+ ('retransmission_window', 1),
+ ('rx_packet_length', 2),
+ ('tx_packet_length', 2),
+ ]
+)
class HCI_Synchronous_Connection_Changed_Event(HCI_Event):
'''
See Bluetooth spec @ 7.7.36 Synchronous Connection Changed Event
@@ -3365,16 +5231,18 @@ class HCI_Synchronous_Connection_Changed_Event(HCI_Event):
# -----------------------------------------------------------------------------
-@HCI_Event.event([
- ('num_responses', 1),
- ('bd_addr', Address.parse_address),
- ('page_scan_repetition_mode', 1),
- ('reserved', 1),
- ('class_of_device', {'size': 3, 'mapper': map_class_of_device}),
- ('clock_offset', 2),
- ('rssi', -1),
- ('extended_inquiry_response', 240),
-])
+@HCI_Event.event(
+ [
+ ('num_responses', 1),
+ ('bd_addr', Address.parse_address),
+ ('page_scan_repetition_mode', 1),
+ ('reserved', 1),
+ ('class_of_device', {'size': 3, 'mapper': map_class_of_device}),
+ ('clock_offset', 2),
+ ('rssi', -1),
+ ('extended_inquiry_response', 240),
+ ]
+)
class HCI_Extended_Inquiry_Result_Event(HCI_Event):
'''
See Bluetooth spec @ 7.7.38 Extended Inquiry Result Event
@@ -3382,10 +5250,7 @@ class HCI_Extended_Inquiry_Result_Event(HCI_Event):
# -----------------------------------------------------------------------------
-@HCI_Event.event([
- ('status', STATUS_SPEC),
- ('connection_handle', 2)
-])
+@HCI_Event.event([('status', STATUS_SPEC), ('connection_handle', 2)])
class HCI_Encryption_Key_Refresh_Complete_Event(HCI_Event):
'''
See Bluetooth spec @ 7.7.39 Encryption Key Refresh Complete Event
@@ -3393,9 +5258,7 @@ class HCI_Encryption_Key_Refresh_Complete_Event(HCI_Event):
# -----------------------------------------------------------------------------
-@HCI_Event.event([
- ('bd_addr', Address.parse_address)
-])
+@HCI_Event.event([('bd_addr', Address.parse_address)])
class HCI_IO_Capability_Request_Event(HCI_Event):
'''
See Bluetooth spec @ 7.7.40 IO Capability Request Event
@@ -3403,12 +5266,17 @@ class HCI_IO_Capability_Request_Event(HCI_Event):
# -----------------------------------------------------------------------------
-@HCI_Event.event([
- ('bd_addr', Address.parse_address),
- ('io_capability', {'size': 1, 'mapper': HCI_Constant.io_capability_name}),
- ('oob_data_present', 1),
- ('authentication_requirements', {'size': 1, 'mapper': HCI_Constant.authentication_requirements_name})
-])
+@HCI_Event.event(
+ [
+ ('bd_addr', Address.parse_address),
+ ('io_capability', {'size': 1, 'mapper': HCI_Constant.io_capability_name}),
+ ('oob_data_present', 1),
+ (
+ 'authentication_requirements',
+ {'size': 1, 'mapper': HCI_Constant.authentication_requirements_name},
+ ),
+ ]
+)
class HCI_IO_Capability_Response_Event(HCI_Event):
'''
See Bluetooth spec @ 7.7.41 IO Capability Response Event
@@ -3416,10 +5284,7 @@ class HCI_IO_Capability_Response_Event(HCI_Event):
# -----------------------------------------------------------------------------
-@HCI_Event.event([
- ('bd_addr', Address.parse_address),
- ('numeric_value', 4)
-])
+@HCI_Event.event([('bd_addr', Address.parse_address), ('numeric_value', 4)])
class HCI_User_Confirmation_Request_Event(HCI_Event):
'''
See Bluetooth spec @ 7.7.42 User Confirmation Request Event
@@ -3427,9 +5292,7 @@ class HCI_User_Confirmation_Request_Event(HCI_Event):
# -----------------------------------------------------------------------------
-@HCI_Event.event([
- ('bd_addr', Address.parse_address)
-])
+@HCI_Event.event([('bd_addr', Address.parse_address)])
class HCI_User_Passkey_Request_Event(HCI_Event):
'''
See Bluetooth spec @ 7.7.43 User Passkey Request Event
@@ -3437,10 +5300,7 @@ class HCI_User_Passkey_Request_Event(HCI_Event):
# -----------------------------------------------------------------------------
-@HCI_Event.event([
- ('status', STATUS_SPEC),
- ('bd_addr', Address.parse_address)
-])
+@HCI_Event.event([('status', STATUS_SPEC), ('bd_addr', Address.parse_address)])
class HCI_Simple_Pairing_Complete_Event(HCI_Event):
'''
See Bluetooth spec @ 7.7.45 Simple Pairing Complete Event
@@ -3448,10 +5308,7 @@ class HCI_Simple_Pairing_Complete_Event(HCI_Event):
# -----------------------------------------------------------------------------
-@HCI_Event.event([
- ('connection_handle', 2),
- ('link_supervision_timeout', 2)
-])
+@HCI_Event.event([('connection_handle', 2), ('link_supervision_timeout', 2)])
class HCI_Link_Supervision_Timeout_Changed_Event(HCI_Event):
'''
See Bluetooth spec @ 7.7.46 Link Supervision Timeout Changed Event
@@ -3459,10 +5316,15 @@ class HCI_Link_Supervision_Timeout_Changed_Event(HCI_Event):
# -----------------------------------------------------------------------------
-@HCI_Event.event([
- ('bd_addr', Address.parse_address),
- ('host_supported_features', 8)
-])
+@HCI_Event.event([('bd_addr', Address.parse_address), ('passkey', 4)])
+class HCI_User_Passkey_Notification_Event(HCI_Event):
+ '''
+ See Bluetooth spec @ 7.7.48 User Passkey Notification Event
+ '''
+
+
+# -----------------------------------------------------------------------------
+@HCI_Event.event([('bd_addr', Address.parse_address), ('host_supported_features', 8)])
class HCI_Remote_Host_Supported_Features_Notification_Event(HCI_Event):
'''
See Bluetooth spec @ 7.7.50 Remote Host Supported Features Notification Event
@@ -3470,10 +5332,11 @@ class HCI_Remote_Host_Supported_Features_Notification_Event(HCI_Event):
# -----------------------------------------------------------------------------
-class HCI_AclDataPacket(HCI_Packet):
+class HCI_AclDataPacket:
'''
See Bluetooth spec @ 5.4.2 HCI ACL Data Packets
'''
+
hci_packet_type = HCI_ACL_DATA_PACKET
@staticmethod
@@ -3486,11 +5349,16 @@ class HCI_AclDataPacket(HCI_Packet):
data = packet[5:]
if len(data) != data_total_length:
raise ValueError('invalid packet length')
- return HCI_AclDataPacket(connection_handle, pb_flag, bc_flag, data_total_length, data)
+ return HCI_AclDataPacket(
+ connection_handle, pb_flag, bc_flag, data_total_length, data
+ )
def to_bytes(self):
h = (self.pb_flag << 12) | (self.bc_flag << 14) | self.connection_handle
- return struct.pack('<BHH', HCI_ACL_DATA_PACKET, h, self.data_total_length) + self.data
+ return (
+ struct.pack('<BHH', HCI_ACL_DATA_PACKET, h, self.data_total_length)
+ + self.data
+ )
def __init__(self, connection_handle, pb_flag, bc_flag, data_total_length, data):
self.connection_handle = connection_handle
@@ -3503,20 +5371,29 @@ class HCI_AclDataPacket(HCI_Packet):
return self.to_bytes()
def __str__(self):
- return f'{color("ACL", "blue")}: handle=0x{self.connection_handle:04x}, pb={self.pb_flag}, bc={self.bc_flag}, data_total_length={self.data_total_length}, data={self.data.hex()}'
+ return (
+ f'{color("ACL", "blue")}: '
+ f'handle=0x{self.connection_handle:04x}'
+ f'pb={self.pb_flag}, bc={self.bc_flag}, '
+ f'data_total_length={self.data_total_length}, '
+ f'data={self.data.hex()}'
+ )
# -----------------------------------------------------------------------------
class HCI_AclDataPacketAssembler:
def __init__(self, callback):
- self.callback = callback
- self.current_data = None
+ self.callback = callback
+ self.current_data = None
self.l2cap_pdu_length = 0
def feed_packet(self, packet):
- if packet.pb_flag == HCI_ACL_PB_FIRST_NON_FLUSHABLE or packet.pb_flag == HCI_ACL_PB_FIRST_FLUSHABLE:
- (l2cap_pdu_length,) = struct.unpack_from('<H', packet.data, 0)
- self.current_data = packet.data
+ if packet.pb_flag in (
+ HCI_ACL_PB_FIRST_NON_FLUSHABLE,
+ HCI_ACL_PB_FIRST_FLUSHABLE,
+ ):
+ (l2cap_pdu_length,) = struct.unpack_from('<H', packet.data, 0)
+ self.current_data = packet.data
self.l2cap_pdu_length = l2cap_pdu_length
elif packet.pb_flag == HCI_ACL_PB_CONTINUATION:
if self.current_data is None:
@@ -3530,11 +5407,11 @@ class HCI_AclDataPacketAssembler:
self.callback(self.current_data)
# Reset
- self.current_data = None
+ self.current_data = None
self.l2cap_pdu_length = 0
else:
# Sanity check
if len(self.current_data) > self.l2cap_pdu_length + 4:
logger.warning('!!! ACL data exceeds L2CAP PDU')
- self.current_data = None
+ self.current_data = None
self.l2cap_pdu_length = 0
diff --git a/bumble/helpers.py b/bumble/helpers.py
index 09b86ef..83c7c6d 100644
--- a/bumble/helpers.py
+++ b/bumble/helpers.py
@@ -16,10 +16,11 @@
# Imports
# -----------------------------------------------------------------------------
import logging
-from colors import color
+from .colors import color
+from .att import ATT_CID, ATT_PDU
+from .smp import SMP_CID, SMP_Command
from .core import name_or_number
-from .gatt import ATT_PDU, ATT_CID
from .l2cap import (
L2CAP_PDU,
L2CAP_CONNECTION_REQUEST,
@@ -27,20 +28,17 @@ from .l2cap import (
L2CAP_SIGNALING_CID,
L2CAP_LE_SIGNALING_CID,
L2CAP_Control_Frame,
- L2CAP_Connection_Response
+ L2CAP_Connection_Response,
)
from .hci import (
HCI_EVENT_PACKET,
HCI_ACL_DATA_PACKET,
HCI_DISCONNECTION_COMPLETE_EVENT,
- HCI_AclDataPacketAssembler
+ HCI_AclDataPacketAssembler,
)
from .rfcomm import RFCOMM_Frame, RFCOMM_PSM
from .sdp import SDP_PDU, SDP_PSM
-from .avdtp import (
- MessageAssembler as AVDTP_MessageAssembler,
- AVDTP_PSM
-)
+from .avdtp import MessageAssembler as AVDTP_MessageAssembler, AVDTP_PSM
# -----------------------------------------------------------------------------
# Logging
@@ -51,8 +49,8 @@ logger = logging.getLogger(__name__)
# -----------------------------------------------------------------------------
PSM_NAMES = {
RFCOMM_PSM: 'RFCOMM',
- SDP_PSM: 'SDP',
- AVDTP_PSM: 'AVDTP'
+ SDP_PSM: 'SDP',
+ AVDTP_PSM: 'AVDTP'
# TODO: add more PSM values
}
@@ -61,19 +59,23 @@ PSM_NAMES = {
class PacketTracer:
class AclStream:
def __init__(self, analyzer):
- self.analyzer = analyzer
+ self.analyzer = analyzer
self.packet_assembler = HCI_AclDataPacketAssembler(self.on_acl_pdu)
- self.avdtp_assemblers = {} # AVDTP assemblers, by source_cid
- self.psms = {} # PSM, by source_cid
- self.peer = None # ACL stream in the other direction
+ self.avdtp_assemblers = {} # AVDTP assemblers, by source_cid
+ self.psms = {} # PSM, by source_cid
+ self.peer = None # ACL stream in the other direction
+ # pylint: disable=too-many-nested-blocks
def on_acl_pdu(self, pdu):
l2cap_pdu = L2CAP_PDU.from_bytes(pdu)
if l2cap_pdu.cid == ATT_CID:
att_pdu = ATT_PDU.from_bytes(l2cap_pdu.payload)
self.analyzer.emit(att_pdu)
- elif l2cap_pdu.cid == L2CAP_SIGNALING_CID or l2cap_pdu.cid == L2CAP_LE_SIGNALING_CID:
+ elif l2cap_pdu.cid == SMP_CID:
+ smp_command = SMP_Command.from_bytes(l2cap_pdu.payload)
+ self.analyzer.emit(smp_command)
+ elif l2cap_pdu.cid in (L2CAP_SIGNALING_CID, L2CAP_LE_SIGNALING_CID):
control_frame = L2CAP_Control_Frame.from_bytes(l2cap_pdu.payload)
self.analyzer.emit(control_frame)
@@ -81,16 +83,26 @@ class PacketTracer:
if control_frame.code == L2CAP_CONNECTION_REQUEST:
self.psms[control_frame.source_cid] = control_frame.psm
elif control_frame.code == L2CAP_CONNECTION_RESPONSE:
- if control_frame.result == L2CAP_Connection_Response.CONNECTION_SUCCESSFUL:
+ if (
+ control_frame.result
+ == L2CAP_Connection_Response.CONNECTION_SUCCESSFUL
+ ):
if self.peer:
if psm := self.peer.psms.get(control_frame.source_cid):
# Found a pending connection
self.psms[control_frame.destination_cid] = psm
- # For AVDTP connections, create a packet assembler for each direction
+ # For AVDTP connections, create a packet assembler for
+ # each direction
if psm == AVDTP_PSM:
- self.avdtp_assemblers[control_frame.source_cid] = AVDTP_MessageAssembler(self.on_avdtp_message)
- self.peer.avdtp_assemblers[control_frame.destination_cid] = AVDTP_MessageAssembler(self.peer.on_avdtp_message)
+ self.avdtp_assemblers[
+ control_frame.source_cid
+ ] = AVDTP_MessageAssembler(self.on_avdtp_message)
+ self.peer.avdtp_assemblers[
+ control_frame.destination_cid
+ ] = AVDTP_MessageAssembler(
+ self.peer.on_avdtp_message
+ )
else:
# Try to find the PSM associated with this PDU
@@ -102,31 +114,42 @@ class PacketTracer:
rfcomm_frame = RFCOMM_Frame.from_bytes(l2cap_pdu.payload)
self.analyzer.emit(rfcomm_frame)
elif psm == AVDTP_PSM:
- self.analyzer.emit(f'{color("L2CAP", "green")} [CID={l2cap_pdu.cid}, PSM=AVDTP]: {l2cap_pdu.payload.hex()}')
+ self.analyzer.emit(
+ f'{color("L2CAP", "green")} [CID={l2cap_pdu.cid}, '
+ f'PSM=AVDTP]: {l2cap_pdu.payload.hex()}'
+ )
assembler = self.avdtp_assemblers.get(l2cap_pdu.cid)
if assembler:
assembler.on_pdu(l2cap_pdu.payload)
else:
psm_string = name_or_number(PSM_NAMES, psm)
- self.analyzer.emit(f'{color("L2CAP", "green")} [CID={l2cap_pdu.cid}, PSM={psm_string}]: {l2cap_pdu.payload.hex()}')
+ self.analyzer.emit(
+ f'{color("L2CAP", "green")} [CID={l2cap_pdu.cid}, '
+ f'PSM={psm_string}]: {l2cap_pdu.payload.hex()}'
+ )
else:
self.analyzer.emit(l2cap_pdu)
def on_avdtp_message(self, transaction_label, message):
- self.analyzer.emit(f'{color("AVDTP", "green")} [{transaction_label}] {message}')
+ self.analyzer.emit(
+ f'{color("AVDTP", "green")} [{transaction_label}] {message}'
+ )
def feed_packet(self, packet):
self.packet_assembler.feed_packet(packet)
class Analyzer:
def __init__(self, label, emit_message):
- self.label = label
+ self.label = label
self.emit_message = emit_message
- self.acl_streams = {} # ACL streams, by connection handle
- self.peer = None # Analyzer in the other direction
+ self.acl_streams = {} # ACL streams, by connection handle
+ self.peer = None # Analyzer in the other direction
def start_acl_stream(self, connection_handle):
- logger.info(f'[{self.label}] +++ Creating ACL stream for connection 0x{connection_handle:04X}')
+ logger.info(
+ f'[{self.label}] +++ Creating ACL stream for connection '
+ f'0x{connection_handle:04X}'
+ )
stream = PacketTracer.AclStream(self)
self.acl_streams[connection_handle] = stream
@@ -139,7 +162,10 @@ class PacketTracer:
def end_acl_stream(self, connection_handle):
if connection_handle in self.acl_streams:
- logger.info(f'[{self.label}] --- Removing ACL stream for connection 0x{connection_handle:04X}')
+ logger.info(
+ f'[{self.label}] --- Removing ACL stream for connection '
+ f'0x{connection_handle:04X}'
+ )
del self.acl_streams[connection_handle]
# Let the other forwarder know so it can cleanup its stream as well
@@ -171,9 +197,13 @@ class PacketTracer:
self,
host_to_controller_label=color('HOST->CONTROLLER', 'blue'),
controller_to_host_label=color('CONTROLLER->HOST', 'cyan'),
- emit_message=logger.info
+ emit_message=logger.info,
):
- self.host_to_controller_analyzer = PacketTracer.Analyzer(host_to_controller_label, emit_message)
- self.controller_to_host_analyzer = PacketTracer.Analyzer(controller_to_host_label, emit_message)
+ self.host_to_controller_analyzer = PacketTracer.Analyzer(
+ host_to_controller_label, emit_message
+ )
+ self.controller_to_host_analyzer = PacketTracer.Analyzer(
+ controller_to_host_label, emit_message
+ )
self.host_to_controller_analyzer.peer = self.controller_to_host_analyzer
self.controller_to_host_analyzer.peer = self.host_to_controller_analyzer
diff --git a/bumble/hfp.py b/bumble/hfp.py
index 6eeb0d9..7bb9f08 100644
--- a/bumble/hfp.py
+++ b/bumble/hfp.py
@@ -18,7 +18,8 @@
import logging
import asyncio
import collections
-from colors import color
+
+from .colors import color
# -----------------------------------------------------------------------------
@@ -34,16 +35,16 @@ logger = logging.getLogger(__name__)
# -----------------------------------------------------------------------------
class HfpProtocol:
def __init__(self, dlc):
- self.dlc = dlc
- self.buffer = ''
- self.lines = collections.deque()
+ self.dlc = dlc
+ self.buffer = ''
+ self.lines = collections.deque()
self.lines_available = asyncio.Event()
dlc.sink = self.feed
def feed(self, data):
# Convert the data to a string if needed
- if type(data) == bytes:
+ if isinstance(data, bytes):
data = data.decode('utf-8')
logger.debug(f'<<< Data received: {data}')
@@ -52,7 +53,7 @@ class HfpProtocol:
self.buffer += data
while (separator := self.buffer.find('\r')) >= 0:
line = self.buffer[:separator].strip()
- self.buffer = self.buffer[separator + 1:]
+ self.buffer = self.buffer[separator + 1 :]
if len(line) > 0:
self.on_line(line)
@@ -79,16 +80,16 @@ class HfpProtocol:
async def initialize_service(self):
# Perform Service Level Connection Initialization
self.send_command_line('AT+BRSF=2072') # Retrieve Supported Features
- line = await(self.next_line())
- line = await(self.next_line())
+ await (self.next_line())
+ await (self.next_line())
self.send_command_line('AT+CIND=?')
- line = await(self.next_line())
- line = await(self.next_line())
+ await (self.next_line())
+ await (self.next_line())
self.send_command_line('AT+CIND?')
- line = await(self.next_line())
- line = await(self.next_line())
+ await (self.next_line())
+ await (self.next_line())
self.send_command_line('AT+CMER=3,0,0,1')
- line = await(self.next_line())
+ await (self.next_line())
diff --git a/bumble/host.py b/bumble/host.py
index 4057402..afde2ee 100644
--- a/bumble/host.py
+++ b/bumble/host.py
@@ -16,16 +16,62 @@
# Imports
# -----------------------------------------------------------------------------
import asyncio
+import collections
import logging
-from pyee import EventEmitter
-from colors import color
+import struct
+
+from bumble.colors import color
+from bumble.l2cap import L2CAP_PDU
+from bumble.snoop import Snooper
+
+from typing import Optional
+
+from .hci import (
+ Address,
+ HCI_ACL_DATA_PACKET,
+ HCI_COMMAND_COMPLETE_EVENT,
+ HCI_COMMAND_PACKET,
+ HCI_EVENT_PACKET,
+ HCI_LE_READ_BUFFER_SIZE_COMMAND,
+ HCI_LE_READ_LOCAL_SUPPORTED_FEATURES_COMMAND,
+ HCI_LE_READ_SUGGESTED_DEFAULT_DATA_LENGTH_COMMAND,
+ HCI_LE_WRITE_SUGGESTED_DEFAULT_DATA_LENGTH_COMMAND,
+ HCI_READ_BUFFER_SIZE_COMMAND,
+ HCI_READ_LOCAL_VERSION_INFORMATION_COMMAND,
+ HCI_RESET_COMMAND,
+ HCI_SUCCESS,
+ HCI_SUPPORTED_COMMANDS_FLAGS,
+ HCI_VERSION_BLUETOOTH_CORE_4_0,
+ HCI_AclDataPacket,
+ HCI_AclDataPacketAssembler,
+ HCI_Constant,
+ HCI_Error,
+ HCI_LE_Long_Term_Key_Request_Negative_Reply_Command,
+ HCI_LE_Long_Term_Key_Request_Reply_Command,
+ HCI_LE_Read_Buffer_Size_Command,
+ HCI_LE_Read_Local_Supported_Features_Command,
+ HCI_LE_Read_Suggested_Default_Data_Length_Command,
+ HCI_LE_Remote_Connection_Parameter_Request_Reply_Command,
+ HCI_LE_Set_Event_Mask_Command,
+ HCI_LE_Write_Suggested_Default_Data_Length_Command,
+ HCI_Link_Key_Request_Negative_Reply_Command,
+ HCI_Link_Key_Request_Reply_Command,
+ HCI_Packet,
+ HCI_Read_Buffer_Size_Command,
+ HCI_Read_Local_Supported_Commands_Command,
+ HCI_Read_Local_Version_Information_Command,
+ HCI_Reset_Command,
+ HCI_Set_Event_Mask_Command,
+)
+from .core import (
+ BT_BR_EDR_TRANSPORT,
+ BT_CENTRAL_ROLE,
+ BT_LE_TRANSPORT,
+ ConnectionPHY,
+ ConnectionParameters,
+)
+from .utils import AbortableEventEmitter
-from .hci import *
-from .l2cap import *
-from .att import *
-from .gatt import *
-from .smp import *
-from .core import ConnectionParameters
# -----------------------------------------------------------------------------
# Logging
@@ -36,56 +82,60 @@ logger = logging.getLogger(__name__)
# -----------------------------------------------------------------------------
# Constants
# -----------------------------------------------------------------------------
+# fmt: off
+
HOST_DEFAULT_HC_LE_ACL_DATA_PACKET_LENGTH = 27
HOST_HC_TOTAL_NUM_LE_ACL_DATA_PACKETS = 1
HOST_DEFAULT_HC_ACL_DATA_PACKET_LENGTH = 27
HOST_HC_TOTAL_NUM_ACL_DATA_PACKETS = 1
+# fmt: on
+
# -----------------------------------------------------------------------------
class Connection:
- def __init__(self, host, handle, role, peer_address):
- self.host = host
- self.handle = handle
- self.role = role
- self.peer_address = peer_address
- self.assembler = HCI_AclDataPacketAssembler(self.on_acl_pdu)
+ def __init__(self, host, handle, peer_address, transport):
+ self.host = host
+ self.handle = handle
+ self.peer_address = peer_address
+ self.assembler = HCI_AclDataPacketAssembler(self.on_acl_pdu)
+ self.transport = transport
def on_hci_acl_data_packet(self, packet):
self.assembler.feed_packet(packet)
def on_acl_pdu(self, pdu):
l2cap_pdu = L2CAP_PDU.from_bytes(pdu)
-
- if l2cap_pdu.cid == ATT_CID:
- self.host.on_gatt_pdu(self, l2cap_pdu.payload)
- elif l2cap_pdu.cid == SMP_CID:
- self.host.on_smp_pdu(self, l2cap_pdu.payload)
- else:
- self.host.on_l2cap_pdu(self, l2cap_pdu.cid, l2cap_pdu.payload)
+ self.host.on_l2cap_pdu(self, l2cap_pdu.cid, l2cap_pdu.payload)
# -----------------------------------------------------------------------------
-class Host(EventEmitter):
- def __init__(self, controller_source = None, controller_sink = None):
+class Host(AbortableEventEmitter):
+ def __init__(self, controller_source=None, controller_sink=None):
super().__init__()
- self.hci_sink = None
- self.ready = False # True when we can accept incoming packets
- self.connections = {} # Connections, by connection handle
- self.pending_command = None
- self.pending_response = None
- self.hc_le_acl_data_packet_length = HOST_DEFAULT_HC_LE_ACL_DATA_PACKET_LENGTH
+ self.hci_sink = None
+ self.ready = False # True when we can accept incoming packets
+ self.reset_done = False
+ self.connections = {} # Connections, by connection handle
+ self.pending_command = None
+ self.pending_response = None
+ self.hc_le_acl_data_packet_length = HOST_DEFAULT_HC_LE_ACL_DATA_PACKET_LENGTH
self.hc_total_num_le_acl_data_packets = HOST_HC_TOTAL_NUM_LE_ACL_DATA_PACKETS
- self.hc_acl_data_packet_length = HOST_DEFAULT_HC_ACL_DATA_PACKET_LENGTH
- self.hc_total_num_acl_data_packets = HOST_HC_TOTAL_NUM_ACL_DATA_PACKETS
- self.acl_packet_queue = collections.deque()
- self.acl_packets_in_flight = 0
- self.local_supported_commands = bytes(64)
- self.command_semaphore = asyncio.Semaphore(1)
- self.long_term_key_provider = None
- self.link_key_provider = None
- self.pairing_io_capability_provider = None # Classic only
+ self.hc_acl_data_packet_length = HOST_DEFAULT_HC_ACL_DATA_PACKET_LENGTH
+ self.hc_total_num_acl_data_packets = HOST_HC_TOTAL_NUM_ACL_DATA_PACKETS
+ self.acl_packet_queue = collections.deque()
+ self.acl_packets_in_flight = 0
+ self.local_version = None
+ self.local_supported_commands = bytes(64)
+ self.local_le_features = 0
+ self.suggested_max_tx_octets = 251 # Max allowed
+ self.suggested_max_tx_time = 2120 # Max allowed
+ self.command_semaphore = asyncio.Semaphore(1)
+ self.long_term_key_provider = None
+ self.link_key_provider = None
+ self.pairing_io_capability_provider = None # Classic only
+ self.snooper = None
# Connect to the source and sink if specified
if controller_source:
@@ -93,38 +143,140 @@ class Host(EventEmitter):
if controller_sink:
self.set_packet_sink(controller_sink)
+ def find_connection_by_bd_addr(
+ self,
+ bd_addr: Address,
+ transport: Optional[int] = None,
+ check_address_type: bool = False,
+ ) -> Optional[Connection]:
+ for connection in self.connections.values():
+ if connection.peer_address.to_bytes() == bd_addr.to_bytes():
+ if (
+ check_address_type
+ and connection.peer_address.address_type != bd_addr.address_type
+ ):
+ continue
+ if transport is None or connection.transport == transport:
+ return connection
+
+ return None
+
+ async def flush(self) -> None:
+ # Make sure no command is pending
+ await self.command_semaphore.acquire()
+
+ # Flush current host state, then release command semaphore
+ self.emit('flush')
+ self.command_semaphore.release()
+
async def reset(self):
- await self.send_command(HCI_Reset_Command())
+ if self.ready:
+ self.ready = False
+ await self.flush()
+
+ await self.send_command(HCI_Reset_Command(), check_result=True)
self.ready = True
- response = await self.send_command(HCI_Read_Local_Supported_Commands_Command())
- if response.return_parameters.status != HCI_SUCCESS:
- raise ProtocolError(response.return_parameters.status, 'hci')
+ response = await self.send_command(
+ HCI_Read_Local_Supported_Commands_Command(), check_result=True
+ )
self.local_supported_commands = response.return_parameters.supported_commands
- await self.send_command(HCI_Set_Event_Mask_Command(event_mask = bytes.fromhex('FFFFFFFFFFFFFFFF')))
- await self.send_command(HCI_LE_Set_Event_Mask_Command(le_event_mask = bytes.fromhex('FFFFF00000000000')))
- await self.send_command(HCI_Read_Local_Version_Information_Command())
- await self.send_command(HCI_Write_LE_Host_Support_Command(le_supported_host = 1, simultaneous_le_host = 0))
+ if self.supports_command(HCI_LE_READ_LOCAL_SUPPORTED_FEATURES_COMMAND):
+ response = await self.send_command(
+ HCI_LE_Read_Local_Supported_Features_Command(), check_result=True
+ )
+ self.local_le_features = struct.unpack(
+ '<Q', response.return_parameters.le_features
+ )[0]
- response = await self.send_command(HCI_LE_Read_Buffer_Size_Command())
- if response.return_parameters.status == HCI_SUCCESS:
- self.hc_le_acl_data_packet_length = response.return_parameters.hc_le_acl_data_packet_length
- self.hc_total_num_le_acl_data_packets = response.return_parameters.hc_total_num_le_acl_data_packets
- logger.debug(f'HCI LE ACL flow control: hc_le_acl_data_packet_length={response.return_parameters.hc_le_acl_data_packet_length}, hc_total_num_le_acl_data_packets={response.return_parameters.hc_total_num_le_acl_data_packets}')
+ if self.supports_command(HCI_READ_LOCAL_VERSION_INFORMATION_COMMAND):
+ response = await self.send_command(
+ HCI_Read_Local_Version_Information_Command(), check_result=True
+ )
+ self.local_version = response.return_parameters
+
+ await self.send_command(
+ HCI_Set_Event_Mask_Command(event_mask=bytes.fromhex('FFFFFFFFFFFFFF3F'))
+ )
+
+ if (
+ self.local_version is not None
+ and self.local_version.hci_version <= HCI_VERSION_BLUETOOTH_CORE_4_0
+ ):
+ # Some older controllers don't like event masks with bits they don't
+ # understand
+ le_event_mask = bytes.fromhex('1F00000000000000')
else:
- logger.warn(f'HCI_LE_Read_Buffer_Size_Command failed: {response.return_parameters.status}')
- if response.return_parameters.hc_le_acl_data_packet_length == 0 or response.return_parameters.hc_total_num_le_acl_data_packets == 0:
- # Read the non-LE-specific values
- response = await self.send_command(HCI_Read_Buffer_Size_Command())
- if response.return_parameters.status == HCI_SUCCESS:
- self.hc_acl_data_packet_length = response.return_parameters.hc_le_acl_data_packet_length
- self.hc_le_acl_data_packet_length = self.hc_le_acl_data_packet_length or self.hc_acl_data_packet_length
- self.hc_total_num_acl_data_packets = response.return_parameters.hc_total_num_le_acl_data_packets
- self.hc_total_num_le_acl_data_packets = self.hc_total_num_le_acl_data_packets or self.hc_total_num_acl_data_packets
- logger.debug(f'HCI LE ACL flow control: hc_le_acl_data_packet_length={self.hc_le_acl_data_packet_length}, hc_total_num_le_acl_data_packets={self.hc_total_num_le_acl_data_packets}')
- else:
- logger.warn(f'HCI_Read_Buffer_Size_Command failed: {response.return_parameters.status}')
+ le_event_mask = bytes.fromhex('FFFFF00000000000')
+
+ await self.send_command(
+ HCI_LE_Set_Event_Mask_Command(le_event_mask=le_event_mask)
+ )
+
+ if self.supports_command(HCI_READ_BUFFER_SIZE_COMMAND):
+ response = await self.send_command(
+ HCI_Read_Buffer_Size_Command(), check_result=True
+ )
+ self.hc_acl_data_packet_length = (
+ response.return_parameters.hc_acl_data_packet_length
+ )
+ self.hc_total_num_acl_data_packets = (
+ response.return_parameters.hc_total_num_acl_data_packets
+ )
+
+ logger.debug(
+ 'HCI ACL flow control: '
+ f'hc_acl_data_packet_length={self.hc_acl_data_packet_length},'
+ f'hc_total_num_acl_data_packets={self.hc_total_num_acl_data_packets}'
+ )
+
+ if self.supports_command(HCI_LE_READ_BUFFER_SIZE_COMMAND):
+ response = await self.send_command(
+ HCI_LE_Read_Buffer_Size_Command(), check_result=True
+ )
+ self.hc_le_acl_data_packet_length = (
+ response.return_parameters.hc_le_acl_data_packet_length
+ )
+ self.hc_total_num_le_acl_data_packets = (
+ response.return_parameters.hc_total_num_le_acl_data_packets
+ )
+
+ logger.debug(
+ 'HCI LE ACL flow control: '
+ f'hc_le_acl_data_packet_length={self.hc_le_acl_data_packet_length},'
+ 'hc_total_num_le_acl_data_packets='
+ f'{self.hc_total_num_le_acl_data_packets}'
+ )
+
+ if (
+ response.return_parameters.hc_le_acl_data_packet_length == 0
+ or response.return_parameters.hc_total_num_le_acl_data_packets == 0
+ ):
+ # LE and Classic share the same values
+ self.hc_le_acl_data_packet_length = self.hc_acl_data_packet_length
+ self.hc_total_num_le_acl_data_packets = (
+ self.hc_total_num_acl_data_packets
+ )
+
+ if self.supports_command(
+ HCI_LE_READ_SUGGESTED_DEFAULT_DATA_LENGTH_COMMAND
+ ) and self.supports_command(HCI_LE_WRITE_SUGGESTED_DEFAULT_DATA_LENGTH_COMMAND):
+ response = await self.send_command(
+ HCI_LE_Read_Suggested_Default_Data_Length_Command()
+ )
+ suggested_max_tx_octets = response.return_parameters.suggested_max_tx_octets
+ suggested_max_tx_time = response.return_parameters.suggested_max_tx_time
+ if (
+ suggested_max_tx_octets != self.suggested_max_tx_octets
+ or suggested_max_tx_time != self.suggested_max_tx_time
+ ):
+ await self.send_command(
+ HCI_LE_Write_Suggested_Default_Data_Length_Command(
+ suggested_max_tx_octets=self.suggested_max_tx_octets,
+ suggested_max_tx_time=self.suggested_max_tx_time,
+ )
+ )
self.reset_done = True
@@ -142,15 +294,18 @@ class Host(EventEmitter):
self.hci_sink = sink
def send_hci_packet(self, packet):
+ if self.snooper:
+ self.snooper.snoop(bytes(packet), Snooper.Direction.HOST_TO_CONTROLLER)
+
self.hci_sink.on_packet(packet.to_bytes())
- async def send_command(self, command):
+ async def send_command(self, command, check_result=False):
logger.debug(f'{color("### HOST -> CONTROLLER", "blue")}: {command}')
# Wait until we can send (only one pending command at a time)
async with self.command_semaphore:
- assert(self.pending_command is None)
- assert(self.pending_response is None)
+ assert self.pending_command is None
+ assert self.pending_response is None
# Create a future value to hold the eventual response
self.pending_response = asyncio.get_running_loop().create_future()
@@ -159,11 +314,29 @@ class Host(EventEmitter):
try:
self.send_hci_packet(command)
response = await self.pending_response
- # TODO: check error values
+
+ # Check the return parameters if required
+ if check_result:
+ if isinstance(response.return_parameters, int):
+ status = response.return_parameters
+ elif isinstance(response.return_parameters, bytes):
+ # return parameters first field is a one byte status code
+ status = response.return_parameters[0]
+ else:
+ status = response.return_parameters.status
+
+ if status != HCI_SUCCESS:
+ logger.warning(
+ f'{command.name} failed ({HCI_Constant.error_name(status)})'
+ )
+ raise HCI_Error(status)
+
return response
except Exception as error:
- logger.warning(f'{color("!!! Exception while sending HCI packet:", "red")} {error}')
- # raise error
+ logger.warning(
+ f'{color("!!! Exception while sending HCI packet:", "red")} {error}'
+ )
+ raise error
finally:
self.pending_command = None
self.pending_response = None
@@ -183,15 +356,18 @@ class Host(EventEmitter):
offset = 0
pb_flag = 0
while bytes_remaining:
+ # TODO: support different LE/Classic lengths
data_total_length = min(bytes_remaining, self.hc_le_acl_data_packet_length)
acl_packet = HCI_AclDataPacket(
- connection_handle = connection_handle,
- pb_flag = pb_flag,
- bc_flag = 0,
- data_total_length = data_total_length,
- data = l2cap_pdu[offset:offset + data_total_length]
+ connection_handle=connection_handle,
+ pb_flag=pb_flag,
+ bc_flag=0,
+ data_total_length=data_total_length,
+ data=l2cap_pdu[offset : offset + data_total_length],
+ )
+ logger.debug(
+ f'{color("### HOST -> CONTROLLER", "blue")}: (CID={cid}) {acl_packet}'
)
- logger.debug(f'{color("### HOST -> CONTROLLER", "blue")}: (CID={cid}) {acl_packet}')
self.queue_acl_packet(acl_packet)
pb_flag = 1
offset += data_total_length
@@ -202,22 +378,63 @@ class Host(EventEmitter):
self.check_acl_packet_queue()
if len(self.acl_packet_queue):
- logger.debug(f'{self.acl_packets_in_flight} ACL packets in flight, {len(self.acl_packet_queue)} in queue')
+ logger.debug(
+ f'{self.acl_packets_in_flight} ACL packets in flight, '
+ f'{len(self.acl_packet_queue)} in queue'
+ )
def check_acl_packet_queue(self):
- # Send all we can
- while len(self.acl_packet_queue) > 0 and self.acl_packets_in_flight < self.hc_total_num_le_acl_data_packets:
+ # Send all we can (TODO: support different LE/Classic limits)
+ while (
+ len(self.acl_packet_queue) > 0
+ and self.acl_packets_in_flight < self.hc_total_num_le_acl_data_packets
+ ):
packet = self.acl_packet_queue.pop()
self.send_hci_packet(packet)
self.acl_packets_in_flight += 1
+ def supports_command(self, command):
+ # Find the support flag position for this command
+ for octet, flags in enumerate(HCI_SUPPORTED_COMMANDS_FLAGS):
+ for flag_position, value in enumerate(flags):
+ if value == command:
+ # Check if the flag is set
+ if octet < len(self.local_supported_commands) and flag_position < 8:
+ return (
+ self.local_supported_commands[octet] & (1 << flag_position)
+ ) != 0
+
+ return False
+
+ @property
+ def supported_commands(self):
+ commands = []
+ for octet, flags in enumerate(self.local_supported_commands):
+ if octet < len(HCI_SUPPORTED_COMMANDS_FLAGS):
+ for flag in range(8):
+ if flags & (1 << flag) != 0:
+ command = HCI_SUPPORTED_COMMANDS_FLAGS[octet][flag]
+ if command is not None:
+ commands.append(command)
+
+ return commands
+
+ def supports_le_feature(self, feature):
+ return (self.local_le_features & (1 << feature)) != 0
+
+ @property
+ def supported_le_features(self):
+ return [
+ feature for feature in range(64) if self.local_le_features & (1 << feature)
+ ]
+
# Packet Sink protocol (packets coming from the controller via HCI)
def on_packet(self, packet):
hci_packet = HCI_Packet.from_bytes(packet)
if self.ready or (
- hci_packet.hci_packet_type == HCI_EVENT_PACKET and
- hci_packet.event_code == HCI_COMMAND_COMPLETE_EVENT and
- hci_packet.command_opcode == HCI_RESET_COMMAND
+ hci_packet.hci_packet_type == HCI_EVENT_PACKET
+ and hci_packet.event_code == HCI_COMMAND_COMPLETE_EVENT
+ and hci_packet.command_opcode == HCI_RESET_COMMAND
):
self.on_hci_packet(hci_packet)
else:
@@ -226,6 +443,9 @@ class Host(EventEmitter):
def on_hci_packet(self, packet):
logger.debug(f'{color("### CONTROLLER -> HOST", "green")}: {packet}')
+ if self.snooper:
+ self.snooper.snoop(bytes(packet), Snooper.Direction.CONTROLLER_TO_HOST)
+
# If the packet is a command, invoke the handler for this packet
if packet.hci_packet_type == HCI_COMMAND_PACKET:
self.on_hci_command_packet(packet)
@@ -249,12 +469,6 @@ class Host(EventEmitter):
if connection := self.connections.get(packet.connection_handle):
connection.on_hci_acl_data_packet(packet)
- def on_gatt_pdu(self, connection, pdu):
- self.emit('gatt_pdu', connection.handle, pdu)
-
- def on_smp_pdu(self, connection, pdu):
- self.emit('smp_pdu', connection.handle, pdu)
-
def on_l2cap_pdu(self, connection, cid, pdu):
self.emit('l2cap_pdu', connection.handle, cid, pdu)
@@ -262,7 +476,11 @@ class Host(EventEmitter):
if self.pending_response:
# Check that it is what we were expecting
if self.pending_command.op_code != event.command_opcode:
- logger.warning(f'!!! command result mismatch, expected 0x{self.pending_command.op_code:X} but got 0x{event.command_opcode:X}')
+ logger.warning(
+ '!!! command result mismatch, expected '
+ f'0x{self.pending_command.op_code:X} but got '
+ f'0x{event.command_opcode:X}'
+ )
self.pending_response.set_result(event)
else:
@@ -276,10 +494,12 @@ class Host(EventEmitter):
def on_hci_command_complete_event(self, event):
if event.command_opcode == 0:
- # This is used just for the Num_HCI_Command_Packets field, not related to an actual command
+ # This is used just for the Num_HCI_Command_Packets field, not related to
+ # an actual command
logger.debug('no-command event')
- else:
- return self.on_command_processed(event)
+ return None
+
+ return self.on_command_processed(event)
def on_hci_command_status_event(self, event):
return self.on_command_processed(event)
@@ -290,51 +510,64 @@ class Host(EventEmitter):
self.acl_packets_in_flight -= total_packets
self.check_acl_packet_queue()
else:
- logger.warning(color(f'!!! {total_packets} completed but only {self.acl_packets_in_flight} in flight'))
+ logger.warning(
+ color(
+ '!!! {total_packets} completed but only '
+ f'{self.acl_packets_in_flight} in flight'
+ )
+ )
self.acl_packets_in_flight = 0
# Classic only
def on_hci_connection_request_event(self, event):
- # For now, just accept everything
- # TODO: delegate the decision
- self.send_command_sync(
- HCI_Accept_Connection_Request_Command(
- bd_addr = event.bd_addr,
- role = 0x01 # Remain the peripheral
- )
+ # Notify the listeners
+ self.emit(
+ 'connection_request',
+ event.bd_addr,
+ event.class_of_device,
+ event.link_type,
)
def on_hci_le_connection_complete_event(self, event):
# Check if this is a cancellation
if event.status == HCI_SUCCESS:
# Create/update the connection
- logger.debug(f'### CONNECTION: [0x{event.connection_handle:04X}] {event.peer_address} as {HCI_Constant.role_name(event.role)}')
+ logger.debug(
+ f'### LE CONNECTION: [0x{event.connection_handle:04X}] '
+ f'{event.peer_address} as {HCI_Constant.role_name(event.role)}'
+ )
connection = self.connections.get(event.connection_handle)
if connection is None:
- connection = Connection(self, event.connection_handle, event.role, event.peer_address)
+ connection = Connection(
+ self,
+ event.connection_handle,
+ event.peer_address,
+ BT_LE_TRANSPORT,
+ )
self.connections[event.connection_handle] = connection
# Notify the client
connection_parameters = ConnectionParameters(
- event.conn_interval,
- event.conn_latency,
- event.supervision_timeout
+ event.connection_interval,
+ event.peripheral_latency,
+ event.supervision_timeout,
)
self.emit(
'connection',
event.connection_handle,
BT_LE_TRANSPORT,
event.peer_address,
- None,
event.role,
- connection_parameters
+ connection_parameters,
)
else:
logger.debug(f'### CONNECTION FAILED: {event.status}')
# Notify the listeners
- self.emit('connection_failure', event.status)
+ self.emit(
+ 'connection_failure', BT_LE_TRANSPORT, event.peer_address, event.status
+ )
def on_hci_le_enhanced_connection_complete_event(self, event):
# Just use the same implementation as for the non-enhanced event for now
@@ -343,11 +576,19 @@ class Host(EventEmitter):
def on_hci_connection_complete_event(self, event):
if event.status == HCI_SUCCESS:
# Create/update the connection
- logger.debug(f'### BR/EDR CONNECTION: [0x{event.connection_handle:04X}] {event.bd_addr}')
+ logger.debug(
+ f'### BR/EDR CONNECTION: [0x{event.connection_handle:04X}] '
+ f'{event.bd_addr}'
+ )
connection = self.connections.get(event.connection_handle)
if connection is None:
- connection = Connection(self, event.connection_handle, BT_CENTRAL_ROLE, event.bd_addr)
+ connection = Connection(
+ self,
+ event.connection_handle,
+ event.bd_addr,
+ BT_BR_EDR_TRANSPORT,
+ )
self.connections[event.connection_handle] = connection
# Notify the client
@@ -357,14 +598,15 @@ class Host(EventEmitter):
BT_BR_EDR_TRANSPORT,
event.bd_addr,
None,
- BT_CENTRAL_ROLE,
- None
+ None,
)
else:
logger.debug(f'### BR/EDR CONNECTION FAILED: {event.status}')
# Notify the client
- self.emit('connection_failure', event.connection_handle, event.status)
+ self.emit(
+ 'connection_failure', BT_BR_EDR_TRANSPORT, event.bd_addr, event.status
+ )
def on_hci_disconnection_complete_event(self, event):
# Find the connection
@@ -373,7 +615,11 @@ class Host(EventEmitter):
return
if event.status == HCI_SUCCESS:
- logger.debug(f'### DISCONNECTION: [0x{event.connection_handle:04X}] {connection.peer_address} as {HCI_Constant.role_name(connection.role)}, reason={event.reason}')
+ logger.debug(
+ f'### DISCONNECTION: [0x{event.connection_handle:04X}] '
+ f'{connection.peer_address} '
+ f'reason={event.reason}'
+ )
del self.connections[event.connection_handle]
# Notify the listeners
@@ -382,7 +628,7 @@ class Host(EventEmitter):
logger.debug(f'### DISCONNECTION FAILED: {event.status}')
# Notify the listeners
- self.emit('disconnection_failure', event.status)
+ self.emit('disconnection_failure', event.connection_handle, event.status)
def on_hci_le_connection_update_complete_event(self, event):
if (connection := self.connections.get(event.connection_handle)) is None:
@@ -392,13 +638,17 @@ class Host(EventEmitter):
# Notify the client
if event.status == HCI_SUCCESS:
connection_parameters = ConnectionParameters(
- event.conn_interval,
- event.conn_latency,
- event.supervision_timeout
+ event.connection_interval,
+ event.peripheral_latency,
+ event.supervision_timeout,
+ )
+ self.emit(
+ 'connection_parameters_update', connection.handle, connection_parameters
)
- self.emit('connection_parameters_update', connection.handle, connection_parameters)
else:
- self.emit('connection_parameters_update_failure', connection.handle, event.status)
+ self.emit(
+ 'connection_parameters_update_failure', connection.handle, event.status
+ )
def on_hci_le_phy_update_complete_event(self, event):
if (connection := self.connections.get(event.connection_handle)) is None:
@@ -414,13 +664,10 @@ class Host(EventEmitter):
def on_hci_le_advertising_report_event(self, event):
for report in event.reports:
- self.emit(
- 'advertising_report',
- report.address,
- report.data,
- report.rssi,
- report.event_type
- )
+ self.emit('advertising_report', report)
+
+ def on_hci_le_extended_advertising_report_event(self, event):
+ self.on_hci_le_advertising_report_event(event)
def on_hci_le_remote_connection_parameter_request_event(self, event):
if event.connection_handle not in self.connections:
@@ -431,13 +678,13 @@ class Host(EventEmitter):
# TODO: delegate the decision
self.send_command_sync(
HCI_LE_Remote_Connection_Parameter_Request_Reply_Command(
- connection_handle = event.connection_handle,
- interval_min = event.interval_min,
- interval_max = event.interval_max,
- latency = event.latency,
- timeout = event.timeout,
- minimum_ce_length = 0,
- maximum_ce_length = 0
+ connection_handle=event.connection_handle,
+ interval_min=event.interval_min,
+ interval_max=event.interval_max,
+ max_latency=event.max_latency,
+ timeout=event.timeout,
+ min_ce_length=0,
+ max_ce_length=0,
)
)
@@ -451,19 +698,23 @@ class Host(EventEmitter):
logger.debug('no long term key provider')
long_term_key = None
else:
- long_term_key = await self.long_term_key_provider(
- connection.handle,
- event.random_number,
- event.encryption_diversifier
+ long_term_key = await self.abort_on(
+ 'flush',
+ # pylint: disable-next=not-callable
+ self.long_term_key_provider(
+ connection.handle,
+ event.random_number,
+ event.encryption_diversifier,
+ ),
)
if long_term_key:
response = HCI_LE_Long_Term_Key_Request_Reply_Command(
- connection_handle = event.connection_handle,
- long_term_key = long_term_key
+ connection_handle=event.connection_handle,
+ long_term_key=long_term_key,
)
else:
response = HCI_LE_Long_Term_Key_Request_Negative_Reply_Command(
- connection_handle = event.connection_handle
+ connection_handle=event.connection_handle
)
await self.send_command(response)
@@ -478,10 +729,17 @@ class Host(EventEmitter):
def on_hci_role_change_event(self, event):
if event.status == HCI_SUCCESS:
- logger.debug(f'role change for {event.bd_addr}: {HCI_Constant.role_name(event.new_role)}')
- # TODO: lookup the connection and update the role
+ logger.debug(
+ f'role change for {event.bd_addr}: '
+ f'{HCI_Constant.role_name(event.new_role)}'
+ )
+ self.emit('role_change', event.bd_addr, event.new_role)
else:
- logger.debug(f'role change for {event.bd_addr} failed: {HCI_Constant.error_name(event.status)}')
+ logger.debug(
+ f'role change for {event.bd_addr} failed: '
+ f'{HCI_Constant.error_name(event.status)}'
+ )
+ self.emit('role_change_failure', event.bd_addr, event.status)
def on_hci_le_data_length_change_event(self, event):
self.emit(
@@ -490,7 +748,7 @@ class Host(EventEmitter):
event.max_tx_octets,
event.max_tx_time,
event.max_rx_octets,
- event.max_rx_time
+ event.max_rx_time,
)
def on_hci_authentication_complete_event(self, event):
@@ -498,21 +756,35 @@ class Host(EventEmitter):
if event.status == HCI_SUCCESS:
self.emit('connection_authentication', event.connection_handle)
else:
- self.emit('connection_authentication_failure', event.connection_handle, event.status)
+ self.emit(
+ 'connection_authentication_failure',
+ event.connection_handle,
+ event.status,
+ )
def on_hci_encryption_change_event(self, event):
# Notify the client
if event.status == HCI_SUCCESS:
- self.emit('connection_encryption_change', event.connection_handle, event.encryption_enabled)
+ self.emit(
+ 'connection_encryption_change',
+ event.connection_handle,
+ event.encryption_enabled,
+ )
else:
- self.emit('connection_encryption_failure', event.connection_handle, event.status)
+ self.emit(
+ 'connection_encryption_failure', event.connection_handle, event.status
+ )
def on_hci_encryption_key_refresh_complete_event(self, event):
# Notify the client
if event.status == HCI_SUCCESS:
self.emit('connection_encryption_key_refresh', event.connection_handle)
else:
- self.emit('connection_encryption_key_refresh_failure', event.connection_handle, event.status)
+ self.emit(
+ 'connection_encryption_key_refresh_failure',
+ event.connection_handle,
+ event.status,
+ )
def on_hci_link_supervision_timeout_changed_event(self, event):
pass
@@ -524,20 +796,20 @@ class Host(EventEmitter):
pass
def on_hci_link_key_notification_event(self, event):
- logger.debug(f'link key for {event.bd_addr}: {event.link_key.hex()}, type={HCI_Constant.link_key_type_name(event.key_type)}')
+ logger.debug(
+ f'link key for {event.bd_addr}: {event.link_key.hex()}, '
+ f'type={HCI_Constant.link_key_type_name(event.key_type)}'
+ )
self.emit('link_key', event.bd_addr, event.link_key, event.key_type)
def on_hci_simple_pairing_complete_event(self, event):
- logger.debug(f'simple pairing complete for {event.bd_addr}: status={HCI_Constant.status_name(event.status)}')
+ logger.debug(
+ f'simple pairing complete for {event.bd_addr}: '
+ f'status={HCI_Constant.status_name(event.status)}'
+ )
def on_hci_pin_code_request_event(self, event):
- # For now, just refuse all requests
- # TODO: delegate the decision
- self.send_command_sync(
- HCI_PIN_Code_Request_Negative_Reply_Command(
- bd_addr = event.bd_addr
- )
- )
+ self.emit('pin_code_request', event.bd_addr)
def on_hci_link_key_request_event(self, event):
async def send_link_key():
@@ -545,15 +817,18 @@ class Host(EventEmitter):
logger.debug('no link key provider')
link_key = None
else:
- link_key = await self.link_key_provider(event.bd_addr)
+ link_key = await self.abort_on(
+ 'flush',
+ # pylint: disable-next=not-callable
+ self.link_key_provider(event.bd_addr),
+ )
if link_key:
response = HCI_Link_Key_Request_Reply_Command(
- bd_addr = event.bd_addr,
- link_key = link_key
+ bd_addr=event.bd_addr, link_key=link_key
)
else:
response = HCI_Link_Key_Request_Negative_Reply_Command(
- bd_addr = event.bd_addr
+ bd_addr=event.bd_addr
)
await self.send_command(response)
@@ -564,15 +839,29 @@ class Host(EventEmitter):
self.emit('authentication_io_capability_request', event.bd_addr)
def on_hci_io_capability_response_event(self, event):
- pass
+ self.emit(
+ 'authentication_io_capability_response',
+ event.bd_addr,
+ event.io_capability,
+ event.authentication_requirements,
+ )
def on_hci_user_confirmation_request_event(self, event):
- self.emit('authentication_user_confirmation_request', event.bd_addr, event.numeric_value)
+ self.emit(
+ 'authentication_user_confirmation_request',
+ event.bd_addr,
+ event.numeric_value,
+ )
def on_hci_user_passkey_request_event(self, event):
self.emit('authentication_user_passkey_request', event.bd_addr)
- def on_hci_inquiry_complete_event(self, event):
+ def on_hci_user_passkey_notification_event(self, event):
+ self.emit(
+ 'authentication_user_passkey_notification', event.bd_addr, event.passkey
+ )
+
+ def on_hci_inquiry_complete_event(self, _event):
self.emit('inquiry_complete')
def on_hci_inquiry_result_with_rssi_event(self, event):
@@ -582,7 +871,7 @@ class Host(EventEmitter):
response.bd_addr,
response.class_of_device,
b'',
- response.rssi
+ response.rssi,
)
def on_hci_extended_inquiry_result_event(self, event):
@@ -591,7 +880,7 @@ class Host(EventEmitter):
event.bd_addr,
event.class_of_device,
event.extended_inquiry_response,
- event.rssi
+ event.rssi,
)
def on_hci_remote_name_request_complete_event(self, event):
@@ -599,3 +888,10 @@ class Host(EventEmitter):
self.emit('remote_name_failure', event.bd_addr, event.status)
else:
self.emit('remote_name', event.bd_addr, event.remote_name)
+
+ def on_hci_remote_host_supported_features_notification_event(self, event):
+ self.emit(
+ 'remote_host_supported_features',
+ event.bd_addr,
+ event.host_supported_features,
+ )
diff --git a/bumble/keys.py b/bumble/keys.py
index f51cfe6..a30e753 100644
--- a/bumble/keys.py
+++ b/bumble/keys.py
@@ -20,13 +20,19 @@
# -----------------------------------------------------------------------------
# Imports
# -----------------------------------------------------------------------------
+from __future__ import annotations
+import asyncio
import logging
import os
import json
-from colors import color
+from typing import TYPE_CHECKING, Dict, List, Optional, Tuple
+from .colors import color
from .hci import Address
+if TYPE_CHECKING:
+ from .device import Device
+
# -----------------------------------------------------------------------------
# Logging
@@ -38,10 +44,10 @@ logger = logging.getLogger(__name__)
class PairingKeys:
class Key:
def __init__(self, value, authenticated=False, ediv=None, rand=None):
- self.value = value
+ self.value = value
self.authenticated = authenticated
- self.ediv = ediv
- self.rand = rand
+ self.ediv = ediv
+ self.rand = rand
@classmethod
def from_dict(cls, key_dict):
@@ -64,31 +70,33 @@ class PairingKeys:
return key_dict
def __init__(self):
- self.address_type = None
- self.ltk = None
- self.ltk_central = None
+ self.address_type = None
+ self.ltk = None
+ self.ltk_central = None
self.ltk_peripheral = None
- self.irk = None
- self.csrk = None
- self.link_key = None # Classic
+ self.irk = None
+ self.csrk = None
+ self.link_key = None # Classic
@staticmethod
def key_from_dict(keys_dict, key_name):
key_dict = keys_dict.get(key_name)
- if key_dict is not None:
- return PairingKeys.Key.from_dict(key_dict)
+ if key_dict is None:
+ return None
+
+ return PairingKeys.Key.from_dict(key_dict)
@staticmethod
def from_dict(keys_dict):
keys = PairingKeys()
- keys.address_type = keys_dict.get('address_type')
- keys.ltk = PairingKeys.key_from_dict(keys_dict, 'ltk')
- keys.ltk_central = PairingKeys.key_from_dict(keys_dict, 'ltk_central')
+ keys.address_type = keys_dict.get('address_type')
+ keys.ltk = PairingKeys.key_from_dict(keys_dict, 'ltk')
+ keys.ltk_central = PairingKeys.key_from_dict(keys_dict, 'ltk_central')
keys.ltk_peripheral = PairingKeys.key_from_dict(keys_dict, 'ltk_peripheral')
- keys.irk = PairingKeys.key_from_dict(keys_dict, 'irk')
- keys.csrk = PairingKeys.key_from_dict(keys_dict, 'csrk')
- keys.link_key = PairingKeys.key_from_dict(keys_dict, 'link_key')
+ keys.irk = PairingKeys.key_from_dict(keys_dict, 'irk')
+ keys.csrk = PairingKeys.key_from_dict(keys_dict, 'csrk')
+ keys.link_key = PairingKeys.key_from_dict(keys_dict, 'link_key')
return keys
@@ -120,29 +128,33 @@ class PairingKeys:
def print(self, prefix=''):
keys_dict = self.to_dict()
- for (property, value) in keys_dict.items():
- if type(value) is dict:
- print(f'{prefix}{color(property, "cyan")}:')
+ for (container_property, value) in keys_dict.items():
+ if isinstance(value, dict):
+ print(f'{prefix}{color(container_property, "cyan")}:')
for (key_property, key_value) in value.items():
print(f'{prefix} {color(key_property, "green")}: {key_value}')
else:
- print(f'{prefix}{color(property, "cyan")}: {value}')
+ print(f'{prefix}{color(container_property, "cyan")}: {value}')
# -----------------------------------------------------------------------------
class KeyStore:
- async def delete(self, name):
+ async def delete(self, name: str):
pass
- async def update(self, name, keys):
+ async def update(self, name: str, keys: PairingKeys) -> None:
pass
- async def get(self, name):
- return PairingKeys()
+ async def get(self, _name: str) -> Optional[PairingKeys]:
+ return None
- async def get_all(self):
+ async def get_all(self) -> List[Tuple[str, PairingKeys]]:
return []
+ async def delete_all(self) -> None:
+ all_keys = await self.get_all()
+ await asyncio.gather(*(self.delete(name) for (name, _) in all_keys))
+
async def get_resolving_keys(self):
all_keys = await self.get_all()
resolving_keys = []
@@ -161,26 +173,26 @@ class KeyStore:
separator = ''
for (name, keys) in entries:
print(separator + prefix + color(name, 'yellow'))
- keys.print(prefix = prefix + ' ')
+ keys.print(prefix=prefix + ' ')
separator = '\n'
@staticmethod
- def create_for_device(device_config):
- if device_config.keystore is None:
- return None
+ def create_for_device(device: Device) -> KeyStore:
+ if device.config.keystore is None:
+ return MemoryKeyStore()
- keystore_type = device_config.keystore.split(':', 1)[0]
+ keystore_type = device.config.keystore.split(':', 1)[0]
if keystore_type == 'JsonKeyStore':
- return JsonKeyStore.from_device_config(device_config)
+ return JsonKeyStore.from_device(device)
- return None
+ return MemoryKeyStore()
# -----------------------------------------------------------------------------
class JsonKeyStore(KeyStore):
- APP_NAME = 'Bumble'
- APP_AUTHOR = 'Google'
- KEYS_DIR = 'Pairing'
+ APP_NAME = 'Bumble'
+ APP_AUTHOR = 'Google'
+ KEYS_DIR = 'Pairing'
DEFAULT_NAMESPACE = '__DEFAULT__'
def __init__(self, namespace, filename=None):
@@ -188,12 +200,17 @@ class JsonKeyStore(KeyStore):
if filename is None:
# Use a default for the current user
+
+ # Import here because this may not exist on all platforms
+ # pylint: disable=import-outside-toplevel
import appdirs
+
self.directory_name = os.path.join(
- appdirs.user_data_dir(self.APP_NAME, self.APP_AUTHOR),
- self.KEYS_DIR
+ appdirs.user_data_dir(self.APP_NAME, self.APP_AUTHOR), self.KEYS_DIR
+ )
+ json_filename = (
+ f'{self.namespace}.json'.lower().replace(':', '-').replace('/p', '-p')
)
- json_filename = f'{self.namespace}.json'.lower().replace(':', '-')
self.filename = os.path.join(self.directory_name, json_filename)
else:
self.filename = filename
@@ -202,11 +219,21 @@ class JsonKeyStore(KeyStore):
logger.debug(f'JSON keystore: {self.filename}')
@staticmethod
- def from_device_config(device_config):
- params = device_config.keystore.split(':', 1)[1:]
- namespace = str(device_config.address)
+ def from_device(device: Device) -> Optional[JsonKeyStore]:
+ if not device.config.keystore:
+ return None
+
+ params = device.config.keystore.split(':', 1)[1:]
+
+ # Use a namespace based on the device address
+ if device.public_address not in (Address.ANY, Address.ANY_RANDOM):
+ namespace = str(device.public_address)
+ elif device.random_address != Address.ANY_RANDOM:
+ namespace = str(device.random_address)
+ else:
+ namespace = JsonKeyStore.DEFAULT_NAMESPACE
if params:
- filename = params[1]
+ filename = params[0]
else:
filename = None
@@ -214,7 +241,7 @@ class JsonKeyStore(KeyStore):
async def load(self):
try:
- with open(self.filename, 'r') as json_file:
+ with open(self.filename, 'r', encoding='utf-8') as json_file:
return json.load(json_file)
except FileNotFoundError:
return {}
@@ -226,13 +253,13 @@ class JsonKeyStore(KeyStore):
# Save to a temporary file
temp_filename = self.filename + '.tmp'
- with open(temp_filename, 'w') as output:
+ with open(temp_filename, 'w', encoding='utf-8') as output:
json.dump(db, output, sort_keys=True, indent=4)
# Atomically replace the previous file
- os.rename(temp_filename, self.filename)
+ os.replace(temp_filename, self.filename)
- async def delete(self, name):
+ async def delete(self, name: str) -> None:
db = await self.load()
namespace = db.get(self.namespace)
@@ -246,7 +273,7 @@ class JsonKeyStore(KeyStore):
db = await self.load()
namespace = db.setdefault(self.namespace, {})
- namespace[name] = keys.to_dict()
+ namespace.setdefault(name, {}).update(keys.to_dict())
await self.save(db)
@@ -257,9 +284,18 @@ class JsonKeyStore(KeyStore):
if namespace is None:
return []
- return [(name, PairingKeys.from_dict(keys)) for (name, keys) in namespace.items()]
+ return [
+ (name, PairingKeys.from_dict(keys)) for (name, keys) in namespace.items()
+ ]
+
+ async def delete_all(self):
+ db = await self.load()
+
+ db.pop(self.namespace, None)
+
+ await self.save(db)
- async def get(self, name):
+ async def get(self, name: str) -> Optional[PairingKeys]:
db = await self.load()
namespace = db.get(self.namespace)
@@ -271,3 +307,24 @@ class JsonKeyStore(KeyStore):
return None
return PairingKeys.from_dict(keys)
+
+
+# -----------------------------------------------------------------------------
+class MemoryKeyStore(KeyStore):
+ all_keys: Dict[str, PairingKeys]
+
+ def __init__(self) -> None:
+ self.all_keys = {}
+
+ async def delete(self, name: str) -> None:
+ if name in self.all_keys:
+ del self.all_keys[name]
+
+ async def update(self, name: str, keys: PairingKeys) -> None:
+ self.all_keys[name] = keys
+
+ async def get(self, name: str) -> Optional[PairingKeys]:
+ return self.all_keys.get(name)
+
+ async def get_all(self) -> List[Tuple[str, PairingKeys]]:
+ return list(self.all_keys.items())
diff --git a/bumble/l2cap.py b/bumble/l2cap.py
index 7a2ca2b..ef7fdab 100644
--- a/bumble/l2cap.py
+++ b/bumble/l2cap.py
@@ -15,16 +15,23 @@
# -----------------------------------------------------------------------------
# Imports
# -----------------------------------------------------------------------------
+from __future__ import annotations
import asyncio
import logging
import struct
-from colors import color
+from collections import deque
+from pyee import EventEmitter
+from typing import Dict, Type
+from .colors import color
from .core import BT_CENTRAL_ROLE, InvalidStateError, ProtocolError
-from .hci import (HCI_LE_Connection_Update_Command, HCI_Object, key_with_value,
- name_or_number)
-from .utils import EventEmitter
+from .hci import (
+ HCI_LE_Connection_Update_Command,
+ HCI_Object,
+ key_with_value,
+ name_or_number,
+)
# -----------------------------------------------------------------------------
# Logging
@@ -35,6 +42,9 @@ logger = logging.getLogger(__name__)
# -----------------------------------------------------------------------------
# Constants
# -----------------------------------------------------------------------------
+# fmt: off
+# pylint: disable=line-too-long
+
L2CAP_SIGNALING_CID = 0x01
L2CAP_LE_SIGNALING_CID = 0x05
@@ -43,13 +53,23 @@ L2CAP_MIN_BR_EDR_MTU = 48
L2CAP_DEFAULT_MTU = 2048 # Default value for the MTU we are willing to accept
+L2CAP_DEFAULT_CONNECTIONLESS_MTU = 1024
+
# See Bluetooth spec @ Vol 3, Part A - Table 2.1: CID name space on ACL-U, ASB-U, and AMP-U logical links
L2CAP_ACL_U_DYNAMIC_CID_RANGE_START = 0x0040
L2CAP_ACL_U_DYNAMIC_CID_RANGE_END = 0xFFFF
# See Bluetooth spec @ Vol 3, Part A - Table 2.2: CID name space on LE-U logical link
L2CAP_LE_U_DYNAMIC_CID_RANGE_START = 0x0040
-L2CAP_LE_U_DYNAMIC_CID_RANGE_START = 0x007F
+L2CAP_LE_U_DYNAMIC_CID_RANGE_END = 0x007F
+
+# PSM Range - See Bluetooth spec @ Vol 3, Part A / Table 4.5: PSM ranges and usage
+L2CAP_PSM_DYNAMIC_RANGE_START = 0x1001
+L2CAP_PSM_DYNAMIC_RANGE_END = 0xFFFF
+
+# LE PSM Ranges - See Bluetooth spec @ Vol 3, Part A / Table 4.19: LE Credit Based Connection Request LE_PSM ranges
+L2CAP_LE_PSM_DYNAMIC_RANGE_START = 0x0080
+L2CAP_LE_PSM_DYNAMIC_RANGE_END = 0x00FF
# Frame types
L2CAP_COMMAND_REJECT = 0x01
@@ -107,17 +127,28 @@ L2CAP_COMMAND_NOT_UNDERSTOOD_REASON = 0x0000
L2CAP_SIGNALING_MTU_EXCEEDED_REASON = 0x0001
L2CAP_INVALID_CID_IN_REQUEST_REASON = 0x0002
-L2CAP_LE_CREDIT_BASED_CONNECTION_DEFAULT_MTU = 2048
-L2CAP_LE_CREDIT_BASED_CONNECTION_DEFAULT_MPS = 2048
+L2CAP_LE_CREDIT_BASED_CONNECTION_MAX_CREDITS = 65535
+L2CAP_LE_CREDIT_BASED_CONNECTION_MIN_MTU = 23
+L2CAP_LE_CREDIT_BASED_CONNECTION_MIN_MPS = 23
+L2CAP_LE_CREDIT_BASED_CONNECTION_MAX_MPS = 65533
+L2CAP_LE_CREDIT_BASED_CONNECTION_DEFAULT_MTU = 2046
+L2CAP_LE_CREDIT_BASED_CONNECTION_DEFAULT_MPS = 2048
+L2CAP_LE_CREDIT_BASED_CONNECTION_DEFAULT_INITIAL_CREDITS = 256
L2CAP_MAXIMUM_TRANSMISSION_UNIT_CONFIGURATION_OPTION_TYPE = 0x01
L2CAP_MTU_CONFIGURATION_PARAMETER_TYPE = 0x01
+# fmt: on
+# pylint: enable=line-too-long
+
# -----------------------------------------------------------------------------
# Classes
# -----------------------------------------------------------------------------
+# pylint: disable=invalid-name
+
+
class L2CAP_PDU:
'''
See Bluetooth spec @ Vol 3, Part A - 3 DATA PACKET FORMAT
@@ -139,7 +170,7 @@ class L2CAP_PDU:
return header + self.payload
def __init__(self, cid, payload):
- self.cid = cid
+ self.cid = cid
self.payload = payload
def __bytes__(self):
@@ -154,8 +185,10 @@ class L2CAP_Control_Frame:
'''
See Bluetooth spec @ Vol 3, Part A - 4 SIGNALING PACKET FORMATS
'''
- classes = {}
+
+ classes: Dict[int, Type[L2CAP_Control_Frame]] = {}
code = 0
+ name = None
@staticmethod
def from_bytes(pdu):
@@ -172,7 +205,12 @@ class L2CAP_Control_Frame:
self.identifier = pdu[1]
length = struct.unpack_from('<H', pdu, 2)[0]
if length + 4 != len(pdu):
- logger.warn(color(f'!!! length mismatch: expected {len(pdu) - 4} but got {length}', 'red'))
+ logger.warning(
+ color(
+ f'!!! length mismatch: expected {len(pdu) - 4} but got {length}',
+ 'red',
+ )
+ )
if hasattr(self, 'fields'):
self.init_from_bytes(pdu, 4)
return self
@@ -185,17 +223,19 @@ class L2CAP_Control_Frame:
def decode_configuration_options(data):
options = []
while len(data) >= 2:
- type = data[0]
+ value_type = data[0]
length = data[1]
- value = data[2:2 + length]
- data = data[2 + length:]
- options.append((type, value))
+ value = data[2 : 2 + length]
+ data = data[2 + length :]
+ options.append((value_type, value))
return options
@staticmethod
def encode_configuration_options(options):
- return b''.join([bytes([option[0], len(option[1])]) + option[1] for option in options])
+ return b''.join(
+ [bytes([option[0], len(option[1])]) + option[1] for option in options]
+ )
@staticmethod
def subclass(fields):
@@ -203,7 +243,10 @@ class L2CAP_Control_Frame:
cls.name = cls.__name__.upper()
cls.code = key_with_value(L2CAP_CONTROL_FRAME_NAMES, cls.name)
if cls.code is None:
- raise KeyError(f'Control Frame name {cls.name} not found in L2CAP_CONTROL_FRAME_NAMES')
+ raise KeyError(
+ f'Control Frame name {cls.name} '
+ 'not found in L2CAP_CONTROL_FRAME_NAMES'
+ )
cls.fields = fields
# Register a factory for this class
@@ -219,7 +262,11 @@ class L2CAP_Control_Frame:
HCI_Object.init_from_fields(self, self.fields, kwargs)
if pdu is None:
data = HCI_Object.dict_to_bytes(kwargs, self.fields)
- pdu = bytes([self.code, self.identifier]) + struct.pack('<H', len(data)) + data
+ pdu = (
+ bytes([self.code, self.identifier])
+ + struct.pack('<H', len(data))
+ + data
+ )
self.pdu = pdu
def init_from_bytes(self, pdu, offset):
@@ -242,10 +289,16 @@ class L2CAP_Control_Frame:
# -----------------------------------------------------------------------------
-@L2CAP_Control_Frame.subclass([
- ('reason', {'size': 2, 'mapper': lambda x: L2CAP_Command_Reject.reason_name(x)}),
- ('data', '*')
-])
+@L2CAP_Control_Frame.subclass(
+ # pylint: disable=unnecessary-lambda
+ [
+ (
+ 'reason',
+ {'size': 2, 'mapper': lambda x: L2CAP_Command_Reject.reason_name(x)},
+ ),
+ ('data', '*'),
+ ]
+)
class L2CAP_Command_Reject(L2CAP_Control_Frame):
'''
See Bluetooth spec @ Vol 3, Part A - 4.1 COMMAND REJECT
@@ -258,7 +311,7 @@ class L2CAP_Command_Reject(L2CAP_Control_Frame):
REASON_NAMES = {
COMMAND_NOT_UNDERSTOOD: 'COMMAND_NOT_UNDERSTOOD',
SIGNALING_MTU_EXCEEDED: 'SIGNALING_MTU_EXCEEDED',
- INVALID_CID_IN_REQUEST: 'INVALID_CID_IN_REQUEST'
+ INVALID_CID_IN_REQUEST: 'INVALID_CID_IN_REQUEST',
}
@staticmethod
@@ -267,59 +320,97 @@ class L2CAP_Command_Reject(L2CAP_Control_Frame):
# -----------------------------------------------------------------------------
-@L2CAP_Control_Frame.subclass([
- ('psm', 2),
- ('source_cid', 2)
-])
+@L2CAP_Control_Frame.subclass(
+ # pylint: disable=unnecessary-lambda
+ [
+ (
+ 'psm',
+ {
+ 'parser': lambda data, offset: L2CAP_Connection_Request.parse_psm(
+ data, offset
+ ),
+ 'serializer': lambda value: L2CAP_Connection_Request.serialize_psm(
+ value
+ ),
+ },
+ ),
+ ('source_cid', 2),
+ ]
+)
class L2CAP_Connection_Request(L2CAP_Control_Frame):
'''
See Bluetooth spec @ Vol 3, Part A - 4.2 CONNECTION REQUEST
'''
+ @staticmethod
+ def parse_psm(data, offset=0):
+ psm_length = 2
+ psm = data[offset] | data[offset + 1] << 8
+
+ # The PSM field extends until the first even octet (inclusive)
+ while data[offset + psm_length - 1] % 2 == 1:
+ psm |= data[offset + psm_length] << (8 * psm_length)
+ psm_length += 1
+
+ return offset + psm_length, psm
+
+ @staticmethod
+ def serialize_psm(psm):
+ serialized = struct.pack('<H', psm & 0xFFFF)
+ psm >>= 16
+ while psm:
+ serialized += bytes([psm & 0xFF])
+ psm >>= 8
+
+ return serialized
+
# -----------------------------------------------------------------------------
-@L2CAP_Control_Frame.subclass([
- ('destination_cid', 2),
- ('source_cid', 2),
- ('result', {'size': 2, 'mapper': lambda x: L2CAP_Connection_Response.result_name(x)}),
- ('status', 2)
-])
+@L2CAP_Control_Frame.subclass(
+ # pylint: disable=unnecessary-lambda
+ [
+ ('destination_cid', 2),
+ ('source_cid', 2),
+ (
+ 'result',
+ {'size': 2, 'mapper': lambda x: L2CAP_Connection_Response.result_name(x)},
+ ),
+ ('status', 2),
+ ]
+)
class L2CAP_Connection_Response(L2CAP_Control_Frame):
'''
See Bluetooth spec @ Vol 3, Part A - 4.3 CONNECTION RESPONSE
'''
- CONNECTION_SUCCESSFUL = 0x0000
- CONNECTION_PENDING = 0x0001
- CONNECTION_REFUSED_LE_PSM_NOT_SUPPORTED = 0x0002
- CONNECTION_REFUSED_SECURITY_BLOCK = 0x0003
- CONNECTION_REFUSED_NO_RESOURCES_AVAILABLE = 0x0004
- CONNECTION_REFUSED_INVALID_SOURCE_CID = 0x0006
- CONNECTION_REFUSED_SOURCE_CID_ALREADY_ALLOCATED = 0x0007
- CONNECTION_REFUSED_UNACCEPTABLE_PARAMETERS = 0x000B
-
- CONNECTION_RESULT_NAMES = {
- CONNECTION_SUCCESSFUL: 'CONNECTION_SUCCESSFUL',
- CONNECTION_PENDING: 'CONNECTION_PENDING',
- CONNECTION_REFUSED_LE_PSM_NOT_SUPPORTED: 'CONNECTION_REFUSED_LE_PSM_NOT_SUPPORTED',
- CONNECTION_REFUSED_SECURITY_BLOCK: 'CONNECTION_REFUSED_SECURITY_BLOCK',
- CONNECTION_REFUSED_NO_RESOURCES_AVAILABLE: 'CONNECTION_REFUSED_NO_RESOURCES_AVAILABLE',
- CONNECTION_REFUSED_INVALID_SOURCE_CID: 'CONNECTION_REFUSED_INVALID_SOURCE_CID',
+ CONNECTION_SUCCESSFUL = 0x0000
+ CONNECTION_PENDING = 0x0001
+ CONNECTION_REFUSED_PSM_NOT_SUPPORTED = 0x0002
+ CONNECTION_REFUSED_SECURITY_BLOCK = 0x0003
+ CONNECTION_REFUSED_NO_RESOURCES_AVAILABLE = 0x0004
+ CONNECTION_REFUSED_INVALID_SOURCE_CID = 0x0006
+ CONNECTION_REFUSED_SOURCE_CID_ALREADY_ALLOCATED = 0x0007
+ CONNECTION_REFUSED_UNACCEPTABLE_PARAMETERS = 0x000B
+
+ # pylint: disable=line-too-long
+ RESULT_NAMES = {
+ CONNECTION_SUCCESSFUL: 'CONNECTION_SUCCESSFUL',
+ CONNECTION_PENDING: 'CONNECTION_PENDING',
+ CONNECTION_REFUSED_PSM_NOT_SUPPORTED: 'CONNECTION_REFUSED_PSM_NOT_SUPPORTED',
+ CONNECTION_REFUSED_SECURITY_BLOCK: 'CONNECTION_REFUSED_SECURITY_BLOCK',
+ CONNECTION_REFUSED_NO_RESOURCES_AVAILABLE: 'CONNECTION_REFUSED_NO_RESOURCES_AVAILABLE',
+ CONNECTION_REFUSED_INVALID_SOURCE_CID: 'CONNECTION_REFUSED_INVALID_SOURCE_CID',
CONNECTION_REFUSED_SOURCE_CID_ALREADY_ALLOCATED: 'CONNECTION_REFUSED_SOURCE_CID_ALREADY_ALLOCATED',
- CONNECTION_REFUSED_UNACCEPTABLE_PARAMETERS: 'CONNECTION_REFUSED_UNACCEPTABLE_PARAMETERS'
+ CONNECTION_REFUSED_UNACCEPTABLE_PARAMETERS: 'CONNECTION_REFUSED_UNACCEPTABLE_PARAMETERS',
}
@staticmethod
def result_name(result):
- return name_or_number(L2CAP_Connection_Response.CONNECTION_RESULT_NAMES, result)
+ return name_or_number(L2CAP_Connection_Response.RESULT_NAMES, result)
# -----------------------------------------------------------------------------
-@L2CAP_Control_Frame.subclass([
- ('destination_cid', 2),
- ('flags', 2),
- ('options', '*')
-])
+@L2CAP_Control_Frame.subclass([('destination_cid', 2), ('flags', 2), ('options', '*')])
class L2CAP_Configure_Request(L2CAP_Control_Frame):
'''
See Bluetooth spec @ Vol 3, Part A - 4.4 CONFIGURATION REQUEST
@@ -327,31 +418,37 @@ class L2CAP_Configure_Request(L2CAP_Control_Frame):
# -----------------------------------------------------------------------------
-@L2CAP_Control_Frame.subclass([
- ('source_cid', 2),
- ('flags', 2),
- ('result', {'size': 2, 'mapper': lambda x: L2CAP_Configure_Response.result_name(x)}),
- ('options', '*')
-])
+@L2CAP_Control_Frame.subclass(
+ # pylint: disable=unnecessary-lambda
+ [
+ ('source_cid', 2),
+ ('flags', 2),
+ (
+ 'result',
+ {'size': 2, 'mapper': lambda x: L2CAP_Configure_Response.result_name(x)},
+ ),
+ ('options', '*'),
+ ]
+)
class L2CAP_Configure_Response(L2CAP_Control_Frame):
'''
See Bluetooth spec @ Vol 3, Part A - 4.5 CONFIGURATION RESPONSE
'''
- SUCCESS = 0x0000
+ SUCCESS = 0x0000
FAILURE_UNACCEPTABLE_PARAMETERS = 0x0001
- FAILURE_REJECTED = 0x0002
- FAILURE_UNKNOWN_OPTIONS = 0x0003
- PENDING = 0x0004
- FAILURE_FLOW_SPEC_REJECTED = 0x0005
+ FAILURE_REJECTED = 0x0002
+ FAILURE_UNKNOWN_OPTIONS = 0x0003
+ PENDING = 0x0004
+ FAILURE_FLOW_SPEC_REJECTED = 0x0005
RESULT_NAMES = {
- SUCCESS: 'SUCCESS',
+ SUCCESS: 'SUCCESS',
FAILURE_UNACCEPTABLE_PARAMETERS: 'FAILURE_UNACCEPTABLE_PARAMETERS',
- FAILURE_REJECTED: 'FAILURE_REJECTED',
- FAILURE_UNKNOWN_OPTIONS: 'FAILURE_UNKNOWN_OPTIONS',
- PENDING: 'PENDING',
- FAILURE_FLOW_SPEC_REJECTED: 'FAILURE_FLOW_SPEC_REJECTED'
+ FAILURE_REJECTED: 'FAILURE_REJECTED',
+ FAILURE_UNKNOWN_OPTIONS: 'FAILURE_UNKNOWN_OPTIONS',
+ PENDING: 'PENDING',
+ FAILURE_FLOW_SPEC_REJECTED: 'FAILURE_FLOW_SPEC_REJECTED',
}
@staticmethod
@@ -360,10 +457,7 @@ class L2CAP_Configure_Response(L2CAP_Control_Frame):
# -----------------------------------------------------------------------------
-@L2CAP_Control_Frame.subclass([
- ('destination_cid', 2),
- ('source_cid', 2)
-])
+@L2CAP_Control_Frame.subclass([('destination_cid', 2), ('source_cid', 2)])
class L2CAP_Disconnection_Request(L2CAP_Control_Frame):
'''
See Bluetooth spec @ Vol 3, Part A - 4.6 DISCONNECTION REQUEST
@@ -371,10 +465,7 @@ class L2CAP_Disconnection_Request(L2CAP_Control_Frame):
# -----------------------------------------------------------------------------
-@L2CAP_Control_Frame.subclass([
- ('destination_cid', 2),
- ('source_cid', 2)
-])
+@L2CAP_Control_Frame.subclass([('destination_cid', 2), ('source_cid', 2)])
class L2CAP_Disconnection_Response(L2CAP_Control_Frame):
'''
See Bluetooth spec @ Vol 3, Part A - 4.7 DISCONNECTION RESPONSE
@@ -382,9 +473,7 @@ class L2CAP_Disconnection_Response(L2CAP_Control_Frame):
# -----------------------------------------------------------------------------
-@L2CAP_Control_Frame.subclass([
- ('data', '*')
-])
+@L2CAP_Control_Frame.subclass([('data', '*')])
class L2CAP_Echo_Request(L2CAP_Control_Frame):
'''
See Bluetooth spec @ Vol 3, Part A - 4.8 ECHO REQUEST
@@ -392,9 +481,7 @@ class L2CAP_Echo_Request(L2CAP_Control_Frame):
# -----------------------------------------------------------------------------
-@L2CAP_Control_Frame.subclass([
- ('data', '*')
-])
+@L2CAP_Control_Frame.subclass([('data', '*')])
class L2CAP_Echo_Response(L2CAP_Control_Frame):
'''
See Bluetooth spec @ Vol 3, Part A - 4.9 ECHO RESPONSE
@@ -402,22 +489,43 @@ class L2CAP_Echo_Response(L2CAP_Control_Frame):
# -----------------------------------------------------------------------------
-@L2CAP_Control_Frame.subclass([
- ('info_type', {'size': 2, 'mapper': lambda x: L2CAP_Information_Request.info_type_name(x)})
-])
+@L2CAP_Control_Frame.subclass(
+ [
+ (
+ 'info_type',
+ {
+ 'size': 2,
+ # pylint: disable-next=unnecessary-lambda
+ 'mapper': lambda x: L2CAP_Information_Request.info_type_name(x),
+ },
+ )
+ ]
+)
class L2CAP_Information_Request(L2CAP_Control_Frame):
'''
See Bluetooth spec @ Vol 3, Part A - 4.10 INFORMATION REQUEST
'''
- CONNECTIONLESS_MTU = 0x0001
+ CONNECTIONLESS_MTU = 0x0001
EXTENDED_FEATURES_SUPPORTED = 0x0002
- FIXED_CHANNELS_SUPPORTED = 0x0003
+ FIXED_CHANNELS_SUPPORTED = 0x0003
+
+ EXTENDED_FEATURE_FLOW_MODE_CONTROL = 0x0001
+ EXTENDED_FEATURE_RETRANSMISSION_MODE = 0x0002
+ EXTENDED_FEATURE_BIDIRECTIONAL_QOS = 0x0004
+ EXTENDED_FEATURE_ENHANCED_RETRANSMISSION_MODE = 0x0008
+ EXTENDED_FEATURE_STREAMING_MODE = 0x0010
+ EXTENDED_FEATURE_FCS_OPTION = 0x0020
+ EXTENDED_FEATURE_EXTENDED_FLOW_SPEC = 0x0040
+ EXTENDED_FEATURE_FIXED_CHANNELS = 0x0080
+ EXTENDED_FEATURE_EXTENDED_WINDOW_SIZE = 0x0100
+ EXTENDED_FEATURE_UNICAST_CONNECTIONLESS_DATA = 0x0200
+ EXTENDED_FEATURE_ENHANCED_CREDIT_BASE_FLOW_CONTROL = 0x0400
INFO_TYPE_NAMES = {
- CONNECTIONLESS_MTU: 'CONNECTIONLESS_MTU',
+ CONNECTIONLESS_MTU: 'CONNECTIONLESS_MTU',
EXTENDED_FEATURES_SUPPORTED: 'EXTENDED_FEATURES_SUPPORTED',
- FIXED_CHANNELS_SUPPORTED: 'FIXED_CHANNELS_SUPPORTED'
+ FIXED_CHANNELS_SUPPORTED: 'FIXED_CHANNELS_SUPPORTED',
}
@staticmethod
@@ -426,22 +534,26 @@ class L2CAP_Information_Request(L2CAP_Control_Frame):
# -----------------------------------------------------------------------------
-@L2CAP_Control_Frame.subclass([
- ('info_type', {'size': 2, 'mapper': L2CAP_Information_Request.info_type_name}),
- ('result', {'size': 2, 'mapper': lambda x: L2CAP_Information_Response.result_name(x)}),
- ('data', '*')
-])
+@L2CAP_Control_Frame.subclass(
+ [
+ ('info_type', {'size': 2, 'mapper': L2CAP_Information_Request.info_type_name}),
+ (
+ 'result',
+ # pylint: disable-next=unnecessary-lambda
+ {'size': 2, 'mapper': lambda x: L2CAP_Information_Response.result_name(x)},
+ ),
+ ('data', '*'),
+ ]
+)
class L2CAP_Information_Response(L2CAP_Control_Frame):
'''
See Bluetooth spec @ Vol 3, Part A - 4.11 INFORMATION RESPONSE
'''
- SUCCESS = 0x00
+
+ SUCCESS = 0x00
NOT_SUPPORTED = 0x01
- RESULT_NAMES = {
- SUCCESS: 'SUCCESS',
- NOT_SUPPORTED: 'NOT_SUPPORTED'
- }
+ RESULT_NAMES = {SUCCESS: 'SUCCESS', NOT_SUPPORTED: 'NOT_SUPPORTED'}
@staticmethod
def result_name(result):
@@ -449,12 +561,9 @@ class L2CAP_Information_Response(L2CAP_Control_Frame):
# -----------------------------------------------------------------------------
-@L2CAP_Control_Frame.subclass([
- ('interval_min', 2),
- ('interval_max', 2),
- ('slave_latency', 2),
- ('timeout_multiplier', 2)
-])
+@L2CAP_Control_Frame.subclass(
+ [('interval_min', 2), ('interval_max', 2), ('latency', 2), ('timeout', 2)]
+)
class L2CAP_Connection_Parameter_Update_Request(L2CAP_Control_Frame):
'''
See Bluetooth spec @ Vol 3, Part A - 4.20 CONNECTION PARAMETER UPDATE REQUEST
@@ -462,9 +571,7 @@ class L2CAP_Connection_Parameter_Update_Request(L2CAP_Control_Frame):
# -----------------------------------------------------------------------------
-@L2CAP_Control_Frame.subclass([
- ('result', 2)
-])
+@L2CAP_Control_Frame.subclass([('result', 2)])
class L2CAP_Connection_Parameter_Update_Response(L2CAP_Control_Frame):
'''
See Bluetooth spec @ Vol 3, Part A - 4.21 CONNECTION PARAMETER UPDATE RESPONSE
@@ -472,66 +579,75 @@ class L2CAP_Connection_Parameter_Update_Response(L2CAP_Control_Frame):
# -----------------------------------------------------------------------------
-@L2CAP_Control_Frame.subclass([
- ('le_psm', 2),
- ('source_cid', 2),
- ('mtu', 2),
- ('mps', 2),
- ('initial_credits', 2)
-])
+@L2CAP_Control_Frame.subclass(
+ [('le_psm', 2), ('source_cid', 2), ('mtu', 2), ('mps', 2), ('initial_credits', 2)]
+)
class L2CAP_LE_Credit_Based_Connection_Request(L2CAP_Control_Frame):
'''
- See Bluetooth spec @ Vol 3, Part A - 4.22 LE CREDIT BASED CONNECTION REQUEST (CODE 0x14)
+ See Bluetooth spec @ Vol 3, Part A - 4.22 LE CREDIT BASED CONNECTION REQUEST
+ (CODE 0x14)
'''
# -----------------------------------------------------------------------------
-@L2CAP_Control_Frame.subclass([
- ('destination_cid', 2),
- ('mtu', 2),
- ('mps', 2),
- ('initial_credits', 2),
- ('result', {'size': 2, 'mapper': lambda x: L2CAP_LE_Credit_Based_Connection_Response.result_name(x)})
-])
+@L2CAP_Control_Frame.subclass(
+ # pylint: disable=unnecessary-lambda,line-too-long
+ [
+ ('destination_cid', 2),
+ ('mtu', 2),
+ ('mps', 2),
+ ('initial_credits', 2),
+ (
+ 'result',
+ {
+ 'size': 2,
+ 'mapper': lambda x: L2CAP_LE_Credit_Based_Connection_Response.result_name(
+ x
+ ),
+ },
+ ),
+ ]
+)
class L2CAP_LE_Credit_Based_Connection_Response(L2CAP_Control_Frame):
'''
- See Bluetooth spec @ Vol 3, Part A - 4.23 LE CREDIT BASED CONNECTION RESPONSE (CODE 0x15)
+ See Bluetooth spec @ Vol 3, Part A - 4.23 LE CREDIT BASED CONNECTION RESPONSE
+ (CODE 0x15)
'''
- CONNECTION_SUCCESSFUL = 0x0000
- CONNECTION_REFUSED_LE_PSM_NOT_SUPPORTED = 0x0002
- CONNECTION_REFUSED_NO_RESOURCES_AVAILABLE = 0x0004
- CONNECTION_REFUSED_INSUFFICIENT_AUTHENTICATION = 0x0005
- CONNECTION_REFUSED_INSUFFICIENT_AUTHORIZATION = 0x0006
+ CONNECTION_SUCCESSFUL = 0x0000
+ CONNECTION_REFUSED_LE_PSM_NOT_SUPPORTED = 0x0002
+ CONNECTION_REFUSED_NO_RESOURCES_AVAILABLE = 0x0004
+ CONNECTION_REFUSED_INSUFFICIENT_AUTHENTICATION = 0x0005
+ CONNECTION_REFUSED_INSUFFICIENT_AUTHORIZATION = 0x0006
CONNECTION_REFUSED_INSUFFICIENT_ENCRYPTION_KEY_SIZE = 0x0007
- CONNECTION_REFUSED_INSUFFICIENT_ENCRYPTION = 0x0008
- CONNECTION_REFUSED_INVALID_SOURCE_CID = 0x0009
- CONNECTION_REFUSED_SOURCE_CID_ALREADY_ALLOCATED = 0x000A
- CONNECTION_REFUSED_UNACCEPTABLE_PARAMETERS = 0x000B
-
- CONNECTION_RESULT_NAMES = {
- CONNECTION_SUCCESSFUL: 'CONNECTION_SUCCESSFUL',
- CONNECTION_REFUSED_LE_PSM_NOT_SUPPORTED: 'CONNECTION_REFUSED_LE_PSM_NOT_SUPPORTED',
- CONNECTION_REFUSED_NO_RESOURCES_AVAILABLE: 'CONNECTION_REFUSED_NO_RESOURCES_AVAILABLE',
- CONNECTION_REFUSED_INSUFFICIENT_AUTHENTICATION: 'CONNECTION_REFUSED_INSUFFICIENT_AUTHENTICATION',
- CONNECTION_REFUSED_INSUFFICIENT_AUTHORIZATION: 'CONNECTION_REFUSED_INSUFFICIENT_AUTHORIZATION',
+ CONNECTION_REFUSED_INSUFFICIENT_ENCRYPTION = 0x0008
+ CONNECTION_REFUSED_INVALID_SOURCE_CID = 0x0009
+ CONNECTION_REFUSED_SOURCE_CID_ALREADY_ALLOCATED = 0x000A
+ CONNECTION_REFUSED_UNACCEPTABLE_PARAMETERS = 0x000B
+
+ # pylint: disable=line-too-long
+ RESULT_NAMES = {
+ CONNECTION_SUCCESSFUL: 'CONNECTION_SUCCESSFUL',
+ CONNECTION_REFUSED_LE_PSM_NOT_SUPPORTED: 'CONNECTION_REFUSED_LE_PSM_NOT_SUPPORTED',
+ CONNECTION_REFUSED_NO_RESOURCES_AVAILABLE: 'CONNECTION_REFUSED_NO_RESOURCES_AVAILABLE',
+ CONNECTION_REFUSED_INSUFFICIENT_AUTHENTICATION: 'CONNECTION_REFUSED_INSUFFICIENT_AUTHENTICATION',
+ CONNECTION_REFUSED_INSUFFICIENT_AUTHORIZATION: 'CONNECTION_REFUSED_INSUFFICIENT_AUTHORIZATION',
CONNECTION_REFUSED_INSUFFICIENT_ENCRYPTION_KEY_SIZE: 'CONNECTION_REFUSED_INSUFFICIENT_ENCRYPTION_KEY_SIZE',
- CONNECTION_REFUSED_INSUFFICIENT_ENCRYPTION: 'CONNECTION_REFUSED_INSUFFICIENT_ENCRYPTION',
- CONNECTION_REFUSED_INVALID_SOURCE_CID: 'CONNECTION_REFUSED_INVALID_SOURCE_CID',
- CONNECTION_REFUSED_SOURCE_CID_ALREADY_ALLOCATED: 'CONNECTION_REFUSED_SOURCE_CID_ALREADY_ALLOCATED',
- CONNECTION_REFUSED_UNACCEPTABLE_PARAMETERS: 'CONNECTION_REFUSED_UNACCEPTABLE_PARAMETERS'
+ CONNECTION_REFUSED_INSUFFICIENT_ENCRYPTION: 'CONNECTION_REFUSED_INSUFFICIENT_ENCRYPTION',
+ CONNECTION_REFUSED_INVALID_SOURCE_CID: 'CONNECTION_REFUSED_INVALID_SOURCE_CID',
+ CONNECTION_REFUSED_SOURCE_CID_ALREADY_ALLOCATED: 'CONNECTION_REFUSED_SOURCE_CID_ALREADY_ALLOCATED',
+ CONNECTION_REFUSED_UNACCEPTABLE_PARAMETERS: 'CONNECTION_REFUSED_UNACCEPTABLE_PARAMETERS',
}
@staticmethod
def result_name(result):
- return name_or_number(L2CAP_LE_Credit_Based_Connection_Response.CONNECTION_RESULT_NAMES, result)
+ return name_or_number(
+ L2CAP_LE_Credit_Based_Connection_Response.RESULT_NAMES, result
+ )
# -----------------------------------------------------------------------------
-@L2CAP_Control_Frame.subclass([
- ('cid', 2),
- ('credits', 2)
-])
+@L2CAP_Control_Frame.subclass([('cid', 2), ('credits', 2)])
class L2CAP_LE_Flow_Control_Credit(L2CAP_Control_Frame):
'''
See Bluetooth spec @ Vol 3, Part A - 4.24 LE FLOW CONTROL CREDIT (CODE 0x16)
@@ -541,72 +657,77 @@ class L2CAP_LE_Flow_Control_Credit(L2CAP_Control_Frame):
# -----------------------------------------------------------------------------
class Channel(EventEmitter):
# States
- CLOSED = 0x00
- WAIT_CONNECT = 0x01
- WAIT_CONNECT_RSP = 0x02
- OPEN = 0x03
- WAIT_DISCONNECT = 0x04
- WAIT_CREATE = 0x05
- WAIT_CREATE_RSP = 0x06
- WAIT_MOVE = 0x07
- WAIT_MOVE_RSP = 0x08
+ CLOSED = 0x00
+ WAIT_CONNECT = 0x01
+ WAIT_CONNECT_RSP = 0x02
+ OPEN = 0x03
+ WAIT_DISCONNECT = 0x04
+ WAIT_CREATE = 0x05
+ WAIT_CREATE_RSP = 0x06
+ WAIT_MOVE = 0x07
+ WAIT_MOVE_RSP = 0x08
WAIT_MOVE_CONFIRM = 0x09
- WAIT_CONFIRM_RSP = 0x0A
+ WAIT_CONFIRM_RSP = 0x0A
# CONFIG substates
- WAIT_CONFIG = 0x10
- WAIT_SEND_CONFIG = 0x11
+ WAIT_CONFIG = 0x10
+ WAIT_SEND_CONFIG = 0x11
WAIT_CONFIG_REQ_RSP = 0x12
- WAIT_CONFIG_RSP = 0x13
- WAIT_CONFIG_REQ = 0x14
- WAIT_IND_FINAL_RSP = 0x15
- WAIT_FINAL_RSP = 0x16
- WAIT_CONTROL_IND = 0x17
+ WAIT_CONFIG_RSP = 0x13
+ WAIT_CONFIG_REQ = 0x14
+ WAIT_IND_FINAL_RSP = 0x15
+ WAIT_FINAL_RSP = 0x16
+ WAIT_CONTROL_IND = 0x17
STATE_NAMES = {
- CLOSED: 'CLOSED',
- WAIT_CONNECT: 'WAIT_CONNECT',
- WAIT_CONNECT_RSP: 'WAIT_CONNECT_RSP',
- OPEN: 'OPEN',
- WAIT_DISCONNECT: 'WAIT_DISCONNECT',
- WAIT_CREATE: 'WAIT_CREATE',
- WAIT_CREATE_RSP: 'WAIT_CREATE_RSP',
- WAIT_MOVE: 'WAIT_MOVE',
- WAIT_MOVE_RSP: 'WAIT_MOVE_RSP',
+ CLOSED: 'CLOSED',
+ WAIT_CONNECT: 'WAIT_CONNECT',
+ WAIT_CONNECT_RSP: 'WAIT_CONNECT_RSP',
+ OPEN: 'OPEN',
+ WAIT_DISCONNECT: 'WAIT_DISCONNECT',
+ WAIT_CREATE: 'WAIT_CREATE',
+ WAIT_CREATE_RSP: 'WAIT_CREATE_RSP',
+ WAIT_MOVE: 'WAIT_MOVE',
+ WAIT_MOVE_RSP: 'WAIT_MOVE_RSP',
WAIT_MOVE_CONFIRM: 'WAIT_MOVE_CONFIRM',
- WAIT_CONFIRM_RSP: 'WAIT_CONFIRM_RSP',
-
- WAIT_CONFIG: 'WAIT_CONFIG',
- WAIT_SEND_CONFIG: 'WAIT_SEND_CONFIG',
+ WAIT_CONFIRM_RSP: 'WAIT_CONFIRM_RSP',
+ WAIT_CONFIG: 'WAIT_CONFIG',
+ WAIT_SEND_CONFIG: 'WAIT_SEND_CONFIG',
WAIT_CONFIG_REQ_RSP: 'WAIT_CONFIG_REQ_RSP',
- WAIT_CONFIG_RSP: 'WAIT_CONFIG_RSP',
- WAIT_CONFIG_REQ: 'WAIT_CONFIG_REQ',
- WAIT_IND_FINAL_RSP: 'WAIT_IND_FINAL_RSP',
- WAIT_FINAL_RSP: 'WAIT_FINAL_RSP',
- WAIT_CONTROL_IND: 'WAIT_CONTROL_IND'
+ WAIT_CONFIG_RSP: 'WAIT_CONFIG_RSP',
+ WAIT_CONFIG_REQ: 'WAIT_CONFIG_REQ',
+ WAIT_IND_FINAL_RSP: 'WAIT_IND_FINAL_RSP',
+ WAIT_FINAL_RSP: 'WAIT_FINAL_RSP',
+ WAIT_CONTROL_IND: 'WAIT_CONTROL_IND',
}
def __init__(self, manager, connection, signaling_cid, psm, source_cid, mtu):
super().__init__()
- self.manager = manager
- self.connection = connection
- self.signaling_cid = signaling_cid
- self.state = Channel.CLOSED
- self.mtu = mtu
- self.psm = psm
- self.source_cid = source_cid
- self.destination_cid = 0
- self.response = None
+ self.manager = manager
+ self.connection = connection
+ self.signaling_cid = signaling_cid
+ self.state = Channel.CLOSED
+ self.mtu = mtu
+ self.psm = psm
+ self.source_cid = source_cid
+ self.destination_cid = 0
+ self.response = None
self.connection_result = None
- self.sink = None
+ self.disconnection_result = None
+ self.sink = None
def change_state(self, new_state):
- logger.debug(f'{self} state change -> {color(Channel.STATE_NAMES[new_state], "cyan")}')
+ logger.debug(
+ f'{self} state change -> {color(Channel.STATE_NAMES[new_state], "cyan")}'
+ )
self.state = new_state
def send_pdu(self, pdu):
self.manager.send_pdu(self.connection, self.destination_cid, pdu)
+ def send_control_frame(self, frame):
+ self.manager.send_control_frame(self.connection, self.signaling_cid, frame)
+
async def send_request(self, request):
# Check that there isn't already a request pending
if self.response:
@@ -623,29 +744,39 @@ class Channel(EventEmitter):
self.response.set_result(pdu)
self.response = None
elif self.sink:
+ # pylint: disable=not-callable
self.sink(pdu)
else:
- logger.warn(color('received pdu without a pending request or sink', 'red'))
-
- def send_control_frame(self, frame):
- self.manager.send_control_frame(self.connection, self.signaling_cid, frame)
+ logger.warning(
+ color('received pdu without a pending request or sink', 'red')
+ )
async def connect(self):
if self.state != Channel.CLOSED:
raise InvalidStateError('invalid state')
+ # Check that we can start a new connection
+ if self.connection_result:
+ raise RuntimeError('connection already pending')
+
self.change_state(Channel.WAIT_CONNECT_RSP)
self.send_control_frame(
L2CAP_Connection_Request(
- identifier = self.manager.next_identifier(self.connection),
- psm = self.psm,
- source_cid = self.source_cid
+ identifier=self.manager.next_identifier(self.connection),
+ psm=self.psm,
+ source_cid=self.source_cid,
)
)
- # Create a future to wait for the state machine to get to a success or error state
+ # Create a future to wait for the state machine to get to a success or error
+ # state
self.connection_result = asyncio.get_running_loop().create_future()
- return await self.connection_result
+
+ # Wait for the connection to succeed or fail
+ try:
+ return await self.connection_result
+ finally:
+ self.connection_result = None
async def disconnect(self):
if self.state != Channel.OPEN:
@@ -654,27 +785,37 @@ class Channel(EventEmitter):
self.change_state(Channel.WAIT_DISCONNECT)
self.send_control_frame(
L2CAP_Disconnection_Request(
- identifier = self.manager.next_identifier(self.connection),
- destination_cid = self.destination_cid,
- source_cid = self.source_cid
+ identifier=self.manager.next_identifier(self.connection),
+ destination_cid=self.destination_cid,
+ source_cid=self.source_cid,
)
)
- # Create a future to wait for the state machine to get to a success or error state
+ # Create a future to wait for the state machine to get to a success or error
+ # state
self.disconnection_result = asyncio.get_running_loop().create_future()
return await self.disconnection_result
+ def abort(self):
+ if self.state == self.OPEN:
+ self.change_state(self.CLOSED)
+ self.emit('close')
+
def send_configure_request(self):
- options = L2CAP_Control_Frame.encode_configuration_options([(
- L2CAP_MAXIMUM_TRANSMISSION_UNIT_CONFIGURATION_OPTION_TYPE,
- struct.pack('<H', L2CAP_DEFAULT_MTU)
- )])
+ options = L2CAP_Control_Frame.encode_configuration_options(
+ [
+ (
+ L2CAP_MAXIMUM_TRANSMISSION_UNIT_CONFIGURATION_OPTION_TYPE,
+ struct.pack('<H', L2CAP_DEFAULT_MTU),
+ )
+ ]
+ )
self.send_control_frame(
L2CAP_Configure_Request(
- identifier = self.manager.next_identifier(self.connection),
- destination_cid = self.destination_cid,
- flags = 0x0000,
- options = options
+ identifier=self.manager.next_identifier(self.connection),
+ destination_cid=self.destination_cid,
+ flags=0x0000,
+ options=options,
)
)
@@ -683,11 +824,11 @@ class Channel(EventEmitter):
self.change_state(Channel.WAIT_CONNECT)
self.send_control_frame(
L2CAP_Connection_Response(
- identifier = request.identifier,
- destination_cid = self.source_cid,
- source_cid = self.destination_cid,
- result = L2CAP_Connection_Response.CONNECTION_SUCCESSFUL,
- status = 0x0000
+ identifier=request.identifier,
+ destination_cid=self.source_cid,
+ source_cid=self.destination_cid,
+ result=L2CAP_Connection_Response.CONNECTION_SUCCESSFUL,
+ status=0x0000,
)
)
self.change_state(Channel.WAIT_CONFIG)
@@ -696,7 +837,7 @@ class Channel(EventEmitter):
def on_connection_response(self, response):
if self.state != Channel.WAIT_CONNECT_RSP:
- logger.warn(color('invalid state', 'red'))
+ logger.warning(color('invalid state', 'red'))
return
if response.result == L2CAP_Connection_Response.CONNECTION_SUCCESSFUL:
@@ -712,17 +853,18 @@ class Channel(EventEmitter):
ProtocolError(
response.result,
'l2cap',
- L2CAP_Connection_Response.result_name(response.result))
+ L2CAP_Connection_Response.result_name(response.result),
+ )
)
self.connection_result = None
def on_configure_request(self, request):
- if (
- self.state != Channel.WAIT_CONFIG and
- self.state != Channel.WAIT_CONFIG_REQ and
- self.state != Channel.WAIT_CONFIG_REQ_RSP
+ if self.state not in (
+ Channel.WAIT_CONFIG,
+ Channel.WAIT_CONFIG_REQ,
+ Channel.WAIT_CONFIG_REQ_RSP,
):
- logger.warn(color('invalid state', 'red'))
+ logger.warning(color('invalid state', 'red'))
return
# Decode the options
@@ -734,11 +876,11 @@ class Channel(EventEmitter):
self.send_control_frame(
L2CAP_Configure_Response(
- identifier = request.identifier,
- source_cid = self.destination_cid,
- flags = 0x0000,
- result = L2CAP_Configure_Response.SUCCESS,
- options = request.options # TODO: don't accept everthing blindly
+ identifier=request.identifier,
+ source_cid=self.destination_cid,
+ flags=0x0000,
+ result=L2CAP_Configure_Response.SUCCESS,
+ options=request.options, # TODO: don't accept everything blindly
)
)
if self.state == Channel.WAIT_CONFIG:
@@ -758,50 +900,61 @@ class Channel(EventEmitter):
if response.result == L2CAP_Configure_Response.SUCCESS:
if self.state == Channel.WAIT_CONFIG_REQ_RSP:
self.change_state(Channel.WAIT_CONFIG_REQ)
- elif self.state == Channel.WAIT_CONFIG_RSP or self.state == Channel.WAIT_CONTROL_IND:
+ elif self.state in (Channel.WAIT_CONFIG_RSP, Channel.WAIT_CONTROL_IND):
self.change_state(Channel.OPEN)
if self.connection_result:
self.connection_result.set_result(None)
self.connection_result = None
self.emit('open')
else:
- logger.warn(color('invalid state', 'red'))
- elif response.result == L2CAP_Configure_Response.FAILURE_UNACCEPTABLE_PARAMETERS:
+ logger.warning(color('invalid state', 'red'))
+ elif (
+ response.result == L2CAP_Configure_Response.FAILURE_UNACCEPTABLE_PARAMETERS
+ ):
# Re-configure with what's suggested in the response
self.send_control_frame(
L2CAP_Configure_Request(
- identifier = self.manager.next_identifier(self.connection),
- destination_cid = self.destination_cid,
- flags = 0x0000,
- options = response.options
+ identifier=self.manager.next_identifier(self.connection),
+ destination_cid=self.destination_cid,
+ flags=0x0000,
+ options=response.options,
)
)
else:
- logger.warn(color(f'!!! configuration rejected: {L2CAP_Configure_Response.result_name(response.result)}', 'red'))
+ logger.warning(
+ color(
+ '!!! configuration rejected: '
+ f'{L2CAP_Configure_Response.result_name(response.result)}',
+ 'red',
+ )
+ )
# TODO: decide how to fail gracefully
def on_disconnection_request(self, request):
- if self.state == Channel.OPEN or self.state == Channel.WAIT_DISCONNECT:
+ if self.state in (Channel.OPEN, Channel.WAIT_DISCONNECT):
self.send_control_frame(
L2CAP_Disconnection_Response(
- identifier = request.identifier,
- destination_cid = request.destination_cid,
- source_cid = request.source_cid
+ identifier=request.identifier,
+ destination_cid=request.destination_cid,
+ source_cid=request.source_cid,
)
)
self.change_state(Channel.CLOSED)
self.emit('close')
self.manager.on_channel_closed(self)
else:
- logger.warn(color('invalid state', 'red'))
+ logger.warning(color('invalid state', 'red'))
def on_disconnection_response(self, response):
if self.state != Channel.WAIT_DISCONNECT:
- logger.warn(color('invalid state', 'red'))
+ logger.warning(color('invalid state', 'red'))
return
- if response.destination_cid != self.destination_cid or response.source_cid != self.source_cid:
- logger.warn('unexpected source or destination CID')
+ if (
+ response.destination_cid != self.destination_cid
+ or response.source_cid != self.source_cid
+ ):
+ logger.warning('unexpected source or destination CID')
return
self.change_state(Channel.CLOSED)
@@ -812,62 +965,594 @@ class Channel(EventEmitter):
self.manager.on_channel_closed(self)
def __str__(self):
- return f'Channel({self.source_cid}->{self.destination_cid}, PSM={self.psm}, MTU={self.mtu}, state={Channel.STATE_NAMES[self.state]})'
+ return (
+ f'Channel({self.source_cid}->{self.destination_cid}, '
+ f'PSM={self.psm}, '
+ f'MTU={self.mtu}, '
+ f'state={Channel.STATE_NAMES[self.state]})'
+ )
+
+
+# -----------------------------------------------------------------------------
+class LeConnectionOrientedChannel(EventEmitter):
+ """
+ LE Credit-based Connection Oriented Channel
+ """
+
+ INIT = 0
+ CONNECTED = 1
+ CONNECTING = 2
+ DISCONNECTING = 3
+ DISCONNECTED = 4
+ CONNECTION_ERROR = 5
+
+ STATE_NAMES = {
+ INIT: 'INIT',
+ CONNECTED: 'CONNECTED',
+ CONNECTING: 'CONNECTING',
+ DISCONNECTING: 'DISCONNECTING',
+ DISCONNECTED: 'DISCONNECTED',
+ CONNECTION_ERROR: 'CONNECTION_ERROR',
+ }
+
+ @staticmethod
+ def state_name(state):
+ return name_or_number(LeConnectionOrientedChannel.STATE_NAMES, state)
+
+ def __init__(
+ self,
+ manager,
+ connection,
+ le_psm,
+ source_cid,
+ destination_cid,
+ mtu,
+ mps,
+ credits, # pylint: disable=redefined-builtin
+ peer_mtu,
+ peer_mps,
+ peer_credits,
+ connected,
+ ):
+ super().__init__()
+ self.manager = manager
+ self.connection = connection
+ self.le_psm = le_psm
+ self.source_cid = source_cid
+ self.destination_cid = destination_cid
+ self.mtu = mtu
+ self.mps = mps
+ self.credits = credits
+ self.peer_mtu = peer_mtu
+ self.peer_mps = peer_mps
+ self.peer_credits = peer_credits
+ self.peer_max_credits = self.peer_credits
+ self.peer_credits_threshold = self.peer_max_credits // 2
+ self.in_sdu = None
+ self.in_sdu_length = 0
+ self.out_queue = deque()
+ self.out_sdu = None
+ self.sink = None
+ self.connected = False
+ self.connection_result = None
+ self.disconnection_result = None
+ self.drained = asyncio.Event()
+
+ self.drained.set()
+
+ if connected:
+ self.state = LeConnectionOrientedChannel.CONNECTED
+ else:
+ self.state = LeConnectionOrientedChannel.INIT
+
+ def change_state(self, new_state):
+ logger.debug(
+ f'{self} state change -> {color(self.state_name(new_state), "cyan")}'
+ )
+ self.state = new_state
+
+ if new_state == self.CONNECTED:
+ self.emit('open')
+ elif new_state == self.DISCONNECTED:
+ self.emit('close')
+
+ def send_pdu(self, pdu):
+ self.manager.send_pdu(self.connection, self.destination_cid, pdu)
+
+ def send_control_frame(self, frame):
+ self.manager.send_control_frame(self.connection, L2CAP_LE_SIGNALING_CID, frame)
+
+ async def connect(self):
+ # Check that we're in the right state
+ if self.state != self.INIT:
+ raise InvalidStateError('not in a connectable state')
+
+ # Check that we can start a new connection
+ identifier = self.manager.next_identifier(self.connection)
+ if identifier in self.manager.le_coc_requests:
+ raise RuntimeError('too many concurrent connection requests')
+
+ self.change_state(self.CONNECTING)
+ request = L2CAP_LE_Credit_Based_Connection_Request(
+ identifier=identifier,
+ le_psm=self.le_psm,
+ source_cid=self.source_cid,
+ mtu=self.mtu,
+ mps=self.mps,
+ initial_credits=self.peer_credits,
+ )
+ self.manager.le_coc_requests[identifier] = request
+ self.send_control_frame(request)
+
+ # Create a future to wait for the response
+ self.connection_result = asyncio.get_running_loop().create_future()
+
+ # Wait for the connection to succeed or fail
+ return await self.connection_result
+
+ async def disconnect(self):
+ # Check that we're connected
+ if self.state != self.CONNECTED:
+ raise InvalidStateError('not connected')
+
+ self.change_state(self.DISCONNECTING)
+ self.flush_output()
+ self.send_control_frame(
+ L2CAP_Disconnection_Request(
+ identifier=self.manager.next_identifier(self.connection),
+ destination_cid=self.destination_cid,
+ source_cid=self.source_cid,
+ )
+ )
+
+ # Create a future to wait for the state machine to get to a success or error
+ # state
+ self.disconnection_result = asyncio.get_running_loop().create_future()
+ return await self.disconnection_result
+
+ def abort(self):
+ if self.state == self.CONNECTED:
+ self.change_state(self.DISCONNECTED)
+
+ def on_pdu(self, pdu):
+ if self.sink is None:
+ logger.warning('received pdu without a sink')
+ return
+
+ if self.state != self.CONNECTED:
+ logger.warning('received PDU while not connected, dropping')
+
+ # Manage the peer credits
+ if self.peer_credits == 0:
+ logger.warning('received LE frame when peer out of credits')
+ else:
+ self.peer_credits -= 1
+ if self.peer_credits <= self.peer_credits_threshold:
+ # The credits fell below the threshold, replenish them to the max
+ self.send_control_frame(
+ L2CAP_LE_Flow_Control_Credit(
+ identifier=self.manager.next_identifier(self.connection),
+ cid=self.source_cid,
+ credits=self.peer_max_credits - self.peer_credits,
+ )
+ )
+ self.peer_credits = self.peer_max_credits
+
+ # Check if this starts a new SDU
+ if self.in_sdu is None:
+ # Start a new SDU
+ self.in_sdu = pdu
+ else:
+ # Continue an SDU
+ self.in_sdu += pdu
+
+ # Check if the SDU is complete
+ if self.in_sdu_length == 0:
+ # We don't know the size yet, check if we have received the header to
+ # compute it
+ if len(self.in_sdu) >= 2:
+ self.in_sdu_length = struct.unpack_from('<H', self.in_sdu, 0)[0]
+ if self.in_sdu_length == 0:
+ # We'll compute it later
+ return
+ if len(self.in_sdu) < 2 + self.in_sdu_length:
+ # Not complete yet
+ logger.debug(
+ f'SDU: {len(self.in_sdu) - 2} of {self.in_sdu_length} bytes received'
+ )
+ return
+ if len(self.in_sdu) != 2 + self.in_sdu_length:
+ # Overflow
+ logger.warning(
+ f'SDU overflow: sdu_length={self.in_sdu_length}, '
+ f'received {len(self.in_sdu) - 2}'
+ )
+ # TODO: we should disconnect
+ self.in_sdu = None
+ self.in_sdu_length = 0
+ return
+
+ # Send the SDU to the sink
+ logger.debug(f'SDU complete: 2+{len(self.in_sdu) - 2} bytes')
+ self.sink(self.in_sdu[2:]) # pylint: disable=not-callable
+
+ # Prepare for a new SDU
+ self.in_sdu = None
+ self.in_sdu_length = 0
+
+ def on_connection_response(self, response):
+ # Look for a matching pending response result
+ if self.connection_result is None:
+ logger.warning(
+ f'received unexpected connection response (id={response.identifier})'
+ )
+ return
+
+ if (
+ response.result
+ == L2CAP_LE_Credit_Based_Connection_Response.CONNECTION_SUCCESSFUL
+ ):
+ self.destination_cid = response.destination_cid
+ self.peer_mtu = response.mtu
+ self.peer_mps = response.mps
+ self.credits = response.initial_credits
+ self.connected = True
+ self.connection_result.set_result(self)
+ self.change_state(self.CONNECTED)
+ else:
+ self.connection_result.set_exception(
+ ProtocolError(
+ response.result,
+ 'l2cap',
+ L2CAP_LE_Credit_Based_Connection_Response.result_name(
+ response.result
+ ),
+ )
+ )
+ self.change_state(self.CONNECTION_ERROR)
+
+ # Cleanup
+ self.connection_result = None
+
+ def on_credits(self, credits): # pylint: disable=redefined-builtin
+ self.credits += credits
+ logger.debug(f'received {credits} credits, total = {self.credits}')
+
+ # Try to send more data if we have any queued up
+ self.process_output()
+
+ def on_disconnection_request(self, request):
+ self.send_control_frame(
+ L2CAP_Disconnection_Response(
+ identifier=request.identifier,
+ destination_cid=request.destination_cid,
+ source_cid=request.source_cid,
+ )
+ )
+ self.change_state(self.DISCONNECTED)
+ self.flush_output()
+
+ def on_disconnection_response(self, response):
+ if self.state != self.DISCONNECTING:
+ logger.warning(color('invalid state', 'red'))
+ return
+
+ if (
+ response.destination_cid != self.destination_cid
+ or response.source_cid != self.source_cid
+ ):
+ logger.warning('unexpected source or destination CID')
+ return
+
+ self.change_state(self.DISCONNECTED)
+ if self.disconnection_result:
+ self.disconnection_result.set_result(None)
+ self.disconnection_result = None
+
+ def flush_output(self):
+ self.out_queue.clear()
+ self.out_sdu = None
+
+ def process_output(self):
+ while self.credits > 0:
+ if self.out_sdu is not None:
+ # Finish the current SDU
+ packet = self.out_sdu[: self.peer_mps]
+ self.send_pdu(packet)
+ self.credits -= 1
+ logger.debug(f'sent {len(packet)} bytes, {self.credits} credits left')
+ if len(packet) == len(self.out_sdu):
+ # We sent everything
+ self.out_sdu = None
+ else:
+ # Keep what's still left to send
+ self.out_sdu = self.out_sdu[len(packet) :]
+ continue
+
+ if self.out_queue:
+ # Create the next SDU (2 bytes header plus up to MTU bytes payload)
+ logger.debug(
+ f'assembling SDU from {len(self.out_queue)} packets in output queue'
+ )
+ payload = b''
+ while self.out_queue and len(payload) < self.peer_mtu:
+ # We can add more data to the payload
+ chunk = self.out_queue[0][: self.peer_mtu - len(payload)]
+ payload += chunk
+ self.out_queue[0] = self.out_queue[0][len(chunk) :]
+ if len(self.out_queue[0]) == 0:
+ # We consumed the entire buffer, remove it
+ self.out_queue.popleft()
+ logger.debug(
+ f'packet completed, {len(self.out_queue)} left in queue'
+ )
+
+ # Construct the SDU with its header
+ assert len(payload) != 0
+ logger.debug(f'SDU complete: {len(payload)} payload bytes')
+ self.out_sdu = struct.pack('<H', len(payload)) + payload
+ else:
+ # Nothing left to send for now
+ self.drained.set()
+ return
+
+ def write(self, data):
+ if self.state != self.CONNECTED:
+ logger.warning('not connected, dropping data')
+ return
+
+ # Queue the data
+ self.out_queue.append(data)
+ self.drained.clear()
+ logger.debug(
+ f'{len(data)} bytes packet queued, {len(self.out_queue)} packets in queue'
+ )
+
+ # Send what we can
+ self.process_output()
+
+ async def drain(self):
+ await self.drained.wait()
+
+ def pause_reading(self):
+ # TODO: not implemented yet
+ pass
+
+ def resume_reading(self):
+ # TODO: not implemented yet
+ pass
+
+ def __str__(self):
+ return (
+ f'CoC({self.source_cid}->{self.destination_cid}, '
+ f'State={self.state_name(self.state)}, '
+ f'PSM={self.le_psm}, '
+ f'MTU={self.mtu}/{self.peer_mtu}, '
+ f'MPS={self.mps}/{self.peer_mps}, '
+ f'credits={self.credits}/{self.peer_credits})'
+ )
# -----------------------------------------------------------------------------
class ChannelManager:
- def __init__(self):
- self.host = None
- self.channels = {} # Channels, mapped by connection and cid
+ def __init__(
+ self, extended_features=(), connectionless_mtu=L2CAP_DEFAULT_CONNECTIONLESS_MTU
+ ):
+ self._host = None
self.identifiers = {} # Incrementing identifier values by connection
- self.servers = {} # Servers accepting connections, by PSM
+ self.channels = {} # All channels, mapped by connection and source cid
+ self.fixed_channels = { # Fixed channel handlers, mapped by cid
+ L2CAP_SIGNALING_CID: None,
+ L2CAP_LE_SIGNALING_CID: None,
+ }
+ self.servers = {} # Servers accepting connections, by PSM
+ self.le_coc_channels = (
+ {}
+ ) # LE CoC channels, mapped by connection and destination cid
+ self.le_coc_servers = {} # LE CoC - Servers accepting connections, by PSM
+ self.le_coc_requests = {} # LE CoC connection requests, by identifier
+ self.extended_features = extended_features
+ self.connectionless_mtu = connectionless_mtu
+
+ @property
+ def host(self):
+ return self._host
+
+ @host.setter
+ def host(self, host):
+ if self._host is not None:
+ self._host.remove_listener('disconnection', self.on_disconnection)
+ self._host = host
+ if host is not None:
+ host.on('disconnection', self.on_disconnection)
def find_channel(self, connection_handle, cid):
if connection_channels := self.channels.get(connection_handle):
return connection_channels.get(cid)
+ return None
+
+ def find_le_coc_channel(self, connection_handle, cid):
+ if connection_channels := self.le_coc_channels.get(connection_handle):
+ return connection_channels.get(cid)
+
+ return None
+
@staticmethod
def find_free_br_edr_cid(channels):
# Pick the smallest valid CID that's not already in the list
# (not necessarily the most efficient algorithm, but the list of CID is
# very small in practice)
- for cid in range(L2CAP_ACL_U_DYNAMIC_CID_RANGE_START, L2CAP_ACL_U_DYNAMIC_CID_RANGE_END + 1):
+ for cid in range(
+ L2CAP_ACL_U_DYNAMIC_CID_RANGE_START, L2CAP_ACL_U_DYNAMIC_CID_RANGE_END + 1
+ ):
+ if cid not in channels:
+ return cid
+
+ raise RuntimeError('no free CID available')
+
+ @staticmethod
+ def find_free_le_cid(channels):
+ # Pick the smallest valid CID that's not already in the list
+ # (not necessarily the most efficient algorithm, but the list of CID is
+ # very small in practice)
+ for cid in range(
+ L2CAP_LE_U_DYNAMIC_CID_RANGE_START, L2CAP_LE_U_DYNAMIC_CID_RANGE_END + 1
+ ):
if cid not in channels:
return cid
+ raise RuntimeError('no free CID')
+
+ @staticmethod
+ def check_le_coc_parameters(max_credits, mtu, mps):
+ if (
+ max_credits < 1
+ or max_credits > L2CAP_LE_CREDIT_BASED_CONNECTION_MAX_CREDITS
+ ):
+ raise ValueError('max credits out of range')
+ if mtu < L2CAP_LE_CREDIT_BASED_CONNECTION_MIN_MTU:
+ raise ValueError('MTU too small')
+ if (
+ mps < L2CAP_LE_CREDIT_BASED_CONNECTION_MIN_MPS
+ or mps > L2CAP_LE_CREDIT_BASED_CONNECTION_MAX_MPS
+ ):
+ raise ValueError('MPS out of range')
+
def next_identifier(self, connection):
identifier = (self.identifiers.setdefault(connection.handle, 0) + 1) % 256
self.identifiers[connection.handle] = identifier
return identifier
+ def register_fixed_channel(self, cid, handler):
+ self.fixed_channels[cid] = handler
+
+ def deregister_fixed_channel(self, cid):
+ if cid in self.fixed_channels:
+ del self.fixed_channels[cid]
+
def register_server(self, psm, server):
+ if psm == 0:
+ # Find a free PSM
+ for candidate in range(
+ L2CAP_PSM_DYNAMIC_RANGE_START, L2CAP_PSM_DYNAMIC_RANGE_END + 1, 2
+ ):
+ if (candidate >> 8) % 2 == 1:
+ continue
+ if candidate in self.servers:
+ continue
+ psm = candidate
+ break
+ else:
+ raise InvalidStateError('no free PSM')
+ else:
+ # Check that the PSM isn't already in use
+ if psm in self.servers:
+ raise ValueError('PSM already in use')
+
+ # Check that the PSM is valid
+ if psm % 2 == 0:
+ raise ValueError('invalid PSM (not odd)')
+ check = psm >> 8
+ while check:
+ if check % 2 != 0:
+ raise ValueError('invalid PSM')
+ check >>= 8
+
self.servers[psm] = server
+ return psm
+
+ def register_le_coc_server(
+ self,
+ psm,
+ server,
+ max_credits=L2CAP_LE_CREDIT_BASED_CONNECTION_DEFAULT_INITIAL_CREDITS,
+ mtu=L2CAP_LE_CREDIT_BASED_CONNECTION_DEFAULT_MTU,
+ mps=L2CAP_LE_CREDIT_BASED_CONNECTION_DEFAULT_MPS,
+ ):
+ self.check_le_coc_parameters(max_credits, mtu, mps)
+
+ if psm == 0:
+ # Find a free PSM
+ for candidate in range(
+ L2CAP_LE_PSM_DYNAMIC_RANGE_START, L2CAP_LE_PSM_DYNAMIC_RANGE_END + 1
+ ):
+ if candidate in self.le_coc_servers:
+ continue
+ psm = candidate
+ break
+ else:
+ raise InvalidStateError('no free PSM')
+ else:
+ # Check that the PSM isn't already in use
+ if psm in self.le_coc_servers:
+ raise ValueError('PSM already in use')
+
+ self.le_coc_servers[psm] = (
+ server,
+ max_credits or L2CAP_LE_CREDIT_BASED_CONNECTION_DEFAULT_INITIAL_CREDITS,
+ mtu or L2CAP_LE_CREDIT_BASED_CONNECTION_DEFAULT_MTU,
+ mps or L2CAP_LE_CREDIT_BASED_CONNECTION_DEFAULT_MPS,
+ )
+
+ return psm
+
+ def on_disconnection(self, connection_handle, _reason):
+ logger.debug(f'disconnection from {connection_handle}, cleaning up channels')
+ if connection_handle in self.channels:
+ for _, channel in self.channels[connection_handle].items():
+ channel.abort()
+ del self.channels[connection_handle]
+ if connection_handle in self.le_coc_channels:
+ for _, channel in self.le_coc_channels[connection_handle].items():
+ channel.abort()
+ del self.le_coc_channels[connection_handle]
+ if connection_handle in self.identifiers:
+ del self.identifiers[connection_handle]
+
def send_pdu(self, connection, cid, pdu):
- pdu_str = pdu.hex() if type(pdu) is bytes else str(pdu)
- logger.debug(f'{color(">>> Sending L2CAP PDU", "blue")} on connection [0x{connection.handle:04X}] (CID={cid}) {connection.peer_address}: {pdu_str}')
+ pdu_str = pdu.hex() if isinstance(pdu, bytes) else str(pdu)
+ logger.debug(
+ f'{color(">>> Sending L2CAP PDU", "blue")} '
+ f'on connection [0x{connection.handle:04X}] (CID={cid}) '
+ f'{connection.peer_address}: {pdu_str}'
+ )
self.host.send_l2cap_pdu(connection.handle, cid, bytes(pdu))
def on_pdu(self, connection, cid, pdu):
- if cid == L2CAP_SIGNALING_CID or cid == L2CAP_LE_SIGNALING_CID:
+ if cid in (L2CAP_SIGNALING_CID, L2CAP_LE_SIGNALING_CID):
# Parse the L2CAP payload into a Control Frame object
control_frame = L2CAP_Control_Frame.from_bytes(pdu)
self.on_control_frame(connection, cid, control_frame)
+ elif cid in self.fixed_channels:
+ self.fixed_channels[cid](connection.handle, pdu)
else:
if (channel := self.find_channel(connection.handle, cid)) is None:
- logger.warn(color(f'channel not found for 0x{connection.handle:04X}:{cid}', 'red'))
+ logger.warning(
+ color(
+ f'channel not found for 0x{connection.handle:04X}:{cid}', 'red'
+ )
+ )
return
channel.on_pdu(pdu)
def send_control_frame(self, connection, cid, control_frame):
- logger.debug(f'{color(">>> Sending L2CAP Signaling Control Frame", "blue")} on connection [0x{connection.handle:04X}] (CID={cid}) {connection.peer_address}:\n{control_frame}')
+ logger.debug(
+ f'{color(">>> Sending L2CAP Signaling Control Frame", "blue")} '
+ f'on connection [0x{connection.handle:04X}] (CID={cid}) '
+ f'{connection.peer_address}:\n{control_frame}'
+ )
self.host.send_l2cap_pdu(connection.handle, cid, bytes(control_frame))
def on_control_frame(self, connection, cid, control_frame):
- logger.debug(f'{color("<<< Received L2CAP Signaling Control Frame", "green")} on connection [0x{connection.handle:04X}] (CID={cid}) {connection.peer_address}:\n{control_frame}')
+ logger.debug(
+ f'{color("<<< Received L2CAP Signaling Control Frame", "green")} '
+ f'on connection [0x{connection.handle:04X}] (CID={cid}) '
+ f'{connection.peer_address}:\n{control_frame}'
+ )
# Find the handler method
handler_name = f'on_{control_frame.name.lower()}'
@@ -881,10 +1566,10 @@ class ChannelManager:
connection,
cid,
L2CAP_Command_Reject(
- identifier = control_frame.identifier,
- reason = L2CAP_COMMAND_NOT_UNDERSTOOD_REASON,
- data = b''
- )
+ identifier=control_frame.identifier,
+ reason=L2CAP_COMMAND_NOT_UNDERSTOOD_REASON,
+ data=b'',
+ ),
)
raise error
else:
@@ -893,15 +1578,14 @@ class ChannelManager:
connection,
cid,
L2CAP_Command_Reject(
- identifier = control_frame.identifier,
- reason = L2CAP_COMMAND_NOT_UNDERSTOOD_REASON,
- data = b''
- )
+ identifier=control_frame.identifier,
+ reason=L2CAP_COMMAND_NOT_UNDERSTOOD_REASON,
+ data=b'',
+ ),
)
- def on_l2cap_command_reject(self, connection, cid, packet):
+ def on_l2cap_command_reject(self, _connection, _cid, packet):
logger.warning(f'{color("!!! Command rejected:", "red")} {packet.reason}')
- pass
def on_l2cap_connection_request(self, connection, cid, request):
# Check if there's a server for this PSM
@@ -915,68 +1599,117 @@ class ChannelManager:
connection,
cid,
L2CAP_Connection_Response(
- identifier = request.identifier,
- destination_cid = request.source_cid,
- source_cid = 0,
- result = L2CAP_Connection_Response.CONNECTION_REFUSED_NO_RESOURCES_AVAILABLE,
- status = 0x0000
- )
+ identifier=request.identifier,
+ destination_cid=request.source_cid,
+ source_cid=0,
+ # pylint: disable=line-too-long
+ result=L2CAP_Connection_Response.CONNECTION_REFUSED_NO_RESOURCES_AVAILABLE,
+ status=0x0000,
+ ),
)
return
# Create a new channel
- logger.debug(f'creating server channel with cid={source_cid} for psm {request.psm}')
- channel = Channel(self, connection, cid, request.psm, source_cid, L2CAP_MIN_BR_EDR_MTU)
+ logger.debug(
+ f'creating server channel with cid={source_cid} for psm {request.psm}'
+ )
+ channel = Channel(
+ self, connection, cid, request.psm, source_cid, L2CAP_MIN_BR_EDR_MTU
+ )
connection_channels[source_cid] = channel
# Notify
server(channel)
channel.on_connection_request(request)
else:
- logger.warn(f'No server for connection 0x{connection.handle:04X} on PSM {request.psm}')
+ logger.warning(
+ f'No server for connection 0x{connection.handle:04X} '
+ f'on PSM {request.psm}'
+ )
self.send_control_frame(
connection,
cid,
L2CAP_Connection_Response(
- identifier = request.identifier,
- destination_cid = request.source_cid,
- source_cid = 0,
- result = L2CAP_Connection_Response.CONNECTION_REFUSED_LE_PSM_NOT_SUPPORTED,
- status = 0x0000
- )
+ identifier=request.identifier,
+ destination_cid=request.source_cid,
+ source_cid=0,
+ # pylint: disable=line-too-long
+ result=L2CAP_Connection_Response.CONNECTION_REFUSED_PSM_NOT_SUPPORTED,
+ status=0x0000,
+ ),
)
def on_l2cap_connection_response(self, connection, cid, response):
- if (channel := self.find_channel(connection.handle, response.source_cid)) is None:
- logger.warn(color(f'channel {response.source_cid} not found for 0x{connection.handle:04X}:{cid}', 'red'))
+ if (
+ channel := self.find_channel(connection.handle, response.source_cid)
+ ) is None:
+ logger.warning(
+ color(
+ f'channel {response.source_cid} not found for '
+ f'0x{connection.handle:04X}:{cid}',
+ 'red',
+ )
+ )
return
channel.on_connection_response(response)
def on_l2cap_configure_request(self, connection, cid, request):
- if (channel := self.find_channel(connection.handle, request.destination_cid)) is None:
- logger.warn(color(f'channel {request.destination_cid} not found for 0x{connection.handle:04X}:{cid}', 'red'))
+ if (
+ channel := self.find_channel(connection.handle, request.destination_cid)
+ ) is None:
+ logger.warning(
+ color(
+ f'channel {request.destination_cid} not found for '
+ f'0x{connection.handle:04X}:{cid}',
+ 'red',
+ )
+ )
return
channel.on_configure_request(request)
def on_l2cap_configure_response(self, connection, cid, response):
- if (channel := self.find_channel(connection.handle, response.source_cid)) is None:
- logger.warn(color(f'channel {response.source_cid} not found for 0x{connection.handle:04X}:{cid}', 'red'))
+ if (
+ channel := self.find_channel(connection.handle, response.source_cid)
+ ) is None:
+ logger.warning(
+ color(
+ f'channel {response.source_cid} not found for '
+ f'0x{connection.handle:04X}:{cid}',
+ 'red',
+ )
+ )
return
channel.on_configure_response(response)
def on_l2cap_disconnection_request(self, connection, cid, request):
- if (channel := self.find_channel(connection.handle, request.destination_cid)) is None:
- logger.warn(color(f'channel {request.destination_cid} not found for 0x{connection.handle:04X}:{cid}', 'red'))
+ if (
+ channel := self.find_channel(connection.handle, request.destination_cid)
+ ) is None:
+ logger.warning(
+ color(
+ f'channel {request.destination_cid} not found for '
+ f'0x{connection.handle:04X}:{cid}',
+ 'red',
+ )
+ )
return
channel.on_disconnection_request(request)
def on_l2cap_disconnection_response(self, connection, cid, response):
- if (channel := self.find_channel(connection.handle, response.source_cid)) is None:
- logger.warn(color(f'channel {response.source_cid} not found for 0x{connection.handle:04X}:{cid}', 'red'))
+ if (
+ channel := self.find_channel(connection.handle, response.source_cid)
+ ) is None:
+ logger.warning(
+ color(
+ f'channel {response.source_cid} not found for '
+ f'0x{connection.handle:04X}:{cid}',
+ 'red',
+ )
+ )
return
channel.on_disconnection_response(response)
@@ -986,38 +1719,35 @@ class ChannelManager:
self.send_control_frame(
connection,
cid,
- L2CAP_Echo_Response(
- identifier = request.identifier,
- data = request.data
- )
+ L2CAP_Echo_Response(identifier=request.identifier, data=request.data),
)
- def on_l2cap_echo_response(self, connection, cid, response):
+ def on_l2cap_echo_response(self, _connection, _cid, response):
logger.debug(f'<<< Echo response: data={response.data.hex()}')
# TODO notify listeners
def on_l2cap_information_request(self, connection, cid, request):
if request.info_type == L2CAP_Information_Request.CONNECTIONLESS_MTU:
result = L2CAP_Information_Response.SUCCESS
- data = struct.pack('<H', 1024) # TODO: don't use a fixed value
+ data = self.connectionless_mtu.to_bytes(2, 'little')
elif request.info_type == L2CAP_Information_Request.EXTENDED_FEATURES_SUPPORTED:
result = L2CAP_Information_Response.SUCCESS
- data = bytes.fromhex('00000000') # TODO: don't use a fixed value
+ data = sum(self.extended_features).to_bytes(4, 'little')
elif request.info_type == L2CAP_Information_Request.FIXED_CHANNELS_SUPPORTED:
result = L2CAP_Information_Response.SUCCESS
- data = bytes.fromhex('FFFFFFFFFFFFFFFF') # TODO: don't use a fixed value
+ data = sum(1 << cid for cid in self.fixed_channels).to_bytes(8, 'little')
else:
- result = L2CAP_Information_Request.NO_SUPPORTED
+ result = L2CAP_Information_Response.NOT_SUPPORTED
self.send_control_frame(
connection,
cid,
L2CAP_Information_Response(
- identifier = request.identifier,
- info_type = request.info_type,
- result = result,
- data = data
- )
+ identifier=request.identifier,
+ info_type=request.info_type,
+ result=result,
+ data=data,
+ ),
)
def on_l2cap_connection_parameter_update_request(self, connection, cid, request):
@@ -1026,49 +1756,167 @@ class ChannelManager:
connection,
cid,
L2CAP_Connection_Parameter_Update_Response(
- identifier = request.identifier,
- result = L2CAP_CONNECTION_PARAMETERS_ACCEPTED_RESULT
+ identifier=request.identifier,
+ result=L2CAP_CONNECTION_PARAMETERS_ACCEPTED_RESULT,
+ ),
+ )
+ self.host.send_command_sync(
+ HCI_LE_Connection_Update_Command(
+ connection_handle=connection.handle,
+ connection_interval_min=request.interval_min,
+ connection_interval_max=request.interval_max,
+ max_latency=request.latency,
+ supervision_timeout=request.timeout,
+ min_ce_length=0,
+ max_ce_length=0,
)
)
- self.host.send_command_sync(HCI_LE_Connection_Update_Command(
- connection_handle = connection.handle,
- conn_interval_min = request.interval_min,
- conn_interval_max = request.interval_max,
- conn_latency = request.slave_latency,
- supervision_timeout = request.timeout_multiplier,
- minimum_ce_length = 0,
- maximum_ce_length = 0
- ))
else:
self.send_control_frame(
connection,
cid,
L2CAP_Connection_Parameter_Update_Response(
- identifier = request.identifier,
- result = L2CAP_CONNECTION_PARAMETERS_REJECTED_RESULT
- )
+ identifier=request.identifier,
+ result=L2CAP_CONNECTION_PARAMETERS_REJECTED_RESULT,
+ ),
)
def on_l2cap_connection_parameter_update_response(self, connection, cid, response):
+ # TODO: check response
pass
def on_l2cap_le_credit_based_connection_request(self, connection, cid, request):
- # FIXME: temp fixed values
- self.send_control_frame(
- connection,
- cid,
- L2CAP_LE_Credit_Based_Connection_Response(
- identifier = request.identifier,
- destination_cid = 194, # FIXME: for testing only
- mtu = L2CAP_LE_CREDIT_BASED_CONNECTION_DEFAULT_MTU,
- mps = L2CAP_LE_CREDIT_BASED_CONNECTION_DEFAULT_MPS,
- initial_credits = 3, # FIXME: for testing only
- result = L2CAP_LE_Credit_Based_Connection_Response.CONNECTION_SUCCESSFUL
+ if request.le_psm in self.le_coc_servers:
+ (server, max_credits, mtu, mps) = self.le_coc_servers[request.le_psm]
+
+ # Check that the CID isn't already used
+ le_connection_channels = self.le_coc_channels.setdefault(
+ connection.handle, {}
)
- )
+ if request.source_cid in le_connection_channels:
+ logger.warning(f'source CID {request.source_cid} already in use')
+ self.send_control_frame(
+ connection,
+ cid,
+ L2CAP_LE_Credit_Based_Connection_Response(
+ identifier=request.identifier,
+ destination_cid=0,
+ mtu=mtu,
+ mps=mps,
+ initial_credits=0,
+ # pylint: disable=line-too-long
+ result=L2CAP_LE_Credit_Based_Connection_Response.CONNECTION_REFUSED_SOURCE_CID_ALREADY_ALLOCATED,
+ ),
+ )
+ return
- def on_l2cap_le_flow_control_credit(self, connection, cid, packet):
- pass
+ # Find a free CID for this new channel
+ connection_channels = self.channels.setdefault(connection.handle, {})
+ source_cid = self.find_free_le_cid(connection_channels)
+ if source_cid is None: # Should never happen!
+ self.send_control_frame(
+ connection,
+ cid,
+ L2CAP_LE_Credit_Based_Connection_Response(
+ identifier=request.identifier,
+ destination_cid=0,
+ mtu=mtu,
+ mps=mps,
+ initial_credits=0,
+ # pylint: disable=line-too-long
+ result=L2CAP_LE_Credit_Based_Connection_Response.CONNECTION_REFUSED_NO_RESOURCES_AVAILABLE,
+ ),
+ )
+ return
+
+ # Create a new channel
+ logger.debug(
+ f'creating LE CoC server channel with cid={source_cid} for psm '
+ f'{request.le_psm}'
+ )
+ channel = LeConnectionOrientedChannel(
+ self,
+ connection,
+ request.le_psm,
+ source_cid,
+ request.source_cid,
+ mtu,
+ mps,
+ request.initial_credits,
+ request.mtu,
+ request.mps,
+ max_credits,
+ True,
+ )
+ connection_channels[source_cid] = channel
+ le_connection_channels[request.source_cid] = channel
+
+ # Respond
+ self.send_control_frame(
+ connection,
+ cid,
+ L2CAP_LE_Credit_Based_Connection_Response(
+ identifier=request.identifier,
+ destination_cid=source_cid,
+ mtu=mtu,
+ mps=mps,
+ initial_credits=max_credits,
+ # pylint: disable=line-too-long
+ result=L2CAP_LE_Credit_Based_Connection_Response.CONNECTION_SUCCESSFUL,
+ ),
+ )
+
+ # Notify
+ server(channel)
+ else:
+ logger.info(
+ f'No LE server for connection 0x{connection.handle:04X} '
+ f'on PSM {request.le_psm}'
+ )
+ self.send_control_frame(
+ connection,
+ cid,
+ L2CAP_LE_Credit_Based_Connection_Response(
+ identifier=request.identifier,
+ destination_cid=0,
+ mtu=L2CAP_LE_CREDIT_BASED_CONNECTION_DEFAULT_MTU,
+ mps=L2CAP_LE_CREDIT_BASED_CONNECTION_DEFAULT_MPS,
+ initial_credits=0,
+ # pylint: disable=line-too-long
+ result=L2CAP_LE_Credit_Based_Connection_Response.CONNECTION_REFUSED_LE_PSM_NOT_SUPPORTED,
+ ),
+ )
+
+ def on_l2cap_le_credit_based_connection_response(self, connection, _cid, response):
+ # Find the pending request by identifier
+ request = self.le_coc_requests.get(response.identifier)
+ if request is None:
+ logger.warning(color('!!! received response for unknown request', 'red'))
+ return
+ del self.le_coc_requests[response.identifier]
+
+ # Find the channel for this request
+ channel = self.find_channel(connection.handle, request.source_cid)
+ if channel is None:
+ logger.warning(
+ color(
+ 'received connection response for an unknown channel '
+ f'(cid={request.source_cid})',
+ 'red',
+ )
+ )
+ return
+
+ # Process the response
+ channel.on_connection_response(response)
+
+ def on_l2cap_le_flow_control_credit(self, connection, _cid, credit):
+ channel = self.find_le_coc_channel(connection.handle, credit.cid)
+ if channel is None:
+ logger.warning(f'received credits for an unknown channel (cid={credit.cid}')
+ return
+
+ channel.on_credits(credit.credits)
def on_channel_closed(self, channel):
connection_channels = self.channels.get(channel.connection.handle)
@@ -1076,22 +1924,67 @@ class ChannelManager:
if channel.source_cid in connection_channels:
del connection_channels[channel.source_cid]
+ async def open_le_coc(self, connection, psm, max_credits, mtu, mps):
+ self.check_le_coc_parameters(max_credits, mtu, mps)
+
+ # Find a free CID for the new channel
+ connection_channels = self.channels.setdefault(connection.handle, {})
+ source_cid = self.find_free_le_cid(connection_channels)
+ if source_cid is None: # Should never happen!
+ raise RuntimeError('all CIDs already in use')
+
+ # Create the channel
+ logger.debug(f'creating coc channel with cid={source_cid} for psm {psm}')
+ channel = LeConnectionOrientedChannel(
+ manager=self,
+ connection=connection,
+ le_psm=psm,
+ source_cid=source_cid,
+ destination_cid=0,
+ mtu=mtu,
+ mps=mps,
+ credits=0,
+ peer_mtu=0,
+ peer_mps=0,
+ peer_credits=max_credits,
+ connected=False,
+ )
+ connection_channels[source_cid] = channel
+
+ # Connect
+ try:
+ await channel.connect()
+ except Exception as error:
+ logger.warning(f'connection failed: {error}')
+ del connection_channels[source_cid]
+ raise
+
+ # Remember the channel by source CID and destination CID
+ le_connection_channels = self.le_coc_channels.setdefault(connection.handle, {})
+ le_connection_channels[channel.destination_cid] = channel
+
+ return channel
+
async def connect(self, connection, psm):
- # NOTE: this implementation hard-codes BR/EDR more
- # TODO: LE mode (maybe?)
+ # NOTE: this implementation hard-codes BR/EDR
# Find a free CID for a new channel
connection_channels = self.channels.setdefault(connection.handle, {})
- cid = self.find_free_br_edr_cid(connection_channels)
- if cid is None: # Should never happen!
+ source_cid = self.find_free_br_edr_cid(connection_channels)
+ if source_cid is None: # Should never happen!
raise RuntimeError('all CIDs already in use')
# Create the channel
- logger.debug(f'creating client channel with cid={cid} for psm {psm}')
- channel = Channel(self, connection, L2CAP_SIGNALING_CID, psm, cid, L2CAP_MIN_BR_EDR_MTU)
- connection_channels[cid] = channel
+ logger.debug(f'creating client channel with cid={source_cid} for psm {psm}')
+ channel = Channel(
+ self, connection, L2CAP_SIGNALING_CID, psm, source_cid, L2CAP_MIN_BR_EDR_MTU
+ )
+ connection_channels[source_cid] = channel
# Connect
- await channel.connect()
+ try:
+ await channel.connect()
+ except Exception:
+ del connection_channels[source_cid]
return channel
diff --git a/bumble/link.py b/bumble/link.py
index 4463e27..85ad96e 100644
--- a/bumble/link.py
+++ b/bumble/link.py
@@ -17,15 +17,17 @@
# -----------------------------------------------------------------------------
import logging
import asyncio
-import websockets
from functools import partial
-from colors import color
+from bumble.core import BT_PERIPHERAL_ROLE, BT_BR_EDR_TRANSPORT, BT_LE_TRANSPORT
+from bumble.colors import color
from bumble.hci import (
Address,
HCI_SUCCESS,
HCI_CONNECTION_ACCEPT_TIMEOUT_ERROR,
- HCI_CONNECTION_TIMEOUT_ERROR
+ HCI_CONNECTION_TIMEOUT_ERROR,
+ HCI_PAGE_TIMEOUT_ERROR,
+ HCI_Connection_Complete_Event,
)
# -----------------------------------------------------------------------------
@@ -47,7 +49,8 @@ def parse_parameters(params_str):
# -----------------------------------------------------------------------------
-# TODO: add more support for various LL exchanges (see Vol 6, Part B - 2.4 DATA CHANNEL PDU)
+# TODO: add more support for various LL exchanges
+# (see Vol 6, Part B - 2.4 DATA CHANNEL PDU)
# -----------------------------------------------------------------------------
class LocalLink:
'''
@@ -55,8 +58,13 @@ class LocalLink:
'''
def __init__(self):
- self.controllers = set()
+ self.controllers = set()
self.pending_connection = None
+ self.pending_classic_connection = None
+
+ ############################################################
+ # Common utils
+ ############################################################
def add_controller(self, controller):
logger.debug(f'new controller: {controller}')
@@ -71,22 +79,39 @@ class LocalLink:
return controller
return None
- def on_address_changed(self, controller):
- pass
+ def find_classic_controller(self, address):
+ for controller in self.controllers:
+ if controller.public_address == address:
+ return controller
+ return None
def get_pending_connection(self):
return self.pending_connection
+ ############################################################
+ # LE handlers
+ ############################################################
+
+ def on_address_changed(self, controller):
+ pass
+
def send_advertising_data(self, sender_address, data):
# Send the advertising data to all controllers, except the sender
for controller in self.controllers:
if controller.random_address != sender_address:
controller.on_link_advertising_data(sender_address, data)
- def send_acl_data(self, sender_address, destination_address, data):
+ def send_acl_data(self, sender_controller, destination_address, transport, data):
# Send the data to the first controller with a matching address
- if controller := self.find_controller(destination_address):
- controller.on_link_acl_data(sender_address, data)
+ if transport == BT_LE_TRANSPORT:
+ destination_controller = self.find_controller(destination_address)
+ source_address = sender_controller.random_address
+ elif transport == BT_BR_EDR_TRANSPORT:
+ destination_controller = self.find_classic_controller(destination_address)
+ source_address = sender_controller.public_address
+
+ if destination_controller is not None:
+ destination_controller.on_link_acl_data(source_address, transport, data)
def on_connection_complete(self):
# Check that we expect this call
@@ -103,23 +128,31 @@ class LocalLink:
return
# Connect to the first controller with a matching address
- if peripheral_controller := self.find_controller(le_create_connection_command.peer_address):
- central_controller.on_link_peripheral_connection_complete(le_create_connection_command, HCI_SUCCESS)
+ if peripheral_controller := self.find_controller(
+ le_create_connection_command.peer_address
+ ):
+ central_controller.on_link_peripheral_connection_complete(
+ le_create_connection_command, HCI_SUCCESS
+ )
peripheral_controller.on_link_central_connected(central_address)
return
# No peripheral found
central_controller.on_link_peripheral_connection_complete(
- le_create_connection_command,
- HCI_CONNECTION_ACCEPT_TIMEOUT_ERROR
+ le_create_connection_command, HCI_CONNECTION_ACCEPT_TIMEOUT_ERROR
)
def connect(self, central_address, le_create_connection_command):
- logger.debug(f'$$$ CONNECTION {central_address} -> {le_create_connection_command.peer_address}')
+ logger.debug(
+ f'$$$ CONNECTION {central_address} -> '
+ f'{le_create_connection_command.peer_address}'
+ )
self.pending_connection = (central_address, le_create_connection_command)
asyncio.get_running_loop().call_soon(self.on_connection_complete)
- def on_disconnection_complete(self, central_address, peripheral_address, disconnect_command):
+ def on_disconnection_complete(
+ self, central_address, peripheral_address, disconnect_command
+ ):
# Find the controller that initiated the disconnection
if not (central_controller := self.find_controller(central_address)):
logger.warning('!!! Initiating controller not found')
@@ -127,16 +160,26 @@ class LocalLink:
# Disconnect from the first controller with a matching address
if peripheral_controller := self.find_controller(peripheral_address):
- peripheral_controller.on_link_central_disconnected(central_address, disconnect_command.reason)
+ peripheral_controller.on_link_central_disconnected(
+ central_address, disconnect_command.reason
+ )
- central_controller.on_link_peripheral_disconnection_complete(disconnect_command, HCI_SUCCESS)
+ central_controller.on_link_peripheral_disconnection_complete(
+ disconnect_command, HCI_SUCCESS
+ )
def disconnect(self, central_address, peripheral_address, disconnect_command):
- logger.debug(f'$$$ DISCONNECTION {central_address} -> {peripheral_address}: reason = {disconnect_command.reason}')
+ logger.debug(
+ f'$$$ DISCONNECTION {central_address} -> '
+ f'{peripheral_address}: reason = {disconnect_command.reason}'
+ )
args = [central_address, peripheral_address, disconnect_command]
asyncio.get_running_loop().call_soon(self.on_disconnection_complete, *args)
- def on_connection_encrypted(self, central_address, peripheral_address, rand, ediv, ltk):
+ # pylint: disable=too-many-arguments
+ def on_connection_encrypted(
+ self, central_address, peripheral_address, rand, ediv, ltk
+ ):
logger.debug(f'*** ENCRYPTION {central_address} -> {peripheral_address}')
if central_controller := self.find_controller(central_address):
@@ -145,6 +188,89 @@ class LocalLink:
if peripheral_controller := self.find_controller(peripheral_address):
peripheral_controller.on_link_encrypted(central_address, rand, ediv, ltk)
+ ############################################################
+ # Classic handlers
+ ############################################################
+
+ def classic_connect(self, initiator_controller, responder_address):
+ logger.debug(
+ f'[Classic] {initiator_controller.public_address} connects to {responder_address}'
+ )
+ responder_controller = self.find_classic_controller(responder_address)
+ if responder_controller is None:
+ initiator_controller.on_classic_connection_complete(
+ responder_address, HCI_PAGE_TIMEOUT_ERROR
+ )
+ return
+ self.pending_classic_connection = (initiator_controller, responder_controller)
+
+ responder_controller.on_classic_connection_request(
+ initiator_controller.public_address,
+ HCI_Connection_Complete_Event.ACL_LINK_TYPE,
+ )
+
+ def classic_accept_connection(
+ self, responder_controller, initiator_address, responder_role
+ ):
+ logger.debug(
+ f'[Classic] {responder_controller.public_address} accepts to connect {initiator_address}'
+ )
+ initiator_controller = self.find_classic_controller(initiator_address)
+ if initiator_controller is None:
+ responder_controller.on_classic_connection_complete(
+ responder_controller.public_address, HCI_PAGE_TIMEOUT_ERROR
+ )
+ return
+
+ async def task():
+ if responder_role != BT_PERIPHERAL_ROLE:
+ initiator_controller.on_classic_role_change(
+ responder_controller.public_address, int(not (responder_role))
+ )
+ initiator_controller.on_classic_connection_complete(
+ responder_controller.public_address, HCI_SUCCESS
+ )
+
+ asyncio.create_task(task())
+ responder_controller.on_classic_role_change(
+ initiator_controller.public_address, responder_role
+ )
+ responder_controller.on_classic_connection_complete(
+ initiator_controller.public_address, HCI_SUCCESS
+ )
+ self.pending_classic_connection = None
+
+ def classic_disconnect(self, initiator_controller, responder_address, reason):
+ logger.debug(
+ f'[Classic] {initiator_controller.public_address} disconnects {responder_address}'
+ )
+ responder_controller = self.find_classic_controller(responder_address)
+
+ async def task():
+ initiator_controller.on_classic_disconnected(responder_address, reason)
+
+ asyncio.create_task(task())
+ responder_controller.on_classic_disconnected(
+ initiator_controller.public_address, reason
+ )
+
+ def classic_switch_role(
+ self, initiator_controller, responder_address, initiator_new_role
+ ):
+ responder_controller = self.find_classic_controller(responder_address)
+ if responder_controller is None:
+ return
+
+ async def task():
+ initiator_controller.on_classic_role_change(
+ responder_address, initiator_new_role
+ )
+
+ asyncio.create_task(task())
+ responder_controller.on_classic_role_change(
+ initiator_controller.public_address, int(not (initiator_new_role))
+ )
+
# -----------------------------------------------------------------------------
class RemoteLink:
@@ -152,15 +278,18 @@ class RemoteLink:
A Link implementation that communicates with other virtual controllers via a
WebSocket relay
'''
+
def __init__(self, uri):
- self.controller = None
- self.uri = uri
- self.execution_queue = asyncio.Queue()
- self.websocket = asyncio.get_running_loop().create_future()
- self.rpc_result = None
- self.pending_connection = None
- self.central_connections = set() # List of addresses that we have connected to
- self.peripheral_connections = set() # List of addresses that have connected to us
+ self.controller = None
+ self.uri = uri
+ self.execution_queue = asyncio.Queue()
+ self.websocket = asyncio.get_running_loop().create_future()
+ self.rpc_result = None
+ self.pending_connection = None
+ self.central_connections = set() # List of addresses that we have connected to
+ self.peripheral_connections = (
+ set()
+ ) # List of addresses that have connected to us
# Connect and run asynchronously
asyncio.create_task(self.run_connection())
@@ -179,6 +308,9 @@ class RemoteLink:
def get_pending_connection(self):
return self.pending_connection
+ def get_pending_classic_connection(self):
+ return self.pending_classic_connection
+
async def wait_until_connected(self):
await self.websocket
@@ -192,11 +324,16 @@ class RemoteLink:
try:
await item
except Exception as error:
- logger.warning(f'{color("!!! Exception in async handler:", "red")} {error}')
+ logger.warning(
+ f'{color("!!! Exception in async handler:", "red")} {error}'
+ )
async def run_connection(self):
+ import websockets # lazy import
+
# Connect to the relay
logger.debug(f'connecting to {self.uri}')
+ # pylint: disable-next=no-member
websocket = await websockets.connect(self.uri)
self.websocket.set_result(websocket)
logger.debug(f'connected to {self.uri}')
@@ -227,7 +364,9 @@ class RemoteLink:
self.central_connections.remove(address)
if address in self.peripheral_connections:
- self.controller.on_link_central_disconnected(address, HCI_CONNECTION_TIMEOUT_ERROR)
+ self.controller.on_link_central_disconnected(
+ address, HCI_CONNECTION_TIMEOUT_ERROR
+ )
self.peripheral_connections.remove(address)
async def on_unreachable_received(self, target):
@@ -244,7 +383,9 @@ class RemoteLink:
async def on_advertisement_message_received(self, sender, advertisement):
try:
- self.controller.on_link_advertising_data(Address(sender), bytes.fromhex(advertisement))
+ self.controller.on_link_advertising_data(
+ Address(sender), bytes.fromhex(advertisement)
+ )
except Exception:
logger.exception('exception')
@@ -263,11 +404,11 @@ class RemoteLink:
self.controller.on_link_central_connected(Address(sender))
# Accept the connection by responding to it
- await self.send_targetted_message(sender, 'connected')
+ await self.send_targeted_message(sender, 'connected')
async def on_connected_message_received(self, sender, _):
if not self.pending_connection:
- logger.warn('received a connection ack, but no connection is pending')
+ logger.warning('received a connection ack, but no connection is pending')
return
# Remember the connection
@@ -275,7 +416,9 @@ class RemoteLink:
# Notify the controller
logger.debug(f'connected to peripheral {self.pending_connection.peer_address}')
- self.controller.on_link_peripheral_connection_complete(self.pending_connection, HCI_SUCCESS)
+ self.controller.on_link_peripheral_connection_complete(
+ self.pending_connection, HCI_SUCCESS
+ )
async def on_disconnect_message_received(self, sender, message):
# Notify the controller
@@ -287,7 +430,7 @@ class RemoteLink:
if sender in self.peripheral_connections:
self.peripheral_connections.remove(sender)
- async def on_encrypted_message_received(self, sender, message):
+ async def on_encrypted_message_received(self, sender, _):
# TODO parse params to get real args
self.controller.on_link_encrypted(Address(sender), bytes(8), 0, bytes(16))
@@ -296,7 +439,7 @@ class RemoteLink:
websocket = await self.websocket
# Create a future value to hold the eventual result
- assert(self.rpc_result is None)
+ assert self.rpc_result is None
self.rpc_result = asyncio.get_running_loop().create_future()
# Send the command
@@ -309,7 +452,7 @@ class RemoteLink:
# TODO: parse the result
- async def send_targetted_message(self, target, message):
+ async def send_targeted_message(self, target, message):
# Ensure we have a connection
websocket = await self.websocket
@@ -326,35 +469,62 @@ class RemoteLink:
self.execute(self.notify_address_changed)
async def send_advertising_data_to_relay(self, data):
- await self.send_targetted_message('*', f'advertisement:{data.hex()}')
+ await self.send_targeted_message('*', f'advertisement:{data.hex()}')
- def send_advertising_data(self, sender_address, data):
+ def send_advertising_data(self, _, data):
self.execute(partial(self.send_advertising_data_to_relay, data))
async def send_acl_data_to_relay(self, peer_address, data):
- await self.send_targetted_message(peer_address, f'acl:{data.hex()}')
+ await self.send_targeted_message(peer_address, f'acl:{data.hex()}')
- def send_acl_data(self, sender_address, peer_address, data):
+ def send_acl_data(self, _, peer_address, _transport, data):
+ # TODO: handle different transport
self.execute(partial(self.send_acl_data_to_relay, peer_address, data))
async def send_connection_request_to_relay(self, peer_address):
- await self.send_targetted_message(peer_address, 'connect')
+ await self.send_targeted_message(peer_address, 'connect')
- def connect(self, central_address, le_create_connection_command):
+ def connect(self, _, le_create_connection_command):
if self.pending_connection:
- logger.warn('connection already pending')
+ logger.warning('connection already pending')
return
self.pending_connection = le_create_connection_command
- self.execute(partial(self.send_connection_request_to_relay, str(le_create_connection_command.peer_address)))
+ self.execute(
+ partial(
+ self.send_connection_request_to_relay,
+ str(le_create_connection_command.peer_address),
+ )
+ )
def on_disconnection_complete(self, disconnect_command):
- self.controller.on_link_peripheral_disconnection_complete(disconnect_command, HCI_SUCCESS)
+ self.controller.on_link_peripheral_disconnection_complete(
+ disconnect_command, HCI_SUCCESS
+ )
def disconnect(self, central_address, peripheral_address, disconnect_command):
- logger.debug(f'disconnect {central_address} -> {peripheral_address}: reason = {disconnect_command.reason}')
- self.execute(partial(self.send_targetted_message, peripheral_address, f'disconnect:reason={disconnect_command.reason}'))
- asyncio.get_running_loop().call_soon(self.on_disconnection_complete, disconnect_command)
+ logger.debug(
+ f'disconnect {central_address} -> '
+ f'{peripheral_address}: reason = {disconnect_command.reason}'
+ )
+ self.execute(
+ partial(
+ self.send_targeted_message,
+ peripheral_address,
+ f'disconnect:reason={disconnect_command.reason}',
+ )
+ )
+ asyncio.get_running_loop().call_soon(
+ self.on_disconnection_complete, disconnect_command
+ )
- def on_connection_encrypted(self, central_address, peripheral_address, rand, ediv, ltk):
- asyncio.get_running_loop().call_soon(self.controller.on_link_encrypted, peripheral_address, rand, ediv, ltk)
- self.execute(partial(self.send_targetted_message, peripheral_address, f'encrypted:ltk={ltk.hex()}'))
+ def on_connection_encrypted(self, _, peripheral_address, rand, ediv, ltk):
+ asyncio.get_running_loop().call_soon(
+ self.controller.on_link_encrypted, peripheral_address, rand, ediv, ltk
+ )
+ self.execute(
+ partial(
+ self.send_targeted_message,
+ peripheral_address,
+ f'encrypted:ltk={ltk.hex()}',
+ )
+ )
diff --git a/bumble/pairing.py b/bumble/pairing.py
new file mode 100644
index 0000000..ab356ee
--- /dev/null
+++ b/bumble/pairing.py
@@ -0,0 +1,188 @@
+# Copyright 2021-2023 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# -----------------------------------------------------------------------------
+# Imports
+# -----------------------------------------------------------------------------
+import enum
+from typing import Optional, Tuple
+
+from .hci import (
+ HCI_NO_INPUT_NO_OUTPUT_IO_CAPABILITY,
+ HCI_DISPLAY_ONLY_IO_CAPABILITY,
+ HCI_DISPLAY_YES_NO_IO_CAPABILITY,
+ HCI_KEYBOARD_ONLY_IO_CAPABILITY,
+)
+from .smp import (
+ SMP_NO_INPUT_NO_OUTPUT_IO_CAPABILITY,
+ SMP_KEYBOARD_ONLY_IO_CAPABILITY,
+ SMP_DISPLAY_ONLY_IO_CAPABILITY,
+ SMP_DISPLAY_YES_NO_IO_CAPABILITY,
+ SMP_KEYBOARD_DISPLAY_IO_CAPABILITY,
+ SMP_ENC_KEY_DISTRIBUTION_FLAG,
+ SMP_ID_KEY_DISTRIBUTION_FLAG,
+ SMP_SIGN_KEY_DISTRIBUTION_FLAG,
+ SMP_LINK_KEY_DISTRIBUTION_FLAG,
+)
+
+
+# -----------------------------------------------------------------------------
+class PairingDelegate:
+ """Abstract base class for Pairing Delegates."""
+
+ # I/O Capabilities.
+ # These are defined abstractly, and can be mapped to specific Classic pairing
+ # and/or SMP constants.
+ class IoCapability(enum.IntEnum):
+ NO_OUTPUT_NO_INPUT = SMP_NO_INPUT_NO_OUTPUT_IO_CAPABILITY
+ KEYBOARD_INPUT_ONLY = SMP_KEYBOARD_ONLY_IO_CAPABILITY
+ DISPLAY_OUTPUT_ONLY = SMP_DISPLAY_ONLY_IO_CAPABILITY
+ DISPLAY_OUTPUT_AND_YES_NO_INPUT = SMP_DISPLAY_YES_NO_IO_CAPABILITY
+ DISPLAY_OUTPUT_AND_KEYBOARD_INPUT = SMP_KEYBOARD_DISPLAY_IO_CAPABILITY
+
+ # Direct names for backward compatibility.
+ NO_OUTPUT_NO_INPUT = IoCapability.NO_OUTPUT_NO_INPUT
+ KEYBOARD_INPUT_ONLY = IoCapability.KEYBOARD_INPUT_ONLY
+ DISPLAY_OUTPUT_ONLY = IoCapability.DISPLAY_OUTPUT_ONLY
+ DISPLAY_OUTPUT_AND_YES_NO_INPUT = IoCapability.DISPLAY_OUTPUT_AND_YES_NO_INPUT
+ DISPLAY_OUTPUT_AND_KEYBOARD_INPUT = IoCapability.DISPLAY_OUTPUT_AND_KEYBOARD_INPUT
+
+ # Key Distribution [LE only]
+ class KeyDistribution(enum.IntFlag):
+ DISTRIBUTE_ENCRYPTION_KEY = SMP_ENC_KEY_DISTRIBUTION_FLAG
+ DISTRIBUTE_IDENTITY_KEY = SMP_ID_KEY_DISTRIBUTION_FLAG
+ DISTRIBUTE_SIGNING_KEY = SMP_SIGN_KEY_DISTRIBUTION_FLAG
+ DISTRIBUTE_LINK_KEY = SMP_LINK_KEY_DISTRIBUTION_FLAG
+
+ DEFAULT_KEY_DISTRIBUTION: KeyDistribution = (
+ KeyDistribution.DISTRIBUTE_ENCRYPTION_KEY
+ | KeyDistribution.DISTRIBUTE_IDENTITY_KEY
+ )
+
+ # Default mapping from abstract to Classic I/O capabilities.
+ # Subclasses may override this if they prefer a different mapping.
+ CLASSIC_IO_CAPABILITIES_MAP = {
+ NO_OUTPUT_NO_INPUT: HCI_NO_INPUT_NO_OUTPUT_IO_CAPABILITY,
+ KEYBOARD_INPUT_ONLY: HCI_KEYBOARD_ONLY_IO_CAPABILITY,
+ DISPLAY_OUTPUT_ONLY: HCI_DISPLAY_ONLY_IO_CAPABILITY,
+ DISPLAY_OUTPUT_AND_YES_NO_INPUT: HCI_DISPLAY_YES_NO_IO_CAPABILITY,
+ DISPLAY_OUTPUT_AND_KEYBOARD_INPUT: HCI_DISPLAY_YES_NO_IO_CAPABILITY,
+ }
+
+ io_capability: IoCapability
+ local_initiator_key_distribution: KeyDistribution
+ local_responder_key_distribution: KeyDistribution
+
+ def __init__(
+ self,
+ io_capability: IoCapability = NO_OUTPUT_NO_INPUT,
+ local_initiator_key_distribution: KeyDistribution = DEFAULT_KEY_DISTRIBUTION,
+ local_responder_key_distribution: KeyDistribution = DEFAULT_KEY_DISTRIBUTION,
+ ) -> None:
+ self.io_capability = io_capability
+ self.local_initiator_key_distribution = local_initiator_key_distribution
+ self.local_responder_key_distribution = local_responder_key_distribution
+
+ @property
+ def classic_io_capability(self) -> int:
+ """Map the abstract I/O capability to a Classic constant."""
+
+ # pylint: disable=line-too-long
+ return self.CLASSIC_IO_CAPABILITIES_MAP.get(
+ self.io_capability, HCI_NO_INPUT_NO_OUTPUT_IO_CAPABILITY
+ )
+
+ @property
+ def smp_io_capability(self) -> int:
+ """Map the abstract I/O capability to an SMP constant."""
+
+ # This is just a 1-1 direct mapping
+ return self.io_capability
+
+ async def accept(self) -> bool:
+ """Accept or reject a Pairing request."""
+ return True
+
+ async def confirm(self, auto: bool = False) -> bool:
+ """
+ Respond yes or no to a Pairing confirmation question.
+ The `auto` parameter stands for automatic confirmation.
+ """
+ return True
+
+ # pylint: disable-next=unused-argument
+ async def compare_numbers(self, number: int, digits: int) -> bool:
+ """Compare two numbers."""
+ return True
+
+ async def get_number(self) -> Optional[int]:
+ """
+ Return an optional number as an answer to a passkey request.
+ Returning `None` will result in a negative reply.
+ """
+ return 0
+
+ async def get_string(self, max_length: int) -> Optional[str]:
+ """
+ Return a string whose utf-8 encoding is up to max_length bytes.
+ """
+ return None
+
+ # pylint: disable-next=unused-argument
+ async def display_number(self, number: int, digits: int) -> None:
+ """Display a number."""
+
+ # [LE only]
+ async def key_distribution_response(
+ self, peer_initiator_key_distribution: int, peer_responder_key_distribution: int
+ ) -> Tuple[int, int]:
+ """
+ Return the key distribution response in an SMP protocol context.
+
+ NOTE: since it is only used by the SMP protocol, this method's input and output
+ are directly as integers, using the SMP constants, rather than the abstract
+ KeyDistribution enums.
+ """
+ return (
+ int(
+ peer_initiator_key_distribution & self.local_initiator_key_distribution
+ ),
+ int(
+ peer_responder_key_distribution & self.local_responder_key_distribution
+ ),
+ )
+
+
+# -----------------------------------------------------------------------------
+class PairingConfig:
+ """Configuration for the Pairing protocol."""
+
+ def __init__(
+ self,
+ sc: bool = True,
+ mitm: bool = True,
+ bonding: bool = True,
+ delegate: Optional[PairingDelegate] = None,
+ ) -> None:
+ self.sc = sc
+ self.mitm = mitm
+ self.bonding = bonding
+ self.delegate = delegate or PairingDelegate()
+
+ def __str__(self) -> str:
+ return (
+ f'PairingConfig(sc={self.sc}, '
+ f'mitm={self.mitm}, bonding={self.bonding}, '
+ f'delegate[{self.delegate.io_capability}])'
+ )
diff --git a/bumble/pandora/__init__.py b/bumble/pandora/__init__.py
new file mode 100644
index 0000000..e02f54a
--- /dev/null
+++ b/bumble/pandora/__init__.py
@@ -0,0 +1,105 @@
+# Copyright 2022 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""
+Bumble Pandora server.
+This module implement the Pandora Bluetooth test APIs for the Bumble stack.
+"""
+
+__version__ = "0.0.1"
+
+import grpc
+import grpc.aio
+
+from .config import Config
+from .device import PandoraDevice
+from .host import HostService
+from .security import SecurityService, SecurityStorageService
+from pandora.host_grpc_aio import add_HostServicer_to_server
+from pandora.security_grpc_aio import (
+ add_SecurityServicer_to_server,
+ add_SecurityStorageServicer_to_server,
+)
+from typing import Callable, List, Optional
+
+# public symbols
+__all__ = [
+ 'register_servicer_hook',
+ 'serve',
+ 'Config',
+ 'PandoraDevice',
+]
+
+
+# Add servicers hooks.
+_SERVICERS_HOOKS: List[Callable[[PandoraDevice, Config, grpc.aio.Server], None]] = []
+
+
+def register_servicer_hook(
+ hook: Callable[[PandoraDevice, Config, grpc.aio.Server], None]
+) -> None:
+ _SERVICERS_HOOKS.append(hook)
+
+
+async def serve(
+ bumble: PandoraDevice,
+ config: Config = Config(),
+ grpc_server: Optional[grpc.aio.Server] = None,
+ port: int = 0,
+) -> None:
+ # initialize a gRPC server if not provided.
+ server = grpc_server if grpc_server is not None else grpc.aio.server()
+ port = server.add_insecure_port(f'localhost:{port}')
+
+ try:
+ while True:
+ # load server config from dict.
+ config.load_from_dict(bumble.config.get('server', {}))
+
+ # add Pandora services to the gRPC server.
+ add_HostServicer_to_server(
+ HostService(server, bumble.device, config), server
+ )
+ add_SecurityServicer_to_server(
+ SecurityService(bumble.device, config), server
+ )
+ add_SecurityStorageServicer_to_server(
+ SecurityStorageService(bumble.device, config), server
+ )
+
+ # call hooks if any.
+ for hook in _SERVICERS_HOOKS:
+ hook(bumble, config, server)
+
+ # open device.
+ await bumble.open()
+ try:
+ # Pandora require classic devices to be discoverable & connectable.
+ if bumble.device.classic_enabled:
+ await bumble.device.set_discoverable(True)
+ await bumble.device.set_connectable(True)
+
+ # start & serve gRPC server.
+ await server.start()
+ await server.wait_for_termination()
+ finally:
+ # close device.
+ await bumble.close()
+
+ # re-initialize the gRPC server.
+ server = grpc.aio.server()
+ server.add_insecure_port(f'localhost:{port}')
+ finally:
+ # stop server.
+ await server.stop(None)
diff --git a/bumble/pandora/config.py b/bumble/pandora/config.py
new file mode 100644
index 0000000..5edba55
--- /dev/null
+++ b/bumble/pandora/config.py
@@ -0,0 +1,48 @@
+# Copyright 2022 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from bumble.pairing import PairingDelegate
+from dataclasses import dataclass
+from typing import Any, Dict
+
+
+@dataclass
+class Config:
+ io_capability: PairingDelegate.IoCapability = PairingDelegate.NO_OUTPUT_NO_INPUT
+ pairing_sc_enable: bool = True
+ pairing_mitm_enable: bool = True
+ pairing_bonding_enable: bool = True
+ smp_local_initiator_key_distribution: PairingDelegate.KeyDistribution = (
+ PairingDelegate.DEFAULT_KEY_DISTRIBUTION
+ )
+ smp_local_responder_key_distribution: PairingDelegate.KeyDistribution = (
+ PairingDelegate.DEFAULT_KEY_DISTRIBUTION
+ )
+
+ def load_from_dict(self, config: Dict[str, Any]) -> None:
+ io_capability_name: str = config.get(
+ 'io_capability', 'no_output_no_input'
+ ).upper()
+ self.io_capability = getattr(PairingDelegate, io_capability_name)
+ self.pairing_sc_enable = config.get('pairing_sc_enable', True)
+ self.pairing_mitm_enable = config.get('pairing_mitm_enable', True)
+ self.pairing_bonding_enable = config.get('pairing_bonding_enable', True)
+ self.smp_local_initiator_key_distribution = config.get(
+ 'smp_local_initiator_key_distribution',
+ PairingDelegate.DEFAULT_KEY_DISTRIBUTION,
+ )
+ self.smp_local_responder_key_distribution = config.get(
+ 'smp_local_responder_key_distribution',
+ PairingDelegate.DEFAULT_KEY_DISTRIBUTION,
+ )
diff --git a/bumble/pandora/device.py b/bumble/pandora/device.py
new file mode 100644
index 0000000..a4403b6
--- /dev/null
+++ b/bumble/pandora/device.py
@@ -0,0 +1,157 @@
+# Copyright 2022 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Generic & dependency free Bumble (reference) device."""
+
+from bumble import transport
+from bumble.core import (
+ BT_GENERIC_AUDIO_SERVICE,
+ BT_HANDSFREE_SERVICE,
+ BT_L2CAP_PROTOCOL_ID,
+ BT_RFCOMM_PROTOCOL_ID,
+)
+from bumble.device import Device, DeviceConfiguration
+from bumble.host import Host
+from bumble.sdp import (
+ SDP_BLUETOOTH_PROFILE_DESCRIPTOR_LIST_ATTRIBUTE_ID,
+ SDP_PROTOCOL_DESCRIPTOR_LIST_ATTRIBUTE_ID,
+ SDP_SERVICE_CLASS_ID_LIST_ATTRIBUTE_ID,
+ SDP_SERVICE_RECORD_HANDLE_ATTRIBUTE_ID,
+ DataElement,
+ ServiceAttribute,
+)
+from typing import Any, Dict, List, Optional
+
+
+class PandoraDevice:
+ """
+ Small wrapper around a Bumble device and it's HCI transport.
+ Notes:
+ - The Bumble device is idle by default.
+ - Repetitive calls to `open`/`close` will result on new Bumble device instances.
+ """
+
+ # Bumble device instance & configuration.
+ device: Device
+ config: Dict[str, Any]
+
+ # HCI transport name & instance.
+ _hci_name: str
+ _hci: Optional[transport.Transport] # type: ignore[name-defined]
+
+ def __init__(self, config: Dict[str, Any]) -> None:
+ self.config = config
+ self.device = _make_device(config)
+ self._hci_name = config.get('transport', '')
+ self._hci = None
+
+ @property
+ def idle(self) -> bool:
+ return self._hci is None
+
+ async def open(self) -> None:
+ if self._hci is not None:
+ return
+
+ # open HCI transport & set device host.
+ self._hci = await transport.open_transport(self._hci_name)
+ self.device.host = Host(controller_source=self._hci.source, controller_sink=self._hci.sink) # type: ignore[no-untyped-call]
+
+ # power-on.
+ await self.device.power_on()
+
+ async def close(self) -> None:
+ if self._hci is None:
+ return
+
+ # flush & re-initialize device.
+ await self.device.host.flush()
+ self.device.host = None # type: ignore[assignment]
+ self.device = _make_device(self.config)
+
+ # close HCI transport.
+ await self._hci.close()
+ self._hci = None
+
+ async def reset(self) -> None:
+ await self.close()
+ await self.open()
+
+ def info(self) -> Optional[Dict[str, str]]:
+ return {
+ 'public_bd_address': str(self.device.public_address),
+ 'random_address': str(self.device.random_address),
+ }
+
+
+def _make_device(config: Dict[str, Any]) -> Device:
+ """Initialize an idle Bumble device instance."""
+
+ # initialize bumble device.
+ device_config = DeviceConfiguration()
+ device_config.load_from_dict(config)
+ device = Device(config=device_config, host=None)
+
+ # Add fake a2dp service to avoid Android disconnect
+ device.sdp_service_records = _make_sdp_records(1)
+
+ return device
+
+
+# TODO(b/267540823): remove when Pandora A2dp is supported
+def _make_sdp_records(rfcomm_channel: int) -> Dict[int, List[ServiceAttribute]]:
+ return {
+ 0x00010001: [
+ ServiceAttribute(
+ SDP_SERVICE_RECORD_HANDLE_ATTRIBUTE_ID,
+ DataElement.unsigned_integer_32(0x00010001),
+ ),
+ ServiceAttribute(
+ SDP_SERVICE_CLASS_ID_LIST_ATTRIBUTE_ID,
+ DataElement.sequence(
+ [
+ DataElement.uuid(BT_HANDSFREE_SERVICE),
+ DataElement.uuid(BT_GENERIC_AUDIO_SERVICE),
+ ]
+ ),
+ ),
+ ServiceAttribute(
+ SDP_PROTOCOL_DESCRIPTOR_LIST_ATTRIBUTE_ID,
+ DataElement.sequence(
+ [
+ DataElement.sequence([DataElement.uuid(BT_L2CAP_PROTOCOL_ID)]),
+ DataElement.sequence(
+ [
+ DataElement.uuid(BT_RFCOMM_PROTOCOL_ID),
+ DataElement.unsigned_integer_8(rfcomm_channel),
+ ]
+ ),
+ ]
+ ),
+ ),
+ ServiceAttribute(
+ SDP_BLUETOOTH_PROFILE_DESCRIPTOR_LIST_ATTRIBUTE_ID,
+ DataElement.sequence(
+ [
+ DataElement.sequence(
+ [
+ DataElement.uuid(BT_HANDSFREE_SERVICE),
+ DataElement.unsigned_integer_16(0x0105),
+ ]
+ )
+ ]
+ ),
+ ),
+ ]
+ }
diff --git a/bumble/pandora/host.py b/bumble/pandora/host.py
new file mode 100644
index 0000000..63b295d
--- /dev/null
+++ b/bumble/pandora/host.py
@@ -0,0 +1,856 @@
+# Copyright 2022 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import asyncio
+import bumble.device
+import grpc
+import grpc.aio
+import logging
+import struct
+
+from . import utils
+from .config import Config
+from bumble.core import (
+ BT_BR_EDR_TRANSPORT,
+ BT_LE_TRANSPORT,
+ BT_PERIPHERAL_ROLE,
+ UUID,
+ AdvertisingData,
+ ConnectionError,
+)
+from bumble.device import (
+ DEVICE_DEFAULT_SCAN_INTERVAL,
+ DEVICE_DEFAULT_SCAN_WINDOW,
+ Advertisement,
+ AdvertisingType,
+ Device,
+)
+from bumble.gatt import Service
+from bumble.hci import (
+ HCI_CONNECTION_ALREADY_EXISTS_ERROR,
+ HCI_PAGE_TIMEOUT_ERROR,
+ HCI_REMOTE_USER_TERMINATED_CONNECTION_ERROR,
+ Address,
+)
+from google.protobuf import any_pb2, empty_pb2 # pytype: disable=pyi-error
+from pandora.host_grpc_aio import HostServicer
+from pandora.host_pb2 import (
+ NOT_CONNECTABLE,
+ NOT_DISCOVERABLE,
+ PRIMARY_1M,
+ PRIMARY_CODED,
+ SECONDARY_1M,
+ SECONDARY_2M,
+ SECONDARY_CODED,
+ SECONDARY_NONE,
+ AdvertiseRequest,
+ AdvertiseResponse,
+ Connection,
+ ConnectLERequest,
+ ConnectLEResponse,
+ ConnectRequest,
+ ConnectResponse,
+ DataTypes,
+ DisconnectRequest,
+ InquiryResponse,
+ PrimaryPhy,
+ ReadLocalAddressResponse,
+ ScanningResponse,
+ ScanRequest,
+ SecondaryPhy,
+ SetConnectabilityModeRequest,
+ SetDiscoverabilityModeRequest,
+ WaitConnectionRequest,
+ WaitConnectionResponse,
+ WaitDisconnectionRequest,
+)
+from typing import AsyncGenerator, Dict, List, Optional, Set, Tuple, cast
+
+PRIMARY_PHY_MAP: Dict[int, PrimaryPhy] = {
+ # Default value reported by Bumble for legacy Advertising reports.
+ # FIXME(uael): `None` might be a better value, but Bumble need to change accordingly.
+ 0: PRIMARY_1M,
+ 1: PRIMARY_1M,
+ 3: PRIMARY_CODED,
+}
+
+SECONDARY_PHY_MAP: Dict[int, SecondaryPhy] = {
+ 0: SECONDARY_NONE,
+ 1: SECONDARY_1M,
+ 2: SECONDARY_2M,
+ 3: SECONDARY_CODED,
+}
+
+
+class HostService(HostServicer):
+ waited_connections: Set[int]
+
+ def __init__(
+ self, grpc_server: grpc.aio.Server, device: Device, config: Config
+ ) -> None:
+ self.log = utils.BumbleServerLoggerAdapter(
+ logging.getLogger(), {'service_name': 'Host', 'device': device}
+ )
+ self.grpc_server = grpc_server
+ self.device = device
+ self.config = config
+ self.waited_connections = set()
+
+ @utils.rpc
+ async def FactoryReset(
+ self, request: empty_pb2.Empty, context: grpc.ServicerContext
+ ) -> empty_pb2.Empty:
+ self.log.info('FactoryReset')
+
+ # delete all bonds
+ if self.device.keystore is not None:
+ await self.device.keystore.delete_all()
+
+ # trigger gRCP server stop then return
+ asyncio.create_task(self.grpc_server.stop(None))
+ return empty_pb2.Empty()
+
+ @utils.rpc
+ async def Reset(
+ self, request: empty_pb2.Empty, context: grpc.ServicerContext
+ ) -> empty_pb2.Empty:
+ self.log.info('Reset')
+
+ # clear service.
+ self.waited_connections.clear()
+
+ # (re) power device on
+ await self.device.power_on()
+ return empty_pb2.Empty()
+
+ @utils.rpc
+ async def ReadLocalAddress(
+ self, request: empty_pb2.Empty, context: grpc.ServicerContext
+ ) -> ReadLocalAddressResponse:
+ self.log.info('ReadLocalAddress')
+ return ReadLocalAddressResponse(
+ address=bytes(reversed(bytes(self.device.public_address)))
+ )
+
+ @utils.rpc
+ async def Connect(
+ self, request: ConnectRequest, context: grpc.ServicerContext
+ ) -> ConnectResponse:
+ # Need to reverse bytes order since Bumble Address is using MSB.
+ address = Address(
+ bytes(reversed(request.address)), address_type=Address.PUBLIC_DEVICE_ADDRESS
+ )
+ self.log.info(f"Connect to {address}")
+
+ try:
+ connection = await self.device.connect(
+ address, transport=BT_BR_EDR_TRANSPORT
+ )
+ except ConnectionError as e:
+ if e.error_code == HCI_PAGE_TIMEOUT_ERROR:
+ self.log.warning(f"Peer not found: {e}")
+ return ConnectResponse(peer_not_found=empty_pb2.Empty())
+ if e.error_code == HCI_CONNECTION_ALREADY_EXISTS_ERROR:
+ self.log.warning(f"Connection already exists: {e}")
+ return ConnectResponse(connection_already_exists=empty_pb2.Empty())
+ raise e
+
+ self.log.info(f"Connect to {address} done (handle={connection.handle})")
+
+ cookie = any_pb2.Any(value=connection.handle.to_bytes(4, 'big'))
+ return ConnectResponse(connection=Connection(cookie=cookie))
+
+ @utils.rpc
+ async def WaitConnection(
+ self, request: WaitConnectionRequest, context: grpc.ServicerContext
+ ) -> WaitConnectionResponse:
+ if not request.address:
+ raise ValueError('Request address field must be set')
+
+ # Need to reverse bytes order since Bumble Address is using MSB.
+ address = Address(
+ bytes(reversed(request.address)), address_type=Address.PUBLIC_DEVICE_ADDRESS
+ )
+ if address in (Address.NIL, Address.ANY):
+ raise ValueError('Invalid address')
+
+ self.log.info(f"WaitConnection from {address}...")
+
+ connection = self.device.find_connection_by_bd_addr(
+ address, transport=BT_BR_EDR_TRANSPORT
+ )
+ if connection and id(connection) in self.waited_connections:
+ # this connection was already returned: wait for a new one.
+ connection = None
+
+ if not connection:
+ connection = await self.device.accept(address)
+
+ # save connection has waited and respond.
+ self.waited_connections.add(id(connection))
+
+ self.log.info(
+ f"WaitConnection from {address} done (handle={connection.handle})"
+ )
+
+ cookie = any_pb2.Any(value=connection.handle.to_bytes(4, 'big'))
+ return WaitConnectionResponse(connection=Connection(cookie=cookie))
+
+ @utils.rpc
+ async def ConnectLE(
+ self, request: ConnectLERequest, context: grpc.ServicerContext
+ ) -> ConnectLEResponse:
+ address = utils.address_from_request(request, request.WhichOneof("address"))
+ if address in (Address.NIL, Address.ANY):
+ raise ValueError('Invalid address')
+
+ self.log.info(f"ConnectLE to {address}...")
+
+ try:
+ connection = await self.device.connect(
+ address,
+ transport=BT_LE_TRANSPORT,
+ own_address_type=request.own_address_type,
+ )
+ except ConnectionError as e:
+ if e.error_code == HCI_PAGE_TIMEOUT_ERROR:
+ self.log.warning(f"Peer not found: {e}")
+ return ConnectLEResponse(peer_not_found=empty_pb2.Empty())
+ if e.error_code == HCI_CONNECTION_ALREADY_EXISTS_ERROR:
+ self.log.warning(f"Connection already exists: {e}")
+ return ConnectLEResponse(connection_already_exists=empty_pb2.Empty())
+ raise e
+
+ self.log.info(f"ConnectLE to {address} done (handle={connection.handle})")
+
+ cookie = any_pb2.Any(value=connection.handle.to_bytes(4, 'big'))
+ return ConnectLEResponse(connection=Connection(cookie=cookie))
+
+ @utils.rpc
+ async def Disconnect(
+ self, request: DisconnectRequest, context: grpc.ServicerContext
+ ) -> empty_pb2.Empty:
+ connection_handle = int.from_bytes(request.connection.cookie.value, 'big')
+ self.log.info(f"Disconnect: {connection_handle}")
+
+ self.log.info("Disconnecting...")
+ if connection := self.device.lookup_connection(connection_handle):
+ await connection.disconnect(HCI_REMOTE_USER_TERMINATED_CONNECTION_ERROR)
+ self.log.info("Disconnected")
+
+ return empty_pb2.Empty()
+
+ @utils.rpc
+ async def WaitDisconnection(
+ self, request: WaitDisconnectionRequest, context: grpc.ServicerContext
+ ) -> empty_pb2.Empty:
+ connection_handle = int.from_bytes(request.connection.cookie.value, 'big')
+ self.log.info(f"WaitDisconnection: {connection_handle}")
+
+ if connection := self.device.lookup_connection(connection_handle):
+ disconnection_future: asyncio.Future[
+ None
+ ] = asyncio.get_running_loop().create_future()
+
+ def on_disconnection(_: None) -> None:
+ disconnection_future.set_result(None)
+
+ connection.on('disconnection', on_disconnection)
+ try:
+ await disconnection_future
+ self.log.info("Disconnected")
+ finally:
+ connection.remove_listener('disconnection', on_disconnection) # type: ignore
+
+ return empty_pb2.Empty()
+
+ @utils.rpc
+ async def Advertise(
+ self, request: AdvertiseRequest, context: grpc.ServicerContext
+ ) -> AsyncGenerator[AdvertiseResponse, None]:
+ if not request.legacy:
+ raise NotImplementedError(
+ "TODO: add support for extended advertising in Bumble"
+ )
+ if request.interval:
+ raise NotImplementedError("TODO: add support for `request.interval`")
+ if request.interval_range:
+ raise NotImplementedError("TODO: add support for `request.interval_range`")
+ if request.primary_phy:
+ raise NotImplementedError("TODO: add support for `request.primary_phy`")
+ if request.secondary_phy:
+ raise NotImplementedError("TODO: add support for `request.secondary_phy`")
+
+ if self.device.is_advertising:
+ raise NotImplementedError('TODO: add support for advertising sets')
+
+ if data := request.data:
+ self.device.advertising_data = bytes(self.unpack_data_types(data))
+
+ if scan_response_data := request.scan_response_data:
+ self.device.scan_response_data = bytes(
+ self.unpack_data_types(scan_response_data)
+ )
+ scannable = True
+ else:
+ scannable = False
+
+ # Retrieve services data
+ for service in self.device.gatt_server.attributes:
+ if isinstance(service, Service) and (
+ service_data := service.get_advertising_data()
+ ):
+ service_uuid = service.uuid.to_hex_str('-')
+ if (
+ service_uuid in request.data.incomplete_service_class_uuids16
+ or service_uuid in request.data.complete_service_class_uuids16
+ or service_uuid in request.data.incomplete_service_class_uuids32
+ or service_uuid in request.data.complete_service_class_uuids32
+ or service_uuid
+ in request.data.incomplete_service_class_uuids128
+ or service_uuid in request.data.complete_service_class_uuids128
+ ):
+ self.device.advertising_data += service_data
+ if (
+ service_uuid
+ in scan_response_data.incomplete_service_class_uuids16
+ or service_uuid
+ in scan_response_data.complete_service_class_uuids16
+ or service_uuid
+ in scan_response_data.incomplete_service_class_uuids32
+ or service_uuid
+ in scan_response_data.complete_service_class_uuids32
+ or service_uuid
+ in scan_response_data.incomplete_service_class_uuids128
+ or service_uuid
+ in scan_response_data.complete_service_class_uuids128
+ ):
+ self.device.scan_response_data += service_data
+
+ target = None
+ if request.connectable and scannable:
+ advertising_type = AdvertisingType.UNDIRECTED_CONNECTABLE_SCANNABLE
+ elif scannable:
+ advertising_type = AdvertisingType.UNDIRECTED_SCANNABLE
+ else:
+ advertising_type = AdvertisingType.UNDIRECTED
+ else:
+ target = None
+ advertising_type = AdvertisingType.UNDIRECTED
+
+ if request.target:
+ # Need to reverse bytes order since Bumble Address is using MSB.
+ target_bytes = bytes(reversed(request.target))
+ if request.target_variant() == "public":
+ target = Address(target_bytes, Address.PUBLIC_DEVICE_ADDRESS)
+ advertising_type = (
+ AdvertisingType.DIRECTED_CONNECTABLE_HIGH_DUTY
+ ) # FIXME: HIGH_DUTY ?
+ else:
+ target = Address(target_bytes, Address.RANDOM_DEVICE_ADDRESS)
+ advertising_type = (
+ AdvertisingType.DIRECTED_CONNECTABLE_HIGH_DUTY
+ ) # FIXME: HIGH_DUTY ?
+
+ if request.connectable:
+
+ def on_connection(connection: bumble.device.Connection) -> None:
+ if (
+ connection.transport == BT_LE_TRANSPORT
+ and connection.role == BT_PERIPHERAL_ROLE
+ ):
+ pending_connection.set_result(connection)
+
+ self.device.on('connection', on_connection)
+
+ try:
+ while True:
+ if not self.device.is_advertising:
+ self.log.info('Advertise')
+ await self.device.start_advertising(
+ target=target,
+ advertising_type=advertising_type,
+ own_address_type=request.own_address_type,
+ )
+
+ if not request.connectable:
+ await asyncio.sleep(1)
+ continue
+
+ pending_connection: asyncio.Future[
+ bumble.device.Connection
+ ] = asyncio.get_running_loop().create_future()
+
+ self.log.info('Wait for LE connection...')
+ connection = await pending_connection
+
+ self.log.info(
+ f"Advertise: Connected to {connection.peer_address} (handle={connection.handle})"
+ )
+
+ cookie = any_pb2.Any(value=connection.handle.to_bytes(4, 'big'))
+ yield AdvertiseResponse(connection=Connection(cookie=cookie))
+
+ # wait a small delay before restarting the advertisement.
+ await asyncio.sleep(1)
+ finally:
+ if request.connectable:
+ self.device.remove_listener('connection', on_connection) # type: ignore
+
+ try:
+ self.log.info('Stop advertising')
+ await self.device.abort_on('flush', self.device.stop_advertising())
+ except:
+ pass
+
+ @utils.rpc
+ async def Scan(
+ self, request: ScanRequest, context: grpc.ServicerContext
+ ) -> AsyncGenerator[ScanningResponse, None]:
+ # TODO: modify `start_scanning` to accept floats instead of int for ms values
+ if request.phys:
+ raise NotImplementedError("TODO: add support for `request.phys`")
+
+ self.log.info('Scan')
+
+ scan_queue: asyncio.Queue[Advertisement] = asyncio.Queue()
+ handler = self.device.on('advertisement', scan_queue.put_nowait)
+ await self.device.start_scanning(
+ legacy=request.legacy,
+ active=not request.passive,
+ own_address_type=request.own_address_type,
+ scan_interval=int(request.interval)
+ if request.interval
+ else DEVICE_DEFAULT_SCAN_INTERVAL,
+ scan_window=int(request.window)
+ if request.window
+ else DEVICE_DEFAULT_SCAN_WINDOW,
+ )
+
+ try:
+ # TODO: add support for `direct_address` in Bumble
+ # TODO: add support for `periodic_advertising_interval` in Bumble
+ while adv := await scan_queue.get():
+ sr = ScanningResponse(
+ legacy=adv.is_legacy,
+ connectable=adv.is_connectable,
+ scannable=adv.is_scannable,
+ truncated=adv.is_truncated,
+ sid=adv.sid,
+ primary_phy=PRIMARY_PHY_MAP[adv.primary_phy],
+ secondary_phy=SECONDARY_PHY_MAP[adv.secondary_phy],
+ tx_power=adv.tx_power,
+ rssi=adv.rssi,
+ data=self.pack_data_types(adv.data),
+ )
+
+ if adv.address.address_type == Address.PUBLIC_DEVICE_ADDRESS:
+ sr.public = bytes(reversed(bytes(adv.address)))
+ elif adv.address.address_type == Address.RANDOM_DEVICE_ADDRESS:
+ sr.random = bytes(reversed(bytes(adv.address)))
+ elif adv.address.address_type == Address.PUBLIC_IDENTITY_ADDRESS:
+ sr.public_identity = bytes(reversed(bytes(adv.address)))
+ else:
+ sr.random_static_identity = bytes(reversed(bytes(adv.address)))
+
+ yield sr
+
+ finally:
+ self.device.remove_listener('advertisement', handler) # type: ignore
+ try:
+ self.log.info('Stop scanning')
+ await self.device.abort_on('flush', self.device.stop_scanning())
+ except:
+ pass
+
+ @utils.rpc
+ async def Inquiry(
+ self, request: empty_pb2.Empty, context: grpc.ServicerContext
+ ) -> AsyncGenerator[InquiryResponse, None]:
+ self.log.info('Inquiry')
+
+ inquiry_queue: asyncio.Queue[
+ Optional[Tuple[Address, int, AdvertisingData, int]]
+ ] = asyncio.Queue()
+ complete_handler = self.device.on(
+ 'inquiry_complete', lambda: inquiry_queue.put_nowait(None)
+ )
+ result_handler = self.device.on( # type: ignore
+ 'inquiry_result',
+ lambda address, class_of_device, eir_data, rssi: inquiry_queue.put_nowait( # type: ignore
+ (address, class_of_device, eir_data, rssi) # type: ignore
+ ),
+ )
+
+ await self.device.start_discovery(auto_restart=False)
+ try:
+ while inquiry_result := await inquiry_queue.get():
+ (address, class_of_device, eir_data, rssi) = inquiry_result
+ # FIXME: if needed, add support for `page_scan_repetition_mode` and `clock_offset` in Bumble
+ yield InquiryResponse(
+ address=bytes(reversed(bytes(address))),
+ class_of_device=class_of_device,
+ rssi=rssi,
+ data=self.pack_data_types(eir_data),
+ )
+
+ finally:
+ self.device.remove_listener('inquiry_complete', complete_handler) # type: ignore
+ self.device.remove_listener('inquiry_result', result_handler) # type: ignore
+ try:
+ self.log.info('Stop inquiry')
+ await self.device.abort_on('flush', self.device.stop_discovery())
+ except:
+ pass
+
+ @utils.rpc
+ async def SetDiscoverabilityMode(
+ self, request: SetDiscoverabilityModeRequest, context: grpc.ServicerContext
+ ) -> empty_pb2.Empty:
+ self.log.info("SetDiscoverabilityMode")
+ await self.device.set_discoverable(request.mode != NOT_DISCOVERABLE)
+ return empty_pb2.Empty()
+
+ @utils.rpc
+ async def SetConnectabilityMode(
+ self, request: SetConnectabilityModeRequest, context: grpc.ServicerContext
+ ) -> empty_pb2.Empty:
+ self.log.info("SetConnectabilityMode")
+ await self.device.set_connectable(request.mode != NOT_CONNECTABLE)
+ return empty_pb2.Empty()
+
+ def unpack_data_types(self, dt: DataTypes) -> AdvertisingData:
+ ad_structures: List[Tuple[int, bytes]] = []
+
+ uuids: List[str]
+ datas: Dict[str, bytes]
+
+ def uuid128_from_str(uuid: str) -> bytes:
+ """Decode a 128-bit uuid encoded as XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
+ to byte format."""
+ return bytes(reversed(bytes.fromhex(uuid.replace('-', ''))))
+
+ def uuid32_from_str(uuid: str) -> bytes:
+ """Decode a 32-bit uuid encoded as XXXXXXXX to byte format."""
+ return bytes(reversed(bytes.fromhex(uuid)))
+
+ def uuid16_from_str(uuid: str) -> bytes:
+ """Decode a 16-bit uuid encoded as XXXX to byte format."""
+ return bytes(reversed(bytes.fromhex(uuid)))
+
+ if uuids := dt.incomplete_service_class_uuids16:
+ ad_structures.append(
+ (
+ AdvertisingData.INCOMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS,
+ b''.join([uuid16_from_str(uuid) for uuid in uuids]),
+ )
+ )
+ if uuids := dt.complete_service_class_uuids16:
+ ad_structures.append(
+ (
+ AdvertisingData.COMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS,
+ b''.join([uuid16_from_str(uuid) for uuid in uuids]),
+ )
+ )
+ if uuids := dt.incomplete_service_class_uuids32:
+ ad_structures.append(
+ (
+ AdvertisingData.INCOMPLETE_LIST_OF_32_BIT_SERVICE_CLASS_UUIDS,
+ b''.join([uuid32_from_str(uuid) for uuid in uuids]),
+ )
+ )
+ if uuids := dt.complete_service_class_uuids32:
+ ad_structures.append(
+ (
+ AdvertisingData.COMPLETE_LIST_OF_32_BIT_SERVICE_CLASS_UUIDS,
+ b''.join([uuid32_from_str(uuid) for uuid in uuids]),
+ )
+ )
+ if uuids := dt.incomplete_service_class_uuids128:
+ ad_structures.append(
+ (
+ AdvertisingData.INCOMPLETE_LIST_OF_128_BIT_SERVICE_CLASS_UUIDS,
+ b''.join([uuid128_from_str(uuid) for uuid in uuids]),
+ )
+ )
+ if uuids := dt.complete_service_class_uuids128:
+ ad_structures.append(
+ (
+ AdvertisingData.COMPLETE_LIST_OF_128_BIT_SERVICE_CLASS_UUIDS,
+ b''.join([uuid128_from_str(uuid) for uuid in uuids]),
+ )
+ )
+ if dt.HasField('include_shortened_local_name'):
+ ad_structures.append(
+ (
+ AdvertisingData.SHORTENED_LOCAL_NAME,
+ bytes(self.device.name[:8], 'utf-8'),
+ )
+ )
+ elif dt.shortened_local_name:
+ ad_structures.append(
+ (
+ AdvertisingData.SHORTENED_LOCAL_NAME,
+ bytes(dt.shortened_local_name, 'utf-8'),
+ )
+ )
+ if dt.HasField('include_complete_local_name'):
+ ad_structures.append(
+ (AdvertisingData.COMPLETE_LOCAL_NAME, bytes(self.device.name, 'utf-8'))
+ )
+ elif dt.complete_local_name:
+ ad_structures.append(
+ (
+ AdvertisingData.COMPLETE_LOCAL_NAME,
+ bytes(dt.complete_local_name, 'utf-8'),
+ )
+ )
+ if dt.HasField('include_tx_power_level'):
+ raise ValueError('unsupported data type')
+ elif dt.tx_power_level:
+ ad_structures.append(
+ (
+ AdvertisingData.TX_POWER_LEVEL,
+ bytes(struct.pack('<I', dt.tx_power_level)[:1]),
+ )
+ )
+ if dt.HasField('include_class_of_device'):
+ ad_structures.append(
+ (
+ AdvertisingData.CLASS_OF_DEVICE,
+ bytes(struct.pack('<I', self.device.class_of_device)[:-1]),
+ )
+ )
+ elif dt.class_of_device:
+ ad_structures.append(
+ (
+ AdvertisingData.CLASS_OF_DEVICE,
+ bytes(struct.pack('<I', dt.class_of_device)[:-1]),
+ )
+ )
+ if dt.peripheral_connection_interval_min:
+ ad_structures.append(
+ (
+ AdvertisingData.PERIPHERAL_CONNECTION_INTERVAL_RANGE,
+ bytes(
+ [
+ *struct.pack('<H', dt.peripheral_connection_interval_min),
+ *struct.pack(
+ '<H',
+ dt.peripheral_connection_interval_max
+ if dt.peripheral_connection_interval_max
+ else dt.peripheral_connection_interval_min,
+ ),
+ ]
+ ),
+ )
+ )
+ if uuids := dt.service_solicitation_uuids16:
+ ad_structures.append(
+ (
+ AdvertisingData.LIST_OF_16_BIT_SERVICE_SOLICITATION_UUIDS,
+ b''.join([uuid16_from_str(uuid) for uuid in uuids]),
+ )
+ )
+ if uuids := dt.service_solicitation_uuids32:
+ ad_structures.append(
+ (
+ AdvertisingData.LIST_OF_32_BIT_SERVICE_SOLICITATION_UUIDS,
+ b''.join([uuid32_from_str(uuid) for uuid in uuids]),
+ )
+ )
+ if uuids := dt.service_solicitation_uuids128:
+ ad_structures.append(
+ (
+ AdvertisingData.LIST_OF_128_BIT_SERVICE_SOLICITATION_UUIDS,
+ b''.join([uuid128_from_str(uuid) for uuid in uuids]),
+ )
+ )
+ if datas := dt.service_data_uuid16:
+ ad_structures.extend(
+ [
+ (
+ AdvertisingData.SERVICE_DATA_16_BIT_UUID,
+ uuid16_from_str(uuid) + data,
+ )
+ for uuid, data in datas.items()
+ ]
+ )
+ if datas := dt.service_data_uuid32:
+ ad_structures.extend(
+ [
+ (
+ AdvertisingData.SERVICE_DATA_32_BIT_UUID,
+ uuid32_from_str(uuid) + data,
+ )
+ for uuid, data in datas.items()
+ ]
+ )
+ if datas := dt.service_data_uuid128:
+ ad_structures.extend(
+ [
+ (
+ AdvertisingData.SERVICE_DATA_128_BIT_UUID,
+ uuid128_from_str(uuid) + data,
+ )
+ for uuid, data in datas.items()
+ ]
+ )
+ if dt.appearance:
+ ad_structures.append(
+ (AdvertisingData.APPEARANCE, struct.pack('<H', dt.appearance))
+ )
+ if dt.advertising_interval:
+ ad_structures.append(
+ (
+ AdvertisingData.ADVERTISING_INTERVAL,
+ struct.pack('<H', dt.advertising_interval),
+ )
+ )
+ if dt.uri:
+ ad_structures.append((AdvertisingData.URI, bytes(dt.uri, 'utf-8')))
+ if dt.le_supported_features:
+ ad_structures.append(
+ (AdvertisingData.LE_SUPPORTED_FEATURES, dt.le_supported_features)
+ )
+ if dt.manufacturer_specific_data:
+ ad_structures.append(
+ (
+ AdvertisingData.MANUFACTURER_SPECIFIC_DATA,
+ dt.manufacturer_specific_data,
+ )
+ )
+
+ return AdvertisingData(ad_structures)
+
+ def pack_data_types(self, ad: AdvertisingData) -> DataTypes:
+ dt = DataTypes()
+ uuids: List[UUID]
+ s: str
+ i: int
+ ij: Tuple[int, int]
+ uuid_data: Tuple[UUID, bytes]
+ data: bytes
+
+ if uuids := cast(
+ List[UUID],
+ ad.get(AdvertisingData.INCOMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS),
+ ):
+ dt.incomplete_service_class_uuids16.extend(
+ list(map(lambda x: x.to_hex_str('-'), uuids))
+ )
+ if uuids := cast(
+ List[UUID],
+ ad.get(AdvertisingData.COMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS),
+ ):
+ dt.complete_service_class_uuids16.extend(
+ list(map(lambda x: x.to_hex_str('-'), uuids))
+ )
+ if uuids := cast(
+ List[UUID],
+ ad.get(AdvertisingData.INCOMPLETE_LIST_OF_32_BIT_SERVICE_CLASS_UUIDS),
+ ):
+ dt.incomplete_service_class_uuids32.extend(
+ list(map(lambda x: x.to_hex_str('-'), uuids))
+ )
+ if uuids := cast(
+ List[UUID],
+ ad.get(AdvertisingData.COMPLETE_LIST_OF_32_BIT_SERVICE_CLASS_UUIDS),
+ ):
+ dt.complete_service_class_uuids32.extend(
+ list(map(lambda x: x.to_hex_str('-'), uuids))
+ )
+ if uuids := cast(
+ List[UUID],
+ ad.get(AdvertisingData.INCOMPLETE_LIST_OF_128_BIT_SERVICE_CLASS_UUIDS),
+ ):
+ dt.incomplete_service_class_uuids128.extend(
+ list(map(lambda x: x.to_hex_str('-'), uuids))
+ )
+ if uuids := cast(
+ List[UUID],
+ ad.get(AdvertisingData.COMPLETE_LIST_OF_128_BIT_SERVICE_CLASS_UUIDS),
+ ):
+ dt.complete_service_class_uuids128.extend(
+ list(map(lambda x: x.to_hex_str('-'), uuids))
+ )
+ if s := cast(str, ad.get(AdvertisingData.SHORTENED_LOCAL_NAME)):
+ dt.shortened_local_name = s
+ if s := cast(str, ad.get(AdvertisingData.COMPLETE_LOCAL_NAME)):
+ dt.complete_local_name = s
+ if i := cast(int, ad.get(AdvertisingData.TX_POWER_LEVEL)):
+ dt.tx_power_level = i
+ if i := cast(int, ad.get(AdvertisingData.CLASS_OF_DEVICE)):
+ dt.class_of_device = i
+ if ij := cast(
+ Tuple[int, int],
+ ad.get(AdvertisingData.PERIPHERAL_CONNECTION_INTERVAL_RANGE),
+ ):
+ dt.peripheral_connection_interval_min = ij[0]
+ dt.peripheral_connection_interval_max = ij[1]
+ if uuids := cast(
+ List[UUID],
+ ad.get(AdvertisingData.LIST_OF_16_BIT_SERVICE_SOLICITATION_UUIDS),
+ ):
+ dt.service_solicitation_uuids16.extend(
+ list(map(lambda x: x.to_hex_str('-'), uuids))
+ )
+ if uuids := cast(
+ List[UUID],
+ ad.get(AdvertisingData.LIST_OF_32_BIT_SERVICE_SOLICITATION_UUIDS),
+ ):
+ dt.service_solicitation_uuids32.extend(
+ list(map(lambda x: x.to_hex_str('-'), uuids))
+ )
+ if uuids := cast(
+ List[UUID],
+ ad.get(AdvertisingData.LIST_OF_128_BIT_SERVICE_SOLICITATION_UUIDS),
+ ):
+ dt.service_solicitation_uuids128.extend(
+ list(map(lambda x: x.to_hex_str('-'), uuids))
+ )
+ if uuid_data := cast(
+ Tuple[UUID, bytes], ad.get(AdvertisingData.SERVICE_DATA_16_BIT_UUID)
+ ):
+ dt.service_data_uuid16[uuid_data[0].to_hex_str('-')] = uuid_data[1]
+ if uuid_data := cast(
+ Tuple[UUID, bytes], ad.get(AdvertisingData.SERVICE_DATA_32_BIT_UUID)
+ ):
+ dt.service_data_uuid32[uuid_data[0].to_hex_str('-')] = uuid_data[1]
+ if uuid_data := cast(
+ Tuple[UUID, bytes], ad.get(AdvertisingData.SERVICE_DATA_128_BIT_UUID)
+ ):
+ dt.service_data_uuid128[uuid_data[0].to_hex_str('-')] = uuid_data[1]
+ if data := cast(bytes, ad.get(AdvertisingData.PUBLIC_TARGET_ADDRESS, raw=True)):
+ dt.public_target_addresses.extend(
+ [data[i * 6 :: i * 6 + 6] for i in range(int(len(data) / 6))]
+ )
+ if data := cast(bytes, ad.get(AdvertisingData.RANDOM_TARGET_ADDRESS, raw=True)):
+ dt.random_target_addresses.extend(
+ [data[i * 6 :: i * 6 + 6] for i in range(int(len(data) / 6))]
+ )
+ if i := cast(int, ad.get(AdvertisingData.APPEARANCE)):
+ dt.appearance = i
+ if i := cast(int, ad.get(AdvertisingData.ADVERTISING_INTERVAL)):
+ dt.advertising_interval = i
+ if s := cast(str, ad.get(AdvertisingData.URI)):
+ dt.uri = s
+ if data := cast(bytes, ad.get(AdvertisingData.LE_SUPPORTED_FEATURES, raw=True)):
+ dt.le_supported_features = data
+ if data := cast(
+ bytes, ad.get(AdvertisingData.MANUFACTURER_SPECIFIC_DATA, raw=True)
+ ):
+ dt.manufacturer_specific_data = data
+
+ return dt
diff --git a/bumble/pandora/py.typed b/bumble/pandora/py.typed
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/bumble/pandora/py.typed
diff --git a/bumble/pandora/security.py b/bumble/pandora/security.py
new file mode 100644
index 0000000..fee1b7a
--- /dev/null
+++ b/bumble/pandora/security.py
@@ -0,0 +1,529 @@
+# Copyright 2022 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import asyncio
+import grpc
+import logging
+
+from . import utils
+from .config import Config
+from bumble import hci
+from bumble.core import (
+ BT_BR_EDR_TRANSPORT,
+ BT_LE_TRANSPORT,
+ BT_PERIPHERAL_ROLE,
+ ProtocolError,
+)
+from bumble.device import Connection as BumbleConnection, Device
+from bumble.hci import HCI_Error
+from bumble.pairing import PairingConfig, PairingDelegate as BasePairingDelegate
+from contextlib import suppress
+from google.protobuf import (
+ any_pb2,
+ empty_pb2,
+ wrappers_pb2,
+) # pytype: disable=pyi-error
+from google.protobuf.wrappers_pb2 import BoolValue # pytype: disable=pyi-error
+from pandora.host_pb2 import Connection
+from pandora.security_grpc_aio import SecurityServicer, SecurityStorageServicer
+from pandora.security_pb2 import (
+ LE_LEVEL1,
+ LE_LEVEL2,
+ LE_LEVEL3,
+ LE_LEVEL4,
+ LEVEL0,
+ LEVEL1,
+ LEVEL2,
+ LEVEL3,
+ LEVEL4,
+ DeleteBondRequest,
+ IsBondedRequest,
+ LESecurityLevel,
+ PairingEvent,
+ PairingEventAnswer,
+ SecureRequest,
+ SecureResponse,
+ SecurityLevel,
+ WaitSecurityRequest,
+ WaitSecurityResponse,
+)
+from typing import Any, AsyncGenerator, AsyncIterator, Callable, Dict, Optional, Union
+
+
+class PairingDelegate(BasePairingDelegate):
+ def __init__(
+ self,
+ connection: BumbleConnection,
+ service: "SecurityService",
+ io_capability: BasePairingDelegate.IoCapability = BasePairingDelegate.NO_OUTPUT_NO_INPUT,
+ local_initiator_key_distribution: BasePairingDelegate.KeyDistribution = BasePairingDelegate.DEFAULT_KEY_DISTRIBUTION,
+ local_responder_key_distribution: BasePairingDelegate.KeyDistribution = BasePairingDelegate.DEFAULT_KEY_DISTRIBUTION,
+ ) -> None:
+ self.log = utils.BumbleServerLoggerAdapter(
+ logging.getLogger(),
+ {'service_name': 'Security', 'device': connection.device},
+ )
+ self.connection = connection
+ self.service = service
+ super().__init__(
+ io_capability,
+ local_initiator_key_distribution,
+ local_responder_key_distribution,
+ )
+
+ async def accept(self) -> bool:
+ return True
+
+ def add_origin(self, ev: PairingEvent) -> PairingEvent:
+ if not self.connection.is_incomplete:
+ assert ev.connection
+ ev.connection.CopyFrom(
+ Connection(
+ cookie=any_pb2.Any(value=self.connection.handle.to_bytes(4, 'big'))
+ )
+ )
+ else:
+ # In BR/EDR, connection may not be complete,
+ # use address instead
+ assert self.connection.transport == BT_BR_EDR_TRANSPORT
+ ev.address = bytes(reversed(bytes(self.connection.peer_address)))
+
+ return ev
+
+ async def confirm(self, auto: bool = False) -> bool:
+ self.log.info(
+ f"Pairing event: `just_works` (io_capability: {self.io_capability})"
+ )
+
+ if self.service.event_queue is None or self.service.event_answer is None:
+ return True
+
+ event = self.add_origin(PairingEvent(just_works=empty_pb2.Empty()))
+ self.service.event_queue.put_nowait(event)
+ answer = await anext(self.service.event_answer) # pytype: disable=name-error
+ assert answer.event == event
+ assert answer.answer_variant() == 'confirm' and answer.confirm is not None
+ return answer.confirm
+
+ async def compare_numbers(self, number: int, digits: int = 6) -> bool:
+ self.log.info(
+ f"Pairing event: `numeric_comparison` (io_capability: {self.io_capability})"
+ )
+
+ if self.service.event_queue is None or self.service.event_answer is None:
+ raise RuntimeError('security: unhandled number comparison request')
+
+ event = self.add_origin(PairingEvent(numeric_comparison=number))
+ self.service.event_queue.put_nowait(event)
+ answer = await anext(self.service.event_answer) # pytype: disable=name-error
+ assert answer.event == event
+ assert answer.answer_variant() == 'confirm' and answer.confirm is not None
+ return answer.confirm
+
+ async def get_number(self) -> Optional[int]:
+ self.log.info(
+ f"Pairing event: `passkey_entry_request` (io_capability: {self.io_capability})"
+ )
+
+ if self.service.event_queue is None or self.service.event_answer is None:
+ raise RuntimeError('security: unhandled number request')
+
+ event = self.add_origin(PairingEvent(passkey_entry_request=empty_pb2.Empty()))
+ self.service.event_queue.put_nowait(event)
+ answer = await anext(self.service.event_answer) # pytype: disable=name-error
+ assert answer.event == event
+ if answer.answer_variant() is None:
+ return None
+ assert answer.answer_variant() == 'passkey'
+ return answer.passkey
+
+ async def get_string(self, max_length: int) -> Optional[str]:
+ self.log.info(
+ f"Pairing event: `pin_code_request` (io_capability: {self.io_capability})"
+ )
+
+ if self.service.event_queue is None or self.service.event_answer is None:
+ raise RuntimeError('security: unhandled pin_code request')
+
+ event = self.add_origin(PairingEvent(pin_code_request=empty_pb2.Empty()))
+ self.service.event_queue.put_nowait(event)
+ answer = await anext(self.service.event_answer) # pytype: disable=name-error
+ assert answer.event == event
+ if answer.answer_variant() is None:
+ return None
+ assert answer.answer_variant() == 'pin'
+
+ if answer.pin is None:
+ return None
+
+ pin = answer.pin.decode('utf-8')
+ if not pin or len(pin) > max_length:
+ raise ValueError(f'Pin must be utf-8 encoded up to {max_length} bytes')
+
+ return pin
+
+ async def display_number(self, number: int, digits: int = 6) -> None:
+ if (
+ self.connection.transport == BT_BR_EDR_TRANSPORT
+ and self.io_capability == BasePairingDelegate.DISPLAY_OUTPUT_ONLY
+ ):
+ return
+
+ self.log.info(
+ f"Pairing event: `passkey_entry_notification` (io_capability: {self.io_capability})"
+ )
+
+ if self.service.event_queue is None:
+ raise RuntimeError('security: unhandled number display request')
+
+ event = self.add_origin(PairingEvent(passkey_entry_notification=number))
+ self.service.event_queue.put_nowait(event)
+
+
+BR_LEVEL_REACHED: Dict[SecurityLevel, Callable[[BumbleConnection], bool]] = {
+ LEVEL0: lambda connection: True,
+ LEVEL1: lambda connection: connection.encryption == 0 or connection.authenticated,
+ LEVEL2: lambda connection: connection.encryption != 0 and connection.authenticated,
+ LEVEL3: lambda connection: connection.encryption != 0
+ and connection.authenticated
+ and connection.link_key_type
+ in (
+ hci.HCI_AUTHENTICATED_COMBINATION_KEY_GENERATED_FROM_P_192_TYPE,
+ hci.HCI_AUTHENTICATED_COMBINATION_KEY_GENERATED_FROM_P_256_TYPE,
+ ),
+ LEVEL4: lambda connection: connection.encryption
+ == hci.HCI_Encryption_Change_Event.AES_CCM
+ and connection.authenticated
+ and connection.link_key_type
+ == hci.HCI_AUTHENTICATED_COMBINATION_KEY_GENERATED_FROM_P_256_TYPE,
+}
+
+LE_LEVEL_REACHED: Dict[LESecurityLevel, Callable[[BumbleConnection], bool]] = {
+ LE_LEVEL1: lambda connection: True,
+ LE_LEVEL2: lambda connection: connection.encryption != 0,
+ LE_LEVEL3: lambda connection: connection.encryption != 0
+ and connection.authenticated,
+ LE_LEVEL4: lambda connection: connection.encryption != 0
+ and connection.authenticated
+ and connection.sc,
+}
+
+
+class SecurityService(SecurityServicer):
+ def __init__(self, device: Device, config: Config) -> None:
+ self.log = utils.BumbleServerLoggerAdapter(
+ logging.getLogger(), {'service_name': 'Security', 'device': device}
+ )
+ self.event_queue: Optional[asyncio.Queue[PairingEvent]] = None
+ self.event_answer: Optional[AsyncIterator[PairingEventAnswer]] = None
+ self.device = device
+ self.config = config
+
+ def pairing_config_factory(connection: BumbleConnection) -> PairingConfig:
+ return PairingConfig(
+ sc=config.pairing_sc_enable,
+ mitm=config.pairing_mitm_enable,
+ bonding=config.pairing_bonding_enable,
+ delegate=PairingDelegate(
+ connection,
+ self,
+ io_capability=config.io_capability,
+ local_initiator_key_distribution=config.smp_local_initiator_key_distribution,
+ local_responder_key_distribution=config.smp_local_responder_key_distribution,
+ ),
+ )
+
+ self.device.pairing_config_factory = pairing_config_factory
+
+ @utils.rpc
+ async def OnPairing(
+ self, request: AsyncIterator[PairingEventAnswer], context: grpc.ServicerContext
+ ) -> AsyncGenerator[PairingEvent, None]:
+ self.log.info('OnPairing')
+
+ if self.event_queue is not None:
+ raise RuntimeError('already streaming pairing events')
+
+ if len(self.device.connections):
+ raise RuntimeError(
+ 'the `OnPairing` method shall be initiated before establishing any connections.'
+ )
+
+ self.event_queue = asyncio.Queue()
+ self.event_answer = request
+
+ try:
+ while event := await self.event_queue.get():
+ yield event
+
+ finally:
+ self.event_queue = None
+ self.event_answer = None
+
+ @utils.rpc
+ async def Secure(
+ self, request: SecureRequest, context: grpc.ServicerContext
+ ) -> SecureResponse:
+ connection_handle = int.from_bytes(request.connection.cookie.value, 'big')
+ self.log.info(f"Secure: {connection_handle}")
+
+ connection = self.device.lookup_connection(connection_handle)
+ assert connection
+
+ oneof = request.WhichOneof('level')
+ level = getattr(request, oneof)
+ assert {BT_BR_EDR_TRANSPORT: 'classic', BT_LE_TRANSPORT: 'le'}[
+ connection.transport
+ ] == oneof
+
+ # security level already reached
+ if self.reached_security_level(connection, level):
+ return SecureResponse(success=empty_pb2.Empty())
+
+ # trigger pairing if needed
+ if self.need_pairing(connection, level):
+ try:
+ self.log.info('Pair...')
+
+ if (
+ connection.transport == BT_LE_TRANSPORT
+ and connection.role == BT_PERIPHERAL_ROLE
+ ):
+ wait_for_security: asyncio.Future[
+ bool
+ ] = asyncio.get_running_loop().create_future()
+ connection.on("pairing", lambda *_: wait_for_security.set_result(True)) # type: ignore
+ connection.on("pairing_failure", wait_for_security.set_exception)
+
+ connection.request_pairing()
+
+ await wait_for_security
+ else:
+ await connection.pair()
+
+ self.log.info('Paired')
+ except asyncio.CancelledError:
+ self.log.warning("Connection died during encryption")
+ return SecureResponse(connection_died=empty_pb2.Empty())
+ except (HCI_Error, ProtocolError) as e:
+ self.log.warning(f"Pairing failure: {e}")
+ return SecureResponse(pairing_failure=empty_pb2.Empty())
+
+ # trigger authentication if needed
+ if self.need_authentication(connection, level):
+ try:
+ self.log.info('Authenticate...')
+ await connection.authenticate()
+ self.log.info('Authenticated')
+ except asyncio.CancelledError:
+ self.log.warning("Connection died during authentication")
+ return SecureResponse(connection_died=empty_pb2.Empty())
+ except (HCI_Error, ProtocolError) as e:
+ self.log.warning(f"Authentication failure: {e}")
+ return SecureResponse(authentication_failure=empty_pb2.Empty())
+
+ # trigger encryption if needed
+ if self.need_encryption(connection, level):
+ try:
+ self.log.info('Encrypt...')
+ await connection.encrypt()
+ self.log.info('Encrypted')
+ except asyncio.CancelledError:
+ self.log.warning("Connection died during encryption")
+ return SecureResponse(connection_died=empty_pb2.Empty())
+ except (HCI_Error, ProtocolError) as e:
+ self.log.warning(f"Encryption failure: {e}")
+ return SecureResponse(encryption_failure=empty_pb2.Empty())
+
+ # security level has been reached ?
+ if self.reached_security_level(connection, level):
+ return SecureResponse(success=empty_pb2.Empty())
+ return SecureResponse(not_reached=empty_pb2.Empty())
+
+ @utils.rpc
+ async def WaitSecurity(
+ self, request: WaitSecurityRequest, context: grpc.ServicerContext
+ ) -> WaitSecurityResponse:
+ connection_handle = int.from_bytes(request.connection.cookie.value, 'big')
+ self.log.info(f"WaitSecurity: {connection_handle}")
+
+ connection = self.device.lookup_connection(connection_handle)
+ assert connection
+
+ assert request.level
+ level = request.level
+ assert {BT_BR_EDR_TRANSPORT: 'classic', BT_LE_TRANSPORT: 'le'}[
+ connection.transport
+ ] == request.level_variant()
+
+ wait_for_security: asyncio.Future[
+ str
+ ] = asyncio.get_running_loop().create_future()
+ authenticate_task: Optional[asyncio.Future[None]] = None
+
+ async def authenticate() -> None:
+ assert connection
+ if (encryption := connection.encryption) != 0:
+ self.log.debug('Disable encryption...')
+ try:
+ await connection.encrypt(enable=False)
+ except:
+ pass
+ self.log.debug('Disable encryption: done')
+
+ self.log.debug('Authenticate...')
+ await connection.authenticate()
+ self.log.debug('Authenticate: done')
+
+ if encryption != 0 and connection.encryption != encryption:
+ self.log.debug('Re-enable encryption...')
+ await connection.encrypt()
+ self.log.debug('Re-enable encryption: done')
+
+ def set_failure(name: str) -> Callable[..., None]:
+ def wrapper(*args: Any) -> None:
+ self.log.info(f'Wait for security: error `{name}`: {args}')
+ wait_for_security.set_result(name)
+
+ return wrapper
+
+ def try_set_success(*_: Any) -> None:
+ assert connection
+ if self.reached_security_level(connection, level):
+ self.log.info('Wait for security: done')
+ wait_for_security.set_result('success')
+
+ def on_encryption_change(*_: Any) -> None:
+ assert connection
+ if self.reached_security_level(connection, level):
+ self.log.info('Wait for security: done')
+ wait_for_security.set_result('success')
+ elif (
+ connection.transport == BT_BR_EDR_TRANSPORT
+ and self.need_authentication(connection, level)
+ ):
+ nonlocal authenticate_task
+ if authenticate_task is None:
+ authenticate_task = asyncio.create_task(authenticate())
+
+ listeners: Dict[str, Callable[..., None]] = {
+ 'disconnection': set_failure('connection_died'),
+ 'pairing_failure': set_failure('pairing_failure'),
+ 'connection_authentication_failure': set_failure('authentication_failure'),
+ 'connection_encryption_failure': set_failure('encryption_failure'),
+ 'pairing': try_set_success,
+ 'connection_authentication': try_set_success,
+ 'connection_encryption_change': on_encryption_change,
+ }
+
+ # register event handlers
+ for event, listener in listeners.items():
+ connection.on(event, listener)
+
+ # security level already reached
+ if self.reached_security_level(connection, level):
+ return WaitSecurityResponse(success=empty_pb2.Empty())
+
+ self.log.info('Wait for security...')
+ kwargs = {}
+ kwargs[await wait_for_security] = empty_pb2.Empty()
+
+ # remove event handlers
+ for event, listener in listeners.items():
+ connection.remove_listener(event, listener) # type: ignore
+
+ # wait for `authenticate` to finish if any
+ if authenticate_task is not None:
+ self.log.info('Wait for authentication...')
+ try:
+ await authenticate_task # type: ignore
+ except:
+ pass
+ self.log.info('Authenticated')
+
+ return WaitSecurityResponse(**kwargs)
+
+ def reached_security_level(
+ self, connection: BumbleConnection, level: Union[SecurityLevel, LESecurityLevel]
+ ) -> bool:
+ self.log.debug(
+ str(
+ {
+ 'level': level,
+ 'encryption': connection.encryption,
+ 'authenticated': connection.authenticated,
+ 'sc': connection.sc,
+ 'link_key_type': connection.link_key_type,
+ }
+ )
+ )
+
+ if isinstance(level, LESecurityLevel):
+ return LE_LEVEL_REACHED[level](connection)
+
+ return BR_LEVEL_REACHED[level](connection)
+
+ def need_pairing(self, connection: BumbleConnection, level: int) -> bool:
+ if connection.transport == BT_LE_TRANSPORT:
+ return level >= LE_LEVEL3 and not connection.authenticated
+ return False
+
+ def need_authentication(self, connection: BumbleConnection, level: int) -> bool:
+ if connection.transport == BT_LE_TRANSPORT:
+ return False
+ if level == LEVEL2 and connection.encryption != 0:
+ return not connection.authenticated
+ return level >= LEVEL2 and not connection.authenticated
+
+ def need_encryption(self, connection: BumbleConnection, level: int) -> bool:
+ # TODO(abel): need to support MITM
+ if connection.transport == BT_LE_TRANSPORT:
+ return level == LE_LEVEL2 and not connection.encryption
+ return level >= LEVEL2 and not connection.encryption
+
+
+class SecurityStorageService(SecurityStorageServicer):
+ def __init__(self, device: Device, config: Config) -> None:
+ self.log = utils.BumbleServerLoggerAdapter(
+ logging.getLogger(), {'service_name': 'SecurityStorage', 'device': device}
+ )
+ self.device = device
+ self.config = config
+
+ @utils.rpc
+ async def IsBonded(
+ self, request: IsBondedRequest, context: grpc.ServicerContext
+ ) -> wrappers_pb2.BoolValue:
+ address = utils.address_from_request(request, request.WhichOneof("address"))
+ self.log.info(f"IsBonded: {address}")
+
+ if self.device.keystore is not None:
+ is_bonded = await self.device.keystore.get(str(address)) is not None
+ else:
+ is_bonded = False
+
+ return BoolValue(value=is_bonded)
+
+ @utils.rpc
+ async def DeleteBond(
+ self, request: DeleteBondRequest, context: grpc.ServicerContext
+ ) -> empty_pb2.Empty:
+ address = utils.address_from_request(request, request.WhichOneof("address"))
+ self.log.info(f"DeleteBond: {address}")
+
+ if self.device.keystore is not None:
+ with suppress(KeyError):
+ await self.device.keystore.delete(str(address))
+
+ return empty_pb2.Empty()
diff --git a/bumble/pandora/utils.py b/bumble/pandora/utils.py
new file mode 100644
index 0000000..c07a5bc
--- /dev/null
+++ b/bumble/pandora/utils.py
@@ -0,0 +1,112 @@
+# Copyright 2022 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import contextlib
+import functools
+import grpc
+import inspect
+import logging
+
+from bumble.device import Device
+from bumble.hci import Address
+from google.protobuf.message import Message # pytype: disable=pyi-error
+from typing import Any, Dict, Generator, MutableMapping, Optional, Tuple
+
+ADDRESS_TYPES: Dict[str, int] = {
+ "public": Address.PUBLIC_DEVICE_ADDRESS,
+ "random": Address.RANDOM_DEVICE_ADDRESS,
+ "public_identity": Address.PUBLIC_IDENTITY_ADDRESS,
+ "random_static_identity": Address.RANDOM_IDENTITY_ADDRESS,
+}
+
+
+def address_from_request(request: Message, field: Optional[str]) -> Address:
+ if field is None:
+ return Address.ANY
+ return Address(bytes(reversed(getattr(request, field))), ADDRESS_TYPES[field])
+
+
+class BumbleServerLoggerAdapter(logging.LoggerAdapter): # type: ignore
+ """Formats logs from the PandoraClient."""
+
+ def process(
+ self, msg: str, kwargs: MutableMapping[str, Any]
+ ) -> Tuple[str, MutableMapping[str, Any]]:
+ assert self.extra
+ service_name = self.extra['service_name']
+ assert isinstance(service_name, str)
+ device = self.extra['device']
+ assert isinstance(device, Device)
+ addr_bytes = bytes(
+ reversed(bytes(device.public_address))
+ ) # pytype: disable=attribute-error
+ addr = ':'.join([f'{x:02X}' for x in addr_bytes[4:]])
+ return (f'[bumble.{service_name}:{addr}] {msg}', kwargs)
+
+
+@contextlib.contextmanager
+def exception_to_rpc_error(
+ context: grpc.ServicerContext,
+) -> Generator[None, None, None]:
+ try:
+ yield None
+ except NotImplementedError as e:
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED) # type: ignore
+ context.set_details(str(e)) # type: ignore
+ except ValueError as e:
+ context.set_code(grpc.StatusCode.INVALID_ARGUMENT) # type: ignore
+ context.set_details(str(e)) # type: ignore
+ except RuntimeError as e:
+ context.set_code(grpc.StatusCode.ABORTED) # type: ignore
+ context.set_details(str(e)) # type: ignore
+
+
+# Decorate an RPC servicer method with a wrapper that transform exceptions to gRPC errors.
+def rpc(func: Any) -> Any:
+ @functools.wraps(func)
+ async def asyncgen_wrapper(
+ self: Any, request: Any, context: grpc.ServicerContext
+ ) -> Any:
+ with exception_to_rpc_error(context):
+ async for v in func(self, request, context):
+ yield v
+
+ @functools.wraps(func)
+ async def async_wrapper(
+ self: Any, request: Any, context: grpc.ServicerContext
+ ) -> Any:
+ with exception_to_rpc_error(context):
+ return await func(self, request, context)
+
+ @functools.wraps(func)
+ def gen_wrapper(self: Any, request: Any, context: grpc.ServicerContext) -> Any:
+ with exception_to_rpc_error(context):
+ for v in func(self, request, context):
+ yield v
+
+ @functools.wraps(func)
+ def wrapper(self: Any, request: Any, context: grpc.ServicerContext) -> Any:
+ with exception_to_rpc_error(context):
+ return func(self, request, context)
+
+ if inspect.isasyncgenfunction(func):
+ return asyncgen_wrapper
+
+ if inspect.iscoroutinefunction(func):
+ return async_wrapper
+
+ if inspect.isgenerator(func):
+ return gen_wrapper
+
+ return wrapper
diff --git a/bumble/profiles/asha_service.py b/bumble/profiles/asha_service.py
new file mode 100644
index 0000000..6898397
--- /dev/null
+++ b/bumble/profiles/asha_service.py
@@ -0,0 +1,188 @@
+# Copyright 2021-2022 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+# -----------------------------------------------------------------------------
+# Imports
+# -----------------------------------------------------------------------------
+import struct
+import logging
+from typing import List
+from ..core import AdvertisingData
+from ..device import Device, Connection
+from ..gatt import (
+ GATT_ASHA_SERVICE,
+ GATT_ASHA_READ_ONLY_PROPERTIES_CHARACTERISTIC,
+ GATT_ASHA_AUDIO_CONTROL_POINT_CHARACTERISTIC,
+ GATT_ASHA_AUDIO_STATUS_CHARACTERISTIC,
+ GATT_ASHA_VOLUME_CHARACTERISTIC,
+ GATT_ASHA_LE_PSM_OUT_CHARACTERISTIC,
+ TemplateService,
+ Characteristic,
+ CharacteristicValue,
+)
+from ..utils import AsyncRunner
+
+# -----------------------------------------------------------------------------
+# Logging
+# -----------------------------------------------------------------------------
+logger = logging.getLogger(__name__)
+
+
+# -----------------------------------------------------------------------------
+class AshaService(TemplateService):
+ UUID = GATT_ASHA_SERVICE
+ OPCODE_START = 1
+ OPCODE_STOP = 2
+ OPCODE_STATUS = 3
+ PROTOCOL_VERSION = 0x01
+ RESERVED_FOR_FUTURE_USE = [00, 00]
+ FEATURE_MAP = [0x01] # [LE CoC audio output streaming supported]
+ SUPPORTED_CODEC_ID = [0x02, 0x01] # Codec IDs [G.722 at 16 kHz]
+ RENDER_DELAY = [00, 00]
+
+ def __init__(self, capability: int, hisyncid: List[int], device: Device, psm=0):
+ self.hisyncid = hisyncid
+ self.capability = capability # Device Capabilities [Left, Monaural]
+ self.device = device
+ self.audio_out_data = b''
+ self.psm = psm # a non-zero psm is mainly for testing purpose
+
+ # Handler for volume control
+ def on_volume_write(connection, value):
+ logger.info(f'--- VOLUME Write:{value[0]}')
+ self.emit('volume', connection, value[0])
+
+ # Handler for audio control commands
+ def on_audio_control_point_write(connection: Connection, value):
+ logger.info(f'--- AUDIO CONTROL POINT Write:{value.hex()}')
+ opcode = value[0]
+ if opcode == AshaService.OPCODE_START:
+ # Start
+ audio_type = ('Unknown', 'Ringtone', 'Phone Call', 'Media')[value[2]]
+ logger.info(
+ f'### START: codec={value[1]}, '
+ f'audio_type={audio_type}, '
+ f'volume={value[3]}, '
+ f'otherstate={value[4]}'
+ )
+ self.emit(
+ 'start',
+ connection,
+ {
+ 'codec': value[1],
+ 'audiotype': value[2],
+ 'volume': value[3],
+ 'otherstate': value[4],
+ },
+ )
+ elif opcode == AshaService.OPCODE_STOP:
+ logger.info('### STOP')
+ self.emit('stop', connection)
+ elif opcode == AshaService.OPCODE_STATUS:
+ logger.info(f'### STATUS: connected={value[1]}')
+
+ # OPCODE_STATUS does not need audio status point update
+ if opcode != AshaService.OPCODE_STATUS:
+ AsyncRunner.spawn(
+ device.notify_subscribers(
+ self.audio_status_characteristic, force=True
+ )
+ )
+
+ self.read_only_properties_characteristic = Characteristic(
+ GATT_ASHA_READ_ONLY_PROPERTIES_CHARACTERISTIC,
+ Characteristic.Properties.READ,
+ Characteristic.READABLE,
+ bytes(
+ [
+ AshaService.PROTOCOL_VERSION, # Version
+ self.capability,
+ ]
+ )
+ + bytes(self.hisyncid)
+ + bytes(AshaService.FEATURE_MAP)
+ + bytes(AshaService.RENDER_DELAY)
+ + bytes(AshaService.RESERVED_FOR_FUTURE_USE)
+ + bytes(AshaService.SUPPORTED_CODEC_ID),
+ )
+
+ self.audio_control_point_characteristic = Characteristic(
+ GATT_ASHA_AUDIO_CONTROL_POINT_CHARACTERISTIC,
+ Characteristic.Properties.WRITE
+ | Characteristic.Properties.WRITE_WITHOUT_RESPONSE,
+ Characteristic.WRITEABLE,
+ CharacteristicValue(write=on_audio_control_point_write),
+ )
+ self.audio_status_characteristic = Characteristic(
+ GATT_ASHA_AUDIO_STATUS_CHARACTERISTIC,
+ Characteristic.Properties.READ | Characteristic.Properties.NOTIFY,
+ Characteristic.READABLE,
+ bytes([0]),
+ )
+ self.volume_characteristic = Characteristic(
+ GATT_ASHA_VOLUME_CHARACTERISTIC,
+ Characteristic.Properties.WRITE_WITHOUT_RESPONSE,
+ Characteristic.WRITEABLE,
+ CharacteristicValue(write=on_volume_write),
+ )
+
+ # Register an L2CAP CoC server
+ def on_coc(channel):
+ def on_data(data):
+ logging.debug(f'<<< data received:{data}')
+
+ self.emit('data', channel.connection, data)
+ self.audio_out_data += data
+
+ channel.sink = on_data
+
+ # let the server find a free PSM
+ self.psm = self.device.register_l2cap_channel_server(self.psm, on_coc, 8)
+ self.le_psm_out_characteristic = Characteristic(
+ GATT_ASHA_LE_PSM_OUT_CHARACTERISTIC,
+ Characteristic.Properties.READ,
+ Characteristic.READABLE,
+ struct.pack('<H', self.psm),
+ )
+
+ characteristics = [
+ self.read_only_properties_characteristic,
+ self.audio_control_point_characteristic,
+ self.audio_status_characteristic,
+ self.volume_characteristic,
+ self.le_psm_out_characteristic,
+ ]
+
+ super().__init__(characteristics)
+
+ def get_advertising_data(self):
+ # Advertisement only uses 4 least significant bytes of the HiSyncId.
+ return bytes(
+ AdvertisingData(
+ [
+ (
+ AdvertisingData.SERVICE_DATA_16_BIT_UUID,
+ bytes(GATT_ASHA_SERVICE)
+ + bytes(
+ [
+ AshaService.PROTOCOL_VERSION,
+ self.capability,
+ ]
+ )
+ + bytes(self.hisyncid[:4]),
+ ),
+ ]
+ )
+ )
diff --git a/bumble/profiles/battery_service.py b/bumble/profiles/battery_service.py
index a978c05..211fee0 100644
--- a/bumble/profiles/battery_service.py
+++ b/bumble/profiles/battery_service.py
@@ -23,7 +23,7 @@ from ..gatt import (
TemplateService,
Characteristic,
CharacteristicValue,
- PackedCharacteristicAdapter
+ PackedCharacteristicAdapter,
)
@@ -36,11 +36,11 @@ class BatteryService(TemplateService):
self.battery_level_characteristic = PackedCharacteristicAdapter(
Characteristic(
GATT_BATTERY_LEVEL_CHARACTERISTIC,
- Characteristic.READ | Characteristic.NOTIFY,
+ Characteristic.Properties.READ | Characteristic.Properties.NOTIFY,
Characteristic.READABLE,
- CharacteristicValue(read=read_battery_level)
+ CharacteristicValue(read=read_battery_level),
),
- format=BatteryService.BATTERY_LEVEL_FORMAT
+ pack_format=BatteryService.BATTERY_LEVEL_FORMAT,
)
super().__init__([self.battery_level_characteristic])
@@ -52,10 +52,11 @@ class BatteryServiceProxy(ProfileServiceProxy):
def __init__(self, service_proxy):
self.service_proxy = service_proxy
- if characteristics := service_proxy.get_characteristics_by_uuid(GATT_BATTERY_LEVEL_CHARACTERISTIC):
+ if characteristics := service_proxy.get_characteristics_by_uuid(
+ GATT_BATTERY_LEVEL_CHARACTERISTIC
+ ):
self.battery_level = PackedCharacteristicAdapter(
- characteristics[0],
- format=BatteryService.BATTERY_LEVEL_FORMAT
+ characteristics[0], pack_format=BatteryService.BATTERY_LEVEL_FORMAT
)
else:
self.battery_level = None
diff --git a/bumble/profiles/device_information_service.py b/bumble/profiles/device_information_service.py
index 99765b4..09bfd6c 100644
--- a/bumble/profiles/device_information_service.py
+++ b/bumble/profiles/device_information_service.py
@@ -17,7 +17,7 @@
# Imports
# -----------------------------------------------------------------------------
import struct
-from typing import Tuple
+from typing import Optional, Tuple
from ..gatt_client import ProfileServiceProxy
from ..gatt import (
@@ -33,7 +33,7 @@ from ..gatt import (
TemplateService,
Characteristic,
DelegatedCharacteristicAdapter,
- UTF8CharacteristicAdapter
+ UTF8CharacteristicAdapter,
)
@@ -52,49 +52,50 @@ class DeviceInformationService(TemplateService):
def __init__(
self,
- manufacturer_name: str = None,
- model_number: str = None,
- serial_number: str = None,
- hardware_revision: str = None,
- firmware_revision: str = None,
- software_revision: str = None,
- system_id: Tuple[int, int] = None, # (OUI, Manufacturer ID)
- ieee_regulatory_certification_data_list: bytes = None
+ manufacturer_name: Optional[str] = None,
+ model_number: Optional[str] = None,
+ serial_number: Optional[str] = None,
+ hardware_revision: Optional[str] = None,
+ firmware_revision: Optional[str] = None,
+ software_revision: Optional[str] = None,
+ system_id: Optional[Tuple[int, int]] = None, # (OUI, Manufacturer ID)
+ ieee_regulatory_certification_data_list: Optional[bytes] = None
# TODO: pnp_id
):
characteristics = [
Characteristic(
- uuid,
- Characteristic.READ,
- Characteristic.READABLE,
- field
+ uuid, Characteristic.Properties.READ, Characteristic.READABLE, field
)
for (field, uuid) in (
(manufacturer_name, GATT_MANUFACTURER_NAME_STRING_CHARACTERISTIC),
- (model_number, GATT_MODEL_NUMBER_STRING_CHARACTERISTIC),
- (serial_number, GATT_SERIAL_NUMBER_STRING_CHARACTERISTIC),
+ (model_number, GATT_MODEL_NUMBER_STRING_CHARACTERISTIC),
+ (serial_number, GATT_SERIAL_NUMBER_STRING_CHARACTERISTIC),
(hardware_revision, GATT_HARDWARE_REVISION_STRING_CHARACTERISTIC),
(firmware_revision, GATT_FIRMWARE_REVISION_STRING_CHARACTERISTIC),
- (software_revision, GATT_SOFTWARE_REVISION_STRING_CHARACTERISTIC)
+ (software_revision, GATT_SOFTWARE_REVISION_STRING_CHARACTERISTIC),
)
if field is not None
]
if system_id is not None:
- characteristics.append(Characteristic(
- GATT_SYSTEM_ID_CHARACTERISTIC,
- Characteristic.READ,
- Characteristic.READABLE,
- self.pack_system_id(*system_id)
- ))
+ characteristics.append(
+ Characteristic(
+ GATT_SYSTEM_ID_CHARACTERISTIC,
+ Characteristic.Properties.READ,
+ Characteristic.READABLE,
+ self.pack_system_id(*system_id),
+ )
+ )
if ieee_regulatory_certification_data_list is not None:
- characteristics.append(Characteristic(
- GATT_REGULATORY_CERTIFICATION_DATA_LIST_CHARACTERISTIC,
- Characteristic.READ,
- Characteristic.READABLE,
- ieee_regulatory_certification_data_list
- ))
+ characteristics.append(
+ Characteristic(
+ GATT_REGULATORY_CERTIFICATION_DATA_LIST_CHARACTERISTIC,
+ Characteristic.Properties.READ,
+ Characteristic.READABLE,
+ ieee_regulatory_certification_data_list,
+ )
+ )
super().__init__(characteristics)
@@ -108,11 +109,11 @@ class DeviceInformationServiceProxy(ProfileServiceProxy):
for (field, uuid) in (
('manufacturer_name', GATT_MANUFACTURER_NAME_STRING_CHARACTERISTIC),
- ('model_number', GATT_MODEL_NUMBER_STRING_CHARACTERISTIC),
- ('serial_number', GATT_SERIAL_NUMBER_STRING_CHARACTERISTIC),
+ ('model_number', GATT_MODEL_NUMBER_STRING_CHARACTERISTIC),
+ ('serial_number', GATT_SERIAL_NUMBER_STRING_CHARACTERISTIC),
('hardware_revision', GATT_HARDWARE_REVISION_STRING_CHARACTERISTIC),
('firmware_revision', GATT_FIRMWARE_REVISION_STRING_CHARACTERISTIC),
- ('software_revision', GATT_SOFTWARE_REVISION_STRING_CHARACTERISTIC)
+ ('software_revision', GATT_SOFTWARE_REVISION_STRING_CHARACTERISTIC),
):
if characteristics := service_proxy.get_characteristics_by_uuid(uuid):
characteristic = UTF8CharacteristicAdapter(characteristics[0])
@@ -120,16 +121,20 @@ class DeviceInformationServiceProxy(ProfileServiceProxy):
characteristic = None
self.__setattr__(field, characteristic)
- if characteristics := service_proxy.get_characteristics_by_uuid(GATT_SYSTEM_ID_CHARACTERISTIC):
+ if characteristics := service_proxy.get_characteristics_by_uuid(
+ GATT_SYSTEM_ID_CHARACTERISTIC
+ ):
self.system_id = DelegatedCharacteristicAdapter(
characteristics[0],
encode=lambda v: DeviceInformationService.pack_system_id(*v),
- decode=DeviceInformationService.unpack_system_id
+ decode=DeviceInformationService.unpack_system_id,
)
else:
self.system_id = None
- if characteristics := service_proxy.get_characteristics_by_uuid(GATT_REGULATORY_CERTIFICATION_DATA_LIST_CHARACTERISTIC):
+ if characteristics := service_proxy.get_characteristics_by_uuid(
+ GATT_REGULATORY_CERTIFICATION_DATA_LIST_CHARACTERISTIC
+ ):
self.ieee_regulatory_certification_data_list = characteristics[0]
else:
self.ieee_regulatory_certification_data_list = None
diff --git a/bumble/profiles/heart_rate_service.py b/bumble/profiles/heart_rate_service.py
new file mode 100644
index 0000000..c7d3018
--- /dev/null
+++ b/bumble/profiles/heart_rate_service.py
@@ -0,0 +1,237 @@
+# Copyright 2021-2022 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+# -----------------------------------------------------------------------------
+# Imports
+# -----------------------------------------------------------------------------
+from enum import IntEnum
+import struct
+
+from ..gatt_client import ProfileServiceProxy
+from ..att import ATT_Error
+from ..gatt import (
+ GATT_HEART_RATE_SERVICE,
+ GATT_HEART_RATE_MEASUREMENT_CHARACTERISTIC,
+ GATT_BODY_SENSOR_LOCATION_CHARACTERISTIC,
+ GATT_HEART_RATE_CONTROL_POINT_CHARACTERISTIC,
+ TemplateService,
+ Characteristic,
+ CharacteristicValue,
+ DelegatedCharacteristicAdapter,
+ PackedCharacteristicAdapter,
+)
+
+
+# -----------------------------------------------------------------------------
+class HeartRateService(TemplateService):
+ UUID = GATT_HEART_RATE_SERVICE
+ HEART_RATE_CONTROL_POINT_FORMAT = 'B'
+ CONTROL_POINT_NOT_SUPPORTED = 0x80
+ RESET_ENERGY_EXPENDED = 0x01
+
+ class BodySensorLocation(IntEnum):
+ OTHER = (0,)
+ CHEST = (1,)
+ WRIST = (2,)
+ FINGER = (3,)
+ HAND = (4,)
+ EAR_LOBE = (5,)
+ FOOT = 6
+
+ class HeartRateMeasurement:
+ def __init__(
+ self,
+ heart_rate,
+ sensor_contact_detected=None,
+ energy_expended=None,
+ rr_intervals=None,
+ ):
+ if heart_rate < 0 or heart_rate > 0xFFFF:
+ raise ValueError('heart_rate out of range')
+
+ if energy_expended is not None and (
+ energy_expended < 0 or energy_expended > 0xFFFF
+ ):
+ raise ValueError('energy_expended out of range')
+
+ if rr_intervals:
+ for rr_interval in rr_intervals:
+ if rr_interval < 0 or rr_interval * 1024 > 0xFFFF:
+ raise ValueError('rr_intervals out of range')
+
+ self.heart_rate = heart_rate
+ self.sensor_contact_detected = sensor_contact_detected
+ self.energy_expended = energy_expended
+ self.rr_intervals = rr_intervals
+
+ @classmethod
+ def from_bytes(cls, data):
+ flags = data[0]
+ offset = 1
+
+ if flags & 1:
+ hr = struct.unpack_from('<H', data, offset)[0]
+ offset += 2
+ else:
+ hr = struct.unpack_from('B', data, offset)[0]
+ offset += 1
+
+ if flags & (1 << 2):
+ sensor_contact_detected = flags & (1 << 1) != 0
+ else:
+ sensor_contact_detected = None
+
+ if flags & (1 << 3):
+ energy_expended = struct.unpack_from('<H', data, offset)[0]
+ offset += 2
+ else:
+ energy_expended = None
+
+ if flags & (1 << 4):
+ rr_intervals = tuple(
+ struct.unpack_from('<H', data, offset + i * 2)[0] / 1024
+ for i in range((len(data) - offset) // 2)
+ )
+ else:
+ rr_intervals = ()
+
+ return cls(hr, sensor_contact_detected, energy_expended, rr_intervals)
+
+ def __bytes__(self):
+ if self.heart_rate < 256:
+ flags = 0
+ data = struct.pack('B', self.heart_rate)
+ else:
+ flags = 1
+ data = struct.pack('<H', self.heart_rate)
+
+ if self.sensor_contact_detected is not None:
+ flags |= ((1 if self.sensor_contact_detected else 0) << 1) | (1 << 2)
+
+ if self.energy_expended is not None:
+ flags |= 1 << 3
+ data += struct.pack('<H', self.energy_expended)
+
+ if self.rr_intervals:
+ flags |= 1 << 4
+ data += b''.join(
+ [
+ struct.pack('<H', int(rr_interval * 1024))
+ for rr_interval in self.rr_intervals
+ ]
+ )
+
+ return bytes([flags]) + data
+
+ def __str__(self):
+ return (
+ f'HeartRateMeasurement(heart_rate={self.heart_rate},'
+ f' sensor_contact_detected={self.sensor_contact_detected},'
+ f' energy_expended={self.energy_expended},'
+ f' rr_intervals={self.rr_intervals})'
+ )
+
+ def __init__(
+ self,
+ read_heart_rate_measurement,
+ body_sensor_location=None,
+ reset_energy_expended=None,
+ ):
+ self.heart_rate_measurement_characteristic = DelegatedCharacteristicAdapter(
+ Characteristic(
+ GATT_HEART_RATE_MEASUREMENT_CHARACTERISTIC,
+ Characteristic.Properties.NOTIFY,
+ 0,
+ CharacteristicValue(read=read_heart_rate_measurement),
+ ),
+ # pylint: disable=unnecessary-lambda
+ encode=lambda value: bytes(value),
+ )
+ characteristics = [self.heart_rate_measurement_characteristic]
+
+ if body_sensor_location is not None:
+ self.body_sensor_location_characteristic = Characteristic(
+ GATT_BODY_SENSOR_LOCATION_CHARACTERISTIC,
+ Characteristic.Properties.READ,
+ Characteristic.READABLE,
+ bytes([int(body_sensor_location)]),
+ )
+ characteristics.append(self.body_sensor_location_characteristic)
+
+ if reset_energy_expended:
+
+ def write_heart_rate_control_point_value(connection, value):
+ if value == self.RESET_ENERGY_EXPENDED:
+ if reset_energy_expended is not None:
+ reset_energy_expended(connection)
+ else:
+ raise ATT_Error(self.CONTROL_POINT_NOT_SUPPORTED)
+
+ self.heart_rate_control_point_characteristic = PackedCharacteristicAdapter(
+ Characteristic(
+ GATT_HEART_RATE_CONTROL_POINT_CHARACTERISTIC,
+ Characteristic.Properties.WRITE,
+ Characteristic.WRITEABLE,
+ CharacteristicValue(write=write_heart_rate_control_point_value),
+ ),
+ pack_format=HeartRateService.HEART_RATE_CONTROL_POINT_FORMAT,
+ )
+ characteristics.append(self.heart_rate_control_point_characteristic)
+
+ super().__init__(characteristics)
+
+
+# -----------------------------------------------------------------------------
+class HeartRateServiceProxy(ProfileServiceProxy):
+ SERVICE_CLASS = HeartRateService
+
+ def __init__(self, service_proxy):
+ self.service_proxy = service_proxy
+
+ if characteristics := service_proxy.get_characteristics_by_uuid(
+ GATT_HEART_RATE_MEASUREMENT_CHARACTERISTIC
+ ):
+ self.heart_rate_measurement = DelegatedCharacteristicAdapter(
+ characteristics[0],
+ decode=HeartRateService.HeartRateMeasurement.from_bytes,
+ )
+ else:
+ self.heart_rate_measurement = None
+
+ if characteristics := service_proxy.get_characteristics_by_uuid(
+ GATT_BODY_SENSOR_LOCATION_CHARACTERISTIC
+ ):
+ self.body_sensor_location = DelegatedCharacteristicAdapter(
+ characteristics[0],
+ decode=lambda value: HeartRateService.BodySensorLocation(value[0]),
+ )
+ else:
+ self.body_sensor_location = None
+
+ if characteristics := service_proxy.get_characteristics_by_uuid(
+ GATT_HEART_RATE_CONTROL_POINT_CHARACTERISTIC
+ ):
+ self.heart_rate_control_point = PackedCharacteristicAdapter(
+ characteristics[0],
+ pack_format=HeartRateService.HEART_RATE_CONTROL_POINT_FORMAT,
+ )
+ else:
+ self.heart_rate_control_point = None
+
+ async def reset_energy_expended(self):
+ if self.heart_rate_control_point is not None:
+ return await self.heart_rate_control_point.write_value(
+ HeartRateService.RESET_ENERGY_EXPENDED
+ )
diff --git a/bumble/profiles/py.typed b/bumble/profiles/py.typed
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/bumble/profiles/py.typed
diff --git a/bumble/py.typed b/bumble/py.typed
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/bumble/py.typed
diff --git a/bumble/rfcomm.py b/bumble/rfcomm.py
index 527eaf1..71be8dc 100644
--- a/bumble/rfcomm.py
+++ b/bumble/rfcomm.py
@@ -17,10 +17,12 @@
# -----------------------------------------------------------------------------
import logging
import asyncio
-from colors import color
-from .utils import EventEmitter
-from .core import InvalidStateError, ProtocolError, ConnectionError
+from pyee import EventEmitter
+
+from . import core
+from .colors import color
+from .core import BT_BR_EDR_TRANSPORT, InvalidStateError, ProtocolError
# -----------------------------------------------------------------------------
# Logging
@@ -31,6 +33,8 @@ logger = logging.getLogger(__name__)
# -----------------------------------------------------------------------------
# Constants
# -----------------------------------------------------------------------------
+# fmt: off
+
RFCOMM_PSM = 0x0003
@@ -97,22 +101,24 @@ RFCOMM_DEFAULT_PREFERRED_MTU = 1280
RFCOMM_DYNAMIC_CHANNEL_NUMBER_START = 1
RFCOMM_DYNAMIC_CHANNEL_NUMBER_END = 30
+# fmt: on
+
# -----------------------------------------------------------------------------
-def fcs(buffer):
- fcs = 0xFF
+def compute_fcs(buffer):
+ result = 0xFF
for byte in buffer:
- fcs = CRC_TABLE[fcs ^ byte]
- return 0xFF - fcs
+ result = CRC_TABLE[result ^ byte]
+ return 0xFF - result
# -----------------------------------------------------------------------------
class RFCOMM_Frame:
- def __init__(self, type, c_r, dlci, p_f, information = b'', with_credits = False):
- self.type = type
- self.c_r = c_r
- self.dlci = dlci
- self.p_f = p_f
+ def __init__(self, frame_type, c_r, dlci, p_f, information=b'', with_credits=False):
+ self.type = frame_type
+ self.c_r = c_r
+ self.dlci = dlci
+ self.p_f = p_f
self.information = information
length = len(information)
if with_credits:
@@ -123,19 +129,19 @@ class RFCOMM_Frame:
else:
# 1-byte length indicator
self.length = bytes([(length << 1) | 1])
- self.address = (dlci << 2) | (c_r << 1) | 1
- self.control = type | (p_f << 4)
- if type == RFCOMM_UIH_FRAME:
- self.fcs = fcs(bytes([self.address, self.control]))
+ self.address = (dlci << 2) | (c_r << 1) | 1
+ self.control = frame_type | (p_f << 4)
+ if frame_type == RFCOMM_UIH_FRAME:
+ self.fcs = compute_fcs(bytes([self.address, self.control]))
else:
- self.fcs = fcs(bytes([self.address, self.control]) + self.length)
+ self.fcs = compute_fcs(bytes([self.address, self.control]) + self.length)
def type_name(self):
return RFCOMM_FRAME_TYPE_NAMES[self.type]
@staticmethod
def parse_mcc(data):
- type = data[0] >> 2
+ mcc_type = data[0] >> 2
c_r = (data[0] >> 1) & 1
length = data[1]
if data[1] & 1:
@@ -143,13 +149,16 @@ class RFCOMM_Frame:
value = data[2:]
else:
length = (data[3] << 7) & (length >> 1)
- value = data[3:3 + length]
+ value = data[3 : 3 + length]
- return (type, c_r, value)
+ return (mcc_type, c_r, value)
@staticmethod
- def make_mcc(type, c_r, data):
- return bytes([(type << 2 | c_r << 1 | 1) & 0xFF, (len(data) & 0x7F) << 1 | 1]) + data
+ def make_mcc(mcc_type, c_r, data):
+ return (
+ bytes([(mcc_type << 2 | c_r << 1 | 1) & 0xFF, (len(data) & 0x7F) << 1 | 1])
+ + data
+ )
@staticmethod
def sabm(c_r, dlci):
@@ -168,15 +177,17 @@ class RFCOMM_Frame:
return RFCOMM_Frame(RFCOMM_DISC_FRAME, c_r, dlci, 1)
@staticmethod
- def uih(c_r, dlci, information, p_f = 0):
- return RFCOMM_Frame(RFCOMM_UIH_FRAME, c_r, dlci, p_f, information, with_credits = (p_f == 1))
+ def uih(c_r, dlci, information, p_f=0):
+ return RFCOMM_Frame(
+ RFCOMM_UIH_FRAME, c_r, dlci, p_f, information, with_credits=(p_f == 1)
+ )
@staticmethod
def from_bytes(data):
# Extract fields
dlci = (data[0] >> 2) & 0x3F
c_r = (data[0] >> 1) & 0x01
- type = data[1] & 0xEF
+ frame_type = data[1] & 0xEF
p_f = (data[1] >> 4) & 0x01
length = data[2]
if length & 0x01:
@@ -188,132 +199,182 @@ class RFCOMM_Frame:
fcs = data[-1]
# Construct the frame and check the CRC
- frame = RFCOMM_Frame(type, c_r, dlci, p_f, information)
+ frame = RFCOMM_Frame(frame_type, c_r, dlci, p_f, information)
if frame.fcs != fcs:
- logger.warn(f'FCS mismatch: got {fcs:02X}, expected {frame.fcs:02X}')
+ logger.warning(f'FCS mismatch: got {fcs:02X}, expected {frame.fcs:02X}')
raise ValueError('fcs mismatch')
return frame
def __bytes__(self):
- return bytes([self.address, self.control]) + self.length + self.information + bytes([self.fcs])
+ return (
+ bytes([self.address, self.control])
+ + self.length
+ + self.information
+ + bytes([self.fcs])
+ )
def __str__(self):
- return f'{color(self.type_name(), "yellow")}(c/r={self.c_r},dlci={self.dlci},p/f={self.p_f},length={len(self.information)},fcs=0x{self.fcs:02X})'
+ return (
+ f'{color(self.type_name(), "yellow")}'
+ f'(c/r={self.c_r},'
+ f'dlci={self.dlci},'
+ f'p/f={self.p_f},'
+ f'length={len(self.information)},'
+ f'fcs=0x{self.fcs:02X})'
+ )
# -----------------------------------------------------------------------------
class RFCOMM_MCC_PN:
- def __init__(self, dlci, cl, priority, ack_timer, max_frame_size, max_retransmissions, window_size):
- self.dlci = dlci
- self.cl = cl
- self.priority = priority
- self.ack_timer = ack_timer
- self.max_frame_size = max_frame_size
+ def __init__(
+ self,
+ dlci,
+ cl,
+ priority,
+ ack_timer,
+ max_frame_size,
+ max_retransmissions,
+ window_size,
+ ):
+ self.dlci = dlci
+ self.cl = cl
+ self.priority = priority
+ self.ack_timer = ack_timer
+ self.max_frame_size = max_frame_size
self.max_retransmissions = max_retransmissions
- self.window_size = window_size
+ self.window_size = window_size
@staticmethod
def from_bytes(data):
return RFCOMM_MCC_PN(
- dlci = data[0],
- cl = data[1],
- priority = data[2],
- ack_timer = data[3],
- max_frame_size = data[4] | data[5] << 8,
- max_retransmissions = data[6],
- window_size = data[7]
+ dlci=data[0],
+ cl=data[1],
+ priority=data[2],
+ ack_timer=data[3],
+ max_frame_size=data[4] | data[5] << 8,
+ max_retransmissions=data[6],
+ window_size=data[7],
)
def __bytes__(self):
- return bytes([
- self.dlci & 0xFF,
- self.cl & 0xFF,
- self.priority & 0xFF,
- self.ack_timer & 0xFF,
- self.max_frame_size & 0xFF,
- (self.max_frame_size >> 8) & 0xFF,
- self.max_retransmissions & 0xFF,
- self.window_size & 0xFF
- ])
+ return bytes(
+ [
+ self.dlci & 0xFF,
+ self.cl & 0xFF,
+ self.priority & 0xFF,
+ self.ack_timer & 0xFF,
+ self.max_frame_size & 0xFF,
+ (self.max_frame_size >> 8) & 0xFF,
+ self.max_retransmissions & 0xFF,
+ self.window_size & 0xFF,
+ ]
+ )
def __str__(self):
- return f'PN(dlci={self.dlci},cl={self.cl},priority={self.priority},ack_timer={self.ack_timer},max_frame_size={self.max_frame_size},max_retransmissions={self.max_retransmissions},window_size={self.window_size})'
+ return (
+ f'PN(dlci={self.dlci},'
+ f'cl={self.cl},'
+ f'priority={self.priority},'
+ f'ack_timer={self.ack_timer},'
+ f'max_frame_size={self.max_frame_size},'
+ f'max_retransmissions={self.max_retransmissions},'
+ f'window_size={self.window_size})'
+ )
# -----------------------------------------------------------------------------
class RFCOMM_MCC_MSC:
def __init__(self, dlci, fc, rtc, rtr, ic, dv):
self.dlci = dlci
- self.fc = fc
- self.rtc = rtc
- self.rtr = rtr
- self.ic = ic
- self.dv = dv
+ self.fc = fc
+ self.rtc = rtc
+ self.rtr = rtr
+ self.ic = ic
+ self.dv = dv
@staticmethod
def from_bytes(data):
return RFCOMM_MCC_MSC(
- dlci = data[0] >> 2,
- fc = data[1] >> 1 & 1,
- rtc = data[1] >> 2 & 1,
- rtr = data[1] >> 3 & 1,
- ic = data[1] >> 6 & 1,
- dv = data[1] >> 7 & 1
+ dlci=data[0] >> 2,
+ fc=data[1] >> 1 & 1,
+ rtc=data[1] >> 2 & 1,
+ rtr=data[1] >> 3 & 1,
+ ic=data[1] >> 6 & 1,
+ dv=data[1] >> 7 & 1,
)
def __bytes__(self):
- return bytes([
- (self.dlci << 2) | 3,
- 1 | self.fc << 1 | self.rtc << 2 | self.rtr << 3 | self.ic << 6 | self.dv << 7
- ])
+ return bytes(
+ [
+ (self.dlci << 2) | 3,
+ 1
+ | self.fc << 1
+ | self.rtc << 2
+ | self.rtr << 3
+ | self.ic << 6
+ | self.dv << 7,
+ ]
+ )
def __str__(self):
- return f'MSC(dlci={self.dlci},fc={self.fc},rtc={self.rtc},rtr={self.rtr},ic={self.ic},dv={self.dv})'
+ return (
+ f'MSC(dlci={self.dlci},'
+ f'fc={self.fc},'
+ f'rtc={self.rtc},'
+ f'rtr={self.rtr},'
+ f'ic={self.ic},'
+ f'dv={self.dv})'
+ )
# -----------------------------------------------------------------------------
class DLC(EventEmitter):
# States
- INIT = 0x00
- CONNECTING = 0x01
- CONNECTED = 0x02
+ INIT = 0x00
+ CONNECTING = 0x01
+ CONNECTED = 0x02
DISCONNECTING = 0x03
- DISCONNECTED = 0x04
- RESET = 0x05
+ DISCONNECTED = 0x04
+ RESET = 0x05
STATE_NAMES = {
- INIT: 'INIT',
- CONNECTING: 'CONNECTING',
- CONNECTED: 'CONNECTED',
+ INIT: 'INIT',
+ CONNECTING: 'CONNECTING',
+ CONNECTED: 'CONNECTED',
DISCONNECTING: 'DISCONNECTING',
- DISCONNECTED: 'DISCONNECTED',
- RESET: 'RESET'
+ DISCONNECTED: 'DISCONNECTED',
+ RESET: 'RESET',
}
def __init__(self, multiplexer, dlci, max_frame_size, initial_tx_credits):
super().__init__()
- self.multiplexer = multiplexer
- self.dlci = dlci
- self.rx_credits = RFCOMM_DEFAULT_INITIAL_RX_CREDITS
+ self.multiplexer = multiplexer
+ self.dlci = dlci
+ self.rx_credits = RFCOMM_DEFAULT_INITIAL_RX_CREDITS
self.rx_threshold = self.rx_credits // 2
- self.tx_credits = initial_tx_credits
- self.tx_buffer = b''
- self.state = DLC.INIT
- self.role = multiplexer.role
- self.c_r = 1 if self.role == Multiplexer.INITIATOR else 0
- self.sink = None
+ self.tx_credits = initial_tx_credits
+ self.tx_buffer = b''
+ self.state = DLC.INIT
+ self.role = multiplexer.role
+ self.c_r = 1 if self.role == Multiplexer.INITIATOR else 0
+ self.sink = None
+ self.connection_result = None
# Compute the MTU
max_overhead = 4 + 1 # header with 2-byte length + fcs
- self.mtu = min(max_frame_size, self.multiplexer.l2cap_channel.mtu - max_overhead)
+ self.mtu = min(
+ max_frame_size, self.multiplexer.l2cap_channel.mtu - max_overhead
+ )
@staticmethod
def state_name(state):
return DLC.STATE_NAMES[state]
def change_state(self, new_state):
- logger.debug(f'{self} state change -> {color(self.state_name(new_state), "magenta")}')
+ logger.debug(
+ f'{self} state change -> {color(self.state_name(new_state), "magenta")}'
+ )
self.state = new_state
def send_frame(self, frame):
@@ -323,58 +384,40 @@ class DLC(EventEmitter):
handler = getattr(self, f'on_{frame.type_name()}_frame'.lower())
handler(frame)
- def on_sabm_frame(self, frame):
+ def on_sabm_frame(self, _frame):
if self.state != DLC.CONNECTING:
- logger.warn(color('!!! received SABM when not in CONNECTING state', 'red'))
+ logger.warning(
+ color('!!! received SABM when not in CONNECTING state', 'red')
+ )
return
- self.send_frame(RFCOMM_Frame.ua(c_r = 1 - self.c_r, dlci = self.dlci))
+ self.send_frame(RFCOMM_Frame.ua(c_r=1 - self.c_r, dlci=self.dlci))
# Exchange the modem status with the peer
- msc = RFCOMM_MCC_MSC(
- dlci = self.dlci,
- fc = 0,
- rtc = 1,
- rtr = 1,
- ic = 0,
- dv = 1
+ msc = RFCOMM_MCC_MSC(dlci=self.dlci, fc=0, rtc=1, rtr=1, ic=0, dv=1)
+ mcc = RFCOMM_Frame.make_mcc(
+ mcc_type=RFCOMM_MCC_MSC_TYPE, c_r=1, data=bytes(msc)
)
- mcc = RFCOMM_Frame.make_mcc(type = RFCOMM_MCC_MSC_TYPE, c_r = 1, data = bytes(msc))
logger.debug(f'>>> MCC MSC Command: {msc}')
- self.send_frame(
- RFCOMM_Frame.uih(
- c_r = self.c_r,
- dlci = 0,
- information = mcc
- )
- )
+ self.send_frame(RFCOMM_Frame.uih(c_r=self.c_r, dlci=0, information=mcc))
self.change_state(DLC.CONNECTED)
self.emit('open')
- def on_ua_frame(self, frame):
+ def on_ua_frame(self, _frame):
if self.state != DLC.CONNECTING:
- logger.warn(color('!!! received SABM when not in CONNECTING state', 'red'))
+ logger.warning(
+ color('!!! received SABM when not in CONNECTING state', 'red')
+ )
return
# Exchange the modem status with the peer
- msc = RFCOMM_MCC_MSC(
- dlci = self.dlci,
- fc = 0,
- rtc = 1,
- rtr = 1,
- ic = 0,
- dv = 1
+ msc = RFCOMM_MCC_MSC(dlci=self.dlci, fc=0, rtc=1, rtr=1, ic=0, dv=1)
+ mcc = RFCOMM_Frame.make_mcc(
+ mcc_type=RFCOMM_MCC_MSC_TYPE, c_r=1, data=bytes(msc)
)
- mcc = RFCOMM_Frame.make_mcc(type = RFCOMM_MCC_MSC_TYPE, c_r = 1, data = bytes(msc))
logger.debug(f'>>> MCC MSC Command: {msc}')
- self.send_frame(
- RFCOMM_Frame.uih(
- c_r = self.c_r,
- dlci = 0,
- information = mcc
- )
- )
+ self.send_frame(RFCOMM_Frame.uih(c_r=self.c_r, dlci=0, information=mcc))
self.change_state(DLC.CONNECTED)
self.multiplexer.on_dlc_open_complete(self)
@@ -383,29 +426,36 @@ class DLC(EventEmitter):
# TODO: handle all states
pass
- def on_disc_frame(self, frame):
+ def on_disc_frame(self, _frame):
# TODO: handle all states
- self.send_frame(RFCOMM_Frame.ua(c_r = 1 - self.c_r, dlci = self.dlci))
+ self.send_frame(RFCOMM_Frame.ua(c_r=1 - self.c_r, dlci=self.dlci))
def on_uih_frame(self, frame):
data = frame.information
if frame.p_f == 1:
# With credits
- credits = frame.information[0]
- self.tx_credits += credits
+ received_credits = frame.information[0]
+ self.tx_credits += received_credits
- logger.debug(f'<<< Credits [{self.dlci}]: received {credits}, total={self.tx_credits}')
+ logger.debug(
+ f'<<< Credits [{self.dlci}]: '
+ f'received {received_credits}, total={self.tx_credits}'
+ )
data = data[1:]
- logger.debug(f'{color("<<< Data", "yellow")} [{self.dlci}] {len(data)} bytes, rx_credits={self.rx_credits}: {data.hex()}')
+ logger.debug(
+ f'{color("<<< Data", "yellow")} '
+ f'[{self.dlci}] {len(data)} bytes, '
+ f'rx_credits={self.rx_credits}: {data.hex()}'
+ )
if len(data) and self.sink:
- self.sink(data)
+ self.sink(data) # pylint: disable=not-callable
# Update the credits
if self.rx_credits > 0:
self.rx_credits -= 1
else:
- logger.warn(color('!!! received frame with no rx credits', 'red'))
+ logger.warning(color('!!! received frame with no rx credits', 'red'))
# Check if there's anything to send (including credits)
self.process_tx()
@@ -417,69 +467,47 @@ class DLC(EventEmitter):
if c_r:
# Command
logger.debug(f'<<< MCC MSC Command: {msc}')
- msc = RFCOMM_MCC_MSC(
- dlci = self.dlci,
- fc = 0,
- rtc = 1,
- rtr = 1,
- ic = 0,
- dv = 1
+ msc = RFCOMM_MCC_MSC(dlci=self.dlci, fc=0, rtc=1, rtr=1, ic=0, dv=1)
+ mcc = RFCOMM_Frame.make_mcc(
+ mcc_type=RFCOMM_MCC_MSC_TYPE, c_r=0, data=bytes(msc)
)
- mcc = RFCOMM_Frame.make_mcc(type = RFCOMM_MCC_MSC_TYPE, c_r = 0, data = bytes(msc))
logger.debug(f'>>> MCC MSC Response: {msc}')
- self.send_frame(
- RFCOMM_Frame.uih(
- c_r = self.c_r,
- dlci = 0,
- information = mcc
- )
- )
+ self.send_frame(RFCOMM_Frame.uih(c_r=self.c_r, dlci=0, information=mcc))
else:
# Response
logger.debug(f'<<< MCC MSC Response: {msc}')
def connect(self):
- if not self.state == DLC.INIT:
+ if self.state != DLC.INIT:
raise InvalidStateError('invalid state')
self.change_state(DLC.CONNECTING)
self.connection_result = asyncio.get_running_loop().create_future()
- self.send_frame(
- RFCOMM_Frame.sabm(
- c_r = self.c_r,
- dlci = self.dlci
- )
- )
+ self.send_frame(RFCOMM_Frame.sabm(c_r=self.c_r, dlci=self.dlci))
def accept(self):
- if not self.state == DLC.INIT:
+ if self.state != DLC.INIT:
raise InvalidStateError('invalid state')
pn = RFCOMM_MCC_PN(
- dlci = self.dlci,
- cl = 0xE0,
- priority = 7,
- ack_timer = 0,
- max_frame_size = RFCOMM_DEFAULT_PREFERRED_MTU,
- max_retransmissions = 0,
- window_size = RFCOMM_DEFAULT_INITIAL_RX_CREDITS
+ dlci=self.dlci,
+ cl=0xE0,
+ priority=7,
+ ack_timer=0,
+ max_frame_size=RFCOMM_DEFAULT_PREFERRED_MTU,
+ max_retransmissions=0,
+ window_size=RFCOMM_DEFAULT_INITIAL_RX_CREDITS,
)
- mcc = RFCOMM_Frame.make_mcc(type = RFCOMM_MCC_PN_TYPE, c_r = 0, data = bytes(pn))
+ mcc = RFCOMM_Frame.make_mcc(mcc_type=RFCOMM_MCC_PN_TYPE, c_r=0, data=bytes(pn))
logger.debug(f'>>> PN Response: {pn}')
- self.send_frame(
- RFCOMM_Frame.uih(
- c_r = self.c_r,
- dlci = 0,
- information = mcc
- )
- )
+ self.send_frame(RFCOMM_Frame.uih(c_r=self.c_r, dlci=0, information=mcc))
self.change_state(DLC.CONNECTING)
def rx_credits_needed(self):
if self.rx_credits <= self.rx_threshold:
return RFCOMM_DEFAULT_INITIAL_RX_CREDITS - self.rx_credits
- else:
- return 0
+
+ return 0
def process_tx(self):
# Send anything we can (or an empty frame if we need to send rx credits)
@@ -487,13 +515,13 @@ class DLC(EventEmitter):
while (self.tx_buffer and self.tx_credits > 0) or rx_credits_needed > 0:
# Get the next chunk, up to MTU size
if rx_credits_needed > 0:
- chunk = bytes([rx_credits_needed]) + self.tx_buffer[:self.mtu - 1]
- self.tx_buffer = self.tx_buffer[len(chunk) - 1:]
+ chunk = bytes([rx_credits_needed]) + self.tx_buffer[: self.mtu - 1]
+ self.tx_buffer = self.tx_buffer[len(chunk) - 1 :]
self.rx_credits += rx_credits_needed
- tx_credit_spent = (len(chunk) > 1)
+ tx_credit_spent = len(chunk) > 1
else:
- chunk = self.tx_buffer[:self.mtu]
- self.tx_buffer = self.tx_buffer[len(chunk):]
+ chunk = self.tx_buffer[: self.mtu]
+ self.tx_buffer = self.tx_buffer[len(chunk) :]
tx_credit_spent = True
# Update the tx credits
@@ -502,13 +530,17 @@ class DLC(EventEmitter):
self.tx_credits -= 1
# Send the frame
- logger.debug(f'>>> sending {len(chunk)} bytes with {rx_credits_needed} credits, rx_credits={self.rx_credits}, tx_credits={self.tx_credits}')
+ logger.debug(
+ f'>>> sending {len(chunk)} bytes with {rx_credits_needed} credits, '
+ f'rx_credits={self.rx_credits}, '
+ f'tx_credits={self.tx_credits}'
+ )
self.send_frame(
RFCOMM_Frame.uih(
- c_r = self.c_r,
- dlci = self.dlci,
- information = chunk,
- p_f = 1 if rx_credits_needed > 0 else 0
+ c_r=self.c_r,
+ dlci=self.dlci,
+ information=chunk,
+ p_f=1 if rx_credits_needed > 0 else 0,
)
)
@@ -517,8 +549,8 @@ class DLC(EventEmitter):
# Stream protocol
def write(self, data):
# We can only send bytes
- if type(data) != bytes:
- if type(data) == str:
+ if not isinstance(data, bytes):
+ if isinstance(data, str):
# Automatically convert strings to bytes using UTF-8
data = data.encode('utf-8')
else:
@@ -542,34 +574,34 @@ class Multiplexer(EventEmitter):
RESPONDER = 0x01
# States
- INIT = 0x00
- CONNECTING = 0x01
- CONNECTED = 0x02
- OPENING = 0x03
+ INIT = 0x00
+ CONNECTING = 0x01
+ CONNECTED = 0x02
+ OPENING = 0x03
DISCONNECTING = 0x04
- DISCONNECTED = 0x05
- RESET = 0x06
+ DISCONNECTED = 0x05
+ RESET = 0x06
STATE_NAMES = {
- INIT: 'INIT',
- CONNECTING: 'CONNECTING',
- CONNECTED: 'CONNECTED',
- OPENING: 'OPENING',
+ INIT: 'INIT',
+ CONNECTING: 'CONNECTING',
+ CONNECTED: 'CONNECTED',
+ OPENING: 'OPENING',
DISCONNECTING: 'DISCONNECTING',
- DISCONNECTED: 'DISCONNECTED',
- RESET: 'RESET'
+ DISCONNECTED: 'DISCONNECTED',
+ RESET: 'RESET',
}
def __init__(self, l2cap_channel, role):
super().__init__()
- self.role = role
- self.l2cap_channel = l2cap_channel
- self.state = Multiplexer.INIT
- self.dlcs = {} # DLCs, by DLCI
- self.connection_result = None
+ self.role = role
+ self.l2cap_channel = l2cap_channel
+ self.state = Multiplexer.INIT
+ self.dlcs = {} # DLCs, by DLCI
+ self.connection_result = None
self.disconnection_result = None
- self.open_result = None
- self.acceptor = None
+ self.open_result = None
+ self.acceptor = None
# Become a sink for the L2CAP channel
l2cap_channel.sink = self.on_pdu
@@ -579,7 +611,9 @@ class Multiplexer(EventEmitter):
return Multiplexer.STATE_NAMES[state]
def change_state(self, new_state):
- logger.debug(f'{self} state change -> {color(self.state_name(new_state), "cyan")}')
+ logger.debug(
+ f'{self} state change -> {color(self.state_name(new_state), "cyan")}'
+ )
self.state = new_state
def send_frame(self, frame):
@@ -595,14 +629,14 @@ class Multiplexer(EventEmitter):
self.on_frame(frame)
else:
if frame.type == RFCOMM_DM_FRAME:
- # DM responses are for a DLCI, but since we only create the dlc when we receive
- # a PN response (because we need the parameters), we handle DM frames at the Multiplexer
- # level
+ # DM responses are for a DLCI, but since we only create the dlc when we
+ # receive a PN response (because we need the parameters), we handle DM
+ # frames at the Multiplexer level
self.on_dm_frame(frame)
else:
dlc = self.dlcs.get(frame.dlci)
if dlc is None:
- logger.warn(f'no dlc for DLCI {frame.dlci}')
+ logger.warning(f'no dlc for DLCI {frame.dlci}')
return
dlc.on_frame(frame)
@@ -610,14 +644,14 @@ class Multiplexer(EventEmitter):
handler = getattr(self, f'on_{frame.type_name()}_frame'.lower())
handler(frame)
- def on_sabm_frame(self, frame):
+ def on_sabm_frame(self, _frame):
if self.state != Multiplexer.INIT:
logger.debug('not in INIT state, ignoring SABM')
return
self.change_state(Multiplexer.CONNECTED)
- self.send_frame(RFCOMM_Frame.ua(c_r = 1, dlci = 0))
+ self.send_frame(RFCOMM_Frame.ua(c_r=1, dlci=0))
- def on_ua_frame(self, frame):
+ def on_ua_frame(self, _frame):
if self.state == Multiplexer.CONNECTING:
self.change_state(Multiplexer.CONNECTED)
if self.connection_result:
@@ -629,25 +663,34 @@ class Multiplexer(EventEmitter):
self.disconnection_result.set_result(None)
self.disconnection_result = None
- def on_dm_frame(self, frame):
+ def on_dm_frame(self, _frame):
if self.state == Multiplexer.OPENING:
self.change_state(Multiplexer.CONNECTED)
if self.open_result:
- self.open_result.set_exception(ConnectionError(ConnectionError.CONNECTION_REFUSED))
+ self.open_result.set_exception(
+ core.ConnectionError(
+ core.ConnectionError.CONNECTION_REFUSED,
+ BT_BR_EDR_TRANSPORT,
+ self.l2cap_channel.connection.peer_address,
+ 'rfcomm',
+ )
+ )
else:
- logger.warn(f'unexpected state for DM: {self}')
+ logger.warning(f'unexpected state for DM: {self}')
- def on_disc_frame(self, frame):
+ def on_disc_frame(self, _frame):
self.change_state(Multiplexer.DISCONNECTED)
- self.send_frame(RFCOMM_Frame.ua(c_r = 0 if self.role == Multiplexer.INITIATOR else 1, dlci = 0))
+ self.send_frame(
+ RFCOMM_Frame.ua(c_r=0 if self.role == Multiplexer.INITIATOR else 1, dlci=0)
+ )
def on_uih_frame(self, frame):
- (type, c_r, value) = RFCOMM_Frame.parse_mcc(frame.information)
+ (mcc_type, c_r, value) = RFCOMM_Frame.parse_mcc(frame.information)
- if type == RFCOMM_MCC_PN_TYPE:
+ if mcc_type == RFCOMM_MCC_PN_TYPE:
pn = RFCOMM_MCC_PN.from_bytes(value)
self.on_mcc_pn(c_r, pn)
- elif type == RFCOMM_MCC_MSC_TYPE:
+ elif mcc_type == RFCOMM_MCC_MSC_TYPE:
mcs = RFCOMM_MCC_MSC.from_bytes(value)
self.on_mcc_msc(c_r, mcs)
@@ -663,7 +706,7 @@ class Multiplexer(EventEmitter):
if pn.dlci & 1:
# Not expected, this is an initiator-side number
# TODO: error out
- logger.warn(f'invalid DLCI: {pn.dlci}')
+ logger.warning(f'invalid DLCI: {pn.dlci}')
else:
if self.acceptor:
channel_number = pn.dlci >> 1
@@ -679,10 +722,10 @@ class Multiplexer(EventEmitter):
dlc.accept()
else:
# No acceptor, we're in Disconnected Mode
- self.send_frame(RFCOMM_Frame.dm(c_r = 1, dlci = pn.dlci))
+ self.send_frame(RFCOMM_Frame.dm(c_r=1, dlci=pn.dlci))
else:
# No acceptor?? shouldn't happen
- logger.warn(color('!!! no acceptor registered', 'red'))
+ logger.warning(color('!!! no acceptor registered', 'red'))
else:
# Response
logger.debug(f'>>> PN Response: {pn}')
@@ -691,12 +734,12 @@ class Multiplexer(EventEmitter):
self.dlcs[pn.dlci] = dlc
dlc.connect()
else:
- logger.warn('ignoring PN response')
+ logger.warning('ignoring PN response')
def on_mcc_msc(self, c_r, msc):
dlc = self.dlcs.get(msc.dlci)
if dlc is None:
- logger.warn(f'no dlc for DLCI {msc.dlci}')
+ logger.warning(f'no dlc for DLCI {msc.dlci}')
return
dlc.on_mcc_msc(c_r, msc)
@@ -706,7 +749,7 @@ class Multiplexer(EventEmitter):
self.change_state(Multiplexer.CONNECTING)
self.connection_result = asyncio.get_running_loop().create_future()
- self.send_frame(RFCOMM_Frame.sabm(c_r = 1, dlci = 0))
+ self.send_frame(RFCOMM_Frame.sabm(c_r=1, dlci=0))
return await self.connection_result
async def disconnect(self):
@@ -715,34 +758,38 @@ class Multiplexer(EventEmitter):
self.disconnection_result = asyncio.get_running_loop().create_future()
self.change_state(Multiplexer.DISCONNECTING)
- self.send_frame(RFCOMM_Frame.disc(c_r = 1 if self.role == Multiplexer.INITIATOR else 0, dlci = 0))
+ self.send_frame(
+ RFCOMM_Frame.disc(
+ c_r=1 if self.role == Multiplexer.INITIATOR else 0, dlci=0
+ )
+ )
await self.disconnection_result
async def open_dlc(self, channel):
if self.state != Multiplexer.CONNECTED:
if self.state == Multiplexer.OPENING:
raise InvalidStateError('open already in progress')
- else:
- raise InvalidStateError('not connected')
+
+ raise InvalidStateError('not connected')
pn = RFCOMM_MCC_PN(
- dlci = channel << 1,
- cl = 0xF0,
- priority = 7,
- ack_timer = 0,
- max_frame_size = RFCOMM_DEFAULT_PREFERRED_MTU,
- max_retransmissions = 0,
- window_size = RFCOMM_DEFAULT_INITIAL_RX_CREDITS
+ dlci=channel << 1,
+ cl=0xF0,
+ priority=7,
+ ack_timer=0,
+ max_frame_size=RFCOMM_DEFAULT_PREFERRED_MTU,
+ max_retransmissions=0,
+ window_size=RFCOMM_DEFAULT_INITIAL_RX_CREDITS,
)
- mcc = RFCOMM_Frame.make_mcc(type = RFCOMM_MCC_PN_TYPE, c_r = 1, data = bytes(pn))
+ mcc = RFCOMM_Frame.make_mcc(mcc_type=RFCOMM_MCC_PN_TYPE, c_r=1, data=bytes(pn))
logger.debug(f'>>> Sending MCC: {pn}')
self.open_result = asyncio.get_running_loop().create_future()
self.change_state(Multiplexer.OPENING)
self.send_frame(
RFCOMM_Frame.uih(
- c_r = 1 if self.role == Multiplexer.INITIATOR else 0,
- dlci = 0,
- information = mcc
+ c_r=1 if self.role == Multiplexer.INITIATOR else 0,
+ dlci=0,
+ information=mcc,
)
)
result = await self.open_result
@@ -762,17 +809,19 @@ class Multiplexer(EventEmitter):
# -----------------------------------------------------------------------------
class Client:
def __init__(self, device, connection):
- self.device = device
- self.connection = connection
+ self.device = device
+ self.connection = connection
self.l2cap_channel = None
- self.multiplexer = None
+ self.multiplexer = None
async def start(self):
# Create a new L2CAP connection
try:
- self.l2cap_channel = await self.device.l2cap_channel_manager.connect(self.connection, RFCOMM_PSM)
+ self.l2cap_channel = await self.device.l2cap_channel_manager.connect(
+ self.connection, RFCOMM_PSM
+ )
except ProtocolError as error:
- logger.warn(f'L2CAP connection failed: {error}')
+ logger.warning(f'L2CAP connection failed: {error}')
raise
# Create a mutliplexer to manage DLCs with the server
@@ -796,22 +845,34 @@ class Client:
class Server(EventEmitter):
def __init__(self, device):
super().__init__()
- self.device = device
+ self.device = device
self.multiplexer = None
- self.acceptors = {}
+ self.acceptors = {}
# Register ourselves with the L2CAP channel manager
device.register_l2cap_server(RFCOMM_PSM, self.on_connection)
- def listen(self, acceptor):
- # Find a free channel number
- for channel in range(RFCOMM_DYNAMIC_CHANNEL_NUMBER_START, RFCOMM_DYNAMIC_CHANNEL_NUMBER_END + 1):
- if channel not in self.acceptors:
- self.acceptors[channel] = acceptor
- return channel
-
- # All channels used...
- return 0
+ def listen(self, acceptor, channel=0):
+ if channel:
+ if channel in self.acceptors:
+ # Busy
+ return 0
+ else:
+ # Find a free channel number
+ for candidate in range(
+ RFCOMM_DYNAMIC_CHANNEL_NUMBER_START,
+ RFCOMM_DYNAMIC_CHANNEL_NUMBER_END + 1,
+ ):
+ if candidate not in self.acceptors:
+ channel = candidate
+ break
+
+ if channel == 0:
+ # All channels used...
+ return 0
+
+ self.acceptors[channel] = acceptor
+ return channel
def on_connection(self, l2cap_channel):
logger.debug(f'+++ new L2CAP connection: {l2cap_channel}')
diff --git a/bumble/sdp.py b/bumble/sdp.py
index 935561e..019b8e6 100644
--- a/bumble/sdp.py
+++ b/bumble/sdp.py
@@ -15,12 +15,13 @@
# -----------------------------------------------------------------------------
# Imports
# -----------------------------------------------------------------------------
+from __future__ import annotations
import logging
import struct
-from colors import color
-import colors
+from typing import Dict, List, Type
from . import core
+from .colors import color
from .core import InvalidStateError
from .hci import HCI_Object, name_or_number, key_with_value
@@ -33,6 +34,9 @@ logger = logging.getLogger(__name__)
# -----------------------------------------------------------------------------
# Constants
# -----------------------------------------------------------------------------
+# fmt: off
+# pylint: disable=line-too-long
+
SDP_CONTINUATION_WATCHDOG = 64 # Maximum number of continuations we're willing to do
SDP_PSM = 0x0001
@@ -112,137 +116,162 @@ SDP_PUBLIC_BROWSE_ROOT = core.UUID.from_16_bits(0x1002, 'PublicBrowseRoot')
# To be used in searches where an attribute ID list allows a range to be specified
SDP_ALL_ATTRIBUTES_RANGE = (0x0000FFFF, 4) # Express this as tuple so we can convey the desired encoding size
+# fmt: on
+# pylint: enable=line-too-long
+# pylint: disable=invalid-name
+
# -----------------------------------------------------------------------------
class DataElement:
- NIL = 0
+ NIL = 0
UNSIGNED_INTEGER = 1
- SIGNED_INTEGER = 2
- UUID = 3
- TEXT_STRING = 4
- BOOLEAN = 5
- SEQUENCE = 6
- ALTERNATIVE = 7
- URL = 8
+ SIGNED_INTEGER = 2
+ UUID = 3
+ TEXT_STRING = 4
+ BOOLEAN = 5
+ SEQUENCE = 6
+ ALTERNATIVE = 7
+ URL = 8
TYPE_NAMES = {
- NIL: 'NIL',
+ NIL: 'NIL',
UNSIGNED_INTEGER: 'UNSIGNED_INTEGER',
- SIGNED_INTEGER: 'SIGNED_INTEGER',
- UUID: 'UUID',
- TEXT_STRING: 'TEXT_STRING',
- BOOLEAN: 'BOOLEAN',
- SEQUENCE: 'SEQUENCE',
- ALTERNATIVE: 'ALTERNATIVE',
- URL: 'URL'
+ SIGNED_INTEGER: 'SIGNED_INTEGER',
+ UUID: 'UUID',
+ TEXT_STRING: 'TEXT_STRING',
+ BOOLEAN: 'BOOLEAN',
+ SEQUENCE: 'SEQUENCE',
+ ALTERNATIVE: 'ALTERNATIVE',
+ URL: 'URL',
}
type_constructors = {
- NIL: lambda x: DataElement(DataElement.NIL, None),
- UNSIGNED_INTEGER: lambda x, y: DataElement(DataElement.UNSIGNED_INTEGER, DataElement.unsigned_integer_from_bytes(x), value_size=y),
- SIGNED_INTEGER: lambda x, y: DataElement(DataElement.SIGNED_INTEGER, DataElement.signed_integer_from_bytes(x), value_size=y),
- UUID: lambda x: DataElement(DataElement.UUID, core.UUID.from_bytes(bytes(reversed(x)))),
- TEXT_STRING: lambda x: DataElement(DataElement.TEXT_STRING, x.decode('utf8')),
- BOOLEAN: lambda x: DataElement(DataElement.BOOLEAN, x[0] == 1),
- SEQUENCE: lambda x: DataElement(DataElement.SEQUENCE, DataElement.list_from_bytes(x)),
- ALTERNATIVE: lambda x: DataElement(DataElement.ALTERNATIVE, DataElement.list_from_bytes(x)),
- URL: lambda x: DataElement(DataElement.URL, x.decode('utf8'))
+ NIL: lambda x: DataElement(DataElement.NIL, None),
+ UNSIGNED_INTEGER: lambda x, y: DataElement(
+ DataElement.UNSIGNED_INTEGER,
+ DataElement.unsigned_integer_from_bytes(x),
+ value_size=y,
+ ),
+ SIGNED_INTEGER: lambda x, y: DataElement(
+ DataElement.SIGNED_INTEGER,
+ DataElement.signed_integer_from_bytes(x),
+ value_size=y,
+ ),
+ UUID: lambda x: DataElement(
+ DataElement.UUID, core.UUID.from_bytes(bytes(reversed(x)))
+ ),
+ TEXT_STRING: lambda x: DataElement(DataElement.TEXT_STRING, x.decode('utf8')),
+ BOOLEAN: lambda x: DataElement(DataElement.BOOLEAN, x[0] == 1),
+ SEQUENCE: lambda x: DataElement(
+ DataElement.SEQUENCE, DataElement.list_from_bytes(x)
+ ),
+ ALTERNATIVE: lambda x: DataElement(
+ DataElement.ALTERNATIVE, DataElement.list_from_bytes(x)
+ ),
+ URL: lambda x: DataElement(DataElement.URL, x.decode('utf8')),
}
- def __init__(self, type, value, value_size=None):
- self.type = type
- self.value = value
+ def __init__(self, element_type, value, value_size=None):
+ self.type = element_type
+ self.value = value
self.value_size = value_size
- self.bytes = None # Used a cache when parsing from bytes so we can emit a byte-for-byte replica
- if type == DataElement.UNSIGNED_INTEGER or type == DataElement.SIGNED_INTEGER:
+ # Used as a cache when parsing from bytes so we can emit a byte-for-byte replica
+ self.bytes = None
+ if element_type in (DataElement.UNSIGNED_INTEGER, DataElement.SIGNED_INTEGER):
if value_size is None:
raise ValueError('integer types must have a value size specified')
@staticmethod
- def nil():
+ def nil() -> DataElement:
return DataElement(DataElement.NIL, None)
@staticmethod
- def unsigned_integer(value, value_size):
+ def unsigned_integer(value: int, value_size: int) -> DataElement:
return DataElement(DataElement.UNSIGNED_INTEGER, value, value_size)
@staticmethod
- def unsigned_integer_8(value):
+ def unsigned_integer_8(value: int) -> DataElement:
return DataElement(DataElement.UNSIGNED_INTEGER, value, value_size=1)
@staticmethod
- def unsigned_integer_16(value):
+ def unsigned_integer_16(value: int) -> DataElement:
return DataElement(DataElement.UNSIGNED_INTEGER, value, value_size=2)
@staticmethod
- def unsigned_integer_32(value):
+ def unsigned_integer_32(value: int) -> DataElement:
return DataElement(DataElement.UNSIGNED_INTEGER, value, value_size=4)
@staticmethod
- def signed_integer(value, value_size):
+ def signed_integer(value: int, value_size: int) -> DataElement:
return DataElement(DataElement.SIGNED_INTEGER, value, value_size)
@staticmethod
- def signed_integer_8(value):
+ def signed_integer_8(value: int) -> DataElement:
return DataElement(DataElement.SIGNED_INTEGER, value, value_size=1)
@staticmethod
- def signed_integer_16(value):
+ def signed_integer_16(value: int) -> DataElement:
return DataElement(DataElement.SIGNED_INTEGER, value, value_size=2)
@staticmethod
- def signed_integer_32(value):
+ def signed_integer_32(value: int) -> DataElement:
return DataElement(DataElement.SIGNED_INTEGER, value, value_size=4)
@staticmethod
- def uuid(value):
+ def uuid(value: core.UUID) -> DataElement:
return DataElement(DataElement.UUID, value)
@staticmethod
- def text_string(value):
+ def text_string(value: str) -> DataElement:
return DataElement(DataElement.TEXT_STRING, value)
@staticmethod
- def boolean(value):
+ def boolean(value: bool) -> DataElement:
return DataElement(DataElement.BOOLEAN, value)
@staticmethod
- def sequence(value):
+ def sequence(value: List[DataElement]) -> DataElement:
return DataElement(DataElement.SEQUENCE, value)
@staticmethod
- def alternative(value):
+ def alternative(value: List[DataElement]) -> DataElement:
return DataElement(DataElement.ALTERNATIVE, value)
@staticmethod
- def url(value):
+ def url(value: str) -> DataElement:
return DataElement(DataElement.URL, value)
@staticmethod
def unsigned_integer_from_bytes(data):
if len(data) == 1:
return data[0]
- elif len(data) == 2:
+
+ if len(data) == 2:
return struct.unpack('>H', data)[0]
- elif len(data) == 4:
+
+ if len(data) == 4:
return struct.unpack('>I', data)[0]
- elif len(data) == 8:
+
+ if len(data) == 8:
return struct.unpack('>Q', data)[0]
- else:
- raise ValueError(f'invalid integer length {len(data)}')
+
+ raise ValueError(f'invalid integer length {len(data)}')
@staticmethod
def signed_integer_from_bytes(data):
if len(data) == 1:
return struct.unpack('b', data)[0]
- elif len(data) == 2:
+
+ if len(data) == 2:
return struct.unpack('>h', data)[0]
- elif len(data) == 4:
+
+ if len(data) == 4:
return struct.unpack('>i', data)[0]
- elif len(data) == 8:
+
+ if len(data) == 8:
return struct.unpack('>q', data)[0]
- else:
- raise ValueError(f'invalid integer length {len(data)}')
+
+ raise ValueError(f'invalid integer length {len(data)}')
@staticmethod
def list_from_bytes(data):
@@ -250,7 +279,7 @@ class DataElement:
while data:
element = DataElement.from_bytes(data)
elements.append(element)
- data = data[len(bytes(element)):]
+ data = data[len(bytes(element)) :]
return elements
@staticmethod
@@ -260,11 +289,11 @@ class DataElement:
@staticmethod
def from_bytes(data):
- type = data[0] >> 3
- size_index = data[0] & 7
+ element_type = data[0] >> 3
+ size_index = data[0] & 7
value_offset = 0
if size_index == 0:
- if type == DataElement.NIL:
+ if element_type == DataElement.NIL:
value_size = 0
else:
value_size = 1
@@ -286,16 +315,21 @@ class DataElement:
value_size = struct.unpack('>I', data[1:5])[0]
value_offset = 4
- value_data = data[1 + value_offset:1 + value_offset + value_size]
- constructor = DataElement.type_constructors.get(type)
+ value_data = data[1 + value_offset : 1 + value_offset + value_size]
+ constructor = DataElement.type_constructors.get(element_type)
if constructor:
- if type == DataElement.UNSIGNED_INTEGER or type == DataElement.SIGNED_INTEGER:
+ if element_type in (
+ DataElement.UNSIGNED_INTEGER,
+ DataElement.SIGNED_INTEGER,
+ ):
result = constructor(value_data, value_size)
else:
result = constructor(value_data)
else:
- result = DataElement(type, value_data)
- result.bytes = data[:1 + value_offset + value_size] # Keep a copy so we can re-serialize to an exact replica
+ result = DataElement(element_type, value_data)
+ result.bytes = data[
+ : 1 + value_offset + value_size
+ ] # Keep a copy so we can re-serialize to an exact replica
return result
def to_bytes(self):
@@ -311,7 +345,8 @@ class DataElement:
elif self.type == DataElement.UNSIGNED_INTEGER:
if self.value < 0:
raise ValueError('UNSIGNED_INTEGER cannot be negative')
- elif self.value_size == 1:
+
+ if self.value_size == 1:
data = struct.pack('B', self.value)
elif self.value_size == 2:
data = struct.pack('>H', self.value)
@@ -334,11 +369,11 @@ class DataElement:
raise ValueError('invalid value_size')
elif self.type == DataElement.UUID:
data = bytes(reversed(bytes(self.value)))
- elif self.type == DataElement.TEXT_STRING or self.type == DataElement.URL:
+ elif self.type in (DataElement.TEXT_STRING, DataElement.URL):
data = self.value.encode('utf8')
elif self.type == DataElement.BOOLEAN:
data = bytes([1 if self.value else 0])
- elif self.type == DataElement.SEQUENCE or self.type == DataElement.ALTERNATIVE:
+ elif self.type in (DataElement.SEQUENCE, DataElement.ALTERNATIVE):
data = b''.join([bytes(element) for element in self.value])
else:
data = self.value
@@ -349,9 +384,11 @@ class DataElement:
if size != 0:
raise ValueError('NIL must be empty')
size_index = 0
- elif (self.type == DataElement.UNSIGNED_INTEGER or
- self.type == DataElement.SIGNED_INTEGER or
- self.type == DataElement.UUID):
+ elif self.type in (
+ DataElement.UNSIGNED_INTEGER,
+ DataElement.SIGNED_INTEGER,
+ DataElement.UUID,
+ ):
if size <= 1:
size_index = 0
elif size == 2:
@@ -364,10 +401,12 @@ class DataElement:
size_index = 4
else:
raise ValueError('invalid data size')
- elif (self.type == DataElement.TEXT_STRING or
- self.type == DataElement.SEQUENCE or
- self.type == DataElement.ALTERNATIVE or
- self.type == DataElement.URL):
+ elif self.type in (
+ DataElement.TEXT_STRING,
+ DataElement.SEQUENCE,
+ DataElement.ALTERNATIVE,
+ DataElement.URL,
+ ):
if size <= 0xFF:
size_index = 5
size_bytes = bytes([size])
@@ -392,11 +431,19 @@ class DataElement:
type_name = name_or_number(self.TYPE_NAMES, self.type)
if self.type == DataElement.NIL:
value_string = ''
- elif self.type == DataElement.SEQUENCE or self.type == DataElement.ALTERNATIVE:
+ elif self.type in (DataElement.SEQUENCE, DataElement.ALTERNATIVE):
container_separator = '\n' if pretty else ''
element_separator = '\n' if pretty else ','
- value_string = f'[{container_separator}{element_separator.join([element.to_string(pretty, indentation + 1 if pretty else 0) for element in self.value])}{container_separator}{prefix}]'
- elif self.type == DataElement.UNSIGNED_INTEGER or self.type == DataElement.SIGNED_INTEGER:
+ elements = [
+ element.to_string(pretty, indentation + 1 if pretty else 0)
+ for element in self.value
+ ]
+ value_string = (
+ f'[{container_separator}'
+ f'{element_separator.join(elements)}'
+ f'{container_separator}{prefix}]'
+ )
+ elif self.type in (DataElement.UNSIGNED_INTEGER, DataElement.SIGNED_INTEGER):
value_string = f'{self.value}#{self.value_size}'
elif isinstance(self.value, DataElement):
value_string = self.value.to_string(pretty, indentation)
@@ -410,17 +457,17 @@ class DataElement:
# -----------------------------------------------------------------------------
class ServiceAttribute:
- def __init__(self, id, value):
- self.id = id
+ def __init__(self, attribute_id: int, value: DataElement) -> None:
+ self.id = attribute_id
self.value = value
@staticmethod
def list_from_data_elements(elements):
attribute_list = []
for i in range(0, len(elements) // 2):
- attribute_id, attribute_value = elements[2 * i:2 * (i + 1)]
+ attribute_id, attribute_value = elements[2 * i : 2 * (i + 1)]
if attribute_id.type != DataElement.UNSIGNED_INTEGER:
- logger.warn('attribute ID element is not an integer')
+ logger.warning('attribute ID element is not an integer')
continue
attribute_list.append(ServiceAttribute(attribute_id.value, attribute_value))
@@ -428,30 +475,41 @@ class ServiceAttribute:
@staticmethod
def find_attribute_in_list(attribute_list, attribute_id):
- return next((attribute.value for attribute in attribute_list if attribute.id == attribute_id), None)
+ return next(
+ (
+ attribute.value
+ for attribute in attribute_list
+ if attribute.id == attribute_id
+ ),
+ None,
+ )
@staticmethod
- def id_name(id):
- return name_or_number(SDP_ATTRIBUTE_ID_NAMES, id)
+ def id_name(id_code):
+ return name_or_number(SDP_ATTRIBUTE_ID_NAMES, id_code)
@staticmethod
def is_uuid_in_value(uuid, value):
# Find if a uuid matches a value, either directly or recursing into sequences
if value.type == DataElement.UUID:
return value.value == uuid
- elif value.type == DataElement.SEQUENCE:
+
+ if value.type == DataElement.SEQUENCE:
for element in value.value:
if ServiceAttribute.is_uuid_in_value(uuid, element):
return True
return False
- else:
- return False
- def to_string(self, color=False):
- if color:
- return f'Attribute(id={colors.color(self.id_name(self.id),"magenta")},value={self.value})'
- else:
- return f'Attribute(id={self.id_name(self.id)},value={self.value})'
+ return False
+
+ def to_string(self, with_colors=False):
+ if with_colors:
+ return (
+ f'Attribute(id={color(self.id_name(self.id),"magenta")},'
+ f'value={self.value})'
+ )
+
+ return f'Attribute(id={self.id_name(self.id)},value={self.value})'
def __str__(self):
return self.to_string()
@@ -462,11 +520,14 @@ class SDP_PDU:
'''
See Bluetooth spec @ Vol 3, Part B - 4.2 PROTOCOL DATA UNIT FORMAT
'''
- sdp_pdu_classes = {}
+
+ sdp_pdu_classes: Dict[int, Type[SDP_PDU]] = {}
+ name = None
+ pdu_id = 0
@staticmethod
def from_bytes(pdu):
- pdu_id, transaction_id, parameters_length = struct.unpack_from('>BHH', pdu, 0)
+ pdu_id, transaction_id, _parameters_length = struct.unpack_from('>BHH', pdu, 0)
cls = SDP_PDU.sdp_pdu_classes.get(pdu_id)
if cls is None:
@@ -484,13 +545,15 @@ class SDP_PDU:
@staticmethod
def parse_service_record_handle_list_preceded_by_count(data, offset):
count = struct.unpack_from('>H', data, offset - 2)[0]
- handle_list = [struct.unpack_from('>I', data, offset + x * 4)[0] for x in range(count)]
+ handle_list = [
+ struct.unpack_from('>I', data, offset + x * 4)[0] for x in range(count)
+ ]
return offset + count * 4, handle_list
@staticmethod
def parse_bytes_preceded_by_length(data, offset):
length = struct.unpack_from('>H', data, offset - 2)[0]
- return offset + length, data[offset:offset + length]
+ return offset + length, data[offset : offset + length]
@staticmethod
def error_name(error_code):
@@ -532,7 +595,10 @@ class SDP_PDU:
HCI_Object.init_from_fields(self, self.fields, kwargs)
if pdu is None:
parameters = HCI_Object.dict_to_bytes(kwargs, self.fields)
- pdu = struct.pack('>BHH', self.pdu_id, transaction_id, len(parameters)) + parameters
+ pdu = (
+ struct.pack('>BHH', self.pdu_id, transaction_id, len(parameters))
+ + parameters
+ )
self.pdu = pdu
self.transaction_id = transaction_id
@@ -555,9 +621,7 @@ class SDP_PDU:
# -----------------------------------------------------------------------------
-@SDP_PDU.subclass([
- ('error_code', {'size': 2, 'mapper': SDP_PDU.error_name})
-])
+@SDP_PDU.subclass([('error_code', {'size': 2, 'mapper': SDP_PDU.error_name})])
class SDP_ErrorResponse(SDP_PDU):
'''
See Bluetooth spec @ Vol 3, Part B - 4.4.1 SDP_ErrorResponse PDU
@@ -565,11 +629,13 @@ class SDP_ErrorResponse(SDP_PDU):
# -----------------------------------------------------------------------------
-@SDP_PDU.subclass([
- ('service_search_pattern', DataElement.parse_from_bytes),
- ('maximum_service_record_count', '>2'),
- ('continuation_state', '*')
-])
+@SDP_PDU.subclass(
+ [
+ ('service_search_pattern', DataElement.parse_from_bytes),
+ ('maximum_service_record_count', '>2'),
+ ('continuation_state', '*'),
+ ]
+)
class SDP_ServiceSearchRequest(SDP_PDU):
'''
See Bluetooth spec @ Vol 3, Part B - 4.5.1 SDP_ServiceSearchRequest PDU
@@ -577,12 +643,17 @@ class SDP_ServiceSearchRequest(SDP_PDU):
# -----------------------------------------------------------------------------
-@SDP_PDU.subclass([
- ('total_service_record_count', '>2'),
- ('current_service_record_count', '>2'),
- ('service_record_handle_list', SDP_PDU.parse_service_record_handle_list_preceded_by_count),
- ('continuation_state', '*')
-])
+@SDP_PDU.subclass(
+ [
+ ('total_service_record_count', '>2'),
+ ('current_service_record_count', '>2'),
+ (
+ 'service_record_handle_list',
+ SDP_PDU.parse_service_record_handle_list_preceded_by_count,
+ ),
+ ('continuation_state', '*'),
+ ]
+)
class SDP_ServiceSearchResponse(SDP_PDU):
'''
See Bluetooth spec @ Vol 3, Part B - 4.5.2 SDP_ServiceSearchResponse PDU
@@ -590,12 +661,14 @@ class SDP_ServiceSearchResponse(SDP_PDU):
# -----------------------------------------------------------------------------
-@SDP_PDU.subclass([
- ('service_record_handle', '>4'),
- ('maximum_attribute_byte_count', '>2'),
- ('attribute_id_list', DataElement.parse_from_bytes),
- ('continuation_state', '*')
-])
+@SDP_PDU.subclass(
+ [
+ ('service_record_handle', '>4'),
+ ('maximum_attribute_byte_count', '>2'),
+ ('attribute_id_list', DataElement.parse_from_bytes),
+ ('continuation_state', '*'),
+ ]
+)
class SDP_ServiceAttributeRequest(SDP_PDU):
'''
See Bluetooth spec @ Vol 3, Part B - 4.6.1 SDP_ServiceAttributeRequest PDU
@@ -603,11 +676,13 @@ class SDP_ServiceAttributeRequest(SDP_PDU):
# -----------------------------------------------------------------------------
-@SDP_PDU.subclass([
- ('attribute_list_byte_count', '>2'),
- ('attribute_list', SDP_PDU.parse_bytes_preceded_by_length),
- ('continuation_state', '*')
-])
+@SDP_PDU.subclass(
+ [
+ ('attribute_list_byte_count', '>2'),
+ ('attribute_list', SDP_PDU.parse_bytes_preceded_by_length),
+ ('continuation_state', '*'),
+ ]
+)
class SDP_ServiceAttributeResponse(SDP_PDU):
'''
See Bluetooth spec @ Vol 3, Part B - 4.6.2 SDP_ServiceAttributeResponse PDU
@@ -615,12 +690,14 @@ class SDP_ServiceAttributeResponse(SDP_PDU):
# -----------------------------------------------------------------------------
-@SDP_PDU.subclass([
- ('service_search_pattern', DataElement.parse_from_bytes),
- ('maximum_attribute_byte_count', '>2'),
- ('attribute_id_list', DataElement.parse_from_bytes),
- ('continuation_state', '*')
-])
+@SDP_PDU.subclass(
+ [
+ ('service_search_pattern', DataElement.parse_from_bytes),
+ ('maximum_attribute_byte_count', '>2'),
+ ('attribute_id_list', DataElement.parse_from_bytes),
+ ('continuation_state', '*'),
+ ]
+)
class SDP_ServiceSearchAttributeRequest(SDP_PDU):
'''
See Bluetooth spec @ Vol 3, Part B - 4.7.1 SDP_ServiceSearchAttributeRequest PDU
@@ -628,11 +705,13 @@ class SDP_ServiceSearchAttributeRequest(SDP_PDU):
# -----------------------------------------------------------------------------
-@SDP_PDU.subclass([
- ('attribute_lists_byte_count', '>2'),
- ('attribute_lists', SDP_PDU.parse_bytes_preceded_by_length),
- ('continuation_state', '*')
-])
+@SDP_PDU.subclass(
+ [
+ ('attribute_lists_byte_count', '>2'),
+ ('attribute_lists', SDP_PDU.parse_bytes_preceded_by_length),
+ ('continuation_state', '*'),
+ ]
+)
class SDP_ServiceSearchAttributeResponse(SDP_PDU):
'''
See Bluetooth spec @ Vol 3, Part B - 4.7.2 SDP_ServiceSearchAttributeResponse PDU
@@ -642,9 +721,9 @@ class SDP_ServiceSearchAttributeResponse(SDP_PDU):
# -----------------------------------------------------------------------------
class Client:
def __init__(self, device):
- self.device = device
+ self.device = device
self.pending_request = None
- self.channel = None
+ self.channel = None
async def connect(self, connection):
result = await self.device.l2cap_channel_manager.connect(connection, SDP_PSM)
@@ -659,7 +738,9 @@ class Client:
if self.pending_request is not None:
raise InvalidStateError('request already pending')
- service_search_pattern = DataElement.sequence([DataElement.uuid(uuid) for uuid in uuids])
+ service_search_pattern = DataElement.sequence(
+ [DataElement.uuid(uuid) for uuid in uuids]
+ )
# Request and accumulate until there's no more continuation
service_record_handle_list = []
@@ -668,10 +749,10 @@ class Client:
while watchdog > 0:
response_pdu = await self.channel.send_request(
SDP_ServiceSearchRequest(
- transaction_id = 0, # Transaction ID TODO: pick a real value
- service_search_pattern = service_search_pattern,
- maximum_service_record_count = 0xFFFF,
- continuation_state = continuation_state
+ transaction_id=0, # Transaction ID TODO: pick a real value
+ service_search_pattern=service_search_pattern,
+ maximum_service_record_count=0xFFFF,
+ continuation_state=continuation_state,
)
)
response = SDP_PDU.from_bytes(response_pdu)
@@ -689,11 +770,15 @@ class Client:
if self.pending_request is not None:
raise InvalidStateError('request already pending')
- service_search_pattern = DataElement.sequence([DataElement.uuid(uuid) for uuid in uuids])
+ service_search_pattern = DataElement.sequence(
+ [DataElement.uuid(uuid) for uuid in uuids]
+ )
attribute_id_list = DataElement.sequence(
[
- DataElement.unsigned_integer(attribute_id[0], value_size=attribute_id[1])
- if type(attribute_id) is tuple
+ DataElement.unsigned_integer(
+ attribute_id[0], value_size=attribute_id[1]
+ )
+ if isinstance(attribute_id, tuple)
else DataElement.unsigned_integer_16(attribute_id)
for attribute_id in attribute_ids
]
@@ -706,11 +791,11 @@ class Client:
while watchdog > 0:
response_pdu = await self.channel.send_request(
SDP_ServiceSearchAttributeRequest(
- transaction_id = 0, # Transaction ID TODO: pick a real value
- service_search_pattern = service_search_pattern,
- maximum_attribute_byte_count = 0xFFFF,
- attribute_id_list = attribute_id_list,
- continuation_state = continuation_state
+ transaction_id=0, # Transaction ID TODO: pick a real value
+ service_search_pattern=service_search_pattern,
+ maximum_attribute_byte_count=0xFFFF,
+ attribute_id_list=attribute_id_list,
+ continuation_state=continuation_state,
)
)
response = SDP_PDU.from_bytes(response_pdu)
@@ -725,7 +810,7 @@ class Client:
# Parse the result into attribute lists
attribute_lists_sequences = DataElement.from_bytes(accumulator)
if attribute_lists_sequences.type != DataElement.SEQUENCE:
- logger.warn('unexpected data type')
+ logger.warning('unexpected data type')
return []
return [
@@ -740,8 +825,10 @@ class Client:
attribute_id_list = DataElement.sequence(
[
- DataElement.unsigned_integer(attribute_id[0], value_size=attribute_id[1])
- if type(attribute_id) is tuple
+ DataElement.unsigned_integer(
+ attribute_id[0], value_size=attribute_id[1]
+ )
+ if isinstance(attribute_id, tuple)
else DataElement.unsigned_integer_16(attribute_id)
for attribute_id in attribute_ids
]
@@ -754,11 +841,11 @@ class Client:
while watchdog > 0:
response_pdu = await self.channel.send_request(
SDP_ServiceAttributeRequest(
- transaction_id = 0, # Transaction ID TODO: pick a real value
- service_record_handle = service_record_handle,
- maximum_attribute_byte_count = 0xFFFF,
- attribute_id_list = attribute_id_list,
- continuation_state = continuation_state
+ transaction_id=0, # Transaction ID TODO: pick a real value
+ service_record_handle=service_record_handle,
+ maximum_attribute_byte_count=0xFFFF,
+ attribute_id_list=attribute_id_list,
+ continuation_state=continuation_state,
)
)
response = SDP_PDU.from_bytes(response_pdu)
@@ -773,7 +860,7 @@ class Client:
# Parse the result into a list of attributes
attribute_list_sequence = DataElement.from_bytes(accumulator)
if attribute_list_sequence.type != DataElement.SEQUENCE:
- logger.warn('unexpected data type')
+ logger.warning('unexpected data type')
return []
return ServiceAttribute.list_from_data_elements(attribute_list_sequence.value)
@@ -784,8 +871,9 @@ class Server:
CONTINUATION_STATE = bytes([0x01, 0x43])
def __init__(self, device):
- self.device = device
- self.service_records = {} # Service records maps, by record handle
+ self.device = device
+ self.service_records = {} # Service records maps, by record handle
+ self.channel = None
self.current_response = None
def register(self, l2cap_channel_manager):
@@ -820,11 +908,10 @@ class Server:
try:
sdp_pdu = SDP_PDU.from_bytes(pdu)
except Exception as error:
- logger.warn(color(f'failed to parse SDP Request PDU: {error}', 'red'))
+ logger.warning(color(f'failed to parse SDP Request PDU: {error}', 'red'))
self.send_response(
SDP_ErrorResponse(
- transaction_id = 0,
- error_code = SDP_INVALID_REQUEST_SYNTAX_ERROR
+ transaction_id=0, error_code=SDP_INVALID_REQUEST_SYNTAX_ERROR
)
)
@@ -840,16 +927,16 @@ class Server:
logger.warning(f'{color("!!! Exception in handler:", "red")} {error}')
self.send_response(
SDP_ErrorResponse(
- transaction_id = sdp_pdu.transaction_id,
- error_code = SDP_INSUFFICIENT_RESOURCES_TO_SATISFY_REQUEST_ERROR
+ transaction_id=sdp_pdu.transaction_id,
+ error_code=SDP_INSUFFICIENT_RESOURCES_TO_SATISFY_REQUEST_ERROR,
)
)
else:
logger.error(color('SDP Request not handled???', 'red'))
self.send_response(
SDP_ErrorResponse(
- transaction_id = sdp_pdu.transaction_id,
- error_code = SDP_INVALID_REQUEST_SYNTAX_ERROR
+ transaction_id=sdp_pdu.transaction_id,
+ error_code=SDP_INVALID_REQUEST_SYNTAX_ERROR,
)
)
@@ -872,17 +959,18 @@ class Server:
if attribute_id.value_size == 4:
# Attribute ID range
id_range_start = attribute_id.value >> 16
- id_range_end = attribute_id.value & 0xFFFF
+ id_range_end = attribute_id.value & 0xFFFF
else:
id_range_start = attribute_id.value
- id_range_end = attribute_id.value
+ id_range_end = attribute_id.value
attributes += [
- attribute for attribute in service
+ attribute
+ for attribute in service
if attribute.id >= id_range_start and attribute.id <= id_range_end
]
- # Return the maching attributes, sorted by attribute id
- attributes.sort(key = lambda x: x.id)
+ # Return the matching attributes, sorted by attribute id
+ attributes.sort(key=lambda x: x.id)
attribute_list = DataElement.sequence([])
for attribute in attributes:
attribute_list.value.append(DataElement.unsigned_integer_16(attribute.id))
@@ -896,8 +984,8 @@ class Server:
if not self.current_response:
self.send_response(
SDP_ErrorResponse(
- transaction_id = request.transaction_id,
- error_code = SDP_INVALID_CONTINUATION_STATE_ERROR
+ transaction_id=request.transaction_id,
+ error_code=SDP_INVALID_CONTINUATION_STATE_ERROR,
)
)
return
@@ -910,30 +998,38 @@ class Server:
service_record_handles = list(matching_services.keys())
# Only return up to the maximum requested
- service_record_handles_subset = service_record_handles[:request.maximum_service_record_count]
+ service_record_handles_subset = service_record_handles[
+ : request.maximum_service_record_count
+ ]
# Serialize to a byte array, and remember the total count
logger.debug(f'Service Record Handles: {service_record_handles}')
self.current_response = (
len(service_record_handles),
- service_record_handles_subset
+ service_record_handles_subset,
)
# Respond, keeping any unsent handles for later
- service_record_handles = self.current_response[1][:request.maximum_service_record_count]
+ service_record_handles = self.current_response[1][
+ : request.maximum_service_record_count
+ ]
self.current_response = (
self.current_response[0],
- self.current_response[1][request.maximum_service_record_count:]
+ self.current_response[1][request.maximum_service_record_count :],
+ )
+ continuation_state = (
+ Server.CONTINUATION_STATE if self.current_response[1] else bytes([0])
+ )
+ service_record_handle_list = b''.join(
+ [struct.pack('>I', handle) for handle in service_record_handles]
)
- continuation_state = Server.CONTINUATION_STATE if self.current_response[1] else bytes([0])
- service_record_handle_list = b''.join([struct.pack('>I', handle) for handle in service_record_handles])
self.send_response(
SDP_ServiceSearchResponse(
- transaction_id = request.transaction_id,
- total_service_record_count = self.current_response[0],
- current_service_record_count = len(service_record_handles),
- service_record_handle_list = service_record_handle_list,
- continuation_state = continuation_state
+ transaction_id=request.transaction_id,
+ total_service_record_count=self.current_response[0],
+ current_service_record_count=len(service_record_handles),
+ service_record_handle_list=service_record_handle_list,
+ continuation_state=continuation_state,
)
)
@@ -943,8 +1039,8 @@ class Server:
if not self.current_response:
self.send_response(
SDP_ErrorResponse(
- transaction_id = request.transaction_id,
- error_code = SDP_INVALID_CONTINUATION_STATE_ERROR
+ transaction_id=request.transaction_id,
+ error_code=SDP_INVALID_CONTINUATION_STATE_ERROR,
)
)
return
@@ -957,27 +1053,31 @@ class Server:
if service is None:
self.send_response(
SDP_ErrorResponse(
- transaction_id = request.transaction_id,
- error_code = SDP_INVALID_SERVICE_RECORD_HANDLE_ERROR
+ transaction_id=request.transaction_id,
+ error_code=SDP_INVALID_SERVICE_RECORD_HANDLE_ERROR,
)
)
return
# Get the attributes for the service
- attribute_list = Server.get_service_attributes(service, request.attribute_id_list.value)
+ attribute_list = Server.get_service_attributes(
+ service, request.attribute_id_list.value
+ )
# Serialize to a byte array
logger.debug(f'Attributes: {attribute_list}')
self.current_response = bytes(attribute_list)
# Respond, keeping any pending chunks for later
- attribute_list, continuation_state = self.get_next_response_payload(request.maximum_attribute_byte_count)
+ attribute_list, continuation_state = self.get_next_response_payload(
+ request.maximum_attribute_byte_count
+ )
self.send_response(
SDP_ServiceAttributeResponse(
- transaction_id = request.transaction_id,
- attribute_list_byte_count = len(attribute_list),
- attribute_list = attribute_list,
- continuation_state = continuation_state
+ transaction_id=request.transaction_id,
+ attribute_list_byte_count=len(attribute_list),
+ attribute_list=attribute_list,
+ continuation_state=continuation_state,
)
)
@@ -987,8 +1087,8 @@ class Server:
if not self.current_response:
self.send_response(
SDP_ErrorResponse(
- transaction_id = request.transaction_id,
- error_code = SDP_INVALID_CONTINUATION_STATE_ERROR
+ transaction_id=request.transaction_id,
+ error_code=SDP_INVALID_CONTINUATION_STATE_ERROR,
)
)
else:
@@ -996,12 +1096,16 @@ class Server:
self.current_response = None
# Find the matching services
- matching_services = self.match_services(request.service_search_pattern).values()
+ matching_services = self.match_services(
+ request.service_search_pattern
+ ).values()
# Filter the required attributes
attribute_lists = DataElement.sequence([])
for service in matching_services:
- attribute_list = Server.get_service_attributes(service, request.attribute_id_list.value)
+ attribute_list = Server.get_service_attributes(
+ service, request.attribute_id_list.value
+ )
if attribute_list.value:
attribute_lists.value.append(attribute_list)
@@ -1010,12 +1114,14 @@ class Server:
self.current_response = bytes(attribute_lists)
# Respond, keeping any pending chunks for later
- attribute_lists, continuation_state = self.get_next_response_payload(request.maximum_attribute_byte_count)
+ attribute_lists, continuation_state = self.get_next_response_payload(
+ request.maximum_attribute_byte_count
+ )
self.send_response(
SDP_ServiceSearchAttributeResponse(
- transaction_id = request.transaction_id,
- attribute_lists_byte_count = len(attribute_lists),
- attribute_lists = attribute_lists,
- continuation_state = continuation_state
+ transaction_id=request.transaction_id,
+ attribute_lists_byte_count=len(attribute_lists),
+ attribute_lists=attribute_lists,
+ continuation_state=continuation_state,
)
)
diff --git a/bumble/smp.py b/bumble/smp.py
index dbb2b7a..f3fbf27 100644
--- a/bumble/smp.py
+++ b/bumble/smp.py
@@ -22,17 +22,45 @@
# -----------------------------------------------------------------------------
# Imports
# -----------------------------------------------------------------------------
+from __future__ import annotations
import logging
import asyncio
import secrets
+from typing import (
+ TYPE_CHECKING,
+ Any,
+ Awaitable,
+ Callable,
+ Dict,
+ List,
+ Optional,
+ Tuple,
+ Type,
+)
+
from pyee import EventEmitter
-from colors import color
-from .core import *
-from .hci import *
+from .colors import color
+from .hci import (
+ Address,
+ HCI_LE_Enable_Encryption_Command,
+ HCI_Object,
+ key_with_value,
+)
+from .core import (
+ BT_BR_EDR_TRANSPORT,
+ BT_CENTRAL_ROLE,
+ BT_LE_TRANSPORT,
+ ProtocolError,
+ name_or_number,
+)
from .keys import PairingKeys
from . import crypto
+if TYPE_CHECKING:
+ from bumble.device import Connection, Device
+ from bumble.pairing import PairingConfig
+
# -----------------------------------------------------------------------------
# Logging
@@ -43,7 +71,11 @@ logger = logging.getLogger(__name__)
# -----------------------------------------------------------------------------
# Constants
# -----------------------------------------------------------------------------
+# fmt: off
+# pylint: disable=line-too-long
+
SMP_CID = 0x06
+SMP_BR_CID = 0x07
SMP_PAIRING_REQUEST_COMMAND = 0x01
SMP_PAIRING_RESPONSE_COMMAND = 0x02
@@ -152,11 +184,17 @@ SMP_CT2_AUTHREQ = 0b00100000
# Crypto salt
SMP_CTKD_H7_LEBR_SALT = bytes.fromhex('00000000000000000000000000000000746D7031')
+SMP_CTKD_H7_BRLE_SALT = bytes.fromhex('00000000000000000000000000000000746D7032')
+
+# fmt: on
+# pylint: enable=line-too-long
+# pylint: disable=invalid-name
+
# -----------------------------------------------------------------------------
# Utils
# -----------------------------------------------------------------------------
-def error_name(error_code):
+def error_name(error_code: int) -> str:
return name_or_number(SMP_ERROR_NAMES, error_code)
@@ -167,11 +205,14 @@ class SMP_Command:
'''
See Bluetooth spec @ Vol 3, Part H - 3 SECURITY MANAGER PROTOCOL
'''
- smp_classes = {}
+
+ smp_classes: Dict[int, Type[SMP_Command]] = {}
+ fields: Any
code = 0
+ name = ''
@staticmethod
- def from_bytes(pdu):
+ def from_bytes(pdu: bytes) -> "SMP_Command":
code = pdu[0]
cls = SMP_Command.smp_classes.get(code)
@@ -187,26 +228,29 @@ class SMP_Command:
return self
@staticmethod
- def command_name(code):
+ def command_name(code: int) -> str:
return name_or_number(SMP_COMMAND_NAMES, code)
@staticmethod
- def auth_req_str(value):
+ def auth_req_str(value: int) -> str:
bonding_flags = value & 3
- mitm = (value >> 2) & 1
- sc = (value >> 3) & 1
- keypress = (value >> 4) & 1
- ct2 = (value >> 5) & 1
+ mitm = (value >> 2) & 1
+ sc = (value >> 3) & 1
+ keypress = (value >> 4) & 1
+ ct2 = (value >> 5) & 1
- return f'bonding_flags={bonding_flags}, MITM={mitm}, sc={sc}, keypress={keypress}, ct2={ct2}'
+ return (
+ f'bonding_flags={bonding_flags}, '
+ f'MITM={mitm}, sc={sc}, keypress={keypress}, ct2={ct2}'
+ )
@staticmethod
- def io_capability_name(io_capability):
+ def io_capability_name(io_capability: int) -> str:
return name_or_number(SMP_IO_CAPABILITY_NAMES, io_capability)
@staticmethod
- def key_distribution_str(value):
- key_types = []
+ def key_distribution_str(value: int) -> str:
+ key_types: List[str] = []
if value & SMP_ENC_KEY_DISTRIBUTION_FLAG:
key_types.append('ENC')
if value & SMP_ID_KEY_DISTRIBUTION_FLAG:
@@ -218,7 +262,7 @@ class SMP_Command:
return ','.join(key_types)
@staticmethod
- def keypress_notification_type_name(notification_type):
+ def keypress_notification_type_name(notification_type: int) -> str:
return name_or_number(SMP_KEYPRESS_NOTIFICATION_TYPE_NAMES, notification_type)
@staticmethod
@@ -227,7 +271,9 @@ class SMP_Command:
cls.name = cls.__name__.upper()
cls.code = key_with_value(SMP_COMMAND_NAMES, cls.name)
if cls.code is None:
- raise KeyError(f'Command name {cls.name} not found in SMP_COMMAND_NAMES')
+ raise KeyError(
+ f'Command name {cls.name} not found in SMP_COMMAND_NAMES'
+ )
cls.fields = fields
# Register a factory for this class
@@ -237,14 +283,14 @@ class SMP_Command:
return inner
- def __init__(self, pdu=None, **kwargs):
+ def __init__(self, pdu: Optional[bytes] = None, **kwargs: Any) -> None:
if hasattr(self, 'fields') and kwargs:
HCI_Object.init_from_fields(self, self.fields, kwargs)
if pdu is None:
pdu = bytes([self.code]) + HCI_Object.dict_to_bytes(kwargs, self.fields)
self.pdu = pdu
- def init_from_bytes(self, pdu, offset):
+ def init_from_bytes(self, pdu: bytes, offset: int) -> None:
return HCI_Object.init_from_bytes(self, pdu, offset, self.fields)
def to_bytes(self):
@@ -264,160 +310,210 @@ class SMP_Command:
# -----------------------------------------------------------------------------
-@SMP_Command.subclass([
- ('io_capability', {'size': 1, 'mapper': SMP_Command.io_capability_name}),
- ('oob_data_flag', 1),
- ('auth_req', {'size': 1, 'mapper': SMP_Command.auth_req_str}),
- ('maximum_encryption_key_size', 1),
- ('initiator_key_distribution', {'size': 1, 'mapper': SMP_Command.key_distribution_str}),
- ('responder_key_distribution', {'size': 1, 'mapper': SMP_Command.key_distribution_str})
-])
+@SMP_Command.subclass(
+ [
+ ('io_capability', {'size': 1, 'mapper': SMP_Command.io_capability_name}),
+ ('oob_data_flag', 1),
+ ('auth_req', {'size': 1, 'mapper': SMP_Command.auth_req_str}),
+ ('maximum_encryption_key_size', 1),
+ (
+ 'initiator_key_distribution',
+ {'size': 1, 'mapper': SMP_Command.key_distribution_str},
+ ),
+ (
+ 'responder_key_distribution',
+ {'size': 1, 'mapper': SMP_Command.key_distribution_str},
+ ),
+ ]
+)
class SMP_Pairing_Request_Command(SMP_Command):
'''
See Bluetooth spec @ Vol 3, Part H - 3.5.1 Pairing Request
'''
+ io_capability: int
+ oob_data_flag: int
+ auth_req: int
+ maximum_encryption_key_size: int
+ initiator_key_distribution: int
+ responder_key_distribution: int
+
# -----------------------------------------------------------------------------
-@SMP_Command.subclass([
- ('io_capability', {'size': 1, 'mapper': SMP_Command.io_capability_name}),
- ('oob_data_flag', 1),
- ('auth_req', {'size': 1, 'mapper': SMP_Command.auth_req_str}),
- ('maximum_encryption_key_size', 1),
- ('initiator_key_distribution', {'size': 1, 'mapper': SMP_Command.key_distribution_str}),
- ('responder_key_distribution', {'size': 1, 'mapper': SMP_Command.key_distribution_str})
-])
+@SMP_Command.subclass(
+ [
+ ('io_capability', {'size': 1, 'mapper': SMP_Command.io_capability_name}),
+ ('oob_data_flag', 1),
+ ('auth_req', {'size': 1, 'mapper': SMP_Command.auth_req_str}),
+ ('maximum_encryption_key_size', 1),
+ (
+ 'initiator_key_distribution',
+ {'size': 1, 'mapper': SMP_Command.key_distribution_str},
+ ),
+ (
+ 'responder_key_distribution',
+ {'size': 1, 'mapper': SMP_Command.key_distribution_str},
+ ),
+ ]
+)
class SMP_Pairing_Response_Command(SMP_Command):
'''
See Bluetooth spec @ Vol 3, Part H - 3.5.2 Pairing Response
'''
+ io_capability: int
+ oob_data_flag: int
+ auth_req: int
+ maximum_encryption_key_size: int
+ initiator_key_distribution: int
+ responder_key_distribution: int
+
# -----------------------------------------------------------------------------
-@SMP_Command.subclass([
- ('confirm_value', 16)
-])
+@SMP_Command.subclass([('confirm_value', 16)])
class SMP_Pairing_Confirm_Command(SMP_Command):
'''
See Bluetooth spec @ Vol 3, Part H - 3.5.3 Pairing Confirm
'''
+ confirm_value: bytes
+
# -----------------------------------------------------------------------------
-@SMP_Command.subclass([
- ('random_value', 16)
-])
+@SMP_Command.subclass([('random_value', 16)])
class SMP_Pairing_Random_Command(SMP_Command):
'''
See Bluetooth spec @ Vol 3, Part H - 3.5.4 Pairing Random
'''
+ random_value: bytes
+
# -----------------------------------------------------------------------------
-@SMP_Command.subclass([
- ('reason', {'size': 1, 'mapper': error_name})
-])
+@SMP_Command.subclass([('reason', {'size': 1, 'mapper': error_name})])
class SMP_Pairing_Failed_Command(SMP_Command):
'''
See Bluetooth spec @ Vol 3, Part H - 3.5.5 Pairing Failed
'''
+ reason: int
+
# -----------------------------------------------------------------------------
-@SMP_Command.subclass([
- ('public_key_x', 32),
- ('public_key_y', 32)
-])
+@SMP_Command.subclass([('public_key_x', 32), ('public_key_y', 32)])
class SMP_Pairing_Public_Key_Command(SMP_Command):
'''
See Bluetooth spec @ Vol 3, Part H - 3.5.6 Pairing Public Key
'''
+ public_key_x: bytes
+ public_key_y: bytes
+
# -----------------------------------------------------------------------------
-@SMP_Command.subclass([
- ('dhkey_check', 16),
-])
+@SMP_Command.subclass(
+ [
+ ('dhkey_check', 16),
+ ]
+)
class SMP_Pairing_DHKey_Check_Command(SMP_Command):
'''
See Bluetooth spec @ Vol 3, Part H - 3.5.7 Pairing DHKey Check
'''
+ dhkey_check: bytes
+
# -----------------------------------------------------------------------------
-@SMP_Command.subclass([
- ('notification_type', {'size': 1, 'mapper': SMP_Command.keypress_notification_type_name}),
-])
+@SMP_Command.subclass(
+ [
+ (
+ 'notification_type',
+ {'size': 1, 'mapper': SMP_Command.keypress_notification_type_name},
+ ),
+ ]
+)
class SMP_Pairing_Keypress_Notification_Command(SMP_Command):
'''
See Bluetooth spec @ Vol 3, Part H - 3.5.8 Keypress Notification
'''
+ notification_type: int
+
# -----------------------------------------------------------------------------
-@SMP_Command.subclass([
- ('long_term_key', 16)
-])
+@SMP_Command.subclass([('long_term_key', 16)])
class SMP_Encryption_Information_Command(SMP_Command):
'''
See Bluetooth spec @ Vol 3, Part H - 3.6.2 Encryption Information
'''
+ long_term_key: bytes
+
# -----------------------------------------------------------------------------
-@SMP_Command.subclass([
- ('ediv', 2),
- ('rand', 8)
-])
+@SMP_Command.subclass([('ediv', 2), ('rand', 8)])
class SMP_Master_Identification_Command(SMP_Command):
'''
See Bluetooth spec @ Vol 3, Part H - 3.6.3 Master Identification
'''
+ ediv: int
+ rand: bytes
+
# -----------------------------------------------------------------------------
-@SMP_Command.subclass([
- ('identity_resolving_key', 16)
-])
+@SMP_Command.subclass([('identity_resolving_key', 16)])
class SMP_Identity_Information_Command(SMP_Command):
'''
See Bluetooth spec @ Vol 3, Part H - 3.6.4 Identity Information
'''
+ identity_resolving_key: bytes
+
# -----------------------------------------------------------------------------
-@SMP_Command.subclass([
- ('addr_type', Address.ADDRESS_TYPE_SPEC),
- ('bd_addr', Address.parse_address_preceded_by_type)
-])
+@SMP_Command.subclass(
+ [
+ ('addr_type', Address.ADDRESS_TYPE_SPEC),
+ ('bd_addr', Address.parse_address_preceded_by_type),
+ ]
+)
class SMP_Identity_Address_Information_Command(SMP_Command):
'''
See Bluetooth spec @ Vol 3, Part H - 3.6.5 Identity Address Information
'''
+ addr_type: int
+ bd_addr: Address
+
# -----------------------------------------------------------------------------
-@SMP_Command.subclass([
- ('signature_key', 16)
-])
+@SMP_Command.subclass([('signature_key', 16)])
class SMP_Signing_Information_Command(SMP_Command):
'''
See Bluetooth spec @ Vol 3, Part H - 3.6.6 Signing Information
'''
+ signature_key: bytes
+
# -----------------------------------------------------------------------------
-@SMP_Command.subclass([
- ('auth_req', {'size': 1, 'mapper': SMP_Command.auth_req_str}),
-])
+@SMP_Command.subclass(
+ [
+ ('auth_req', {'size': 1, 'mapper': SMP_Command.auth_req_str}),
+ ]
+)
class SMP_Security_Request_Command(SMP_Command):
'''
See Bluetooth spec @ Vol 3, Part H - 3.6.7 Security Request
'''
+ auth_req: int
+
# -----------------------------------------------------------------------------
-def smp_auth_req(bonding, mitm, sc, keypress, ct2):
+def smp_auth_req(bonding: bool, mitm: bool, sc: bool, keypress: bool, ct2: bool) -> int:
value = 0
if bonding:
value |= SMP_BONDING_AUTHREQ
@@ -439,271 +535,259 @@ class AddressResolver:
def resolve(self, address):
address_bytes = bytes(address)
- hash = address_bytes[0:3]
+ hash_part = address_bytes[0:3]
prand = address_bytes[3:6]
- for (irk, resolved_address) in self.resolving_keys:
+ for irk, resolved_address in self.resolving_keys:
local_hash = crypto.ah(irk, prand)
- if local_hash == hash:
+ if local_hash == hash_part:
# Match!
if resolved_address.address_type == Address.PUBLIC_DEVICE_ADDRESS:
resolved_address_type = Address.PUBLIC_IDENTITY_ADDRESS
else:
resolved_address_type = Address.RANDOM_IDENTITY_ADDRESS
- return Address(address=str(resolved_address), address_type=resolved_address_type)
-
-
-# -----------------------------------------------------------------------------
-class PairingDelegate:
- NO_OUTPUT_NO_INPUT = SMP_NO_INPUT_NO_OUTPUT_IO_CAPABILITY
- KEYBOARD_INPUT_ONLY = SMP_KEYBOARD_ONLY_IO_CAPABILITY
- DISPLAY_OUTPUT_ONLY = SMP_DISPLAY_ONLY_IO_CAPABILITY
- DISPLAY_OUTPUT_AND_YES_NO_INPUT = SMP_DISPLAY_YES_NO_IO_CAPABILITY
- DISPLAY_OUTPUT_AND_KEYBOARD_INPUT = SMP_KEYBOARD_DISPLAY_IO_CAPABILITY
- DEFAULT_KEY_DISTRIBUTION = (SMP_ENC_KEY_DISTRIBUTION_FLAG | SMP_ID_KEY_DISTRIBUTION_FLAG)
-
- def __init__(
- self,
- io_capability=NO_OUTPUT_NO_INPUT,
- local_initiator_key_distribution=DEFAULT_KEY_DISTRIBUTION,
- local_responder_key_distribution=DEFAULT_KEY_DISTRIBUTION
- ):
- self.io_capability = io_capability
- self.local_initiator_key_distribution = local_initiator_key_distribution
- self.local_responder_key_distribution = local_responder_key_distribution
-
- async def accept(self):
- return True
-
- async def compare_numbers(self, number, digits=6):
- return True
-
- async def get_number(self):
- return 0
-
- async def display_number(self, number, digits=6):
- pass
-
- async def key_distribution_response(self, peer_initiator_key_distribution, peer_responder_key_distribution):
- return (
- (peer_initiator_key_distribution &
- self.local_initiator_key_distribution),
- (peer_responder_key_distribution &
- self.local_responder_key_distribution)
- )
-
-
-# -----------------------------------------------------------------------------
-class PairingConfig:
- def __init__(self, sc=True, mitm=True, bonding=True, delegate=None):
- self.sc = sc
- self.mitm = mitm
- self.bonding = bonding
- self.delegate = delegate or PairingDelegate()
+ return Address(
+ address=str(resolved_address), address_type=resolved_address_type
+ )
- def __str__(self):
- io_capability_str = SMP_Command.io_capability_name(self.delegate.io_capability)
- return f'PairingConfig(sc={self.sc}, mitm={self.mitm}, bonding={self.bonding}, delegate[{io_capability_str}])'
+ return None
# -----------------------------------------------------------------------------
class Session:
# Pairing methods
- JUST_WORKS = 0
+ JUST_WORKS = 0
NUMERIC_COMPARISON = 1
- PASSKEY = 2
- OOB = 3
+ PASSKEY = 2
+ OOB = 3
PAIRING_METHOD_NAMES = {
- JUST_WORKS: 'JUST_WORKS',
+ JUST_WORKS: 'JUST_WORKS',
NUMERIC_COMPARISON: 'NUMERIC_COMPARISON',
- PASSKEY: 'PASSKEY',
- OOB: 'OOB'
+ PASSKEY: 'PASSKEY',
+ OOB: 'OOB',
}
# I/O Capability to pairing method decision matrix
#
- # See Bluetooth spec @ Vol 3, part H - Table 2.8: Mapping of IO Capabilities to Key Generation Method
+ # See Bluetooth spec @ Vol 3, part H - Table 2.8: Mapping of IO Capabilities to Key
+ # Generation Method
#
# Map: initiator -> responder -> <method>
- # where <method> may be a simple entry or a 2-element tuple, with the first element for legacy
- # pairing and the second for secure connections, when the two are different.
- # Each entry is either a method name, or, for PASSKEY, a tuple:
+ # where <method> may be a simple entry or a 2-element tuple, with the first element
+ # for legacy pairing and the second for secure connections, when the two are
+ # different. Each entry is either a method name, or, for PASSKEY, a tuple:
# (method, initiator_displays, responder_displays)
- # to specify if the initiator and responder should display (True) or input a code (False).
+ # to specify if the initiator and responder should display (True) or input a code
+ # (False).
PAIRING_METHODS = {
SMP_DISPLAY_ONLY_IO_CAPABILITY: {
- SMP_DISPLAY_ONLY_IO_CAPABILITY: JUST_WORKS,
- SMP_DISPLAY_YES_NO_IO_CAPABILITY: JUST_WORKS,
- SMP_KEYBOARD_ONLY_IO_CAPABILITY: (PASSKEY, True, False),
+ SMP_DISPLAY_ONLY_IO_CAPABILITY: JUST_WORKS,
+ SMP_DISPLAY_YES_NO_IO_CAPABILITY: JUST_WORKS,
+ SMP_KEYBOARD_ONLY_IO_CAPABILITY: (PASSKEY, True, False),
SMP_NO_INPUT_NO_OUTPUT_IO_CAPABILITY: JUST_WORKS,
- SMP_KEYBOARD_DISPLAY_IO_CAPABILITY: (PASSKEY, True, False),
+ SMP_KEYBOARD_DISPLAY_IO_CAPABILITY: (PASSKEY, True, False),
},
SMP_DISPLAY_YES_NO_IO_CAPABILITY: {
- SMP_DISPLAY_ONLY_IO_CAPABILITY: JUST_WORKS,
- SMP_DISPLAY_YES_NO_IO_CAPABILITY: (JUST_WORKS, NUMERIC_COMPARISON),
- SMP_KEYBOARD_ONLY_IO_CAPABILITY: (PASSKEY, True, False),
+ SMP_DISPLAY_ONLY_IO_CAPABILITY: JUST_WORKS,
+ SMP_DISPLAY_YES_NO_IO_CAPABILITY: (JUST_WORKS, NUMERIC_COMPARISON),
+ SMP_KEYBOARD_ONLY_IO_CAPABILITY: (PASSKEY, True, False),
SMP_NO_INPUT_NO_OUTPUT_IO_CAPABILITY: JUST_WORKS,
- SMP_KEYBOARD_DISPLAY_IO_CAPABILITY: ((PASSKEY, True, False), NUMERIC_COMPARISON)
+ SMP_KEYBOARD_DISPLAY_IO_CAPABILITY: (
+ (PASSKEY, True, False),
+ NUMERIC_COMPARISON,
+ ),
},
SMP_KEYBOARD_ONLY_IO_CAPABILITY: {
- SMP_DISPLAY_ONLY_IO_CAPABILITY: (PASSKEY, False, True),
- SMP_DISPLAY_YES_NO_IO_CAPABILITY: (PASSKEY, False, True),
- SMP_KEYBOARD_ONLY_IO_CAPABILITY: (PASSKEY, False, False),
+ SMP_DISPLAY_ONLY_IO_CAPABILITY: (PASSKEY, False, True),
+ SMP_DISPLAY_YES_NO_IO_CAPABILITY: (PASSKEY, False, True),
+ SMP_KEYBOARD_ONLY_IO_CAPABILITY: (PASSKEY, False, False),
SMP_NO_INPUT_NO_OUTPUT_IO_CAPABILITY: JUST_WORKS,
- SMP_KEYBOARD_DISPLAY_IO_CAPABILITY: (PASSKEY, False, True),
+ SMP_KEYBOARD_DISPLAY_IO_CAPABILITY: (PASSKEY, False, True),
},
SMP_NO_INPUT_NO_OUTPUT_IO_CAPABILITY: {
- SMP_DISPLAY_ONLY_IO_CAPABILITY: JUST_WORKS,
- SMP_DISPLAY_YES_NO_IO_CAPABILITY: JUST_WORKS,
- SMP_KEYBOARD_ONLY_IO_CAPABILITY: JUST_WORKS,
+ SMP_DISPLAY_ONLY_IO_CAPABILITY: JUST_WORKS,
+ SMP_DISPLAY_YES_NO_IO_CAPABILITY: JUST_WORKS,
+ SMP_KEYBOARD_ONLY_IO_CAPABILITY: JUST_WORKS,
SMP_NO_INPUT_NO_OUTPUT_IO_CAPABILITY: JUST_WORKS,
- SMP_KEYBOARD_DISPLAY_IO_CAPABILITY: JUST_WORKS
+ SMP_KEYBOARD_DISPLAY_IO_CAPABILITY: JUST_WORKS,
},
SMP_KEYBOARD_DISPLAY_IO_CAPABILITY: {
- SMP_DISPLAY_ONLY_IO_CAPABILITY: (PASSKEY, False, True),
- SMP_DISPLAY_YES_NO_IO_CAPABILITY: ((PASSKEY, False, True), NUMERIC_COMPARISON),
- SMP_KEYBOARD_ONLY_IO_CAPABILITY: (PASSKEY, True, False),
+ SMP_DISPLAY_ONLY_IO_CAPABILITY: (PASSKEY, False, True),
+ SMP_DISPLAY_YES_NO_IO_CAPABILITY: (
+ (PASSKEY, False, True),
+ NUMERIC_COMPARISON,
+ ),
+ SMP_KEYBOARD_ONLY_IO_CAPABILITY: (PASSKEY, True, False),
SMP_NO_INPUT_NO_OUTPUT_IO_CAPABILITY: JUST_WORKS,
- SMP_KEYBOARD_DISPLAY_IO_CAPABILITY: ((PASSKEY, True, False), NUMERIC_COMPARISON)
- }
+ SMP_KEYBOARD_DISPLAY_IO_CAPABILITY: (
+ (PASSKEY, True, False),
+ NUMERIC_COMPARISON,
+ ),
+ },
}
- def __init__(self, manager, connection, pairing_config):
- self.manager = manager
- self.connection = connection
- self.tk = bytes(16)
- self.r = bytes(16)
- self.stk = None
- self.ltk = None
- self.ltk_ediv = 0
- self.ltk_rand = bytes(8)
- self.link_key = None
- self.initiator_key_distribution = 0
- self.responder_key_distribution = 0
- self.peer_random_value = None
- self.peer_public_key_x = bytes(32)
- self.peer_public_key_y = bytes(32)
- self.peer_ltk = None
- self.peer_ediv = None
- self.peer_rand = None
+ def __init__(
+ self,
+ manager: Manager,
+ connection: Connection,
+ pairing_config: PairingConfig,
+ is_initiator: bool,
+ ) -> None:
+ self.manager = manager
+ self.connection = connection
+ self.preq: Optional[bytes] = None
+ self.pres: Optional[bytes] = None
+ self.ea = None
+ self.eb = None
+ self.tk = bytes(16)
+ self.r = bytes(16)
+ self.stk = None
+ self.ltk = None
+ self.ltk_ediv = 0
+ self.ltk_rand = bytes(8)
+ self.link_key = None
+ self.initiator_key_distribution: int = 0
+ self.responder_key_distribution: int = 0
+ self.peer_random_value: Optional[bytes] = None
+ self.peer_public_key_x: bytes = bytes(32)
+ self.peer_public_key_y = bytes(32)
+ self.peer_ltk = None
+ self.peer_ediv = None
+ self.peer_rand: Optional[bytes] = None
self.peer_identity_resolving_key = None
- self.peer_bd_addr = None
- self.peer_signature_key = None
- self.peer_expected_distributions = []
- self.dh_key = None
- self.passkey = 0
- self.passkey_step = 0
- self.passkey_display = False
- self.pairing_method = 0
- self.pairing_config = pairing_config
- self.wait_before_continuing = None
- self.completed = False
+ self.peer_bd_addr: Optional[Address] = None
+ self.peer_signature_key = None
+ self.peer_expected_distributions: List[Type[SMP_Command]] = []
+ self.dh_key = None
+ self.confirm_value = None
+ self.passkey: Optional[int] = None
+ self.passkey_ready = asyncio.Event()
+ self.passkey_step = 0
+ self.passkey_display = False
+ self.pairing_method = 0
+ self.pairing_config = pairing_config
+ self.wait_before_continuing: Optional[asyncio.Future[None]] = None
+ self.completed = False
+ self.ctkd_task: Optional[Awaitable[None]] = None
# Decide if we're the initiator or the responder
- self.is_initiator = (connection.role == BT_CENTRAL_ROLE)
+ self.is_initiator = is_initiator
self.is_responder = not self.is_initiator
# Listen for connection events
connection.on('disconnection', self.on_disconnection)
- connection.on('connection_encryption_change', self.on_connection_encryption_change)
- connection.on('connection_encryption_key_refresh', self.on_connection_encryption_key_refresh)
+ connection.on(
+ 'connection_encryption_change', self.on_connection_encryption_change
+ )
+ connection.on(
+ 'connection_encryption_key_refresh',
+ self.on_connection_encryption_key_refresh,
+ )
# Create a future that can be used to wait for the session to complete
if self.is_initiator:
- self.pairing_result = asyncio.get_running_loop().create_future()
+ self.pairing_result: Optional[
+ asyncio.Future[None]
+ ] = asyncio.get_running_loop().create_future()
else:
self.pairing_result = None
# Key Distribution (default values before negotiation)
- self.initiator_key_distribution = pairing_config.delegate.local_initiator_key_distribution
- self.responder_key_distribution = pairing_config.delegate.local_responder_key_distribution
+ self.initiator_key_distribution = (
+ pairing_config.delegate.local_initiator_key_distribution
+ )
+ self.responder_key_distribution = (
+ pairing_config.delegate.local_responder_key_distribution
+ )
# Authentication Requirements Flags - Vol 3, Part H, Figure 3.3
- self.bonding = pairing_config.bonding
- self.sc = pairing_config.sc
- self.mitm = pairing_config.mitm
+ self.bonding: bool = pairing_config.bonding
+ self.sc: bool = pairing_config.sc
+ self.mitm: bool = pairing_config.mitm
self.keypress = False
- self.ct2 = False
+ self.ct2: bool = False
# I/O Capabilities
- self.io_capability = pairing_config.delegate.io_capability
+ self.io_capability = pairing_config.delegate.io_capability
self.peer_io_capability = SMP_NO_INPUT_NO_OUTPUT_IO_CAPABILITY
# OOB (not supported yet)
self.oob = False
# Set up addresses
+ self_address = connection.self_address
peer_address = connection.peer_resolvable_address or connection.peer_address
if self.is_initiator:
- self.ia = bytes(manager.address)
- self.iat = 1 if manager.address.is_random else 0
- self.ra = bytes(peer_address)
+ self.ia = bytes(self_address)
+ self.iat = 1 if self_address.is_random else 0
+ self.ra = bytes(peer_address)
self.rat = 1 if peer_address.is_random else 0
else:
- self.ra = bytes(manager.address)
- self.rat = 1 if manager.address.is_random else 0
- self.ia = bytes(peer_address)
+ self.ra = bytes(self_address)
+ self.rat = 1 if self_address.is_random else 0
+ self.ia = bytes(peer_address)
self.iat = 1 if peer_address.is_random else 0
@property
- def pkx(self):
- return (
- bytes(reversed(self.manager.ecc_key.x)),
- self.peer_public_key_x
- )
+ def pkx(self) -> Tuple[bytes, bytes]:
+ return (bytes(reversed(self.manager.ecc_key.x)), self.peer_public_key_x)
@property
- def pka(self):
+ def pka(self) -> bytes:
return self.pkx[0 if self.is_initiator else 1]
@property
- def pkb(self):
+ def pkb(self) -> bytes:
return self.pkx[0 if self.is_responder else 1]
@property
- def nx(self):
- return (
- self.r,
- self.peer_random_value
- )
+ def nx(self) -> Tuple[bytes, bytes]:
+ assert self.peer_random_value
+ return (self.r, self.peer_random_value)
@property
- def na(self):
+ def na(self) -> bytes:
return self.nx[0 if self.is_initiator else 1]
@property
- def nb(self):
+ def nb(self) -> bytes:
return self.nx[0 if self.is_responder else 1]
@property
- def auth_req(self):
+ def auth_req(self) -> int:
return smp_auth_req(self.bonding, self.mitm, self.sc, self.keypress, self.ct2)
- def get_long_term_key(self, rand, ediv):
+ def get_long_term_key(self, rand: bytes, ediv: int) -> Optional[bytes]:
if not self.sc and not self.completed:
if rand == self.ltk_rand and ediv == self.ltk_ediv:
return self.stk
else:
return self.ltk
- def decide_pairing_method(self, auth_req, initiator_io_capability, responder_io_capability):
+ return None
+
+ def decide_pairing_method(
+ self, auth_req: int, initiator_io_capability: int, responder_io_capability: int
+ ) -> None:
if (not self.mitm) and (auth_req & SMP_MITM_AUTHREQ == 0):
self.pairing_method = self.JUST_WORKS
return
- details = self.PAIRING_METHODS[initiator_io_capability][responder_io_capability]
- if type(details) is tuple and len(details) == 2:
+ details = self.PAIRING_METHODS[initiator_io_capability][responder_io_capability] # type: ignore[index]
+ if isinstance(details, tuple) and len(details) == 2:
# One entry for legacy pairing and one for secure connections
details = details[1 if self.sc else 0]
- if type(details) is int:
+ if isinstance(details, int):
# Just a method ID
self.pairing_method = details
else:
# PASSKEY method, with a method ID and display/input flags
- self.pairing_method = details[0]
+ self.pairing_method = details[0]
self.passkey_display = details[1 if self.is_initiator else 2]
- def check_expected_value(self, expected, received, error):
+ def check_expected_value(
+ self, expected: bytes, received: bytes, error: int
+ ) -> bool:
logger.debug(f'expected={expected.hex()} got={received.hex()}')
if expected != received:
logger.info(color('pairing confirm/check mismatch', 'red'))
@@ -711,60 +795,93 @@ class Session:
return False
return True
- def prompt_user_for_numeric_comparison(self, code, next_steps):
- async def prompt():
+ def prompt_user_for_confirmation(self, next_steps: Callable[[], None]) -> None:
+ async def prompt() -> None:
+ logger.debug('ask for confirmation')
+ try:
+ response = await self.pairing_config.delegate.confirm()
+ if response:
+ next_steps()
+ return
+ except Exception as error:
+ logger.warning(f'exception while confirm: {error}')
+
+ self.send_pairing_failed(SMP_CONFIRM_VALUE_FAILED_ERROR)
+
+ self.connection.abort_on('disconnection', prompt())
+
+ def prompt_user_for_numeric_comparison(
+ self, code: int, next_steps: Callable[[], None]
+ ) -> None:
+ async def prompt() -> None:
logger.debug(f'verification code: {code}')
try:
- response = await self.pairing_config.delegate.compare_numbers(code, digits=6)
+ response = await self.pairing_config.delegate.compare_numbers(
+ code, digits=6
+ )
if response:
next_steps()
return
except Exception as error:
- logger.warn(f'exception while prompting: {error}')
+ logger.warning(f'exception while prompting: {error}')
self.send_pairing_failed(SMP_CONFIRM_VALUE_FAILED_ERROR)
- asyncio.create_task(prompt())
+ self.connection.abort_on('disconnection', prompt())
- def prompt_user_for_number(self, next_steps):
- async def prompt():
+ def prompt_user_for_number(self, next_steps: Callable[[int], None]) -> None:
+ async def prompt() -> None:
logger.debug('prompting user for passkey')
try:
passkey = await self.pairing_config.delegate.get_number()
+ if passkey is None:
+ logger.debug('Passkey request rejected')
+ self.send_pairing_failed(SMP_PASSKEY_ENTRY_FAILED_ERROR)
+ return
logger.debug(f'user input: {passkey}')
next_steps(passkey)
except Exception as error:
- logger.warn(f'exception while prompting: {error}')
+ logger.warning(f'exception while prompting: {error}')
self.send_pairing_failed(SMP_PASSKEY_ENTRY_FAILED_ERROR)
- asyncio.create_task(prompt())
+ self.connection.abort_on('disconnection', prompt())
- def display_passkey(self):
+ def display_passkey(self) -> None:
# Generate random Passkey/PIN code
self.passkey = secrets.randbelow(1000000)
+ assert self.passkey is not None
logger.debug(f'Pairing PIN CODE: {self.passkey:06}')
+ self.passkey_ready.set()
# The value of TK is computed from the PIN code
if not self.sc:
self.tk = self.passkey.to_bytes(16, byteorder='little')
logger.debug(f'TK from passkey = {self.tk.hex()}')
- asyncio.create_task(self.pairing_config.delegate.display_number(self.passkey, digits=6))
+ self.connection.abort_on(
+ 'disconnection',
+ self.pairing_config.delegate.display_number(self.passkey, digits=6),
+ )
- def input_passkey(self, next_steps=None):
+ def input_passkey(self, next_steps: Optional[Callable[[], None]] = None) -> None:
# Prompt the user for the passkey displayed on the peer
- def after_input(passkey):
+ def after_input(passkey: int) -> None:
self.passkey = passkey
if not self.sc:
self.tk = passkey.to_bytes(16, byteorder='little')
logger.debug(f'TK from passkey = {self.tk.hex()}')
+ self.passkey_ready.set()
+
if next_steps is not None:
next_steps()
+
self.prompt_user_for_number(after_input)
- def display_or_input_passkey(self, next_steps=None):
+ def display_or_input_passkey(
+ self, next_steps: Optional[Callable[[], None]] = None
+ ) -> None:
if self.passkey_display:
self.display_passkey()
if next_steps is not None:
@@ -772,65 +889,68 @@ class Session:
else:
self.input_passkey(next_steps)
- def send_command(self, command):
+ def send_command(self, command: SMP_Command) -> None:
self.manager.send_command(self.connection, command)
- def send_pairing_failed(self, error):
- self.send_command(SMP_Pairing_Failed_Command(reason = error))
+ def send_pairing_failed(self, error: int) -> None:
+ self.send_command(SMP_Pairing_Failed_Command(reason=error))
self.on_pairing_failure(error)
- def send_pairing_request_command(self):
+ def send_pairing_request_command(self) -> None:
self.manager.on_session_start(self)
command = SMP_Pairing_Request_Command(
- io_capability = self.io_capability,
- oob_data_flag = 0,
- auth_req = self.auth_req,
- maximum_encryption_key_size = 16,
- initiator_key_distribution = self.initiator_key_distribution,
- responder_key_distribution = self.responder_key_distribution
+ io_capability=self.io_capability,
+ oob_data_flag=0,
+ auth_req=self.auth_req,
+ maximum_encryption_key_size=16,
+ initiator_key_distribution=self.initiator_key_distribution,
+ responder_key_distribution=self.responder_key_distribution,
)
self.preq = bytes(command)
self.send_command(command)
- def send_pairing_response_command(self):
+ def send_pairing_response_command(self) -> None:
response = SMP_Pairing_Response_Command(
- io_capability = self.io_capability,
- oob_data_flag = 0,
- auth_req = self.auth_req,
- maximum_encryption_key_size = 16,
- initiator_key_distribution = self.initiator_key_distribution,
- responder_key_distribution = self.responder_key_distribution
+ io_capability=self.io_capability,
+ oob_data_flag=0,
+ auth_req=self.auth_req,
+ maximum_encryption_key_size=16,
+ initiator_key_distribution=self.initiator_key_distribution,
+ responder_key_distribution=self.responder_key_distribution,
)
self.pres = bytes(response)
self.send_command(response)
- def send_pairing_confirm_command(self):
+ def send_pairing_confirm_command(self) -> None:
self.r = crypto.r()
logger.debug(f'generated random: {self.r.hex()}')
if self.sc:
- if self.pairing_method == self.JUST_WORKS or self.pairing_method == self.NUMERIC_COMPARISON:
- z = 0
- elif self.pairing_method == self.PASSKEY:
- z = 0x80 + ((self.passkey >> self.passkey_step) & 1)
- else:
- return
- if self.is_initiator:
- confirm_value = crypto.f4(
- self.pka,
- self.pkb,
- self.r,
- bytes([z])
- )
- else:
- confirm_value = crypto.f4(
- self.pkb,
- self.pka,
- self.r,
- bytes([z])
+ async def next_steps() -> None:
+ if self.pairing_method in (self.JUST_WORKS, self.NUMERIC_COMPARISON):
+ z = 0
+ elif self.pairing_method == self.PASSKEY:
+ # We need a passkey
+ await self.passkey_ready.wait()
+ assert self.passkey
+
+ z = 0x80 + ((self.passkey >> self.passkey_step) & 1)
+ else:
+ return
+
+ if self.is_initiator:
+ confirm_value = crypto.f4(self.pka, self.pkb, self.r, bytes([z]))
+ else:
+ confirm_value = crypto.f4(self.pkb, self.pka, self.r, bytes([z]))
+
+ self.send_command(
+ SMP_Pairing_Confirm_Command(confirm_value=confirm_value)
)
+
+ # Perform the next steps asynchronously in case we need to wait for input
+ self.connection.abort_on('disconnection', next_steps())
else:
confirm_value = crypto.c1(
self.tk,
@@ -840,140 +960,203 @@ class Session:
self.iat,
self.rat,
self.ia,
- self.ra
+ self.ra,
)
- self.send_command(SMP_Pairing_Confirm_Command(confirm_value = confirm_value))
+ self.send_command(SMP_Pairing_Confirm_Command(confirm_value=confirm_value))
- def send_pairing_random_command(self):
- self.send_command(SMP_Pairing_Random_Command(random_value = self.r))
+ def send_pairing_random_command(self) -> None:
+ self.send_command(SMP_Pairing_Random_Command(random_value=self.r))
- def send_public_key_command(self):
+ def send_public_key_command(self) -> None:
self.send_command(
SMP_Pairing_Public_Key_Command(
- public_key_x = bytes(reversed(self.manager.ecc_key.x)),
- public_key_y = bytes(reversed(self.manager.ecc_key.y))
+ public_key_x=bytes(reversed(self.manager.ecc_key.x)),
+ public_key_y=bytes(reversed(self.manager.ecc_key.y)),
)
)
- def send_pairing_dhkey_check_command(self):
+ def send_pairing_dhkey_check_command(self) -> None:
self.send_command(
SMP_Pairing_DHKey_Check_Command(
- dhkey_check = self.ea if self.is_initiator else self.eb
+ dhkey_check=self.ea if self.is_initiator else self.eb
)
)
- def start_encryption(self, key):
+ def start_encryption(self, key: bytes) -> None:
# We can now encrypt the connection with the short term key, so that we can
# distribute the long term and/or other keys over an encrypted connection
- asyncio.create_task(
- self.manager.device.host.send_command(
- HCI_LE_Start_Encryption_Command(
- connection_handle = self.connection.handle,
- random_number = bytes(8),
- encrypted_diversifier = 0,
- long_term_key = key
- )
+ self.manager.device.host.send_command_sync(
+ HCI_LE_Enable_Encryption_Command( # type: ignore[call-arg]
+ connection_handle=self.connection.handle,
+ random_number=bytes(8),
+ encrypted_diversifier=0,
+ long_term_key=key,
)
)
- def distribute_keys(self):
+ async def derive_ltk(self) -> None:
+ link_key = await self.manager.device.get_link_key(self.connection.peer_address)
+ assert link_key is not None
+ ilk = (
+ crypto.h7(salt=SMP_CTKD_H7_BRLE_SALT, w=link_key)
+ if self.ct2
+ else crypto.h6(link_key, b'tmp2')
+ )
+ self.ltk = crypto.h6(ilk, b'brle')
+
+ def distribute_keys(self) -> None:
# Distribute the keys as required
if self.is_initiator:
- if not self.sc:
+ # CTKD: Derive LTK from LinkKey
+ if (
+ self.connection.transport == BT_BR_EDR_TRANSPORT
+ and self.initiator_key_distribution & SMP_ENC_KEY_DISTRIBUTION_FLAG
+ ):
+ self.ctkd_task = self.connection.abort_on(
+ 'disconnection', self.derive_ltk()
+ )
+ elif not self.sc:
# Distribute the LTK, EDIV and RAND
if self.initiator_key_distribution & SMP_ENC_KEY_DISTRIBUTION_FLAG:
- self.send_command(SMP_Encryption_Information_Command(long_term_key=self.ltk))
- self.send_command(SMP_Master_Identification_Command(ediv=self.ltk_ediv, rand=self.ltk_rand))
+ self.send_command(
+ SMP_Encryption_Information_Command(long_term_key=self.ltk)
+ )
+ self.send_command(
+ SMP_Master_Identification_Command(
+ ediv=self.ltk_ediv, rand=self.ltk_rand
+ )
+ )
# Distribute IRK & BD ADDR
if self.initiator_key_distribution & SMP_ID_KEY_DISTRIBUTION_FLAG:
self.send_command(
- SMP_Identity_Information_Command(identity_resolving_key=self.manager.device.irk)
+ SMP_Identity_Information_Command(
+ identity_resolving_key=self.manager.device.irk
+ )
+ )
+ self.send_command(
+ SMP_Identity_Address_Information_Command(
+ addr_type=self.connection.self_address.address_type,
+ bd_addr=self.connection.self_address,
+ )
)
- self.send_command(SMP_Identity_Address_Information_Command(
- addr_type = self.manager.address.address_type,
- bd_addr = self.manager.address
- ))
# Distribute CSRK
csrk = bytes(16) # FIXME: testing
if self.initiator_key_distribution & SMP_SIGN_KEY_DISTRIBUTION_FLAG:
self.send_command(SMP_Signing_Information_Command(signature_key=csrk))
-
+
# CTKD, calculate BR/EDR link key
if self.initiator_key_distribution & SMP_LINK_KEY_DISTRIBUTION_FLAG:
- ilk = crypto.h7(
- salt=SMP_CTKD_H7_LEBR_SALT,
- w=self.ltk) if self.ct2 else crypto.h6(self.ltk, b'tmp1')
+ ilk = (
+ crypto.h7(salt=SMP_CTKD_H7_LEBR_SALT, w=self.ltk)
+ if self.ct2
+ else crypto.h6(self.ltk, b'tmp1')
+ )
self.link_key = crypto.h6(ilk, b'lebr')
else:
+ # CTKD: Derive LTK from LinkKey
+ if (
+ self.connection.transport == BT_BR_EDR_TRANSPORT
+ and self.responder_key_distribution & SMP_ENC_KEY_DISTRIBUTION_FLAG
+ ):
+ self.ctkd_task = self.connection.abort_on(
+ 'disconnection', self.derive_ltk()
+ )
# Distribute the LTK, EDIV and RAND
- if not self.sc:
+ elif not self.sc:
if self.responder_key_distribution & SMP_ENC_KEY_DISTRIBUTION_FLAG:
- self.send_command(SMP_Encryption_Information_Command(long_term_key=self.ltk))
- self.send_command(SMP_Master_Identification_Command(ediv=self.ltk_ediv, rand=self.ltk_rand))
+ self.send_command(
+ SMP_Encryption_Information_Command(long_term_key=self.ltk)
+ )
+ self.send_command(
+ SMP_Master_Identification_Command(
+ ediv=self.ltk_ediv, rand=self.ltk_rand
+ )
+ )
# Distribute IRK & BD ADDR
if self.responder_key_distribution & SMP_ID_KEY_DISTRIBUTION_FLAG:
self.send_command(
- SMP_Identity_Information_Command(identity_resolving_key=self.manager.device.irk)
+ SMP_Identity_Information_Command(
+ identity_resolving_key=self.manager.device.irk
+ )
+ )
+ self.send_command(
+ SMP_Identity_Address_Information_Command(
+ addr_type=self.connection.self_address.address_type,
+ bd_addr=self.connection.self_address,
+ )
)
- self.send_command(SMP_Identity_Address_Information_Command(
- addr_type = self.manager.address.address_type,
- bd_addr = self.manager.address
- ))
# Distribute CSRK
csrk = bytes(16) # FIXME: testing
if self.responder_key_distribution & SMP_SIGN_KEY_DISTRIBUTION_FLAG:
self.send_command(SMP_Signing_Information_Command(signature_key=csrk))
-
+
# CTKD, calculate BR/EDR link key
if self.responder_key_distribution & SMP_LINK_KEY_DISTRIBUTION_FLAG:
- ilk = crypto.h7(
- salt=SMP_CTKD_H7_LEBR_SALT,
- w=self.ltk) if self.ct2 else crypto.h6(self.ltk, b'tmp1')
+ ilk = (
+ crypto.h7(salt=SMP_CTKD_H7_LEBR_SALT, w=self.ltk)
+ if self.ct2
+ else crypto.h6(self.ltk, b'tmp1')
+ )
self.link_key = crypto.h6(ilk, b'lebr')
- def compute_peer_expected_distributions(self, key_distribution_flags):
+ def compute_peer_expected_distributions(self, key_distribution_flags: int) -> None:
# Set our expectations for what to wait for in the key distribution phase
self.peer_expected_distributions = []
- if not self.sc:
- if (key_distribution_flags & SMP_ENC_KEY_DISTRIBUTION_FLAG != 0):
- self.peer_expected_distributions.append(SMP_Encryption_Information_Command)
- self.peer_expected_distributions.append(SMP_Master_Identification_Command)
- if (key_distribution_flags & SMP_ID_KEY_DISTRIBUTION_FLAG != 0):
+ if not self.sc and self.connection.transport == BT_LE_TRANSPORT:
+ if key_distribution_flags & SMP_ENC_KEY_DISTRIBUTION_FLAG != 0:
+ self.peer_expected_distributions.append(
+ SMP_Encryption_Information_Command
+ )
+ self.peer_expected_distributions.append(
+ SMP_Master_Identification_Command
+ )
+ if key_distribution_flags & SMP_ID_KEY_DISTRIBUTION_FLAG != 0:
self.peer_expected_distributions.append(SMP_Identity_Information_Command)
- self.peer_expected_distributions.append(SMP_Identity_Address_Information_Command)
- if (key_distribution_flags & SMP_SIGN_KEY_DISTRIBUTION_FLAG != 0):
+ self.peer_expected_distributions.append(
+ SMP_Identity_Address_Information_Command
+ )
+ if key_distribution_flags & SMP_SIGN_KEY_DISTRIBUTION_FLAG != 0:
self.peer_expected_distributions.append(SMP_Signing_Information_Command)
- logger.debug(f'expecting distributions: {[c.__name__ for c in self.peer_expected_distributions]}')
+ logger.debug(
+ 'expecting distributions: '
+ f'{[c.__name__ for c in self.peer_expected_distributions]}'
+ )
- def check_key_distribution(self, command_class):
+ def check_key_distribution(self, command_class: Type[SMP_Command]) -> None:
# First, check that the connection is encrypted
if not self.connection.is_encrypted:
- logger.warn(color('received key distribution on a non-encrypted connection', 'red'))
+ logger.warning(
+ color('received key distribution on a non-encrypted connection', 'red')
+ )
self.send_pairing_failed(SMP_UNSPECIFIED_REASON_ERROR)
return
# Check that this command class is expected
if command_class in self.peer_expected_distributions:
self.peer_expected_distributions.remove(command_class)
- logger.debug(f'remaining distributions: {[c.__name__ for c in self.peer_expected_distributions]}')
+ logger.debug(
+ 'remaining distributions: '
+ f'{[c.__name__ for c in self.peer_expected_distributions]}'
+ )
if not self.peer_expected_distributions:
- # The initiator can now send its keys
- if self.is_initiator:
- self.distribute_keys()
-
- # Nothing left to expect, we're done
- self.on_pairing()
+ self.on_peer_key_distribution_complete()
else:
- logger.warn(color(f'!!! unexpected key distribution command: {command_class.__name__}', 'red'))
+ logger.warning(
+ color(
+ '!!! unexpected key distribution command: '
+ f'{command_class.__name__}',
+ 'red',
+ )
+ )
self.send_pairing_failed(SMP_UNSPECIFIED_REASON_ERROR)
- async def pair(self):
+ async def pair(self) -> None:
# Start pairing as an initiator
# TODO: check that this session isn't already active
@@ -981,101 +1164,116 @@ class Session:
self.send_pairing_request_command()
# Wait for the pairing process to finish
- await self.pairing_result
+ assert self.pairing_result
+ await self.connection.abort_on('disconnection', self.pairing_result)
- def on_disconnection(self, reason):
+ def on_disconnection(self, _: int) -> None:
self.connection.remove_listener('disconnection', self.on_disconnection)
- self.connection.remove_listener('connection_encryption_change', self.on_connection_encryption_change)
- self.connection.remove_listener('connection_encryption_key_refresh', self.on_connection_encryption_key_refresh)
+ self.connection.remove_listener(
+ 'connection_encryption_change', self.on_connection_encryption_change
+ )
+ self.connection.remove_listener(
+ 'connection_encryption_key_refresh',
+ self.on_connection_encryption_key_refresh,
+ )
self.manager.on_session_end(self)
- def on_connection_encryption_change(self):
+ def on_peer_key_distribution_complete(self) -> None:
+ # The initiator can now send its keys
+ if self.is_initiator:
+ self.distribute_keys()
+
+ self.connection.abort_on('disconnection', self.on_pairing())
+
+ def on_connection_encryption_change(self) -> None:
if self.connection.is_encrypted:
if self.is_responder:
# The responder distributes its keys first, the initiator later
self.distribute_keys()
- def on_connection_encryption_key_refresh(self):
+ # If we're not expecting key distributions from the peer, we're done
+ if not self.peer_expected_distributions:
+ self.on_peer_key_distribution_complete()
+
+ def on_connection_encryption_key_refresh(self) -> None:
# Do as if the connection had just been encrypted
self.on_connection_encryption_change()
- def on_pairing(self):
+ async def on_pairing(self) -> None:
logger.debug('pairing complete')
if self.completed:
return
- else:
- self.completed = True
+
+ self.completed = True
if self.pairing_result is not None and not self.pairing_result.done():
self.pairing_result.set_result(None)
# Use the peer address from the pairing protocol or the connection
- if self.peer_bd_addr:
+ if self.peer_bd_addr is not None:
peer_address = self.peer_bd_addr
else:
peer_address = self.connection.peer_address
+ # Wait for link key fetch and key derivation
+ if self.ctkd_task is not None:
+ await self.ctkd_task
+ self.ctkd_task = None
+
# Create an object to hold the keys
keys = PairingKeys()
keys.address_type = peer_address.address_type
authenticated = self.pairing_method != self.JUST_WORKS
- if self.sc:
- keys.ltk = PairingKeys.Key(
- value = self.ltk,
- authenticated = authenticated
- )
+ if self.sc or self.connection.transport == BT_BR_EDR_TRANSPORT:
+ keys.ltk = PairingKeys.Key(value=self.ltk, authenticated=authenticated)
else:
our_ltk_key = PairingKeys.Key(
- value = self.ltk,
- authenticated = authenticated,
- ediv = self.ltk_ediv,
- rand = self.ltk_rand
+ value=self.ltk,
+ authenticated=authenticated,
+ ediv=self.ltk_ediv,
+ rand=self.ltk_rand,
)
peer_ltk_key = PairingKeys.Key(
- value = self.peer_ltk,
- authenticated = authenticated,
- ediv = self.peer_ediv,
- rand = self.peer_rand
+ value=self.peer_ltk,
+ authenticated=authenticated,
+ ediv=self.peer_ediv,
+ rand=self.peer_rand,
)
if self.is_initiator:
- keys.ltk_central = peer_ltk_key
+ keys.ltk_central = peer_ltk_key
keys.ltk_peripheral = our_ltk_key
else:
- keys.ltk_central = our_ltk_key
+ keys.ltk_central = our_ltk_key
keys.ltk_peripheral = peer_ltk_key
if self.peer_identity_resolving_key is not None:
keys.irk = PairingKeys.Key(
- value = self.peer_identity_resolving_key,
- authenticated = authenticated
+ value=self.peer_identity_resolving_key, authenticated=authenticated
)
if self.peer_signature_key is not None:
keys.csrk = PairingKeys.Key(
- value = self.peer_signature_key,
- authenticated = authenticated
+ value=self.peer_signature_key, authenticated=authenticated
)
if self.link_key is not None:
keys.link_key = PairingKeys.Key(
- value = self.link_key,
- authenticated = authenticated
+ value=self.link_key, authenticated=authenticated
)
-
self.manager.on_pairing(self, peer_address, keys)
- def on_pairing_failure(self, reason):
- logger.warn(f'pairing failure ({error_name(reason)})')
+ def on_pairing_failure(self, reason: int) -> None:
+ logger.warning(f'pairing failure ({error_name(reason)})')
if self.completed:
return
- else:
- self.completed = True
+
+ self.completed = True
error = ProtocolError(reason, 'smp', error_name(reason))
if self.pairing_result is not None and not self.pairing_result.done():
self.pairing_result.set_exception(error)
self.manager.on_pairing_failure(self, reason)
- def on_smp_command(self, command):
+ def on_smp_command(self, command: SMP_Command) -> None:
# Find the handler method
handler_name = f'on_{command.name.lower()}'
handler = getattr(self, handler_name, None)
@@ -1084,15 +1282,23 @@ class Session:
handler(command)
except Exception as error:
logger.warning(f'{color("!!! Exception in handler:", "red")} {error}')
- response = SMP_Pairing_Failed_Command(reason = SMP_UNSPECIFIED_REASON_ERROR)
+ response = SMP_Pairing_Failed_Command(
+ reason=SMP_UNSPECIFIED_REASON_ERROR
+ )
self.send_command(response)
else:
logger.error(color('SMP command not handled???', 'red'))
- def on_smp_pairing_request_command(self, command):
- asyncio.create_task(self.on_smp_pairing_request_command_async(command))
+ def on_smp_pairing_request_command(
+ self, command: SMP_Pairing_Request_Command
+ ) -> None:
+ self.connection.abort_on(
+ 'disconnection', self.on_smp_pairing_request_command_async(command)
+ )
- async def on_smp_pairing_request_command_async(self, command):
+ async def on_smp_pairing_request_command_async(
+ self, command: SMP_Pairing_Request_Command
+ ) -> None:
# Check if the request should proceed
accepted = await self.pairing_config.delegate.accept()
if not accepted:
@@ -1105,25 +1311,29 @@ class Session:
# Bonding and SC require both sides to request/support it
self.bonding = self.bonding and (command.auth_req & SMP_BONDING_AUTHREQ != 0)
- self.sc = self.sc and (command.auth_req & SMP_SC_AUTHREQ != 0)
- self.ct2 = self.ct2 and (command.auth_req & SMP_CT2_AUTHREQ != 0)
+ self.sc = self.sc and (command.auth_req & SMP_SC_AUTHREQ != 0)
+ self.ct2 = self.ct2 and (command.auth_req & SMP_CT2_AUTHREQ != 0)
# Check for OOB
if command.oob_data_flag != 0:
- self.terminate(SMP_OOB_NOT_AVAILABLE_ERROR)
+ self.send_pairing_failed(SMP_OOB_NOT_AVAILABLE_ERROR)
return
# Decide which pairing method to use
self.decide_pairing_method(
- command.auth_req,
- command.io_capability,
- self.io_capability
+ command.auth_req, command.io_capability, self.io_capability
+ )
+ logger.debug(
+ f'pairing method: {self.PAIRING_METHOD_NAMES[self.pairing_method]}'
)
- logger.debug(f'pairing method: {self.PAIRING_METHOD_NAMES[self.pairing_method]}')
# Key distribution
- self.initiator_key_distribution, self.responder_key_distribution = await self.pairing_config.delegate.key_distribution_response(
- command.initiator_key_distribution, command.responder_key_distribution)
+ (
+ self.initiator_key_distribution,
+ self.responder_key_distribution,
+ ) = await self.pairing_config.delegate.key_distribution_response(
+ command.initiator_key_distribution, command.responder_key_distribution
+ )
self.compute_peer_expected_distributions(self.initiator_key_distribution)
# The pairing is now starting
@@ -1137,9 +1347,22 @@ class Session:
# Respond
self.send_pairing_response_command()
- def on_smp_pairing_response_command(self, command):
+ # Vol 3, Part C, 5.2.2.1.3
+ # CTKD over BR/EDR should happen after the connection has been encrypted,
+ # so when receiving pairing requests, responder should start distributing keys
+ if (
+ self.connection.transport == BT_BR_EDR_TRANSPORT
+ and self.connection.is_encrypted
+ and self.is_responder
+ and accepted
+ ):
+ self.distribute_keys()
+
+ def on_smp_pairing_response_command(
+ self, command: SMP_Pairing_Response_Command
+ ) -> None:
if self.is_responder:
- logger.warn(color('received pairing response as a responder', 'red'))
+ logger.warning(color('received pairing response as a responder', 'red'))
return
# Save the response
@@ -1148,7 +1371,7 @@ class Session:
# Bonding and SC require both sides to request/support it
self.bonding = self.bonding and (command.auth_req & SMP_BONDING_AUTHREQ != 0)
- self.sc = self.sc and (command.auth_req & SMP_SC_AUTHREQ != 0)
+ self.sc = self.sc and (command.auth_req & SMP_SC_AUTHREQ != 0)
# Check for OOB
if self.sc and command.oob_data_flag:
@@ -1157,15 +1380,18 @@ class Session:
# Decide which pairing method to use
self.decide_pairing_method(
- command.auth_req,
- self.io_capability,
- command.io_capability
+ command.auth_req, self.io_capability, command.io_capability
+ )
+ logger.debug(
+ f'pairing method: {self.PAIRING_METHOD_NAMES[self.pairing_method]}'
)
- logger.debug(f'pairing method: {self.PAIRING_METHOD_NAMES[self.pairing_method]}')
# Key distribution
- if (command.initiator_key_distribution & ~self.initiator_key_distribution != 0) or \
- (command.responder_key_distribution & ~self.responder_key_distribution != 0):
+ if (
+ command.initiator_key_distribution & ~self.initiator_key_distribution != 0
+ ) or (
+ command.responder_key_distribution & ~self.responder_key_distribution != 0
+ ):
# The response isn't a subset of the request
self.send_pairing_failed(SMP_INVALID_PARAMETERS_ERROR)
return
@@ -1175,8 +1401,8 @@ class Session:
# Start phase 2
if self.sc:
- if self.pairing_method == self.PASSKEY and self.passkey_display:
- self.display_passkey()
+ if self.pairing_method == self.PASSKEY:
+ self.display_or_input_passkey()
self.send_public_key_command()
else:
@@ -1185,7 +1411,9 @@ class Session:
else:
self.send_pairing_confirm_command()
- def on_smp_pairing_confirm_command_legacy(self, command):
+ def on_smp_pairing_confirm_command_legacy(
+ self, _: SMP_Pairing_Confirm_Command
+ ) -> None:
if self.is_initiator:
self.send_pairing_random_command()
else:
@@ -1195,8 +1423,10 @@ class Session:
else:
self.send_pairing_confirm_command()
- def on_smp_pairing_confirm_command_secure_connections(self, command):
- if self.pairing_method == self.JUST_WORKS or self.pairing_method == self.NUMERIC_COMPARISON:
+ def on_smp_pairing_confirm_command_secure_connections(
+ self, _: SMP_Pairing_Confirm_Command
+ ) -> None:
+ if self.pairing_method in (self.JUST_WORKS, self.NUMERIC_COMPARISON):
if self.is_initiator:
self.r = crypto.r()
self.send_pairing_random_command()
@@ -1206,14 +1436,18 @@ class Session:
else:
self.send_pairing_confirm_command()
- def on_smp_pairing_confirm_command(self, command):
+ def on_smp_pairing_confirm_command(
+ self, command: SMP_Pairing_Confirm_Command
+ ) -> None:
self.confirm_value = command.confirm_value
if self.sc:
self.on_smp_pairing_confirm_command_secure_connections(command)
else:
self.on_smp_pairing_confirm_command_legacy(command)
- def on_smp_pairing_random_command_legacy(self, command):
+ def on_smp_pairing_random_command_legacy(
+ self, command: SMP_Pairing_Random_Command
+ ) -> None:
# Check that the confirmation values match
confirm_verifier = crypto.c1(
self.tk,
@@ -1223,12 +1457,11 @@ class Session:
self.iat,
self.rat,
self.ia,
- self.ra
+ self.ra,
)
+ assert self.confirm_value
if not self.check_expected_value(
- self.confirm_value,
- confirm_verifier,
- SMP_CONFIRM_VALUE_FAILED_ERROR
+ self.confirm_value, confirm_verifier, SMP_CONFIRM_VALUE_FAILED_ERROR
):
return
@@ -1239,45 +1472,47 @@ class Session:
else:
srand = self.r
mrand = command.random_value
- stk = crypto.s1(self.tk, srand, mrand)
- logger.debug(f'STK = {stk.hex()}')
+ self.stk = crypto.s1(self.tk, srand, mrand)
+ logger.debug(f'STK = {self.stk.hex()}')
# Generate LTK
self.ltk = crypto.r()
if self.is_initiator:
- self.start_encryption(stk)
+ self.start_encryption(self.stk)
else:
self.send_pairing_random_command()
- def on_smp_pairing_random_command_secure_connections(self, command):
+ def on_smp_pairing_random_command_secure_connections(
+ self, command: SMP_Pairing_Random_Command
+ ) -> None:
+ if self.pairing_method == self.PASSKEY and self.passkey is None:
+ logger.warning('no passkey entered, ignoring command')
+ return
+
+ # pylint: disable=too-many-return-statements
if self.is_initiator:
- if self.pairing_method == self.JUST_WORKS or self.pairing_method == self.NUMERIC_COMPARISON:
+ if self.pairing_method in (self.JUST_WORKS, self.NUMERIC_COMPARISON):
+ assert self.confirm_value
# Check that the random value matches what was committed to earlier
confirm_verifier = crypto.f4(
- self.pkb,
- self.pka,
- command.random_value,
- bytes([0])
+ self.pkb, self.pka, command.random_value, bytes([0])
)
if not self.check_expected_value(
- self.confirm_value,
- confirm_verifier,
- SMP_CONFIRM_VALUE_FAILED_ERROR
+ self.confirm_value, confirm_verifier, SMP_CONFIRM_VALUE_FAILED_ERROR
):
return
elif self.pairing_method == self.PASSKEY:
+ assert self.passkey and self.confirm_value
# Check that the random value matches what was committed to earlier
confirm_verifier = crypto.f4(
self.pkb,
self.pka,
command.random_value,
- bytes([0x80 + ((self.passkey >> self.passkey_step) & 1)])
+ bytes([0x80 + ((self.passkey >> self.passkey_step) & 1)]),
)
if not self.check_expected_value(
- self.confirm_value,
- confirm_verifier,
- SMP_CONFIRM_VALUE_FAILED_ERROR
+ self.confirm_value, confirm_verifier, SMP_CONFIRM_VALUE_FAILED_ERROR
):
return
@@ -1290,20 +1525,19 @@ class Session:
else:
return
else:
- if self.pairing_method == self.JUST_WORKS or self.pairing_method == self.NUMERIC_COMPARISON:
+ if self.pairing_method in (self.JUST_WORKS, self.NUMERIC_COMPARISON):
self.send_pairing_random_command()
elif self.pairing_method == self.PASSKEY:
+ assert self.passkey and self.confirm_value
# Check that the random value matches what was committed to earlier
confirm_verifier = crypto.f4(
self.pka,
self.pkb,
command.random_value,
- bytes([0x80 + ((self.passkey >> self.passkey_step) & 1)])
+ bytes([0x80 + ((self.passkey >> self.passkey_step) & 1)]),
)
if not self.check_expected_value(
- self.confirm_value,
- confirm_verifier,
- SMP_CONFIRM_VALUE_FAILED_ERROR
+ self.confirm_value, confirm_verifier, SMP_CONFIRM_VALUE_FAILED_ERROR
):
return
@@ -1324,23 +1558,25 @@ class Session:
(mac_key, self.ltk) = crypto.f5(self.dh_key, self.na, self.nb, a, b)
# Compute the DH Key checks
- if self.pairing_method == self.JUST_WORKS or self.pairing_method == self.NUMERIC_COMPARISON:
+ if self.pairing_method in (self.JUST_WORKS, self.NUMERIC_COMPARISON):
ra = bytes(16)
rb = ra
elif self.pairing_method == self.PASSKEY:
+ assert self.passkey
ra = self.passkey.to_bytes(16, byteorder='little')
rb = ra
else:
# OOB not implemented yet
return
+ assert self.preq and self.pres
io_cap_a = self.preq[1:4]
io_cap_b = self.pres[1:4]
self.ea = crypto.f6(mac_key, self.na, self.nb, rb, io_cap_a, a, b)
self.eb = crypto.f6(mac_key, self.nb, self.na, ra, io_cap_b, b, a)
# Next steps to be performed after possible user confirmation
- def next_steps():
+ def next_steps() -> None:
# The initiator sends the DH Key check to the responder
if self.is_initiator:
self.send_pairing_dhkey_check_command()
@@ -1349,99 +1585,119 @@ class Session:
self.wait_before_continuing.set_result(None)
# Prompt the user for confirmation if needed
- if self.pairing_method == self.JUST_WORKS or self.pairing_method == self.NUMERIC_COMPARISON:
+ if self.pairing_method in (self.JUST_WORKS, self.NUMERIC_COMPARISON):
# Compute the 6-digit code
code = crypto.g2(self.pka, self.pkb, self.na, self.nb) % 1000000
- if self.pairing_method == self.NUMERIC_COMPARISON:
- # Ask for user confirmation
- self.wait_before_continuing = asyncio.get_running_loop().create_future()
- self.prompt_user_for_numeric_comparison(code, next_steps)
+ # Ask for user confirmation
+ self.wait_before_continuing = asyncio.get_running_loop().create_future()
+ if self.pairing_method == self.JUST_WORKS:
+ self.prompt_user_for_confirmation(next_steps)
else:
- next_steps()
+ self.prompt_user_for_numeric_comparison(code, next_steps)
else:
next_steps()
- def on_smp_pairing_random_command(self, command):
+ def on_smp_pairing_random_command(
+ self, command: SMP_Pairing_Random_Command
+ ) -> None:
self.peer_random_value = command.random_value
if self.sc:
self.on_smp_pairing_random_command_secure_connections(command)
else:
self.on_smp_pairing_random_command_legacy(command)
- def on_smp_pairing_public_key_command(self, command):
+ def on_smp_pairing_public_key_command(
+ self, command: SMP_Pairing_Public_Key_Command
+ ) -> None:
# Store the public key so that we can compute the confirmation value later
self.peer_public_key_x = command.public_key_x
self.peer_public_key_y = command.public_key_y
# Compute the DH key
- self.dh_key = bytes(reversed(self.manager.ecc_key.dh(
- bytes(reversed(command.public_key_x)),
- bytes(reversed(command.public_key_y))
- )))
+ self.dh_key = bytes(
+ reversed(
+ self.manager.ecc_key.dh(
+ bytes(reversed(command.public_key_x)),
+ bytes(reversed(command.public_key_y)),
+ )
+ )
+ )
logger.debug(f'DH key: {self.dh_key.hex()}')
if self.is_initiator:
- if self.pairing_method == self.PASSKEY:
- if self.passkey_display:
- self.send_pairing_confirm_command()
- else:
- self.input_passkey(self.send_pairing_confirm_command)
+ self.send_pairing_confirm_command()
else:
- # Send our public key back to the initiator
if self.pairing_method == self.PASSKEY:
- self.display_or_input_passkey(self.send_public_key_command)
- else:
- self.send_public_key_command()
+ self.display_or_input_passkey()
+
+ # Send our public key back to the initiator
+ self.send_public_key_command()
- if self.pairing_method == self.JUST_WORKS or self.pairing_method == self.NUMERIC_COMPARISON:
+ if self.pairing_method in (self.JUST_WORKS, self.NUMERIC_COMPARISON):
# We can now send the confirmation value
self.send_pairing_confirm_command()
- def on_smp_pairing_dhkey_check_command(self, command):
+ def on_smp_pairing_dhkey_check_command(
+ self, command: SMP_Pairing_DHKey_Check_Command
+ ) -> None:
# Check that what we received matches what we computed earlier
expected = self.eb if self.is_initiator else self.ea
+ assert expected
if not self.check_expected_value(
- expected,
- command.dhkey_check,
- SMP_DHKEY_CHECK_FAILED_ERROR
+ expected, command.dhkey_check, SMP_DHKEY_CHECK_FAILED_ERROR
):
return
if self.is_responder:
if self.wait_before_continuing is not None:
- async def next_steps():
+
+ async def next_steps() -> None:
+ assert self.wait_before_continuing
await self.wait_before_continuing
self.wait_before_continuing = None
self.send_pairing_dhkey_check_command()
- asyncio.create_task(next_steps())
+ self.connection.abort_on('disconnection', next_steps())
else:
self.send_pairing_dhkey_check_command()
else:
+ assert self.ltk
self.start_encryption(self.ltk)
- def on_smp_pairing_failed_command(self, command):
+ def on_smp_pairing_failed_command(
+ self, command: SMP_Pairing_Failed_Command
+ ) -> None:
self.on_pairing_failure(command.reason)
- def on_smp_encryption_information_command(self, command):
+ def on_smp_encryption_information_command(
+ self, command: SMP_Encryption_Information_Command
+ ) -> None:
self.peer_ltk = command.long_term_key
self.check_key_distribution(SMP_Encryption_Information_Command)
- def on_smp_master_identification_command(self, command):
+ def on_smp_master_identification_command(
+ self, command: SMP_Master_Identification_Command
+ ) -> None:
self.peer_ediv = command.ediv
self.peer_rand = command.rand
self.check_key_distribution(SMP_Master_Identification_Command)
- def on_smp_identity_information_command(self, command):
+ def on_smp_identity_information_command(
+ self, command: SMP_Identity_Information_Command
+ ) -> None:
self.peer_identity_resolving_key = command.identity_resolving_key
self.check_key_distribution(SMP_Identity_Information_Command)
- def on_smp_identity_address_information_command(self, command):
+ def on_smp_identity_address_information_command(
+ self, command: SMP_Identity_Address_Information_Command
+ ) -> None:
self.peer_bd_addr = command.bd_addr
self.check_key_distribution(SMP_Identity_Address_Information_Command)
- def on_smp_signing_information_command(self, command):
+ def on_smp_signing_information_command(
+ self, command: SMP_Signing_Information_Command
+ ) -> None:
self.peer_signature_key = command.signature_key
self.check_key_distribution(SMP_Signing_Information_Command)
@@ -1452,57 +1708,71 @@ class Manager(EventEmitter):
Implements the Initiator and Responder roles of the Security Manager Protocol
'''
- def __init__(self, device, address):
- super().__init__()
- self.device = device
- self.address = address
- self.sessions = {}
- self._ecc_key = None
- self.pairing_config_factory = lambda connection: PairingConfig()
+ device: Device
+ sessions: Dict[int, Session]
+ pairing_config_factory: Callable[[Connection], PairingConfig]
+ session_proxy: Type[Session]
- def send_command(self, connection, command):
- logger.debug(f'>>> Sending SMP Command on connection [0x{connection.handle:04X}] {connection.peer_address}: {command}')
- connection.send_l2cap_pdu(SMP_CID, command.to_bytes())
+ def __init__(
+ self,
+ device: Device,
+ pairing_config_factory: Callable[[Connection], PairingConfig],
+ ) -> None:
+ super().__init__()
+ self.device = device
+ self.sessions = {}
+ self._ecc_key = None
+ self.pairing_config_factory = pairing_config_factory
+ self.session_proxy = Session
+
+ def send_command(self, connection: Connection, command: SMP_Command) -> None:
+ logger.debug(
+ f'>>> Sending SMP Command on connection [0x{connection.handle:04X}] '
+ f'{connection.peer_address}: {command}'
+ )
+ cid = SMP_BR_CID if connection.transport == BT_BR_EDR_TRANSPORT else SMP_CID
+ connection.send_l2cap_pdu(cid, command.to_bytes())
- def on_smp_pdu(self, connection, pdu):
+ def on_smp_pdu(self, connection: Connection, pdu: bytes) -> None:
# Look for a session with this connection, and create one if none exists
if not (session := self.sessions.get(connection.handle)):
+ if connection.role == BT_CENTRAL_ROLE:
+ logger.warning('Remote starts pairing as Peripheral!')
pairing_config = self.pairing_config_factory(connection)
- if pairing_config is None:
- # Pairing disabled
- self.send_command(
- connection,
- SMP_Pairing_Failed_Command(
- reason = SMP_PAIRING_NOT_SUPPORTED_ERROR
- )
- )
- return
- session = Session(self, connection, pairing_config)
+ session = self.session_proxy(
+ self, connection, pairing_config, is_initiator=False
+ )
self.sessions[connection.handle] = session
# Parse the L2CAP payload into an SMP Command object
command = SMP_Command.from_bytes(pdu)
- logger.debug(f'<<< Received SMP Command on connection [0x{connection.handle:04X}] {connection.peer_address}: {command}')
+ logger.debug(
+ f'<<< Received SMP Command on connection [0x{connection.handle:04X}] '
+ f'{connection.peer_address}: {command}'
+ )
# Delegate the handling of the command to the session
session.on_smp_command(command)
@property
- def ecc_key(self):
+ def ecc_key(self) -> crypto.EccKey:
if self._ecc_key is None:
self._ecc_key = crypto.EccKey.generate()
+ assert self._ecc_key
return self._ecc_key
- async def pair(self, connection):
+ async def pair(self, connection: Connection) -> None:
# TODO: check if there's already a session for this connection
+ if connection.role != BT_CENTRAL_ROLE:
+ logger.warning('Start pairing as Peripheral!')
pairing_config = self.pairing_config_factory(connection)
- if pairing_config is None:
- raise ValueError('pairing config must not be None when initiating')
- session = Session(self, connection, pairing_config)
+ session = self.session_proxy(
+ self, connection, pairing_config, is_initiator=True
+ )
self.sessions[connection.handle] = session
return await session.pair()
- def request_pairing(self, connection):
+ def request_pairing(self, connection: Connection) -> None:
pairing_config = self.pairing_config_factory(connection)
if pairing_config:
auth_req = smp_auth_req(
@@ -1510,36 +1780,45 @@ class Manager(EventEmitter):
pairing_config.mitm,
pairing_config.sc,
False,
- False
+ False,
)
else:
auth_req = 0
self.send_command(connection, SMP_Security_Request_Command(auth_req=auth_req))
- def on_session_start(self, session):
- self.device.on_pairing_start(session.connection.handle)
+ def on_session_start(self, session: Session) -> None:
+ self.device.on_pairing_start(session.connection)
- def on_pairing(self, session, identity_address, keys):
+ def on_pairing(
+ self, session: Session, identity_address: Optional[Address], keys: PairingKeys
+ ) -> None:
# Store the keys in the key store
if self.device.keystore and identity_address is not None:
+
async def store_keys():
try:
+ assert self.device.keystore
await self.device.keystore.update(str(identity_address), keys)
except Exception as error:
- logger.warn(f'!!! error while storing keys: {error}')
- asyncio.create_task(store_keys())
+ logger.warning(f'!!! error while storing keys: {error}')
+
+ self.device.abort_on('flush', store_keys())
# Notify the device
- self.device.on_pairing(session.connection.handle, keys)
+ self.device.on_pairing(session.connection, keys, session.sc)
- def on_pairing_failure(self, session, reason):
- self.device.on_pairing_failure(session.connection.handle, reason)
+ def on_pairing_failure(self, session: Session, reason: int) -> None:
+ self.device.on_pairing_failure(session.connection, reason)
- def on_session_end(self, session):
+ def on_session_end(self, session: Session) -> None:
logger.debug(f'session end for connection 0x{session.connection.handle:04X}')
if session.connection.handle in self.sessions:
del self.sessions[session.connection.handle]
- def get_long_term_key(self, connection, rand, ediv):
+ def get_long_term_key(
+ self, connection: Connection, rand: bytes, ediv: int
+ ) -> Optional[bytes]:
if session := self.sessions.get(connection.handle):
return session.get_long_term_key(rand, ediv)
+
+ return None
diff --git a/bumble/snoop.py b/bumble/snoop.py
new file mode 100644
index 0000000..4b331d2
--- /dev/null
+++ b/bumble/snoop.py
@@ -0,0 +1,170 @@
+# Copyright 2021-2023 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# -----------------------------------------------------------------------------
+# Imports
+# -----------------------------------------------------------------------------
+from contextlib import contextmanager
+from enum import IntEnum
+import logging
+import struct
+import datetime
+from typing import BinaryIO, Generator
+import os
+
+from bumble.hci import HCI_COMMAND_PACKET, HCI_EVENT_PACKET
+
+
+# -----------------------------------------------------------------------------
+# Logging
+# -----------------------------------------------------------------------------
+logger = logging.getLogger(__name__)
+
+
+# -----------------------------------------------------------------------------
+# Classes
+# -----------------------------------------------------------------------------
+class Snooper:
+ """
+ Base class for snooper implementations.
+
+ A snooper is an object that will be provided with HCI packets as they are
+ exchanged between a host and a controller.
+ """
+
+ class Direction(IntEnum):
+ HOST_TO_CONTROLLER = 0
+ CONTROLLER_TO_HOST = 1
+
+ class DataLinkType(IntEnum):
+ H1 = 1001
+ H4 = 1002
+ HCI_BSCP = 1003
+ H5 = 1004
+
+ def snoop(self, hci_packet: bytes, direction: Direction) -> None:
+ """Snoop on an HCI packet."""
+
+
+# -----------------------------------------------------------------------------
+class BtSnooper(Snooper):
+ """
+ Snooper that saves HCI packets using the BTSnoop format, based on RFC 1761.
+ """
+
+ IDENTIFICATION_PATTERN = b'btsnoop\0'
+ TIMESTAMP_ANCHOR = datetime.datetime(2000, 1, 1)
+ TIMESTAMP_DELTA = 0x00E03AB44A676000
+ ONE_MS = datetime.timedelta(microseconds=1)
+
+ def __init__(self, output: BinaryIO):
+ self.output = output
+
+ # Write the header
+ self.output.write(
+ self.IDENTIFICATION_PATTERN + struct.pack('>LL', 1, self.DataLinkType.H4)
+ )
+
+ def snoop(self, hci_packet: bytes, direction: Snooper.Direction) -> None:
+ flags = int(direction)
+ packet_type = hci_packet[0]
+ if packet_type in (HCI_EVENT_PACKET, HCI_COMMAND_PACKET):
+ flags |= 0x10
+
+ # Compute the current timestamp
+ timestamp = (
+ int((datetime.datetime.utcnow() - self.TIMESTAMP_ANCHOR) / self.ONE_MS)
+ + self.TIMESTAMP_DELTA
+ )
+
+ # Emit the record
+ self.output.write(
+ struct.pack(
+ '>IIIIQ',
+ len(hci_packet), # Original Length
+ len(hci_packet), # Included Length
+ flags, # Packet Flags
+ 0, # Cumulative Drops
+ timestamp, # Timestamp
+ )
+ + hci_packet
+ )
+
+
+# -----------------------------------------------------------------------------
+_SNOOPER_INSTANCE_COUNT = 0
+
+
+@contextmanager
+def create_snooper(spec: str) -> Generator[Snooper, None, None]:
+ """
+ Create a snooper given a specification string.
+
+ The general syntax for the specification string is:
+ <snooper-type>:<type-specific-arguments>
+
+ Supported snooper types are:
+
+ btsnoop
+ The syntax for the type-specific arguments for this type is:
+ <io-type>:<io-type-specific-arguments>
+
+ Supported I/O types are:
+
+ file
+ The type-specific arguments for this I/O type is a string that is converted
+ to a file path using the python `str.format()` string formatting. The log
+ records will be written to that file if it can be opened/created.
+ The keyword args that may be referenced by the string pattern are:
+ now: the value of `datetime.now()`
+ utcnow: the value of `datetime.utcnow()`
+ pid: the current process ID.
+ instance: the instance ID in the current process.
+
+ Examples:
+ btsnoop:file:my_btsnoop.log
+ btsnoop:file:/tmp/bumble_{now:%Y-%m-%d-%H:%M:%S}_{pid}.log
+
+ """
+ if ':' not in spec:
+ raise ValueError('snooper type prefix missing')
+
+ snooper_type, snooper_args = spec.split(':', maxsplit=1)
+
+ if snooper_type == 'btsnoop':
+ if ':' not in snooper_args:
+ raise ValueError('I/O type for btsnoop snooper type missing')
+
+ io_type, io_name = snooper_args.split(':', maxsplit=1)
+ if io_type == 'file':
+ # Process the file name string pattern.
+ global _SNOOPER_INSTANCE_COUNT
+ file_path = io_name.format(
+ now=datetime.datetime.now(),
+ utcnow=datetime.datetime.utcnow(),
+ pid=os.getpid(),
+ instance=_SNOOPER_INSTANCE_COUNT,
+ )
+
+ # Open the file
+ logger.debug(f'Snoop file: {file_path}')
+ with open(file_path, 'wb') as snoop_file:
+ _SNOOPER_INSTANCE_COUNT += 1
+ yield BtSnooper(snoop_file)
+ _SNOOPER_INSTANCE_COUNT -= 1
+ return
+
+ raise ValueError(f'I/O type {io_type} not supported')
+
+ raise ValueError(f'snooper type {snooper_type} not found')
diff --git a/bumble/transport/__init__.py b/bumble/transport/__init__.py
index c3bd5f8..840b3e5 100644
--- a/bumble/transport/__init__.py
+++ b/bumble/transport/__init__.py
@@ -1,4 +1,4 @@
-# Copyright 2021-2022 Google LLC
+# Copyright 2021-2023 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,11 +15,13 @@
# -----------------------------------------------------------------------------
# Imports
# -----------------------------------------------------------------------------
+from contextlib import asynccontextmanager
import logging
+import os
-from .common import Transport, AsyncPipeSink
-from ..link import RemoteLink
+from .common import Transport, AsyncPipeSink, SnoopingTransport
from ..controller import Controller
+from ..snoop import create_snooper
# -----------------------------------------------------------------------------
# Logging
@@ -28,68 +30,153 @@ logger = logging.getLogger(__name__)
# -----------------------------------------------------------------------------
-async def open_transport(name):
- '''
+def _wrap_transport(transport: Transport) -> Transport:
+ """
+ Automatically wrap a Transport instance when a wrapping class can be inferred
+ from the environment.
+ If no wrapping class is applicable, the transport argument is returned as-is.
+ """
+
+ # If BUMBLE_SNOOPER is set, try to automatically create a snooper.
+ if snooper_spec := os.getenv('BUMBLE_SNOOPER'):
+ try:
+ return SnoopingTransport.create_with(
+ transport, create_snooper(snooper_spec)
+ )
+ except Exception as exc:
+ logger.warning(f'Exception while creating snooper: {exc}')
+
+ return transport
+
+
+# -----------------------------------------------------------------------------
+async def open_transport(name: str) -> Transport:
+ """
Open a transport by name.
The name must be <type>:<parameters>
Where <parameters> depend on the type (and may be empty for some types).
- The supported types are: serial,udp,tcp,pty,usb
- '''
+ The supported types are:
+ * serial
+ * udp
+ * tcp-client
+ * tcp-server
+ * ws-client
+ * ws-server
+ * pty
+ * file
+ * vhci
+ * hci-socket
+ * usb
+ * pyusb
+ * android-emulator
+ """
+
+ return _wrap_transport(await _open_transport(name))
+
+
+# -----------------------------------------------------------------------------
+async def _open_transport(name: str) -> Transport:
+ # pylint: disable=import-outside-toplevel
+ # pylint: disable=too-many-return-statements
+
scheme, *spec = name.split(':', 1)
if scheme == 'serial' and spec:
from .serial import open_serial_transport
+
return await open_serial_transport(spec[0])
- elif scheme == 'udp' and spec:
+
+ if scheme == 'udp' and spec:
from .udp import open_udp_transport
+
return await open_udp_transport(spec[0])
- elif scheme == 'tcp-client' and spec:
+
+ if scheme == 'tcp-client' and spec:
from .tcp_client import open_tcp_client_transport
+
return await open_tcp_client_transport(spec[0])
- elif scheme == 'tcp-server' and spec:
+
+ if scheme == 'tcp-server' and spec:
from .tcp_server import open_tcp_server_transport
+
return await open_tcp_server_transport(spec[0])
- elif scheme == 'ws-client' and spec:
+
+ if scheme == 'ws-client' and spec:
from .ws_client import open_ws_client_transport
+
return await open_ws_client_transport(spec[0])
- elif scheme == 'ws-server' and spec:
+
+ if scheme == 'ws-server' and spec:
from .ws_server import open_ws_server_transport
+
return await open_ws_server_transport(spec[0])
- elif scheme == 'pty':
+
+ if scheme == 'pty':
from .pty import open_pty_transport
+
return await open_pty_transport(spec[0] if spec else None)
- elif scheme == 'file':
+
+ if scheme == 'file':
from .file import open_file_transport
+
return await open_file_transport(spec[0] if spec else None)
- elif scheme == 'vhci':
+
+ if scheme == 'vhci':
from .vhci import open_vhci_transport
+
return await open_vhci_transport(spec[0] if spec else None)
- elif scheme == 'hci-socket':
+
+ if scheme == 'hci-socket':
from .hci_socket import open_hci_socket_transport
+
return await open_hci_socket_transport(spec[0] if spec else None)
- elif scheme == 'usb':
+
+ if scheme == 'usb':
from .usb import open_usb_transport
+
return await open_usb_transport(spec[0] if spec else None)
- elif scheme == 'pyusb':
+
+ if scheme == 'pyusb':
from .pyusb import open_pyusb_transport
+
return await open_pyusb_transport(spec[0] if spec else None)
- elif scheme == 'android-emulator':
+
+ if scheme == 'android-emulator':
from .android_emulator import open_android_emulator_transport
+
return await open_android_emulator_transport(spec[0] if spec else None)
- else:
- raise ValueError('unknown transport scheme')
+
+ if scheme == 'android-netsim':
+ from .android_netsim import open_android_netsim_transport
+
+ return await open_android_netsim_transport(spec[0] if spec else None)
+
+ raise ValueError('unknown transport scheme')
# -----------------------------------------------------------------------------
-async def open_transport_or_link(name):
+async def open_transport_or_link(name: str) -> Transport:
+ """
+ Open a transport or a link relay.
+
+ Args:
+ name:
+ Name of the transport or link relay to open.
+ When the name starts with "link-relay:", open a link relay (see RemoteLink
+ for details on what the arguments are).
+ For other namespaces, see `open_transport`.
+
+ """
if name.startswith('link-relay:'):
+ from ..link import RemoteLink # lazy import
+
link = RemoteLink(name[11:])
await link.wait_until_connected()
- controller = Controller('remote', link = link)
+ controller = Controller('remote', link=link)
class LinkTransport(Transport):
async def close(self):
link.close()
- return LinkTransport(controller, AsyncPipeSink(controller))
- else:
- return await open_transport(name)
+ return _wrap_transport(LinkTransport(controller, AsyncPipeSink(controller)))
+
+ return await open_transport(name)
diff --git a/bumble/transport/android_emulator.py b/bumble/transport/android_emulator.py
index d27aef6..b78e263 100644
--- a/bumble/transport/android_emulator.py
+++ b/bumble/transport/android_emulator.py
@@ -1,4 +1,4 @@
-# Copyright 2021-2022 Google LLC
+# Copyright 2021-2023 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -16,12 +16,14 @@
# Imports
# -----------------------------------------------------------------------------
import logging
-import grpc
+import grpc.aio
from .common import PumpedTransport, PumpedPacketSource, PumpedPacketSink
-from .emulated_bluetooth_pb2_grpc import EmulatedBluetoothServiceStub
-from .emulated_bluetooth_packets_pb2 import HCIPacket
-from .emulated_bluetooth_vhci_pb2_grpc import VhciForwardingServiceStub
+
+# pylint: disable=no-name-in-module
+from .grpc_protobuf.emulated_bluetooth_pb2_grpc import EmulatedBluetoothServiceStub
+from .grpc_protobuf.emulated_bluetooth_packets_pb2 import HCIPacket
+from .grpc_protobuf.emulated_bluetooth_vhci_pb2_grpc import VhciForwardingServiceStub
# -----------------------------------------------------------------------------
@@ -59,15 +61,10 @@ async def open_android_emulator_transport(spec):
return bytes([packet.type]) + packet.packet
async def write(self, packet):
- await self.hci_device.write(
- HCIPacket(
- type = packet[0],
- packet = packet[1:]
- )
- )
+ await self.hci_device.write(HCIPacket(type=packet[0], packet=packet[1:]))
# Parse the parameters
- mode = 'host'
+ mode = 'host'
server_host = 'localhost'
server_port = 8554
if spec is not None:
@@ -100,7 +97,7 @@ async def open_android_emulator_transport(spec):
transport = PumpedTransport(
PumpedPacketSource(hci_device.read),
PumpedPacketSink(hci_device.write),
- channel.close
+ channel.close,
)
transport.start()
diff --git a/bumble/transport/android_netsim.py b/bumble/transport/android_netsim.py
new file mode 100644
index 0000000..99ebf87
--- /dev/null
+++ b/bumble/transport/android_netsim.py
@@ -0,0 +1,410 @@
+# Copyright 2021-2023 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# -----------------------------------------------------------------------------
+# Imports
+# -----------------------------------------------------------------------------
+import asyncio
+import atexit
+import logging
+import grpc.aio
+import os
+import pathlib
+import sys
+from typing import Optional
+
+from .common import (
+ ParserSource,
+ PumpedTransport,
+ PumpedPacketSource,
+ PumpedPacketSink,
+ Transport,
+)
+
+# pylint: disable=no-name-in-module
+from .grpc_protobuf.packet_streamer_pb2_grpc import PacketStreamerStub
+from .grpc_protobuf.packet_streamer_pb2_grpc import (
+ PacketStreamerServicer,
+ add_PacketStreamerServicer_to_server,
+)
+from .grpc_protobuf.packet_streamer_pb2 import PacketRequest, PacketResponse
+from .grpc_protobuf.hci_packet_pb2 import HCIPacket
+from .grpc_protobuf.startup_pb2 import Chip, ChipInfo
+from .grpc_protobuf.common_pb2 import ChipKind
+
+# -----------------------------------------------------------------------------
+# Logging
+# -----------------------------------------------------------------------------
+logger = logging.getLogger(__name__)
+
+
+# -----------------------------------------------------------------------------
+# Constants
+# -----------------------------------------------------------------------------
+DEFAULT_NAME = 'bumble0'
+DEFAULT_MANUFACTURER = 'Bumble'
+
+
+# -----------------------------------------------------------------------------
+def get_ini_dir() -> Optional[pathlib.Path]:
+ if sys.platform == 'darwin':
+ if tmpdir := os.getenv('TMPDIR', None):
+ return pathlib.Path(tmpdir)
+ if home := os.getenv('HOME', None):
+ return pathlib.Path(home) / 'Library/Caches/TemporaryItems'
+ elif sys.platform == 'linux':
+ if xdg_runtime_dir := os.environ.get('XDG_RUNTIME_DIR', None):
+ return pathlib.Path(xdg_runtime_dir)
+ elif sys.platform == 'win32':
+ if local_app_data_dir := os.environ.get('LOCALAPPDATA', None):
+ return pathlib.Path(local_app_data_dir) / 'Temp'
+
+ return None
+
+
+# -----------------------------------------------------------------------------
+def find_grpc_port() -> int:
+ if not (ini_dir := get_ini_dir()):
+ logger.debug('no known directory for .ini file')
+ return 0
+
+ ini_file = ini_dir / 'netsim.ini'
+ if ini_file.is_file():
+ logger.debug(f'Found .ini file at {ini_file}')
+ with open(ini_file, 'r') as ini_file_data:
+ for line in ini_file_data.readlines():
+ if '=' in line:
+ key, value = line.split('=')
+ if key == 'grpc.port':
+ logger.debug(f'gRPC port = {value}')
+ return int(value)
+
+ # Not found
+ return 0
+
+
+# -----------------------------------------------------------------------------
+def publish_grpc_port(grpc_port) -> bool:
+ if not (ini_dir := get_ini_dir()):
+ logger.debug('no known directory for .ini file')
+ return False
+
+ if not ini_dir.is_dir():
+ logger.debug('ini directory does not exist')
+ return False
+
+ ini_file = ini_dir / 'netsim.ini'
+ try:
+ ini_file.write_text(f'grpc.port={grpc_port}\n')
+ logger.debug(f"published gRPC port at {ini_file}")
+
+ def cleanup():
+ logger.debug("removing .ini file")
+ ini_file.unlink()
+
+ atexit.register(cleanup)
+ return True
+ except OSError:
+ logger.debug('failed to write to .ini file')
+ return False
+
+
+# -----------------------------------------------------------------------------
+async def open_android_netsim_controller_transport(server_host, server_port):
+ if not server_port:
+ raise ValueError('invalid port')
+ if server_host == '_' or not server_host:
+ server_host = 'localhost'
+
+ if not publish_grpc_port(server_port):
+ logger.warning("unable to publish gRPC port")
+
+ class HciDevice:
+ def __init__(self, context, on_data_received):
+ self.context = context
+ self.on_data_received = on_data_received
+ self.name = None
+ self.loop = asyncio.get_running_loop()
+ self.done = self.loop.create_future()
+ self.task = self.loop.create_task(self.pump())
+
+ async def pump(self):
+ try:
+ await self.pump_loop()
+ except asyncio.CancelledError:
+ logger.debug('Pump task canceled')
+ self.done.set_result(None)
+
+ async def pump_loop(self):
+ while True:
+ request = await self.context.read()
+ if request == grpc.aio.EOF:
+ logger.debug('End of request stream')
+ self.done.set_result(None)
+ return
+
+ # If we're not initialized yet, wait for a init packet.
+ if self.name is None:
+ if request.WhichOneof('request_type') == 'initial_info':
+ logger.debug(f'Received initial info: {request}')
+
+ # We only accept BLUETOOTH
+ if request.initial_info.chip.kind != ChipKind.BLUETOOTH:
+ logger.warning('Unsupported chip type')
+ error = PacketResponse(error='Unsupported chip type')
+ await self.context.write(error)
+ return
+
+ self.name = request.initial_info.name
+ continue
+
+ # Expect a data packet
+ request_type = request.WhichOneof('request_type')
+ if request_type != 'hci_packet':
+ logger.warning(f'Unexpected request type: {request_type}')
+ error = PacketResponse(error='Unexpected request type')
+ await self.context.write(error)
+ continue
+
+ # Process the packet
+ data = (
+ bytes([request.hci_packet.packet_type]) + request.hci_packet.packet
+ )
+ logger.debug(f'<<< PACKET: {data.hex()}')
+ self.on_data_received(data)
+
+ def send_packet(self, data):
+ async def send():
+ await self.context.write(
+ PacketResponse(
+ hci_packet=HCIPacket(packet_type=data[0], packet=data[1:])
+ )
+ )
+
+ self.loop.create_task(send())
+
+ def terminate(self):
+ self.task.cancel()
+
+ async def wait_for_termination(self):
+ await self.done
+
+ class Server(PacketStreamerServicer, ParserSource):
+ def __init__(self):
+ PacketStreamerServicer.__init__(self)
+ ParserSource.__init__(self)
+ self.device = None
+
+ # Create a gRPC server with `so_reuseport=0` so that if there's already
+ # a server listening on that port, we get an exception.
+ self.grpc_server = grpc.aio.server(options=(('grpc.so_reuseport', 0),))
+ add_PacketStreamerServicer_to_server(self, self.grpc_server)
+ self.grpc_server.add_insecure_port(f'{server_host}:{server_port}')
+ logger.debug(f'gRPC server listening on {server_host}:{server_port}')
+
+ async def start(self):
+ logger.debug('Starting gRPC server')
+ await self.grpc_server.start()
+
+ async def serve(self):
+ # Keep serving until terminated.
+ try:
+ await self.grpc_server.wait_for_termination()
+ logger.debug('gRPC server terminated')
+ except asyncio.CancelledError:
+ logger.debug('gRPC server cancelled')
+ await self.grpc_server.stop(None)
+
+ def on_packet(self, packet):
+ if not self.device:
+ logger.debug('no device, dropping packet')
+ return
+
+ self.device.send_packet(packet)
+
+ async def StreamPackets(self, _request_iterator, context):
+ logger.debug('StreamPackets request')
+
+ # Check that we won't already have a device
+ if self.device:
+ logger.debug('busy, already serving a device')
+ return PacketResponse(error='Busy')
+
+ # Instantiate a new device
+ self.device = HciDevice(context, self.parser.feed_data)
+
+ # Wait for the device to terminate
+ logger.debug('Waiting for device to terminate')
+ try:
+ await self.device.wait_for_termination()
+ except asyncio.CancelledError:
+ logger.debug('Request canceled')
+ self.device.terminate()
+
+ logger.debug('Device terminated')
+ self.device = None
+
+ server = Server()
+ await server.start()
+ asyncio.get_running_loop().create_task(server.serve())
+
+ class GrpcServerTransport(Transport):
+ async def close(self):
+ await super().close()
+
+ return GrpcServerTransport(server, server)
+
+
+# -----------------------------------------------------------------------------
+async def open_android_netsim_host_transport(server_host, server_port, options):
+ # Wrapper for I/O operations
+ class HciDevice:
+ def __init__(self, name, manufacturer, hci_device):
+ self.name = name
+ self.manufacturer = manufacturer
+ self.hci_device = hci_device
+
+ async def start(self): # Send the startup info
+ chip_info = ChipInfo(
+ name=self.name,
+ chip=Chip(kind=ChipKind.BLUETOOTH, manufacturer=self.manufacturer),
+ )
+ logger.debug(f'Sending chip info to netsim: {chip_info}')
+ await self.hci_device.write(PacketRequest(initial_info=chip_info))
+
+ async def read(self):
+ response = await self.hci_device.read()
+ response_type = response.WhichOneof('response_type')
+ if response_type == 'error':
+ logger.warning(f'received error: {response.error}')
+ raise RuntimeError(response.error)
+ elif response_type == 'hci_packet':
+ return (
+ bytes([response.hci_packet.packet_type])
+ + response.hci_packet.packet
+ )
+
+ raise ValueError('unsupported response type')
+
+ async def write(self, packet):
+ await self.hci_device.write(
+ PacketRequest(
+ hci_packet=HCIPacket(packet_type=packet[0], packet=packet[1:])
+ )
+ )
+
+ name = options.get('name', DEFAULT_NAME)
+ manufacturer = DEFAULT_MANUFACTURER
+
+ if server_host == '_' or not server_host:
+ server_host = 'localhost'
+
+ if not server_port:
+ # Look for the gRPC config in a .ini file
+ server_host = 'localhost'
+ server_port = find_grpc_port()
+ if not server_port:
+ raise RuntimeError('gRPC server port not found')
+
+ # Connect to the gRPC server
+ server_address = f'{server_host}:{server_port}'
+ logger.debug(f'Connecting to gRPC server at {server_address}')
+ channel = grpc.aio.insecure_channel(server_address)
+
+ # Connect as a host
+ service = PacketStreamerStub(channel)
+ hci_device = HciDevice(
+ name=name,
+ manufacturer=manufacturer,
+ hci_device=service.StreamPackets(),
+ )
+ await hci_device.start()
+
+ # Create the transport object
+ transport = PumpedTransport(
+ PumpedPacketSource(hci_device.read),
+ PumpedPacketSink(hci_device.write),
+ channel.close,
+ )
+ transport.start()
+
+ return transport
+
+
+# -----------------------------------------------------------------------------
+async def open_android_netsim_transport(spec):
+ '''
+ Open a transport connection as a client or server, implementing Android's `netsim`
+ simulator protocol over gRPC.
+ The parameter string has this syntax:
+ [<host>:<port>][<options>]
+ Where <options> is a ','-separated list of <name>=<value> pairs.
+
+ General options:
+ mode=host|controller (default: host)
+ Specifies whether the transport is used
+ to connect *to* a netsim server (netsim is the controller), or accept
+ connections *as* a netsim-compatible server.
+
+ In `host` mode:
+ The <host>:<port> part is optional. When not specified, the transport
+ looks for a netsim .ini file, from which it will read the `grpc.backend.port`
+ property.
+ Options for this mode are:
+ name=<name>
+ The "chip" name, used to identify the "chip" instance. This
+ may be useful when several clients are connected, since each needs to use a
+ different name.
+
+ In `controller` mode:
+ The <host>:<port> part is required. <host> may be the address of a local network
+ interface, or '_' to accept connections on all local network interfaces.
+
+ Examples:
+ (empty string) --> connect to netsim on the port specified in the .ini file
+ localhost:8555 --> connect to netsim on localhost:8555
+ name=bumble1 --> connect to netsim, using `bumble1` as the "chip" name.
+ localhost:8555,name=bumble1 --> connect to netsim on localhost:8555, using
+ `bumble1` as the "chip" name.
+ _:8877,mode=controller --> accept connections as a controller on any interface
+ on port 8877.
+ '''
+
+ # Parse the parameters
+ params = spec.split(',') if spec else []
+ if params and ':' in params[0]:
+ # Explicit <host>:<port>
+ host, port = params[0].split(':')
+ params_offset = 1
+ else:
+ host = None
+ port = 0
+ params_offset = 0
+
+ options = {}
+ for param in params[params_offset:]:
+ if '=' not in param:
+ raise ValueError('invalid parameter, expected <name>=<value>')
+ option_name, option_value = param.split('=')
+ options[option_name] = option_value
+
+ mode = options.get('mode', 'host')
+ if mode == 'host':
+ return await open_android_netsim_host_transport(host, port, options)
+ if mode == 'controller':
+ if host is None:
+ raise ValueError('<host>:<port> missing')
+ return await open_android_netsim_controller_transport(host, port)
+
+ raise ValueError('invalid mode option')
diff --git a/bumble/transport/common.py b/bumble/transport/common.py
index d5c1ae9..05a1fb5 100644
--- a/bumble/transport/common.py
+++ b/bumble/transport/common.py
@@ -15,12 +15,16 @@
# -----------------------------------------------------------------------------
# Imports
# -----------------------------------------------------------------------------
+from __future__ import annotations
+import contextlib
import struct
import asyncio
import logging
-from colors import color
+from typing import ContextManager
from .. import hci
+from ..colors import color
+from ..snoop import Snooper
# -----------------------------------------------------------------------------
@@ -33,10 +37,10 @@ logger = logging.getLogger(__name__)
# For each packet type, the info represents:
# (length-size, length-offset, unpack-type)
HCI_PACKET_INFO = {
- hci.HCI_COMMAND_PACKET: (1, 2, 'B'),
- hci.HCI_ACL_DATA_PACKET: (2, 2, 'H'),
+ hci.HCI_COMMAND_PACKET: (1, 2, 'B'),
+ hci.HCI_ACL_DATA_PACKET: (2, 2, 'H'),
hci.HCI_SYNCHRONOUS_DATA_PACKET: (1, 2, 'B'),
- hci.HCI_EVENT_PACKET: (1, 1, 'B')
+ hci.HCI_EVENT_PACKET: (1, 1, 'B'),
}
@@ -48,7 +52,7 @@ class PacketPump:
def __init__(self, reader, sink):
self.reader = reader
- self.sink = sink
+ self.sink = sink
async def run(self):
while True:
@@ -65,43 +69,51 @@ class PacketPump:
# -----------------------------------------------------------------------------
class PacketParser:
'''
- In-line parser that accepts data and emits 'on_packet' when a full packet has been parsed
+ In-line parser that accepts data and emits 'on_packet' when a full packet has been
+ parsed
'''
- NEED_TYPE = 0
+
+ # pylint: disable=attribute-defined-outside-init
+
+ NEED_TYPE = 0
NEED_LENGTH = 1
- NEED_BODY = 2
+ NEED_BODY = 2
- def __init__(self, sink = None):
+ def __init__(self, sink=None):
self.sink = sink
self.extended_packet_info = {}
self.reset()
def reset(self):
- self.state = PacketParser.NEED_TYPE
+ self.state = PacketParser.NEED_TYPE
self.bytes_needed = 1
- self.packet = bytearray()
- self.packet_info = None
+ self.packet = bytearray()
+ self.packet_info = None
def feed_data(self, data):
data_offset = 0
data_left = len(data)
while data_left and self.bytes_needed:
consumed = min(self.bytes_needed, data_left)
- self.packet.extend(data[data_offset:data_offset + consumed])
- data_offset += consumed
- data_left -= consumed
+ self.packet.extend(data[data_offset : data_offset + consumed])
+ data_offset += consumed
+ data_left -= consumed
self.bytes_needed -= consumed
if self.bytes_needed == 0:
if self.state == PacketParser.NEED_TYPE:
packet_type = self.packet[0]
- self.packet_info = HCI_PACKET_INFO.get(packet_type) or self.extended_packet_info.get(packet_type)
+ self.packet_info = HCI_PACKET_INFO.get(
+ packet_type
+ ) or self.extended_packet_info.get(packet_type)
if self.packet_info is None:
raise ValueError(f'invalid packet type {packet_type}')
self.state = PacketParser.NEED_LENGTH
self.bytes_needed = self.packet_info[0] + self.packet_info[1]
elif self.state == PacketParser.NEED_LENGTH:
- body_length = struct.unpack_from(self.packet_info[2], self.packet, 1 + self.packet_info[1])[0]
+ body_length = struct.unpack_from(
+ self.packet_info[2], self.packet, 1 + self.packet_info[1]
+ )[0]
self.bytes_needed = body_length
self.state = PacketParser.NEED_BODY
@@ -111,7 +123,9 @@ class PacketParser:
try:
self.sink.on_packet(bytes(self.packet))
except Exception as error:
- logger.warning(color(f'!!! Exception in on_packet: {error}', 'red'))
+ logger.warning(
+ color(f'!!! Exception in on_packet: {error}', 'red')
+ )
self.reset()
def set_packet_sink(self, sink):
@@ -187,6 +201,7 @@ class AsyncPipeSink:
'''
Sink that forwards packets asynchronously to another sink
'''
+
def __init__(self, sink):
self.sink = sink
self.loop = asyncio.get_running_loop()
@@ -202,7 +217,7 @@ class ParserSource:
"""
def __init__(self):
- self.parser = PacketParser()
+ self.parser = PacketParser()
self.terminated = asyncio.get_running_loop().create_future()
def set_packet_sink(self, sink):
@@ -235,9 +250,23 @@ class StreamPacketSink:
# -----------------------------------------------------------------------------
class Transport:
+ """
+ Base class for all transports.
+
+ A Transport represents a source and a sink together.
+ An instance must be closed by calling close() when no longer used. Instances
+ implement the ContextManager protocol so that they may be used in a `async with`
+ statement.
+ An instance is iterable. The iterator yields, in order, its source and sink, so
+ that it may be used with a convenient call syntax like:
+
+ async with create_transport() as (source, sink):
+ ...
+ """
+
def __init__(self, source, sink):
self.source = source
- self.sink = sink
+ self.sink = sink
async def __aenter__(self):
return self
@@ -248,7 +277,7 @@ class Transport:
def __iter__(self):
return iter((self.source, self.sink))
- async def close(self):
+ async def close(self) -> None:
self.source.close()
self.sink.close()
@@ -258,7 +287,7 @@ class PumpedPacketSource(ParserSource):
def __init__(self, receive):
super().__init__()
self.receive_function = receive
- self.pump_task = None
+ self.pump_task = None
def start(self):
async def pump_packets():
@@ -270,11 +299,11 @@ class PumpedPacketSource(ParserSource):
logger.debug('source pump task done')
break
except Exception as error:
- logger.warn(f'exception while waiting for packet: {error}')
+ logger.warning(f'exception while waiting for packet: {error}')
self.terminated.set_result(error)
break
- self.pump_task = asyncio.get_running_loop().create_task(pump_packets())
+ self.pump_task = asyncio.create_task(pump_packets())
def close(self):
if self.pump_task:
@@ -285,8 +314,8 @@ class PumpedPacketSource(ParserSource):
class PumpedPacketSink:
def __init__(self, send):
self.send_function = send
- self.packet_queue = asyncio.Queue()
- self.pump_task = None
+ self.packet_queue = asyncio.Queue()
+ self.pump_task = None
def on_packet(self, packet):
self.packet_queue.put_nowait(packet)
@@ -301,10 +330,10 @@ class PumpedPacketSink:
logger.debug('sink pump task done')
break
except Exception as error:
- logger.warn(f'exception while sending packet: {error}')
+ logger.warning(f'exception while sending packet: {error}')
break
- self.pump_task = asyncio.get_running_loop().create_task(pump_packets())
+ self.pump_task = asyncio.create_task(pump_packets())
def close(self):
if self.pump_task:
@@ -324,3 +353,60 @@ class PumpedTransport(Transport):
async def close(self):
await super().close()
await self.close_function()
+
+
+# -----------------------------------------------------------------------------
+class SnoopingTransport(Transport):
+ """Transport wrapper that snoops on packets to/from a wrapped transport."""
+
+ @staticmethod
+ def create_with(
+ transport: Transport, snooper: ContextManager[Snooper]
+ ) -> SnoopingTransport:
+ """
+ Create an instance given a snooper that works as as context manager.
+
+ The returned instance will exit the snooper context when it is closed.
+ """
+ with contextlib.ExitStack() as exit_stack:
+ return SnoopingTransport(
+ transport, exit_stack.enter_context(snooper), exit_stack.pop_all().close
+ )
+ raise RuntimeError('unexpected code path') # Satisfy the type checker
+
+ class Source:
+ def __init__(self, source, snooper):
+ self.source = source
+ self.snooper = snooper
+ self.sink = None
+
+ def set_packet_sink(self, sink):
+ self.sink = sink
+ self.source.set_packet_sink(self)
+
+ def on_packet(self, packet):
+ self.snooper.snoop(packet, Snooper.Direction.CONTROLLER_TO_HOST)
+ if self.sink:
+ self.sink.on_packet(packet)
+
+ class Sink:
+ def __init__(self, sink, snooper):
+ self.sink = sink
+ self.snooper = snooper
+
+ def on_packet(self, packet):
+ self.snooper.snoop(packet, Snooper.Direction.HOST_TO_CONTROLLER)
+ if self.sink:
+ self.sink.on_packet(packet)
+
+ def __init__(self, transport, snooper, close_snooper=None):
+ super().__init__(
+ self.Source(transport.source, snooper), self.Sink(transport.sink, snooper)
+ )
+ self.transport = transport
+ self.close_snooper = close_snooper
+
+ async def close(self):
+ await self.transport.close()
+ if self.close_snooper:
+ self.close_snooper()
diff --git a/bumble/transport/emulated_bluetooth_pb2.py b/bumble/transport/emulated_bluetooth_pb2.py
deleted file mode 100644
index 4da12d5..0000000
--- a/bumble/transport/emulated_bluetooth_pb2.py
+++ /dev/null
@@ -1,53 +0,0 @@
-# Copyright 2021-2022 Google LLC
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# -*- coding: utf-8 -*-
-# Generated by the protocol buffer compiler. DO NOT EDIT!
-# source: emulated_bluetooth.proto
-"""Generated protocol buffer code."""
-from google.protobuf import descriptor as _descriptor
-from google.protobuf import descriptor_pool as _descriptor_pool
-from google.protobuf import message as _message
-from google.protobuf import reflection as _reflection
-from google.protobuf import symbol_database as _symbol_database
-# @@protoc_insertion_point(imports)
-
-_sym_db = _symbol_database.Default()
-
-
-from . import emulated_bluetooth_packets_pb2 as emulated__bluetooth__packets__pb2
-
-
-DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x18\x65mulated_bluetooth.proto\x12\x1b\x61ndroid.emulation.bluetooth\x1a emulated_bluetooth_packets.proto\"\x19\n\x07RawData\x12\x0e\n\x06packet\x18\x01 \x01(\x0c\x32\xcb\x02\n\x18\x45mulatedBluetoothService\x12\x64\n\x12registerClassicPhy\x12$.android.emulation.bluetooth.RawData\x1a$.android.emulation.bluetooth.RawData(\x01\x30\x01\x12`\n\x0eregisterBlePhy\x12$.android.emulation.bluetooth.RawData\x1a$.android.emulation.bluetooth.RawData(\x01\x30\x01\x12g\n\x11registerHCIDevice\x12&.android.emulation.bluetooth.HCIPacket\x1a&.android.emulation.bluetooth.HCIPacket(\x01\x30\x01\x42\"\n\x1e\x63om.android.emulator.bluetoothP\x01\x62\x06proto3')
-
-
-
-_RAWDATA = DESCRIPTOR.message_types_by_name['RawData']
-RawData = _reflection.GeneratedProtocolMessageType('RawData', (_message.Message,), {
- 'DESCRIPTOR' : _RAWDATA,
- '__module__' : 'emulated_bluetooth_pb2'
- # @@protoc_insertion_point(class_scope:android.emulation.bluetooth.RawData)
- })
-_sym_db.RegisterMessage(RawData)
-
-_EMULATEDBLUETOOTHSERVICE = DESCRIPTOR.services_by_name['EmulatedBluetoothService']
-if _descriptor._USE_C_DESCRIPTORS == False:
-
- DESCRIPTOR._options = None
- DESCRIPTOR._serialized_options = b'\n\036com.android.emulator.bluetoothP\001'
- _RAWDATA._serialized_start=91
- _RAWDATA._serialized_end=116
- _EMULATEDBLUETOOTHSERVICE._serialized_start=119
- _EMULATEDBLUETOOTHSERVICE._serialized_end=450
-# @@protoc_insertion_point(module_scope)
diff --git a/bumble/transport/file.py b/bumble/transport/file.py
index 841c62a..9c073d2 100644
--- a/bumble/transport/file.py
+++ b/bumble/transport/file.py
@@ -30,8 +30,9 @@ logger = logging.getLogger(__name__)
# -----------------------------------------------------------------------------
async def open_file_transport(spec):
'''
- Open a File transport (typically not for a real file, but for a PTY or other unix virtual files).
- The parameter string is the path of the file to open
+ Open a File transport (typically not for a real file, but for a PTY or other unix
+ virtual files).
+ The parameter string is the path of the file to open.
'''
# Open the file
@@ -39,14 +40,12 @@ async def open_file_transport(spec):
# Setup reading
read_transport, packet_source = await asyncio.get_running_loop().connect_read_pipe(
- lambda: StreamPacketSource(),
- file
+ StreamPacketSource, file
)
# Setup writing
write_transport, _ = await asyncio.get_running_loop().connect_write_pipe(
- lambda: asyncio.BaseProtocol(),
- file
+ asyncio.BaseProtocol, file
)
packet_sink = StreamPacketSink(write_transport)
@@ -57,4 +56,3 @@ async def open_file_transport(spec):
file.close()
return FileTransport(packet_source, packet_sink)
-
diff --git a/bumble/transport/grpc_protobuf/__init__.py b/bumble/transport/grpc_protobuf/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/bumble/transport/grpc_protobuf/__init__.py
diff --git a/bumble/transport/grpc_protobuf/common_pb2.py b/bumble/transport/grpc_protobuf/common_pb2.py
new file mode 100644
index 0000000..c54a2e0
--- /dev/null
+++ b/bumble/transport/grpc_protobuf/common_pb2.py
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: common.proto
+"""Generated protocol buffer code."""
+from google.protobuf.internal import builder as _builder
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import descriptor_pool as _descriptor_pool
+from google.protobuf import symbol_database as _symbol_database
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+
+
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0c\x63ommon.proto\x12\rnetsim.common*=\n\x08\x43hipKind\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\r\n\tBLUETOOTH\x10\x01\x12\x08\n\x04WIFI\x10\x02\x12\x07\n\x03UWB\x10\x03\x62\x06proto3')
+
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'common_pb2', globals())
+if _descriptor._USE_C_DESCRIPTORS == False:
+
+ DESCRIPTOR._options = None
+ _CHIPKIND._serialized_start=31
+ _CHIPKIND._serialized_end=92
+# @@protoc_insertion_point(module_scope)
diff --git a/bumble/transport/grpc_protobuf/common_pb2.pyi b/bumble/transport/grpc_protobuf/common_pb2.pyi
new file mode 100644
index 0000000..4cc934d
--- /dev/null
+++ b/bumble/transport/grpc_protobuf/common_pb2.pyi
@@ -0,0 +1,12 @@
+from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
+from google.protobuf import descriptor as _descriptor
+from typing import ClassVar as _ClassVar
+
+BLUETOOTH: ChipKind
+DESCRIPTOR: _descriptor.FileDescriptor
+UNSPECIFIED: ChipKind
+UWB: ChipKind
+WIFI: ChipKind
+
+class ChipKind(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+ __slots__ = []
diff --git a/bumble/transport/grpc_protobuf/common_pb2_grpc.py b/bumble/transport/grpc_protobuf/common_pb2_grpc.py
new file mode 100644
index 0000000..2daafff
--- /dev/null
+++ b/bumble/transport/grpc_protobuf/common_pb2_grpc.py
@@ -0,0 +1,4 @@
+# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
+"""Client and server classes corresponding to protobuf-defined services."""
+import grpc
+
diff --git a/bumble/transport/grpc_protobuf/emulated_bluetooth_device_pb2.py b/bumble/transport/grpc_protobuf/emulated_bluetooth_device_pb2.py
new file mode 100644
index 0000000..7380cb4
--- /dev/null
+++ b/bumble/transport/grpc_protobuf/emulated_bluetooth_device_pb2.py
@@ -0,0 +1,64 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: emulated_bluetooth_device.proto
+"""Generated protocol buffer code."""
+from google.protobuf.internal import builder as _builder
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import descriptor_pool as _descriptor_pool
+from google.protobuf import symbol_database as _symbol_database
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+from . import grpc_endpoint_description_pb2 as grpc__endpoint__description__pb2
+from google.protobuf import empty_pb2 as google_dot_protobuf_dot_empty__pb2
+
+
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1f\x65mulated_bluetooth_device.proto\x12\x1b\x61ndroid.emulation.bluetooth\x1a\x1fgrpc_endpoint_description.proto\x1a\x1bgoogle/protobuf/empty.proto\"&\n\x12\x43\x61llbackIdentifier\x12\x10\n\x08identity\x18\x01 \x01(\t\"#\n\x10\x44\x65viceIdentifier\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\t\"\xf5\x02\n\x15\x43onnectionStateChange\x12K\n\x12\x63\x61llback_device_id\x18\x01 \x01(\x0b\x32/.android.emulation.bluetooth.CallbackIdentifier\x12\x42\n\x0b\x66rom_device\x18\x02 \x01(\x0b\x32-.android.emulation.bluetooth.DeviceIdentifier\x12U\n\tnew_state\x18\x03 \x01(\x0e\x32\x42.android.emulation.bluetooth.ConnectionStateChange.ConnectionState\"t\n\x0f\x43onnectionState\x12\x1e\n\x1a\x43ONNECTION_STATE_UNDEFINED\x10\x00\x12!\n\x1d\x43ONNECTION_STATE_DISCONNECTED\x10\x01\x12\x1e\n\x1a\x43ONNECTION_STATE_CONNECTED\x10\x02\"A\n\x04Uuid\x12\x0c\n\x02id\x18\x01 \x01(\rH\x00\x12\r\n\x03lsb\x18\x02 \x01(\x04H\x00\x12\x0b\n\x03msb\x18\x03 \x01(\x03\x42\x0f\n\rshort_or_long\"\xf3\x01\n\x1a\x43haracteristicValueRequest\x12K\n\x12\x63\x61llback_device_id\x18\x01 \x01(\x0b\x32/.android.emulation.bluetooth.CallbackIdentifier\x12\x42\n\x0b\x66rom_device\x18\x02 \x01(\x0b\x32-.android.emulation.bluetooth.DeviceIdentifier\x12\x36\n\x0b\x63\x61llback_id\x18\x03 \x01(\x0b\x32!.android.emulation.bluetooth.Uuid\x12\x0c\n\x04\x64\x61ta\x18\x04 \x01(\x0c\"\xdd\x01\n\x1b\x43haracteristicValueResponse\x12S\n\x06status\x18\x01 \x01(\x0e\x32\x43.android.emulation.bluetooth.CharacteristicValueResponse.GattStatus\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\"[\n\nGattStatus\x12\x1b\n\x17GATT_STATUS_UNSPECIFIED\x10\x00\x12\x17\n\x13GATT_STATUS_SUCCESS\x10\x01\x12\x17\n\x13GATT_STATUS_FAILURE\x10\x02\"\xb3\x05\n\x12GattCharacteristic\x12/\n\x04uuid\x18\x01 \x01(\x0b\x32!.android.emulation.bluetooth.Uuid\x12\x12\n\nproperties\x18\x02 \x01(\r\x12\x13\n\x0bpermissions\x18\x03 \x01(\r\x12\x36\n\x0b\x63\x61llback_id\x18\x04 \x01(\x0b\x32!.android.emulation.bluetooth.Uuid\"\xea\x01\n\nProperties\x12\x18\n\x14PROPERTY_UNSPECIFIED\x10\x00\x12\x16\n\x12PROPERTY_BROADCAST\x10\x01\x12\x11\n\rPROPERTY_READ\x10\x02\x12\x1e\n\x1aPROPERTY_WRITE_NO_RESPONSE\x10\x04\x12\x12\n\x0ePROPERTY_WRITE\x10\x08\x12\x13\n\x0fPROPERTY_NOTIFY\x10\x10\x12\x15\n\x11PROPERTY_INDICATE\x10 \x12\x19\n\x15PROPERTY_SIGNED_WRITE\x10@\x12\x1c\n\x17PROPERTY_EXTENDED_PROPS\x10\x80\x01\"\x9d\x02\n\x0bPermissions\x12\x1a\n\x16PERMISSION_UNSPECIFIED\x10\x00\x12\x13\n\x0fPERMISSION_READ\x10\x01\x12\x1d\n\x19PERMISSION_READ_ENCRYPTED\x10\x02\x12\"\n\x1ePERMISSION_READ_ENCRYPTED_MITM\x10\x04\x12\x14\n\x10PERMISSION_WRITE\x10\x10\x12\x1e\n\x1aPERMISSION_WRITE_ENCRYPTED\x10 \x12#\n\x1fPERMISSION_WRITE_ENCRYPTED_MITM\x10@\x12\x1c\n\x17PERMISSION_WRITE_SIGNED\x10\x80\x01\x12!\n\x1cPERMISSION_WRITE_SIGNED_MITM\x10\x80\x02\"\xb7\x02\n\x0bGattService\x12/\n\x04uuid\x18\x01 \x01(\x0b\x32!.android.emulation.bluetooth.Uuid\x12J\n\x0cservice_type\x18\x02 \x01(\x0e\x32\x34.android.emulation.bluetooth.GattService.ServiceType\x12H\n\x0f\x63haracteristics\x18\x03 \x03(\x0b\x32/.android.emulation.bluetooth.GattCharacteristic\"a\n\x0bServiceType\x12\x1c\n\x18SERVICE_TYPE_UNSPECIFIED\x10\x00\x12\x18\n\x14SERVICE_TYPE_PRIMARY\x10\x01\x12\x1a\n\x16SERVICE_TYPE_SECONDARY\x10\x02\"I\n\x0bGattProfile\x12:\n\x08services\x18\x01 \x03(\x0b\x32(.android.emulation.bluetooth.GattService\"\xf0\x03\n\rAdvertisement\x12\x13\n\x0b\x64\x65vice_name\x18\x01 \x01(\t\x12R\n\x0f\x63onnection_mode\x18\x02 \x01(\x0e\x32\x39.android.emulation.bluetooth.Advertisement.ConnectionMode\x12P\n\x0e\x64iscovery_mode\x18\x03 \x01(\x0e\x32\x38.android.emulation.bluetooth.Advertisement.DiscoveryMode\"\x94\x01\n\x0e\x43onnectionMode\x12\x1f\n\x1b\x43ONNECTION_MODE_UNSPECIFIED\x10\x00\x12#\n\x1f\x43ONNECTION_MODE_NON_CONNECTABLE\x10\x01\x12\x1c\n\x18\x43ONNECTION_MODE_DIRECTED\x10\x02\x12\x1e\n\x1a\x43ONNECTION_MODE_UNDIRECTED\x10\x03\"\x8c\x01\n\rDiscoveryMode\x12\x1e\n\x1a\x44ISCOVERY_MODE_UNSPECIFIED\x10\x00\x12#\n\x1f\x44ISCOVERY_MODE_NON_DISCOVERABLE\x10\x01\x12\x1a\n\x16\x44ISCOVERY_MODE_LIMITED\x10\x02\x12\x1a\n\x16\x44ISCOVERY_MODE_GENERAL\x10\x03\"\xc0\x01\n\nGattDevice\x12\x34\n\x08\x65ndpoint\x18\x01 \x01(\x0b\x32\".android.emulation.remote.Endpoint\x12\x41\n\radvertisement\x18\x02 \x01(\x0b\x32*.android.emulation.bluetooth.Advertisement\x12\x39\n\x07profile\x18\x03 \x01(\x0b\x32(.android.emulation.bluetooth.GattProfile2\xb9\x04\n\x11GattDeviceService\x12\x90\x01\n\x1bOnCharacteristicReadRequest\x12\x37.android.emulation.bluetooth.CharacteristicValueRequest\x1a\x38.android.emulation.bluetooth.CharacteristicValueResponse\x12\x91\x01\n\x1cOnCharacteristicWriteRequest\x12\x37.android.emulation.bluetooth.CharacteristicValueRequest\x1a\x38.android.emulation.bluetooth.CharacteristicValueResponse\x12\x95\x01\n\x1eOnCharacteristicObserveRequest\x12\x37.android.emulation.bluetooth.CharacteristicValueRequest\x1a\x38.android.emulation.bluetooth.CharacteristicValueResponse0\x01\x12\x65\n\x17OnConnectionStateChange\x12\x32.android.emulation.bluetooth.ConnectionStateChange\x1a\x16.google.protobuf.EmptyB\"\n\x1e\x63om.android.emulator.bluetoothP\x01\x62\x06proto3')
+
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'emulated_bluetooth_device_pb2', globals())
+if _descriptor._USE_C_DESCRIPTORS == False:
+
+ DESCRIPTOR._options = None
+ DESCRIPTOR._serialized_options = b'\n\036com.android.emulator.bluetoothP\001'
+ _CALLBACKIDENTIFIER._serialized_start=126
+ _CALLBACKIDENTIFIER._serialized_end=164
+ _DEVICEIDENTIFIER._serialized_start=166
+ _DEVICEIDENTIFIER._serialized_end=201
+ _CONNECTIONSTATECHANGE._serialized_start=204
+ _CONNECTIONSTATECHANGE._serialized_end=577
+ _CONNECTIONSTATECHANGE_CONNECTIONSTATE._serialized_start=461
+ _CONNECTIONSTATECHANGE_CONNECTIONSTATE._serialized_end=577
+ _UUID._serialized_start=579
+ _UUID._serialized_end=644
+ _CHARACTERISTICVALUEREQUEST._serialized_start=647
+ _CHARACTERISTICVALUEREQUEST._serialized_end=890
+ _CHARACTERISTICVALUERESPONSE._serialized_start=893
+ _CHARACTERISTICVALUERESPONSE._serialized_end=1114
+ _CHARACTERISTICVALUERESPONSE_GATTSTATUS._serialized_start=1023
+ _CHARACTERISTICVALUERESPONSE_GATTSTATUS._serialized_end=1114
+ _GATTCHARACTERISTIC._serialized_start=1117
+ _GATTCHARACTERISTIC._serialized_end=1808
+ _GATTCHARACTERISTIC_PROPERTIES._serialized_start=1286
+ _GATTCHARACTERISTIC_PROPERTIES._serialized_end=1520
+ _GATTCHARACTERISTIC_PERMISSIONS._serialized_start=1523
+ _GATTCHARACTERISTIC_PERMISSIONS._serialized_end=1808
+ _GATTSERVICE._serialized_start=1811
+ _GATTSERVICE._serialized_end=2122
+ _GATTSERVICE_SERVICETYPE._serialized_start=2025
+ _GATTSERVICE_SERVICETYPE._serialized_end=2122
+ _GATTPROFILE._serialized_start=2124
+ _GATTPROFILE._serialized_end=2197
+ _ADVERTISEMENT._serialized_start=2200
+ _ADVERTISEMENT._serialized_end=2696
+ _ADVERTISEMENT_CONNECTIONMODE._serialized_start=2405
+ _ADVERTISEMENT_CONNECTIONMODE._serialized_end=2553
+ _ADVERTISEMENT_DISCOVERYMODE._serialized_start=2556
+ _ADVERTISEMENT_DISCOVERYMODE._serialized_end=2696
+ _GATTDEVICE._serialized_start=2699
+ _GATTDEVICE._serialized_end=2891
+ _GATTDEVICESERVICE._serialized_start=2894
+ _GATTDEVICESERVICE._serialized_end=3463
+# @@protoc_insertion_point(module_scope)
diff --git a/bumble/transport/grpc_protobuf/emulated_bluetooth_device_pb2.pyi b/bumble/transport/grpc_protobuf/emulated_bluetooth_device_pb2.pyi
new file mode 100644
index 0000000..c14501b
--- /dev/null
+++ b/bumble/transport/grpc_protobuf/emulated_bluetooth_device_pb2.pyi
@@ -0,0 +1,158 @@
+from . import grpc_endpoint_description_pb2 as _grpc_endpoint_description_pb2
+from google.protobuf import empty_pb2 as _empty_pb2
+from google.protobuf.internal import containers as _containers
+from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from typing import ClassVar as _ClassVar, Iterable as _Iterable, Mapping as _Mapping, Optional as _Optional, Union as _Union
+
+DESCRIPTOR: _descriptor.FileDescriptor
+
+class Advertisement(_message.Message):
+ __slots__ = ["connection_mode", "device_name", "discovery_mode"]
+ class ConnectionMode(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+ __slots__ = []
+ class DiscoveryMode(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+ __slots__ = []
+ CONNECTION_MODE_DIRECTED: Advertisement.ConnectionMode
+ CONNECTION_MODE_FIELD_NUMBER: _ClassVar[int]
+ CONNECTION_MODE_NON_CONNECTABLE: Advertisement.ConnectionMode
+ CONNECTION_MODE_UNDIRECTED: Advertisement.ConnectionMode
+ CONNECTION_MODE_UNSPECIFIED: Advertisement.ConnectionMode
+ DEVICE_NAME_FIELD_NUMBER: _ClassVar[int]
+ DISCOVERY_MODE_FIELD_NUMBER: _ClassVar[int]
+ DISCOVERY_MODE_GENERAL: Advertisement.DiscoveryMode
+ DISCOVERY_MODE_LIMITED: Advertisement.DiscoveryMode
+ DISCOVERY_MODE_NON_DISCOVERABLE: Advertisement.DiscoveryMode
+ DISCOVERY_MODE_UNSPECIFIED: Advertisement.DiscoveryMode
+ connection_mode: Advertisement.ConnectionMode
+ device_name: str
+ discovery_mode: Advertisement.DiscoveryMode
+ def __init__(self, device_name: _Optional[str] = ..., connection_mode: _Optional[_Union[Advertisement.ConnectionMode, str]] = ..., discovery_mode: _Optional[_Union[Advertisement.DiscoveryMode, str]] = ...) -> None: ...
+
+class CallbackIdentifier(_message.Message):
+ __slots__ = ["identity"]
+ IDENTITY_FIELD_NUMBER: _ClassVar[int]
+ identity: str
+ def __init__(self, identity: _Optional[str] = ...) -> None: ...
+
+class CharacteristicValueRequest(_message.Message):
+ __slots__ = ["callback_device_id", "callback_id", "data", "from_device"]
+ CALLBACK_DEVICE_ID_FIELD_NUMBER: _ClassVar[int]
+ CALLBACK_ID_FIELD_NUMBER: _ClassVar[int]
+ DATA_FIELD_NUMBER: _ClassVar[int]
+ FROM_DEVICE_FIELD_NUMBER: _ClassVar[int]
+ callback_device_id: CallbackIdentifier
+ callback_id: Uuid
+ data: bytes
+ from_device: DeviceIdentifier
+ def __init__(self, callback_device_id: _Optional[_Union[CallbackIdentifier, _Mapping]] = ..., from_device: _Optional[_Union[DeviceIdentifier, _Mapping]] = ..., callback_id: _Optional[_Union[Uuid, _Mapping]] = ..., data: _Optional[bytes] = ...) -> None: ...
+
+class CharacteristicValueResponse(_message.Message):
+ __slots__ = ["data", "status"]
+ class GattStatus(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+ __slots__ = []
+ DATA_FIELD_NUMBER: _ClassVar[int]
+ GATT_STATUS_FAILURE: CharacteristicValueResponse.GattStatus
+ GATT_STATUS_SUCCESS: CharacteristicValueResponse.GattStatus
+ GATT_STATUS_UNSPECIFIED: CharacteristicValueResponse.GattStatus
+ STATUS_FIELD_NUMBER: _ClassVar[int]
+ data: bytes
+ status: CharacteristicValueResponse.GattStatus
+ def __init__(self, status: _Optional[_Union[CharacteristicValueResponse.GattStatus, str]] = ..., data: _Optional[bytes] = ...) -> None: ...
+
+class ConnectionStateChange(_message.Message):
+ __slots__ = ["callback_device_id", "from_device", "new_state"]
+ class ConnectionState(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+ __slots__ = []
+ CALLBACK_DEVICE_ID_FIELD_NUMBER: _ClassVar[int]
+ CONNECTION_STATE_CONNECTED: ConnectionStateChange.ConnectionState
+ CONNECTION_STATE_DISCONNECTED: ConnectionStateChange.ConnectionState
+ CONNECTION_STATE_UNDEFINED: ConnectionStateChange.ConnectionState
+ FROM_DEVICE_FIELD_NUMBER: _ClassVar[int]
+ NEW_STATE_FIELD_NUMBER: _ClassVar[int]
+ callback_device_id: CallbackIdentifier
+ from_device: DeviceIdentifier
+ new_state: ConnectionStateChange.ConnectionState
+ def __init__(self, callback_device_id: _Optional[_Union[CallbackIdentifier, _Mapping]] = ..., from_device: _Optional[_Union[DeviceIdentifier, _Mapping]] = ..., new_state: _Optional[_Union[ConnectionStateChange.ConnectionState, str]] = ...) -> None: ...
+
+class DeviceIdentifier(_message.Message):
+ __slots__ = ["address"]
+ ADDRESS_FIELD_NUMBER: _ClassVar[int]
+ address: str
+ def __init__(self, address: _Optional[str] = ...) -> None: ...
+
+class GattCharacteristic(_message.Message):
+ __slots__ = ["callback_id", "permissions", "properties", "uuid"]
+ class Permissions(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+ __slots__ = []
+ class Properties(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+ __slots__ = []
+ CALLBACK_ID_FIELD_NUMBER: _ClassVar[int]
+ PERMISSIONS_FIELD_NUMBER: _ClassVar[int]
+ PERMISSION_READ: GattCharacteristic.Permissions
+ PERMISSION_READ_ENCRYPTED: GattCharacteristic.Permissions
+ PERMISSION_READ_ENCRYPTED_MITM: GattCharacteristic.Permissions
+ PERMISSION_UNSPECIFIED: GattCharacteristic.Permissions
+ PERMISSION_WRITE: GattCharacteristic.Permissions
+ PERMISSION_WRITE_ENCRYPTED: GattCharacteristic.Permissions
+ PERMISSION_WRITE_ENCRYPTED_MITM: GattCharacteristic.Permissions
+ PERMISSION_WRITE_SIGNED: GattCharacteristic.Permissions
+ PERMISSION_WRITE_SIGNED_MITM: GattCharacteristic.Permissions
+ PROPERTIES_FIELD_NUMBER: _ClassVar[int]
+ PROPERTY_BROADCAST: GattCharacteristic.Properties
+ PROPERTY_EXTENDED_PROPS: GattCharacteristic.Properties
+ PROPERTY_INDICATE: GattCharacteristic.Properties
+ PROPERTY_NOTIFY: GattCharacteristic.Properties
+ PROPERTY_READ: GattCharacteristic.Properties
+ PROPERTY_SIGNED_WRITE: GattCharacteristic.Properties
+ PROPERTY_UNSPECIFIED: GattCharacteristic.Properties
+ PROPERTY_WRITE: GattCharacteristic.Properties
+ PROPERTY_WRITE_NO_RESPONSE: GattCharacteristic.Properties
+ UUID_FIELD_NUMBER: _ClassVar[int]
+ callback_id: Uuid
+ permissions: int
+ properties: int
+ uuid: Uuid
+ def __init__(self, uuid: _Optional[_Union[Uuid, _Mapping]] = ..., properties: _Optional[int] = ..., permissions: _Optional[int] = ..., callback_id: _Optional[_Union[Uuid, _Mapping]] = ...) -> None: ...
+
+class GattDevice(_message.Message):
+ __slots__ = ["advertisement", "endpoint", "profile"]
+ ADVERTISEMENT_FIELD_NUMBER: _ClassVar[int]
+ ENDPOINT_FIELD_NUMBER: _ClassVar[int]
+ PROFILE_FIELD_NUMBER: _ClassVar[int]
+ advertisement: Advertisement
+ endpoint: _grpc_endpoint_description_pb2.Endpoint
+ profile: GattProfile
+ def __init__(self, endpoint: _Optional[_Union[_grpc_endpoint_description_pb2.Endpoint, _Mapping]] = ..., advertisement: _Optional[_Union[Advertisement, _Mapping]] = ..., profile: _Optional[_Union[GattProfile, _Mapping]] = ...) -> None: ...
+
+class GattProfile(_message.Message):
+ __slots__ = ["services"]
+ SERVICES_FIELD_NUMBER: _ClassVar[int]
+ services: _containers.RepeatedCompositeFieldContainer[GattService]
+ def __init__(self, services: _Optional[_Iterable[_Union[GattService, _Mapping]]] = ...) -> None: ...
+
+class GattService(_message.Message):
+ __slots__ = ["characteristics", "service_type", "uuid"]
+ class ServiceType(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+ __slots__ = []
+ CHARACTERISTICS_FIELD_NUMBER: _ClassVar[int]
+ SERVICE_TYPE_FIELD_NUMBER: _ClassVar[int]
+ SERVICE_TYPE_PRIMARY: GattService.ServiceType
+ SERVICE_TYPE_SECONDARY: GattService.ServiceType
+ SERVICE_TYPE_UNSPECIFIED: GattService.ServiceType
+ UUID_FIELD_NUMBER: _ClassVar[int]
+ characteristics: _containers.RepeatedCompositeFieldContainer[GattCharacteristic]
+ service_type: GattService.ServiceType
+ uuid: Uuid
+ def __init__(self, uuid: _Optional[_Union[Uuid, _Mapping]] = ..., service_type: _Optional[_Union[GattService.ServiceType, str]] = ..., characteristics: _Optional[_Iterable[_Union[GattCharacteristic, _Mapping]]] = ...) -> None: ...
+
+class Uuid(_message.Message):
+ __slots__ = ["id", "lsb", "msb"]
+ ID_FIELD_NUMBER: _ClassVar[int]
+ LSB_FIELD_NUMBER: _ClassVar[int]
+ MSB_FIELD_NUMBER: _ClassVar[int]
+ id: int
+ lsb: int
+ msb: int
+ def __init__(self, id: _Optional[int] = ..., lsb: _Optional[int] = ..., msb: _Optional[int] = ...) -> None: ...
diff --git a/bumble/transport/grpc_protobuf/emulated_bluetooth_device_pb2_grpc.py b/bumble/transport/grpc_protobuf/emulated_bluetooth_device_pb2_grpc.py
new file mode 100644
index 0000000..754627d
--- /dev/null
+++ b/bumble/transport/grpc_protobuf/emulated_bluetooth_device_pb2_grpc.py
@@ -0,0 +1,193 @@
+# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
+"""Client and server classes corresponding to protobuf-defined services."""
+import grpc
+
+from . import emulated_bluetooth_device_pb2 as emulated__bluetooth__device__pb2
+from google.protobuf import empty_pb2 as google_dot_protobuf_dot_empty__pb2
+
+
+class GattDeviceServiceStub(object):
+ """You can provide your own GattDevice by implementing this service
+ and registering it with the android emulator.
+
+ The device will appear as a real bluetooth device, and you will
+ receive callbacks when the bluetooth system wants to
+ read, write or observe a characteristic.
+ """
+
+ def __init__(self, channel):
+ """Constructor.
+
+ Args:
+ channel: A grpc.Channel.
+ """
+ self.OnCharacteristicReadRequest = channel.unary_unary(
+ '/android.emulation.bluetooth.GattDeviceService/OnCharacteristicReadRequest',
+ request_serializer=emulated__bluetooth__device__pb2.CharacteristicValueRequest.SerializeToString,
+ response_deserializer=emulated__bluetooth__device__pb2.CharacteristicValueResponse.FromString,
+ )
+ self.OnCharacteristicWriteRequest = channel.unary_unary(
+ '/android.emulation.bluetooth.GattDeviceService/OnCharacteristicWriteRequest',
+ request_serializer=emulated__bluetooth__device__pb2.CharacteristicValueRequest.SerializeToString,
+ response_deserializer=emulated__bluetooth__device__pb2.CharacteristicValueResponse.FromString,
+ )
+ self.OnCharacteristicObserveRequest = channel.unary_stream(
+ '/android.emulation.bluetooth.GattDeviceService/OnCharacteristicObserveRequest',
+ request_serializer=emulated__bluetooth__device__pb2.CharacteristicValueRequest.SerializeToString,
+ response_deserializer=emulated__bluetooth__device__pb2.CharacteristicValueResponse.FromString,
+ )
+ self.OnConnectionStateChange = channel.unary_unary(
+ '/android.emulation.bluetooth.GattDeviceService/OnConnectionStateChange',
+ request_serializer=emulated__bluetooth__device__pb2.ConnectionStateChange.SerializeToString,
+ response_deserializer=google_dot_protobuf_dot_empty__pb2.Empty.FromString,
+ )
+
+
+class GattDeviceServiceServicer(object):
+ """You can provide your own GattDevice by implementing this service
+ and registering it with the android emulator.
+
+ The device will appear as a real bluetooth device, and you will
+ receive callbacks when the bluetooth system wants to
+ read, write or observe a characteristic.
+ """
+
+ def OnCharacteristicReadRequest(self, request, context):
+ """A remote client has requested to read a local characteristic.
+
+ Return the current observed value.
+ """
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+ context.set_details('Method not implemented!')
+ raise NotImplementedError('Method not implemented!')
+
+ def OnCharacteristicWriteRequest(self, request, context):
+ """A remote client has requested to write to a local characteristic.
+
+ Return the current observed value.
+ """
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+ context.set_details('Method not implemented!')
+ raise NotImplementedError('Method not implemented!')
+
+ def OnCharacteristicObserveRequest(self, request, context):
+ """Listens for notifications from the emulated device, the device should
+ write to the stream with a response when a change has occurred.
+ """
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+ context.set_details('Method not implemented!')
+ raise NotImplementedError('Method not implemented!')
+
+ def OnConnectionStateChange(self, request, context):
+ """A remote device has been connected or disconnected.
+ """
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+ context.set_details('Method not implemented!')
+ raise NotImplementedError('Method not implemented!')
+
+
+def add_GattDeviceServiceServicer_to_server(servicer, server):
+ rpc_method_handlers = {
+ 'OnCharacteristicReadRequest': grpc.unary_unary_rpc_method_handler(
+ servicer.OnCharacteristicReadRequest,
+ request_deserializer=emulated__bluetooth__device__pb2.CharacteristicValueRequest.FromString,
+ response_serializer=emulated__bluetooth__device__pb2.CharacteristicValueResponse.SerializeToString,
+ ),
+ 'OnCharacteristicWriteRequest': grpc.unary_unary_rpc_method_handler(
+ servicer.OnCharacteristicWriteRequest,
+ request_deserializer=emulated__bluetooth__device__pb2.CharacteristicValueRequest.FromString,
+ response_serializer=emulated__bluetooth__device__pb2.CharacteristicValueResponse.SerializeToString,
+ ),
+ 'OnCharacteristicObserveRequest': grpc.unary_stream_rpc_method_handler(
+ servicer.OnCharacteristicObserveRequest,
+ request_deserializer=emulated__bluetooth__device__pb2.CharacteristicValueRequest.FromString,
+ response_serializer=emulated__bluetooth__device__pb2.CharacteristicValueResponse.SerializeToString,
+ ),
+ 'OnConnectionStateChange': grpc.unary_unary_rpc_method_handler(
+ servicer.OnConnectionStateChange,
+ request_deserializer=emulated__bluetooth__device__pb2.ConnectionStateChange.FromString,
+ response_serializer=google_dot_protobuf_dot_empty__pb2.Empty.SerializeToString,
+ ),
+ }
+ generic_handler = grpc.method_handlers_generic_handler(
+ 'android.emulation.bluetooth.GattDeviceService', rpc_method_handlers)
+ server.add_generic_rpc_handlers((generic_handler,))
+
+
+ # This class is part of an EXPERIMENTAL API.
+class GattDeviceService(object):
+ """You can provide your own GattDevice by implementing this service
+ and registering it with the android emulator.
+
+ The device will appear as a real bluetooth device, and you will
+ receive callbacks when the bluetooth system wants to
+ read, write or observe a characteristic.
+ """
+
+ @staticmethod
+ def OnCharacteristicReadRequest(request,
+ target,
+ options=(),
+ channel_credentials=None,
+ call_credentials=None,
+ insecure=False,
+ compression=None,
+ wait_for_ready=None,
+ timeout=None,
+ metadata=None):
+ return grpc.experimental.unary_unary(request, target, '/android.emulation.bluetooth.GattDeviceService/OnCharacteristicReadRequest',
+ emulated__bluetooth__device__pb2.CharacteristicValueRequest.SerializeToString,
+ emulated__bluetooth__device__pb2.CharacteristicValueResponse.FromString,
+ options, channel_credentials,
+ insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
+ @staticmethod
+ def OnCharacteristicWriteRequest(request,
+ target,
+ options=(),
+ channel_credentials=None,
+ call_credentials=None,
+ insecure=False,
+ compression=None,
+ wait_for_ready=None,
+ timeout=None,
+ metadata=None):
+ return grpc.experimental.unary_unary(request, target, '/android.emulation.bluetooth.GattDeviceService/OnCharacteristicWriteRequest',
+ emulated__bluetooth__device__pb2.CharacteristicValueRequest.SerializeToString,
+ emulated__bluetooth__device__pb2.CharacteristicValueResponse.FromString,
+ options, channel_credentials,
+ insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
+ @staticmethod
+ def OnCharacteristicObserveRequest(request,
+ target,
+ options=(),
+ channel_credentials=None,
+ call_credentials=None,
+ insecure=False,
+ compression=None,
+ wait_for_ready=None,
+ timeout=None,
+ metadata=None):
+ return grpc.experimental.unary_stream(request, target, '/android.emulation.bluetooth.GattDeviceService/OnCharacteristicObserveRequest',
+ emulated__bluetooth__device__pb2.CharacteristicValueRequest.SerializeToString,
+ emulated__bluetooth__device__pb2.CharacteristicValueResponse.FromString,
+ options, channel_credentials,
+ insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
+ @staticmethod
+ def OnConnectionStateChange(request,
+ target,
+ options=(),
+ channel_credentials=None,
+ call_credentials=None,
+ insecure=False,
+ compression=None,
+ wait_for_ready=None,
+ timeout=None,
+ metadata=None):
+ return grpc.experimental.unary_unary(request, target, '/android.emulation.bluetooth.GattDeviceService/OnConnectionStateChange',
+ emulated__bluetooth__device__pb2.ConnectionStateChange.SerializeToString,
+ google_dot_protobuf_dot_empty__pb2.Empty.FromString,
+ options, channel_credentials,
+ insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
diff --git a/bumble/transport/emulated_bluetooth_packets_pb2.py b/bumble/transport/grpc_protobuf/emulated_bluetooth_packets_pb2.py
index 9d3591d..8544f95 100644
--- a/bumble/transport/emulated_bluetooth_packets_pb2.py
+++ b/bumble/transport/grpc_protobuf/emulated_bluetooth_packets_pb2.py
@@ -1,25 +1,10 @@
-# Copyright 2021-2022 Google LLC
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: emulated_bluetooth_packets.proto
"""Generated protocol buffer code."""
+from google.protobuf.internal import builder as _builder
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
-from google.protobuf import message as _message
-from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database
# @@protoc_insertion_point(imports)
@@ -30,17 +15,8 @@ _sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n emulated_bluetooth_packets.proto\x12\x1b\x61ndroid.emulation.bluetooth\"\xfb\x01\n\tHCIPacket\x12?\n\x04type\x18\x01 \x01(\x0e\x32\x31.android.emulation.bluetooth.HCIPacket.PacketType\x12\x0e\n\x06packet\x18\x02 \x01(\x0c\"\x9c\x01\n\nPacketType\x12\x1b\n\x17PACKET_TYPE_UNSPECIFIED\x10\x00\x12\x1b\n\x17PACKET_TYPE_HCI_COMMAND\x10\x01\x12\x13\n\x0fPACKET_TYPE_ACL\x10\x02\x12\x13\n\x0fPACKET_TYPE_SCO\x10\x03\x12\x15\n\x11PACKET_TYPE_EVENT\x10\x04\x12\x13\n\x0fPACKET_TYPE_ISO\x10\x05\x42J\n\x1f\x63om.android.emulation.bluetoothP\x01\xf8\x01\x01\xa2\x02\x03\x41\x45\x42\xaa\x02\x1b\x41ndroid.Emulation.Bluetoothb\x06proto3')
-
-
-_HCIPACKET = DESCRIPTOR.message_types_by_name['HCIPacket']
-_HCIPACKET_PACKETTYPE = _HCIPACKET.enum_types_by_name['PacketType']
-HCIPacket = _reflection.GeneratedProtocolMessageType('HCIPacket', (_message.Message,), {
- 'DESCRIPTOR' : _HCIPACKET,
- '__module__' : 'emulated_bluetooth_packets_pb2'
- # @@protoc_insertion_point(class_scope:android.emulation.bluetooth.HCIPacket)
- })
-_sym_db.RegisterMessage(HCIPacket)
-
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'emulated_bluetooth_packets_pb2', globals())
if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None
diff --git a/bumble/transport/grpc_protobuf/emulated_bluetooth_packets_pb2.pyi b/bumble/transport/grpc_protobuf/emulated_bluetooth_packets_pb2.pyi
new file mode 100644
index 0000000..80cdee1
--- /dev/null
+++ b/bumble/transport/grpc_protobuf/emulated_bluetooth_packets_pb2.pyi
@@ -0,0 +1,22 @@
+from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from typing import ClassVar as _ClassVar, Optional as _Optional, Union as _Union
+
+DESCRIPTOR: _descriptor.FileDescriptor
+
+class HCIPacket(_message.Message):
+ __slots__ = ["packet", "type"]
+ class PacketType(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+ __slots__ = []
+ PACKET_FIELD_NUMBER: _ClassVar[int]
+ PACKET_TYPE_ACL: HCIPacket.PacketType
+ PACKET_TYPE_EVENT: HCIPacket.PacketType
+ PACKET_TYPE_HCI_COMMAND: HCIPacket.PacketType
+ PACKET_TYPE_ISO: HCIPacket.PacketType
+ PACKET_TYPE_SCO: HCIPacket.PacketType
+ PACKET_TYPE_UNSPECIFIED: HCIPacket.PacketType
+ TYPE_FIELD_NUMBER: _ClassVar[int]
+ packet: bytes
+ type: HCIPacket.PacketType
+ def __init__(self, type: _Optional[_Union[HCIPacket.PacketType, str]] = ..., packet: _Optional[bytes] = ...) -> None: ...
diff --git a/bumble/transport/grpc_protobuf/emulated_bluetooth_packets_pb2_grpc.py b/bumble/transport/grpc_protobuf/emulated_bluetooth_packets_pb2_grpc.py
new file mode 100644
index 0000000..2daafff
--- /dev/null
+++ b/bumble/transport/grpc_protobuf/emulated_bluetooth_packets_pb2_grpc.py
@@ -0,0 +1,4 @@
+# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
+"""Client and server classes corresponding to protobuf-defined services."""
+import grpc
+
diff --git a/bumble/transport/grpc_protobuf/emulated_bluetooth_pb2.py b/bumble/transport/grpc_protobuf/emulated_bluetooth_pb2.py
new file mode 100644
index 0000000..054b250
--- /dev/null
+++ b/bumble/transport/grpc_protobuf/emulated_bluetooth_pb2.py
@@ -0,0 +1,32 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: emulated_bluetooth.proto
+"""Generated protocol buffer code."""
+from google.protobuf.internal import builder as _builder
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import descriptor_pool as _descriptor_pool
+from google.protobuf import symbol_database as _symbol_database
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+from . import emulated_bluetooth_packets_pb2 as emulated__bluetooth__packets__pb2
+from . import emulated_bluetooth_device_pb2 as emulated__bluetooth__device__pb2
+
+
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x18\x65mulated_bluetooth.proto\x12\x1b\x61ndroid.emulation.bluetooth\x1a emulated_bluetooth_packets.proto\x1a\x1f\x65mulated_bluetooth_device.proto\"\x19\n\x07RawData\x12\x0e\n\x06packet\x18\x01 \x01(\x0c\"a\n\x12RegistrationStatus\x12K\n\x12\x63\x61llback_device_id\x18\x01 \x01(\x0b\x32/.android.emulation.bluetooth.CallbackIdentifier2\xbb\x03\n\x18\x45mulatedBluetoothService\x12\x64\n\x12registerClassicPhy\x12$.android.emulation.bluetooth.RawData\x1a$.android.emulation.bluetooth.RawData(\x01\x30\x01\x12`\n\x0eregisterBlePhy\x12$.android.emulation.bluetooth.RawData\x1a$.android.emulation.bluetooth.RawData(\x01\x30\x01\x12g\n\x11registerHCIDevice\x12&.android.emulation.bluetooth.HCIPacket\x1a&.android.emulation.bluetooth.HCIPacket(\x01\x30\x01\x12n\n\x12registerGattDevice\x12\'.android.emulation.bluetooth.GattDevice\x1a/.android.emulation.bluetooth.RegistrationStatusB\"\n\x1e\x63om.android.emulator.bluetoothP\x01\x62\x06proto3')
+
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'emulated_bluetooth_pb2', globals())
+if _descriptor._USE_C_DESCRIPTORS == False:
+
+ DESCRIPTOR._options = None
+ DESCRIPTOR._serialized_options = b'\n\036com.android.emulator.bluetoothP\001'
+ _RAWDATA._serialized_start=124
+ _RAWDATA._serialized_end=149
+ _REGISTRATIONSTATUS._serialized_start=151
+ _REGISTRATIONSTATUS._serialized_end=248
+ _EMULATEDBLUETOOTHSERVICE._serialized_start=251
+ _EMULATEDBLUETOOTHSERVICE._serialized_end=694
+# @@protoc_insertion_point(module_scope)
diff --git a/bumble/transport/grpc_protobuf/emulated_bluetooth_pb2.pyi b/bumble/transport/grpc_protobuf/emulated_bluetooth_pb2.pyi
new file mode 100644
index 0000000..9f54383
--- /dev/null
+++ b/bumble/transport/grpc_protobuf/emulated_bluetooth_pb2.pyi
@@ -0,0 +1,19 @@
+from . import emulated_bluetooth_packets_pb2 as _emulated_bluetooth_packets_pb2
+from . import emulated_bluetooth_device_pb2 as _emulated_bluetooth_device_pb2
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from typing import ClassVar as _ClassVar, Mapping as _Mapping, Optional as _Optional, Union as _Union
+
+DESCRIPTOR: _descriptor.FileDescriptor
+
+class RawData(_message.Message):
+ __slots__ = ["packet"]
+ PACKET_FIELD_NUMBER: _ClassVar[int]
+ packet: bytes
+ def __init__(self, packet: _Optional[bytes] = ...) -> None: ...
+
+class RegistrationStatus(_message.Message):
+ __slots__ = ["callback_device_id"]
+ CALLBACK_DEVICE_ID_FIELD_NUMBER: _ClassVar[int]
+ callback_device_id: _emulated_bluetooth_device_pb2.CallbackIdentifier
+ def __init__(self, callback_device_id: _Optional[_Union[_emulated_bluetooth_device_pb2.CallbackIdentifier, _Mapping]] = ...) -> None: ...
diff --git a/bumble/transport/emulated_bluetooth_pb2_grpc.py b/bumble/transport/grpc_protobuf/emulated_bluetooth_pb2_grpc.py
index cc0ce37..9ad3bb9 100644
--- a/bumble/transport/emulated_bluetooth_pb2_grpc.py
+++ b/bumble/transport/grpc_protobuf/emulated_bluetooth_pb2_grpc.py
@@ -1,21 +1,8 @@
-# Copyright 2021-2022 Google LLC
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
"""Client and server classes corresponding to protobuf-defined services."""
import grpc
+from . import emulated_bluetooth_device_pb2 as emulated__bluetooth__device__pb2
from . import emulated_bluetooth_packets_pb2 as emulated__bluetooth__packets__pb2
from . import emulated_bluetooth_pb2 as emulated__bluetooth__pb2
@@ -53,6 +40,11 @@ class EmulatedBluetoothServiceStub(object):
request_serializer=emulated__bluetooth__packets__pb2.HCIPacket.SerializeToString,
response_deserializer=emulated__bluetooth__packets__pb2.HCIPacket.FromString,
)
+ self.registerGattDevice = channel.unary_unary(
+ '/android.emulation.bluetooth.EmulatedBluetoothService/registerGattDevice',
+ request_serializer=emulated__bluetooth__device__pb2.GattDevice.SerializeToString,
+ response_deserializer=emulated__bluetooth__pb2.RegistrationStatus.FromString,
+ )
class EmulatedBluetoothServiceServicer(object):
@@ -118,6 +110,22 @@ class EmulatedBluetoothServiceServicer(object):
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
+ def registerGattDevice(self, request, context):
+ """Registers an emulated bluetooth device. The emulator will reach out to
+ the emulated device to read/write and subscribe to properties.
+
+ The following gRPC error codes can be returned:
+ - FAILED_PRECONDITION (code 9):
+ - root canal is not available on this device
+ - unable to reach the endpoint for the GattDevice
+ - INTERNAL (code 13) if there was an internal emulator failure.
+
+ The device will not be discoverable in case of an error.
+ """
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+ context.set_details('Method not implemented!')
+ raise NotImplementedError('Method not implemented!')
+
def add_EmulatedBluetoothServiceServicer_to_server(servicer, server):
rpc_method_handlers = {
@@ -136,6 +144,11 @@ def add_EmulatedBluetoothServiceServicer_to_server(servicer, server):
request_deserializer=emulated__bluetooth__packets__pb2.HCIPacket.FromString,
response_serializer=emulated__bluetooth__packets__pb2.HCIPacket.SerializeToString,
),
+ 'registerGattDevice': grpc.unary_unary_rpc_method_handler(
+ servicer.registerGattDevice,
+ request_deserializer=emulated__bluetooth__device__pb2.GattDevice.FromString,
+ response_serializer=emulated__bluetooth__pb2.RegistrationStatus.SerializeToString,
+ ),
}
generic_handler = grpc.method_handlers_generic_handler(
'android.emulation.bluetooth.EmulatedBluetoothService', rpc_method_handlers)
@@ -205,3 +218,20 @@ class EmulatedBluetoothService(object):
emulated__bluetooth__packets__pb2.HCIPacket.FromString,
options, channel_credentials,
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
+ @staticmethod
+ def registerGattDevice(request,
+ target,
+ options=(),
+ channel_credentials=None,
+ call_credentials=None,
+ insecure=False,
+ compression=None,
+ wait_for_ready=None,
+ timeout=None,
+ metadata=None):
+ return grpc.experimental.unary_unary(request, target, '/android.emulation.bluetooth.EmulatedBluetoothService/registerGattDevice',
+ emulated__bluetooth__device__pb2.GattDevice.SerializeToString,
+ emulated__bluetooth__pb2.RegistrationStatus.FromString,
+ options, channel_credentials,
+ insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
diff --git a/bumble/transport/emulated_bluetooth_vhci_pb2.py b/bumble/transport/grpc_protobuf/emulated_bluetooth_vhci_pb2.py
index a638439..30a2cb6 100644
--- a/bumble/transport/emulated_bluetooth_vhci_pb2.py
+++ b/bumble/transport/grpc_protobuf/emulated_bluetooth_vhci_pb2.py
@@ -1,39 +1,23 @@
-# Copyright 2021-2022 Google LLC
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: emulated_bluetooth_vhci.proto
"""Generated protocol buffer code."""
+from google.protobuf.internal import builder as _builder
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
-from google.protobuf import message as _message
-from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
-import emulated_bluetooth_packets_pb2 as emulated__bluetooth__packets__pb2
+from . import emulated_bluetooth_packets_pb2 as emulated__bluetooth__packets__pb2
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1d\x65mulated_bluetooth_vhci.proto\x12\x1b\x61ndroid.emulation.bluetooth\x1a emulated_bluetooth_packets.proto2y\n\x15VhciForwardingService\x12`\n\nattachVhci\x12&.android.emulation.bluetooth.HCIPacket\x1a&.android.emulation.bluetooth.HCIPacket(\x01\x30\x01\x42J\n\x1f\x63om.android.emulation.bluetoothP\x01\xf8\x01\x01\xa2\x02\x03\x41\x45\x42\xaa\x02\x1b\x41ndroid.Emulation.Bluetoothb\x06proto3')
-
-
-_VHCIFORWARDINGSERVICE = DESCRIPTOR.services_by_name['VhciForwardingService']
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'emulated_bluetooth_vhci_pb2', globals())
if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None
diff --git a/bumble/transport/grpc_protobuf/emulated_bluetooth_vhci_pb2.pyi b/bumble/transport/grpc_protobuf/emulated_bluetooth_vhci_pb2.pyi
new file mode 100644
index 0000000..3311c9b
--- /dev/null
+++ b/bumble/transport/grpc_protobuf/emulated_bluetooth_vhci_pb2.pyi
@@ -0,0 +1,5 @@
+import emulated_bluetooth_packets_pb2 as _emulated_bluetooth_packets_pb2
+from google.protobuf import descriptor as _descriptor
+from typing import ClassVar as _ClassVar
+
+DESCRIPTOR: _descriptor.FileDescriptor
diff --git a/bumble/transport/emulated_bluetooth_vhci_pb2_grpc.py b/bumble/transport/grpc_protobuf/emulated_bluetooth_vhci_pb2_grpc.py
index 94140d7..031f669 100644
--- a/bumble/transport/emulated_bluetooth_vhci_pb2_grpc.py
+++ b/bumble/transport/grpc_protobuf/emulated_bluetooth_vhci_pb2_grpc.py
@@ -1,17 +1,3 @@
-# Copyright 2021-2022 Google LLC
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
"""Client and server classes corresponding to protobuf-defined services."""
import grpc
diff --git a/bumble/transport/grpc_protobuf/grpc_endpoint_description_pb2.py b/bumble/transport/grpc_protobuf/grpc_endpoint_description_pb2.py
new file mode 100644
index 0000000..00d404c
--- /dev/null
+++ b/bumble/transport/grpc_protobuf/grpc_endpoint_description_pb2.py
@@ -0,0 +1,30 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: grpc_endpoint_description.proto
+"""Generated protocol buffer code."""
+from google.protobuf.internal import builder as _builder
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import descriptor_pool as _descriptor_pool
+from google.protobuf import symbol_database as _symbol_database
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+
+
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1fgrpc_endpoint_description.proto\x12\x18\x61ndroid.emulation.remote\"V\n\x0b\x43redentials\x12\x16\n\x0epem_root_certs\x18\x01 \x01(\t\x12\x17\n\x0fpem_private_key\x18\x02 \x01(\t\x12\x16\n\x0epem_cert_chain\x18\x03 \x01(\t\"$\n\x06Header\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t\"\x96\x01\n\x08\x45ndpoint\x12\x0e\n\x06target\x18\x01 \x01(\t\x12>\n\x0ftls_credentials\x18\x02 \x01(\x0b\x32%.android.emulation.remote.Credentials\x12:\n\x10required_headers\x18\x03 \x03(\x0b\x32 .android.emulation.remote.HeaderB \n\x1c\x63om.android.emulation.remoteP\x01\x62\x06proto3')
+
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'grpc_endpoint_description_pb2', globals())
+if _descriptor._USE_C_DESCRIPTORS == False:
+
+ DESCRIPTOR._options = None
+ DESCRIPTOR._serialized_options = b'\n\034com.android.emulation.remoteP\001'
+ _CREDENTIALS._serialized_start=61
+ _CREDENTIALS._serialized_end=147
+ _HEADER._serialized_start=149
+ _HEADER._serialized_end=185
+ _ENDPOINT._serialized_start=188
+ _ENDPOINT._serialized_end=338
+# @@protoc_insertion_point(module_scope)
diff --git a/bumble/transport/grpc_protobuf/grpc_endpoint_description_pb2.pyi b/bumble/transport/grpc_protobuf/grpc_endpoint_description_pb2.pyi
new file mode 100644
index 0000000..3b81215
--- /dev/null
+++ b/bumble/transport/grpc_protobuf/grpc_endpoint_description_pb2.pyi
@@ -0,0 +1,34 @@
+from google.protobuf.internal import containers as _containers
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from typing import ClassVar as _ClassVar, Iterable as _Iterable, Mapping as _Mapping, Optional as _Optional, Union as _Union
+
+DESCRIPTOR: _descriptor.FileDescriptor
+
+class Credentials(_message.Message):
+ __slots__ = ["pem_cert_chain", "pem_private_key", "pem_root_certs"]
+ PEM_CERT_CHAIN_FIELD_NUMBER: _ClassVar[int]
+ PEM_PRIVATE_KEY_FIELD_NUMBER: _ClassVar[int]
+ PEM_ROOT_CERTS_FIELD_NUMBER: _ClassVar[int]
+ pem_cert_chain: str
+ pem_private_key: str
+ pem_root_certs: str
+ def __init__(self, pem_root_certs: _Optional[str] = ..., pem_private_key: _Optional[str] = ..., pem_cert_chain: _Optional[str] = ...) -> None: ...
+
+class Endpoint(_message.Message):
+ __slots__ = ["required_headers", "target", "tls_credentials"]
+ REQUIRED_HEADERS_FIELD_NUMBER: _ClassVar[int]
+ TARGET_FIELD_NUMBER: _ClassVar[int]
+ TLS_CREDENTIALS_FIELD_NUMBER: _ClassVar[int]
+ required_headers: _containers.RepeatedCompositeFieldContainer[Header]
+ target: str
+ tls_credentials: Credentials
+ def __init__(self, target: _Optional[str] = ..., tls_credentials: _Optional[_Union[Credentials, _Mapping]] = ..., required_headers: _Optional[_Iterable[_Union[Header, _Mapping]]] = ...) -> None: ...
+
+class Header(_message.Message):
+ __slots__ = ["key", "value"]
+ KEY_FIELD_NUMBER: _ClassVar[int]
+ VALUE_FIELD_NUMBER: _ClassVar[int]
+ key: str
+ value: str
+ def __init__(self, key: _Optional[str] = ..., value: _Optional[str] = ...) -> None: ...
diff --git a/bumble/transport/grpc_protobuf/grpc_endpoint_description_pb2_grpc.py b/bumble/transport/grpc_protobuf/grpc_endpoint_description_pb2_grpc.py
new file mode 100644
index 0000000..2daafff
--- /dev/null
+++ b/bumble/transport/grpc_protobuf/grpc_endpoint_description_pb2_grpc.py
@@ -0,0 +1,4 @@
+# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
+"""Client and server classes corresponding to protobuf-defined services."""
+import grpc
+
diff --git a/bumble/transport/grpc_protobuf/hci_packet_pb2.py b/bumble/transport/grpc_protobuf/hci_packet_pb2.py
new file mode 100644
index 0000000..ef014c4
--- /dev/null
+++ b/bumble/transport/grpc_protobuf/hci_packet_pb2.py
@@ -0,0 +1,28 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: hci_packet.proto
+"""Generated protocol buffer code."""
+from google.protobuf.internal import builder as _builder
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import descriptor_pool as _descriptor_pool
+from google.protobuf import symbol_database as _symbol_database
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+
+
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x10hci_packet.proto\x12\rnetsim.packet\"\xb2\x01\n\tHCIPacket\x12\x38\n\x0bpacket_type\x18\x01 \x01(\x0e\x32#.netsim.packet.HCIPacket.PacketType\x12\x0e\n\x06packet\x18\x02 \x01(\x0c\"[\n\nPacketType\x12\x1a\n\x16HCI_PACKET_UNSPECIFIED\x10\x00\x12\x0b\n\x07\x43OMMAND\x10\x01\x12\x07\n\x03\x41\x43L\x10\x02\x12\x07\n\x03SCO\x10\x03\x12\t\n\x05\x45VENT\x10\x04\x12\x07\n\x03ISO\x10\x05\x42J\n\x1f\x63om.android.emulation.bluetoothP\x01\xf8\x01\x01\xa2\x02\x03\x41\x45\x42\xaa\x02\x1b\x41ndroid.Emulation.Bluetoothb\x06proto3')
+
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'hci_packet_pb2', globals())
+if _descriptor._USE_C_DESCRIPTORS == False:
+
+ DESCRIPTOR._options = None
+ DESCRIPTOR._serialized_options = b'\n\037com.android.emulation.bluetoothP\001\370\001\001\242\002\003AEB\252\002\033Android.Emulation.Bluetooth'
+ _HCIPACKET._serialized_start=36
+ _HCIPACKET._serialized_end=214
+ _HCIPACKET_PACKETTYPE._serialized_start=123
+ _HCIPACKET_PACKETTYPE._serialized_end=214
+# @@protoc_insertion_point(module_scope)
diff --git a/bumble/transport/grpc_protobuf/hci_packet_pb2.pyi b/bumble/transport/grpc_protobuf/hci_packet_pb2.pyi
new file mode 100644
index 0000000..04bb972
--- /dev/null
+++ b/bumble/transport/grpc_protobuf/hci_packet_pb2.pyi
@@ -0,0 +1,22 @@
+from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from typing import ClassVar as _ClassVar, Optional as _Optional, Union as _Union
+
+DESCRIPTOR: _descriptor.FileDescriptor
+
+class HCIPacket(_message.Message):
+ __slots__ = ["packet", "packet_type"]
+ class PacketType(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+ __slots__ = []
+ ACL: HCIPacket.PacketType
+ COMMAND: HCIPacket.PacketType
+ EVENT: HCIPacket.PacketType
+ HCI_PACKET_UNSPECIFIED: HCIPacket.PacketType
+ ISO: HCIPacket.PacketType
+ PACKET_FIELD_NUMBER: _ClassVar[int]
+ PACKET_TYPE_FIELD_NUMBER: _ClassVar[int]
+ SCO: HCIPacket.PacketType
+ packet: bytes
+ packet_type: HCIPacket.PacketType
+ def __init__(self, packet_type: _Optional[_Union[HCIPacket.PacketType, str]] = ..., packet: _Optional[bytes] = ...) -> None: ...
diff --git a/bumble/transport/grpc_protobuf/hci_packet_pb2_grpc.py b/bumble/transport/grpc_protobuf/hci_packet_pb2_grpc.py
new file mode 100644
index 0000000..2daafff
--- /dev/null
+++ b/bumble/transport/grpc_protobuf/hci_packet_pb2_grpc.py
@@ -0,0 +1,4 @@
+# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
+"""Client and server classes corresponding to protobuf-defined services."""
+import grpc
+
diff --git a/bumble/transport/grpc_protobuf/packet_streamer_pb2.py b/bumble/transport/grpc_protobuf/packet_streamer_pb2.py
new file mode 100644
index 0000000..ea07940
--- /dev/null
+++ b/bumble/transport/grpc_protobuf/packet_streamer_pb2.py
@@ -0,0 +1,31 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: packet_streamer.proto
+"""Generated protocol buffer code."""
+from google.protobuf.internal import builder as _builder
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import descriptor_pool as _descriptor_pool
+from google.protobuf import symbol_database as _symbol_database
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+from . import hci_packet_pb2 as hci__packet__pb2
+from . import startup_pb2 as startup__pb2
+
+
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x15packet_streamer.proto\x12\rnetsim.packet\x1a\x10hci_packet.proto\x1a\rstartup.proto\"\x93\x01\n\rPacketRequest\x12\x30\n\x0cinitial_info\x18\x01 \x01(\x0b\x32\x18.netsim.startup.ChipInfoH\x00\x12.\n\nhci_packet\x18\x02 \x01(\x0b\x32\x18.netsim.packet.HCIPacketH\x00\x12\x10\n\x06packet\x18\x03 \x01(\x0cH\x00\x42\x0e\n\x0crequest_type\"t\n\x0ePacketResponse\x12\x0f\n\x05\x65rror\x18\x01 \x01(\tH\x00\x12.\n\nhci_packet\x18\x02 \x01(\x0b\x32\x18.netsim.packet.HCIPacketH\x00\x12\x10\n\x06packet\x18\x03 \x01(\x0cH\x00\x42\x0f\n\rresponse_type2b\n\x0ePacketStreamer\x12P\n\rStreamPackets\x12\x1c.netsim.packet.PacketRequest\x1a\x1d.netsim.packet.PacketResponse(\x01\x30\x01\x62\x06proto3')
+
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'packet_streamer_pb2', globals())
+if _descriptor._USE_C_DESCRIPTORS == False:
+
+ DESCRIPTOR._options = None
+ _PACKETREQUEST._serialized_start=74
+ _PACKETREQUEST._serialized_end=221
+ _PACKETRESPONSE._serialized_start=223
+ _PACKETRESPONSE._serialized_end=339
+ _PACKETSTREAMER._serialized_start=341
+ _PACKETSTREAMER._serialized_end=439
+# @@protoc_insertion_point(module_scope)
diff --git a/bumble/transport/grpc_protobuf/packet_streamer_pb2.pyi b/bumble/transport/grpc_protobuf/packet_streamer_pb2.pyi
new file mode 100644
index 0000000..d867613
--- /dev/null
+++ b/bumble/transport/grpc_protobuf/packet_streamer_pb2.pyi
@@ -0,0 +1,27 @@
+from . import hci_packet_pb2 as _hci_packet_pb2
+from . import startup_pb2 as _startup_pb2
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from typing import ClassVar as _ClassVar, Mapping as _Mapping, Optional as _Optional, Union as _Union
+
+DESCRIPTOR: _descriptor.FileDescriptor
+
+class PacketRequest(_message.Message):
+ __slots__ = ["hci_packet", "initial_info", "packet"]
+ HCI_PACKET_FIELD_NUMBER: _ClassVar[int]
+ INITIAL_INFO_FIELD_NUMBER: _ClassVar[int]
+ PACKET_FIELD_NUMBER: _ClassVar[int]
+ hci_packet: _hci_packet_pb2.HCIPacket
+ initial_info: _startup_pb2.ChipInfo
+ packet: bytes
+ def __init__(self, initial_info: _Optional[_Union[_startup_pb2.ChipInfo, _Mapping]] = ..., hci_packet: _Optional[_Union[_hci_packet_pb2.HCIPacket, _Mapping]] = ..., packet: _Optional[bytes] = ...) -> None: ...
+
+class PacketResponse(_message.Message):
+ __slots__ = ["error", "hci_packet", "packet"]
+ ERROR_FIELD_NUMBER: _ClassVar[int]
+ HCI_PACKET_FIELD_NUMBER: _ClassVar[int]
+ PACKET_FIELD_NUMBER: _ClassVar[int]
+ error: str
+ hci_packet: _hci_packet_pb2.HCIPacket
+ packet: bytes
+ def __init__(self, error: _Optional[str] = ..., hci_packet: _Optional[_Union[_hci_packet_pb2.HCIPacket, _Mapping]] = ..., packet: _Optional[bytes] = ...) -> None: ...
diff --git a/bumble/transport/grpc_protobuf/packet_streamer_pb2_grpc.py b/bumble/transport/grpc_protobuf/packet_streamer_pb2_grpc.py
new file mode 100644
index 0000000..45ab653
--- /dev/null
+++ b/bumble/transport/grpc_protobuf/packet_streamer_pb2_grpc.py
@@ -0,0 +1,109 @@
+# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
+"""Client and server classes corresponding to protobuf-defined services."""
+import grpc
+
+from . import packet_streamer_pb2 as packet__streamer__pb2
+
+
+class PacketStreamerStub(object):
+ """*
+ This is the packet service for the network simulator.
+
+ Android Virtual Devices (AVDs) and accessory devices use this service to
+ connect to the network simulator and pass packets back and forth.
+
+ AVDs running in a guest VM are built with virtual controllers for each radio
+ chip. These controllers route chip requests to host emulators (qemu and
+ crosvm) using virtio and from there they are forwarded to this gRpc service.
+
+ This setup provides a transparent radio environment across AVDs and
+ accessories because the network simulator contains libraries to emulate
+ Bluetooth, 80211MAC, UWB, and Rtt chips.
+
+ """
+
+ def __init__(self, channel):
+ """Constructor.
+
+ Args:
+ channel: A grpc.Channel.
+ """
+ self.StreamPackets = channel.stream_stream(
+ '/netsim.packet.PacketStreamer/StreamPackets',
+ request_serializer=packet__streamer__pb2.PacketRequest.SerializeToString,
+ response_deserializer=packet__streamer__pb2.PacketResponse.FromString,
+ )
+
+
+class PacketStreamerServicer(object):
+ """*
+ This is the packet service for the network simulator.
+
+ Android Virtual Devices (AVDs) and accessory devices use this service to
+ connect to the network simulator and pass packets back and forth.
+
+ AVDs running in a guest VM are built with virtual controllers for each radio
+ chip. These controllers route chip requests to host emulators (qemu and
+ crosvm) using virtio and from there they are forwarded to this gRpc service.
+
+ This setup provides a transparent radio environment across AVDs and
+ accessories because the network simulator contains libraries to emulate
+ Bluetooth, 80211MAC, UWB, and Rtt chips.
+
+ """
+
+ def StreamPackets(self, request_iterator, context):
+ """Attach a virtual radio controller to the network simulation.
+ """
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+ context.set_details('Method not implemented!')
+ raise NotImplementedError('Method not implemented!')
+
+
+def add_PacketStreamerServicer_to_server(servicer, server):
+ rpc_method_handlers = {
+ 'StreamPackets': grpc.stream_stream_rpc_method_handler(
+ servicer.StreamPackets,
+ request_deserializer=packet__streamer__pb2.PacketRequest.FromString,
+ response_serializer=packet__streamer__pb2.PacketResponse.SerializeToString,
+ ),
+ }
+ generic_handler = grpc.method_handlers_generic_handler(
+ 'netsim.packet.PacketStreamer', rpc_method_handlers)
+ server.add_generic_rpc_handlers((generic_handler,))
+
+
+ # This class is part of an EXPERIMENTAL API.
+class PacketStreamer(object):
+ """*
+ This is the packet service for the network simulator.
+
+ Android Virtual Devices (AVDs) and accessory devices use this service to
+ connect to the network simulator and pass packets back and forth.
+
+ AVDs running in a guest VM are built with virtual controllers for each radio
+ chip. These controllers route chip requests to host emulators (qemu and
+ crosvm) using virtio and from there they are forwarded to this gRpc service.
+
+ This setup provides a transparent radio environment across AVDs and
+ accessories because the network simulator contains libraries to emulate
+ Bluetooth, 80211MAC, UWB, and Rtt chips.
+
+ """
+
+ @staticmethod
+ def StreamPackets(request_iterator,
+ target,
+ options=(),
+ channel_credentials=None,
+ call_credentials=None,
+ insecure=False,
+ compression=None,
+ wait_for_ready=None,
+ timeout=None,
+ metadata=None):
+ return grpc.experimental.stream_stream(request_iterator, target, '/netsim.packet.PacketStreamer/StreamPackets',
+ packet__streamer__pb2.PacketRequest.SerializeToString,
+ packet__streamer__pb2.PacketResponse.FromString,
+ options, channel_credentials,
+ insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
diff --git a/bumble/transport/grpc_protobuf/startup_pb2.py b/bumble/transport/grpc_protobuf/startup_pb2.py
new file mode 100644
index 0000000..532ac0e
--- /dev/null
+++ b/bumble/transport/grpc_protobuf/startup_pb2.py
@@ -0,0 +1,32 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: startup.proto
+"""Generated protocol buffer code."""
+from google.protobuf.internal import builder as _builder
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import descriptor_pool as _descriptor_pool
+from google.protobuf import symbol_database as _symbol_database
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+from . import common_pb2 as common__pb2
+
+
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\rstartup.proto\x12\x0enetsim.startup\x1a\x0c\x63ommon.proto\"\x7f\n\x0bStartupInfo\x12\x33\n\x07\x64\x65vices\x18\x01 \x03(\x0b\x32\".netsim.startup.StartupInfo.Device\x1a;\n\x06\x44\x65vice\x12\x0c\n\x04name\x18\x01 \x01(\t\x12#\n\x05\x63hips\x18\x02 \x03(\x0b\x32\x14.netsim.startup.Chip\"<\n\x08\x43hipInfo\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\"\n\x04\x63hip\x18\x02 \x01(\x0b\x32\x14.netsim.startup.Chip\"\x96\x01\n\x04\x43hip\x12%\n\x04kind\x18\x01 \x01(\x0e\x32\x17.netsim.common.ChipKind\x12\n\n\x02id\x18\x02 \x01(\t\x12\x14\n\x0cmanufacturer\x18\x03 \x01(\t\x12\x14\n\x0cproduct_name\x18\x04 \x01(\t\x12\r\n\x05\x66\x64_in\x18\x05 \x01(\x05\x12\x0e\n\x06\x66\x64_out\x18\x06 \x01(\x05\x12\x10\n\x08loopback\x18\x07 \x01(\x08\x62\x06proto3')
+
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'startup_pb2', globals())
+if _descriptor._USE_C_DESCRIPTORS == False:
+
+ DESCRIPTOR._options = None
+ _STARTUPINFO._serialized_start=47
+ _STARTUPINFO._serialized_end=174
+ _STARTUPINFO_DEVICE._serialized_start=115
+ _STARTUPINFO_DEVICE._serialized_end=174
+ _CHIPINFO._serialized_start=176
+ _CHIPINFO._serialized_end=236
+ _CHIP._serialized_start=239
+ _CHIP._serialized_end=389
+# @@protoc_insertion_point(module_scope)
diff --git a/bumble/transport/grpc_protobuf/startup_pb2.pyi b/bumble/transport/grpc_protobuf/startup_pb2.pyi
new file mode 100644
index 0000000..604d915
--- /dev/null
+++ b/bumble/transport/grpc_protobuf/startup_pb2.pyi
@@ -0,0 +1,46 @@
+from . import common_pb2 as _common_pb2
+from google.protobuf.internal import containers as _containers
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from typing import ClassVar as _ClassVar, Iterable as _Iterable, Mapping as _Mapping, Optional as _Optional, Union as _Union
+
+DESCRIPTOR: _descriptor.FileDescriptor
+
+class Chip(_message.Message):
+ __slots__ = ["fd_in", "fd_out", "id", "kind", "loopback", "manufacturer", "product_name"]
+ FD_IN_FIELD_NUMBER: _ClassVar[int]
+ FD_OUT_FIELD_NUMBER: _ClassVar[int]
+ ID_FIELD_NUMBER: _ClassVar[int]
+ KIND_FIELD_NUMBER: _ClassVar[int]
+ LOOPBACK_FIELD_NUMBER: _ClassVar[int]
+ MANUFACTURER_FIELD_NUMBER: _ClassVar[int]
+ PRODUCT_NAME_FIELD_NUMBER: _ClassVar[int]
+ fd_in: int
+ fd_out: int
+ id: str
+ kind: _common_pb2.ChipKind
+ loopback: bool
+ manufacturer: str
+ product_name: str
+ def __init__(self, kind: _Optional[_Union[_common_pb2.ChipKind, str]] = ..., id: _Optional[str] = ..., manufacturer: _Optional[str] = ..., product_name: _Optional[str] = ..., fd_in: _Optional[int] = ..., fd_out: _Optional[int] = ..., loopback: bool = ...) -> None: ...
+
+class ChipInfo(_message.Message):
+ __slots__ = ["chip", "name"]
+ CHIP_FIELD_NUMBER: _ClassVar[int]
+ NAME_FIELD_NUMBER: _ClassVar[int]
+ chip: Chip
+ name: str
+ def __init__(self, name: _Optional[str] = ..., chip: _Optional[_Union[Chip, _Mapping]] = ...) -> None: ...
+
+class StartupInfo(_message.Message):
+ __slots__ = ["devices"]
+ class Device(_message.Message):
+ __slots__ = ["chips", "name"]
+ CHIPS_FIELD_NUMBER: _ClassVar[int]
+ NAME_FIELD_NUMBER: _ClassVar[int]
+ chips: _containers.RepeatedCompositeFieldContainer[Chip]
+ name: str
+ def __init__(self, name: _Optional[str] = ..., chips: _Optional[_Iterable[_Union[Chip, _Mapping]]] = ...) -> None: ...
+ DEVICES_FIELD_NUMBER: _ClassVar[int]
+ devices: _containers.RepeatedCompositeFieldContainer[StartupInfo.Device]
+ def __init__(self, devices: _Optional[_Iterable[_Union[StartupInfo.Device, _Mapping]]] = ...) -> None: ...
diff --git a/bumble/transport/grpc_protobuf/startup_pb2_grpc.py b/bumble/transport/grpc_protobuf/startup_pb2_grpc.py
new file mode 100644
index 0000000..2daafff
--- /dev/null
+++ b/bumble/transport/grpc_protobuf/startup_pb2_grpc.py
@@ -0,0 +1,4 @@
+# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
+"""Client and server classes corresponding to protobuf-defined services."""
+import grpc
+
diff --git a/bumble/transport/hci_socket.py b/bumble/transport/hci_socket.py
index f74a535..4e1ad99 100644
--- a/bumble/transport/hci_socket.py
+++ b/bumble/transport/hci_socket.py
@@ -40,15 +40,21 @@ async def open_hci_socket_transport(spec):
or a 0-based integer to indicate the adapter number.
'''
- HCI_CHANNEL_USER = 1
+ HCI_CHANNEL_USER = 1 # pylint: disable=invalid-name
# Create a raw HCI socket
try:
- hci_socket = socket.socket(socket.AF_BLUETOOTH, socket.SOCK_RAW | socket.SOCK_NONBLOCK, socket.BTPROTO_HCI)
- except AttributeError:
+ hci_socket = socket.socket(
+ socket.AF_BLUETOOTH,
+ socket.SOCK_RAW | socket.SOCK_NONBLOCK,
+ socket.BTPROTO_HCI,
+ )
+ except AttributeError as error:
# Not supported on this platform
logger.info("HCI sockets not supported on this platform")
- raise Exception('Bluetooth HCI sockets not supported on this platform')
+ raise Exception(
+ 'Bluetooth HCI sockets not supported on this platform'
+ ) from error
# Compute the adapter index
if spec is None:
@@ -62,20 +68,37 @@ async def open_hci_socket_transport(spec):
try:
ctypes.cdll.LoadLibrary('libc.so.6')
libc = ctypes.CDLL('libc.so.6', use_errno=True)
- except OSError:
+ except OSError as error:
logger.info("HCI sockets not supported on this platform")
- raise Exception('Bluetooth HCI sockets not supported on this platform')
+ raise Exception(
+ 'Bluetooth HCI sockets not supported on this platform'
+ ) from error
libc.bind.argtypes = (ctypes.c_int, ctypes.POINTER(ctypes.c_char), ctypes.c_int)
libc.bind.restype = ctypes.c_int
- bind_address = struct.pack('<HHH', socket.AF_BLUETOOTH, adapter_index, HCI_CHANNEL_USER)
- if libc.bind(hci_socket.fileno(), ctypes.create_string_buffer(bind_address), len(bind_address)) != 0:
+ bind_address = struct.pack(
+ # pylint: disable=no-member
+ '<HHH',
+ socket.AF_BLUETOOTH,
+ adapter_index,
+ HCI_CHANNEL_USER,
+ )
+ if (
+ libc.bind(
+ hci_socket.fileno(),
+ ctypes.create_string_buffer(bind_address),
+ len(bind_address),
+ )
+ != 0
+ ):
raise IOError(ctypes.get_errno(), os.strerror(ctypes.get_errno()))
class HciSocketSource(ParserSource):
- def __init__(self, socket):
+ def __init__(self, hci_socket):
super().__init__()
- self.socket = socket
- asyncio.get_running_loop().add_reader(socket.fileno(), self.recv_until_would_block)
+ self.socket = hci_socket
+ asyncio.get_running_loop().add_reader(
+ self.socket.fileno(), self.recv_until_would_block
+ )
def recv_until_would_block(self):
logger.debug('recv until would block +++')
@@ -92,9 +115,9 @@ async def open_hci_socket_transport(spec):
asyncio.get_running_loop().remove_reader(self.socket.fileno())
class HciSocketSink:
- def __init__(self, socket):
- self.socket = socket
- self.packets = collections.deque()
+ def __init__(self, hci_socket):
+ self.socket = hci_socket
+ self.packets = collections.deque()
self.writer_added = False
def send_until_would_block(self):
@@ -112,9 +135,14 @@ async def open_hci_socket_transport(spec):
break
if self.packets:
- # There's still something to send, ensure that we are monitoring the socket
+ # There's still something to send, ensure that we are monitoring the
+ # socket
if not self.writer_added:
- asyncio.get_running_loop().add_writer(socket.fileno(), self.send_until_would_block)
+ asyncio.get_running_loop().add_writer(
+ # pylint: disable=no-member
+ self.socket.fileno(),
+ self.send_until_would_block,
+ )
self.writer_added = True
else:
# Nothing left to send, stop monitoring the socket
@@ -131,9 +159,9 @@ async def open_hci_socket_transport(spec):
asyncio.get_running_loop().remove_writer(self.socket.fileno())
class HciSocketTransport(Transport):
- def __init__(self, socket, source, sink):
+ def __init__(self, hci_socket, source, sink):
super().__init__(source, sink)
- self.socket = socket
+ self.socket = hci_socket
async def close(self):
logger.debug('closing HCI socket transport')
diff --git a/bumble/transport/pty.py b/bumble/transport/pty.py
index 2399d14..e6e2ab5 100644
--- a/bumble/transport/pty.py
+++ b/bumble/transport/pty.py
@@ -47,13 +47,11 @@ async def open_pty_transport(spec):
tty.setraw(replica)
read_transport, packet_source = await asyncio.get_running_loop().connect_read_pipe(
- lambda: StreamPacketSource(),
- io.open(primary, 'rb', closefd=False)
+ StreamPacketSource, io.open(primary, 'rb', closefd=False)
)
write_transport, _ = await asyncio.get_running_loop().connect_write_pipe(
- lambda: asyncio.BaseProtocol(),
- io.open(primary, 'wb', closefd=False)
+ asyncio.BaseProtocol, io.open(primary, 'wb', closefd=False)
)
packet_sink = StreamPacketSink(write_transport)
diff --git a/bumble/transport/py.typed b/bumble/transport/py.typed
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/bumble/transport/py.typed
diff --git a/bumble/transport/pyusb.py b/bumble/transport/pyusb.py
index ea5bc0d..8ad8598 100644
--- a/bumble/transport/pyusb.py
+++ b/bumble/transport/pyusb.py
@@ -17,14 +17,15 @@
# -----------------------------------------------------------------------------
import asyncio
import logging
-import usb.core
-import usb.util
import threading
import time
-from colors import color
+
+import usb.core
+import usb.util
from .common import Transport, ParserSource
from .. import hci
+from ..colors import color
# -----------------------------------------------------------------------------
@@ -48,25 +49,26 @@ async def open_pyusb_transport(spec):
04b4:f901 --> the BT USB dongle with vendor=04b4 and product=f901
'''
- USB_RECIPIENT_DEVICE = 0x00
- USB_REQUEST_TYPE_CLASS = 0x01 << 5
- USB_ENDPOINT_EVENTS_IN = 0x81
- USB_ENDPOINT_ACL_IN = 0x82
- USB_ENDPOINT_SCO_IN = 0x83
- USB_ENDPOINT_ACL_OUT = 0x02
+ # pylint: disable=invalid-name
+ USB_RECIPIENT_DEVICE = 0x00
+ USB_REQUEST_TYPE_CLASS = 0x01 << 5
+ USB_ENDPOINT_EVENTS_IN = 0x81
+ USB_ENDPOINT_ACL_IN = 0x82
+ USB_ENDPOINT_SCO_IN = 0x83
+ USB_ENDPOINT_ACL_OUT = 0x02
# USB_ENDPOINT_SCO_OUT = 0x03
- USB_DEVICE_CLASS_WIRELESS_CONTROLLER = 0xE0
- USB_DEVICE_SUBCLASS_RF_CONTROLLER = 0x01
+ USB_DEVICE_CLASS_WIRELESS_CONTROLLER = 0xE0
+ USB_DEVICE_SUBCLASS_RF_CONTROLLER = 0x01
USB_DEVICE_PROTOCOL_BLUETOOTH_PRIMARY_CONTROLLER = 0x01
- READ_SIZE = 1024
+ READ_SIZE = 1024
READ_TIMEOUT = 1000
class UsbPacketSink:
def __init__(self, device):
- self.device = device
- self.thread = threading.Thread(target=self.run)
- self.loop = asyncio.get_running_loop()
+ self.device = device
+ self.thread = threading.Thread(target=self.run)
+ self.loop = asyncio.get_running_loop()
self.stop_event = None
def on_packet(self, packet):
@@ -80,9 +82,17 @@ async def open_pyusb_transport(spec):
if packet_type == hci.HCI_ACL_DATA_PACKET:
self.device.write(USB_ENDPOINT_ACL_OUT, packet[1:])
elif packet_type == hci.HCI_COMMAND_PACKET:
- self.device.ctrl_transfer(USB_RECIPIENT_DEVICE | USB_REQUEST_TYPE_CLASS, 0, 0, 0, packet[1:])
+ self.device.ctrl_transfer(
+ USB_RECIPIENT_DEVICE | USB_REQUEST_TYPE_CLASS,
+ 0,
+ 0,
+ 0,
+ packet[1:],
+ )
else:
- logger.warning(color(f'unsupported packet type {packet_type}', 'red'))
+ logger.warning(
+ color(f'unsupported packet type {packet_type}', 'red')
+ )
except usb.core.USBTimeoutError:
logger.warning('USB Write Timeout')
except usb.core.USBError as error:
@@ -100,22 +110,21 @@ async def open_pyusb_transport(spec):
def run(self):
while self.stop_event is None:
time.sleep(1)
- self.loop.call_soon_threadsafe(lambda: self.stop_event.set())
+ self.loop.call_soon_threadsafe(self.stop_event.set)
class UsbPacketSource(asyncio.Protocol, ParserSource):
def __init__(self, device, sco_enabled):
super().__init__()
- self.device = device
- self.loop = asyncio.get_running_loop()
- self.queue = asyncio.Queue()
+ self.device = device
+ self.loop = asyncio.get_running_loop()
+ self.queue = asyncio.Queue()
+ self.dequeue_task = None
self.event_thread = threading.Thread(
- target=self.run,
- args=(USB_ENDPOINT_EVENTS_IN, hci.HCI_EVENT_PACKET)
+ target=self.run, args=(USB_ENDPOINT_EVENTS_IN, hci.HCI_EVENT_PACKET)
)
self.event_thread.stop_event = None
self.acl_thread = threading.Thread(
- target=self.run,
- args=(USB_ENDPOINT_ACL_IN, hci.HCI_ACL_DATA_PACKET)
+ target=self.run, args=(USB_ENDPOINT_ACL_IN, hci.HCI_ACL_DATA_PACKET)
)
self.acl_thread.stop_event = None
@@ -124,12 +133,12 @@ async def open_pyusb_transport(spec):
if sco_enabled:
self.sco_thread = threading.Thread(
target=self.run,
- args=(USB_ENDPOINT_SCO_IN, hci.HCI_SYNCHRONOUS_DATA_PACKET)
+ args=(USB_ENDPOINT_SCO_IN, hci.HCI_SYNCHRONOUS_DATA_PACKET),
)
self.sco_thread.stop_event = None
- def data_received(self, packet):
- self.parser.feed_data(packet)
+ def data_received(self, data):
+ self.parser.feed_data(data)
def enqueue(self, packet):
self.queue.put_nowait(packet)
@@ -155,7 +164,7 @@ async def open_pyusb_transport(spec):
# Create stop events and wait for them to be signaled
self.event_thread.stop_event = asyncio.Event()
- self.acl_thread.stop_event = asyncio.Event()
+ self.acl_thread.stop_event = asyncio.Event()
await self.event_thread.stop_event.wait()
await self.acl_thread.stop_event.wait()
if self.sco_enabled:
@@ -173,16 +182,17 @@ async def open_pyusb_transport(spec):
except usb.core.USBTimeoutError:
continue
except usb.core.USBError:
- # Don't log this: because pyusb doesn't really support multiple threads
- # reading at the same time, we can get occasional USBError(errno=5)
- # Input/Output errors reported, but they seem to be harmless.
+ # Don't log this: because pyusb doesn't really support multiple
+ # threads reading at the same time, we can get occasional
+ # USBError(errno=5) Input/Output errors reported, but they seem to
+ # be harmless.
# Until support for async or multi-thread support is added to pyusb,
# we'll just live with this as is...
# logger.warning(f'USB read error: {error}')
time.sleep(1) # Sleep one second to avoid busy looping
stop_event = current_thread.stop_event
- self.loop.call_soon_threadsafe(lambda: stop_event.set())
+ self.loop.call_soon_threadsafe(stop_event.set)
class UsbTransport(Transport):
def __init__(self, device, source, sink):
@@ -194,18 +204,28 @@ async def open_pyusb_transport(spec):
await self.sink.stop()
usb.util.release_interface(self.device, 0)
+ usb_find = usb.core.find
+ try:
+ import libusb_package
+ except ImportError:
+ logger.debug('libusb_package is not available')
+ else:
+ usb_find = libusb_package.find
+
# Find the device according to the spec moniker
if ':' in spec:
vendor_id, product_id = spec.split(':')
- device = usb.core.find(idVendor=int(vendor_id, 16), idProduct=int(product_id, 16))
+ device = usb_find(idVendor=int(vendor_id, 16), idProduct=int(product_id, 16))
else:
device_index = int(spec)
- devices = list(usb.core.find(
- find_all = 1,
- bDeviceClass = USB_DEVICE_CLASS_WIRELESS_CONTROLLER,
- bDeviceSubClass = USB_DEVICE_SUBCLASS_RF_CONTROLLER,
- bDeviceProtocol = USB_DEVICE_PROTOCOL_BLUETOOTH_PRIMARY_CONTROLLER
- ))
+ devices = list(
+ usb_find(
+ find_all=1,
+ bDeviceClass=USB_DEVICE_CLASS_WIRELESS_CONTROLLER,
+ bDeviceSubClass=USB_DEVICE_SUBCLASS_RF_CONTROLLER,
+ bDeviceProtocol=USB_DEVICE_PROTOCOL_BLUETOOTH_PRIMARY_CONTROLLER,
+ )
+ )
if len(devices) > device_index:
device = devices[device_index]
else:
@@ -232,6 +252,7 @@ async def open_pyusb_transport(spec):
# Select an alternate setting for SCO, if available
sco_enabled = False
+ # pylint: disable=line-too-long
# NOTE: this is disabled for now, because SCO with alternate settings is broken,
# see: https://github.com/libusb/libusb/issues/36
#
@@ -273,4 +294,4 @@ async def open_pyusb_transport(spec):
packet_source.start()
packet_sink.start()
- return UsbTransport(device, packet_source, packet_sink) \ No newline at end of file
+ return UsbTransport(device, packet_source, packet_sink)
diff --git a/bumble/transport/serial.py b/bumble/transport/serial.py
index b760a29..c83b605 100644
--- a/bumble/transport/serial.py
+++ b/bumble/transport/serial.py
@@ -60,13 +60,12 @@ async def open_serial_transport(spec):
device = spec
serial_transport, packet_source = await serial_asyncio.create_serial_connection(
asyncio.get_running_loop(),
- lambda: StreamPacketSource(),
+ StreamPacketSource,
device,
baudrate=speed,
rtscts=rtscts,
- dsrdtr=dsrdtr
+ dsrdtr=dsrdtr,
)
packet_sink = StreamPacketSink(serial_transport)
return Transport(packet_source, packet_sink)
-
diff --git a/bumble/transport/tcp_client.py b/bumble/transport/tcp_client.py
index e250f25..934a521 100644
--- a/bumble/transport/tcp_client.py
+++ b/bumble/transport/tcp_client.py
@@ -37,13 +37,13 @@ async def open_tcp_client_transport(spec):
'''
class TcpPacketSource(StreamPacketSource):
- def connection_lost(self, error):
- logger.debug(f'connection lost: {error}')
- self.terminated.set_result(error)
+ def connection_lost(self, exc):
+ logger.debug(f'connection lost: {exc}')
+ self.terminated.set_result(exc)
remote_host, remote_port = spec.split(':')
tcp_transport, packet_source = await asyncio.get_running_loop().create_connection(
- lambda: TcpPacketSource(),
+ TcpPacketSource,
host=remote_host,
port=int(remote_port),
)
diff --git a/bumble/transport/tcp_server.py b/bumble/transport/tcp_server.py
index 6806683..11b0453 100644
--- a/bumble/transport/tcp_server.py
+++ b/bumble/transport/tcp_server.py
@@ -45,12 +45,12 @@ async def open_tcp_server_transport(spec):
class TcpServerProtocol:
def __init__(self, packet_source, packet_sink):
self.packet_source = packet_source
- self.packet_sink = packet_sink
+ self.packet_sink = packet_sink
# Called when a new connection is established
def connection_made(self, transport):
- peername = transport.get_extra_info('peername')
- logger.debug('connection from {}'.format(peername))
+ peer_name = transport.get_extra_info('peer_name')
+ logger.debug(f'connection from {peer_name}')
self.packet_sink.transport = transport
# Called when the client is disconnected
@@ -78,7 +78,7 @@ async def open_tcp_server_transport(spec):
local_host, local_port = spec.split(':')
packet_source = StreamPacketSource()
- packet_sink = TcpServerPacketSink()
+ packet_sink = TcpServerPacketSink()
await asyncio.get_running_loop().create_server(
lambda: TcpServerProtocol(packet_source, packet_sink),
host=local_host if local_host != '_' else None,
diff --git a/bumble/transport/udp.py b/bumble/transport/udp.py
index f4c59ea..e5e26fa 100644
--- a/bumble/transport/udp.py
+++ b/bumble/transport/udp.py
@@ -53,10 +53,13 @@ async def open_udp_transport(spec):
local, remote = spec.split(',')
local_host, local_port = local.split(':')
remote_host, remote_port = remote.split(':')
- udp_transport, packet_source = await asyncio.get_running_loop().create_datagram_endpoint(
- lambda: UdpPacketSource(),
+ (
+ udp_transport,
+ packet_source,
+ ) = await asyncio.get_running_loop().create_datagram_endpoint(
+ UdpPacketSource,
local_addr=(local_host, int(local_port)),
- remote_addr=(remote_host, int(remote_port))
+ remote_addr=(remote_host, int(remote_port)),
)
packet_sink = UdpPacketSink(udp_transport)
diff --git a/bumble/transport/usb.py b/bumble/transport/usb.py
index dfc169f..68c5a6f 100644
--- a/bumble/transport/usb.py
+++ b/bumble/transport/usb.py
@@ -17,13 +17,16 @@
# -----------------------------------------------------------------------------
import asyncio
import logging
-import usb1
import threading
import collections
-from colors import color
+import ctypes
+import platform
+
+import usb1
from .common import Transport, ParserSource
from .. import hci
+from ..colors import color
# -----------------------------------------------------------------------------
@@ -33,42 +36,88 @@ logger = logging.getLogger(__name__)
# -----------------------------------------------------------------------------
+def load_libusb():
+ '''
+ Attempt to load the libusb-1.0 C library from libusb_package in site-packages.
+ If the library exists, we create a DLL object and initialize the usb1 backend.
+ This only needs to be done once, but before a usb1.USBContext is created.
+ If the library does not exists, do nothing and usb1 will search default system paths
+ when usb1.USBContext is created.
+ '''
+ try:
+ import libusb_package
+ except ImportError:
+ logger.debug('libusb_package is not available')
+ else:
+ if libusb_path := libusb_package.get_library_path():
+ logger.debug(f'loading libusb library at {libusb_path}')
+ dll_loader = (
+ ctypes.WinDLL if platform.system() == 'Windows' else ctypes.CDLL
+ )
+ libusb_dll = dll_loader(
+ str(libusb_path), use_errno=True, use_last_error=True
+ )
+ usb1.loadLibrary(libusb_dll)
+
+
async def open_usb_transport(spec):
'''
Open a USB transport.
- The parameter string has this syntax:
- either <index> or <vendor>:<product>[/<serial-number>]
+ The moniker string has this syntax:
+ either <index> or
+ <vendor>:<product> or
+ <vendor>:<product>/<serial-number>] or
+ <vendor>:<product>#<index>
With <index> as the 0-based index to select amongst all the devices that appear
to be supporting Bluetooth HCI (0 being the first one), or
Where <vendor> and <product> are the vendor ID and product ID in hexadecimal. The
- /<serial-number> suffix max be specified when more than one device with the same
- vendor and product identifiers are present.
+ /<serial-number> suffix or #<index> suffix max be specified when more than one
+ device with the same vendor and product identifiers are present.
+
+ In addition, if the moniker ends with the symbol "!", the device will be used in
+ "forced" mode:
+ the first USB interface of the device will be used, regardless of the interface
+ class/subclass.
+ This may be useful for some devices that use a custom class/subclass but may
+ nonetheless work as-is.
Examples:
0 --> the first BT USB dongle
04b4:f901 --> the BT USB dongle with vendor=04b4 and product=f901
- 04b4:f901/00E04C239987 --> the BT USB dongle with vendor=04b4 and product=f901 and serial number 00E04C239987
+ 04b4:f901#2 --> the third USB device with vendor=04b4 and product=f901
+ 04b4:f901/00E04C239987 --> the BT USB dongle with vendor=04b4 and product=f901 and
+ serial number 00E04C239987
+ usb:0B05:17CB! --> the BT USB dongle vendor=0B05 and product=17CB, in "forced" mode.
'''
- USB_RECIPIENT_DEVICE = 0x00
- USB_REQUEST_TYPE_CLASS = 0x01 << 5
- USB_ENDPOINT_EVENTS_IN = 0x81
- USB_ENDPOINT_ACL_IN = 0x82
- USB_ENDPOINT_ACL_OUT = 0x02
- USB_DEVICE_CLASS_WIRELESS_CONTROLLER = 0xE0
- USB_DEVICE_SUBCLASS_RF_CONTROLLER = 0x01
+ # pylint: disable=invalid-name
+ USB_RECIPIENT_DEVICE = 0x00
+ USB_REQUEST_TYPE_CLASS = 0x01 << 5
+ USB_DEVICE_CLASS_DEVICE = 0x00
+ USB_DEVICE_CLASS_WIRELESS_CONTROLLER = 0xE0
+ USB_DEVICE_SUBCLASS_RF_CONTROLLER = 0x01
USB_DEVICE_PROTOCOL_BLUETOOTH_PRIMARY_CONTROLLER = 0x01
+ USB_ENDPOINT_TRANSFER_TYPE_BULK = 0x02
+ USB_ENDPOINT_TRANSFER_TYPE_INTERRUPT = 0x03
+ USB_ENDPOINT_IN = 0x80
+
+ USB_BT_HCI_CLASS_TUPLE = (
+ USB_DEVICE_CLASS_WIRELESS_CONTROLLER,
+ USB_DEVICE_SUBCLASS_RF_CONTROLLER,
+ USB_DEVICE_PROTOCOL_BLUETOOTH_PRIMARY_CONTROLLER,
+ )
READ_SIZE = 1024
class UsbPacketSink:
- def __init__(self, device):
- self.device = device
- self.transfer = device.getTransfer()
- self.packets = collections.deque() # Queue of packets waiting to be sent
- self.loop = asyncio.get_running_loop()
+ def __init__(self, device, acl_out):
+ self.device = device
+ self.acl_out = acl_out
+ self.transfer = device.getTransfer()
+ self.packets = collections.deque() # Queue of packets waiting to be sent
+ self.loop = asyncio.get_running_loop()
self.cancel_done = self.loop.create_future()
- self.closed = False
+ self.closed = False
def start(self):
pass
@@ -92,12 +141,15 @@ async def open_usb_transport(spec):
status = transfer.getStatus()
# logger.debug(f'<<< USB out transfer callback: status={status}')
+ # pylint: disable=no-member
if status == usb1.TRANSFER_COMPLETED:
self.loop.call_soon_threadsafe(self.on_packet_sent_)
elif status == usb1.TRANSFER_CANCELLED:
self.loop.call_soon_threadsafe(self.cancel_done.set_result, None)
else:
- logger.warning(color(f'!!! out transfer not completed: status={status}', 'red'))
+ logger.warning(
+ color(f'!!! out transfer not completed: status={status}', 'red')
+ )
def on_packet_sent_(self):
if self.packets:
@@ -112,32 +164,38 @@ async def open_usb_transport(spec):
packet_type = packet[0]
if packet_type == hci.HCI_ACL_DATA_PACKET:
self.transfer.setBulk(
- USB_ENDPOINT_ACL_OUT,
- packet[1:],
- callback=self.on_packet_sent
+ self.acl_out, packet[1:], callback=self.on_packet_sent
)
logger.debug('submit ACL')
self.transfer.submit()
elif packet_type == hci.HCI_COMMAND_PACKET:
self.transfer.setControl(
- USB_RECIPIENT_DEVICE | USB_REQUEST_TYPE_CLASS, 0, 0, 0,
+ USB_RECIPIENT_DEVICE | USB_REQUEST_TYPE_CLASS,
+ 0,
+ 0,
+ 0,
packet[1:],
- callback=self.on_packet_sent
+ callback=self.on_packet_sent,
)
logger.debug('submit COMMAND')
self.transfer.submit()
else:
logger.warning(color(f'unsupported packet type {packet_type}', 'red'))
- async def close(self):
+ def close(self):
self.closed = True
+ async def terminate(self):
+ if not self.closed:
+ self.close()
+
# Empty the packet queue so that we don't send any more data
self.packets.clear()
# If we have a transfer in flight, cancel it
if self.transfer.isSubmitted():
- # Try to cancel the transfer, but that may fail because it may have already completed
+ # Try to cancel the transfer, but that may fail because it may have
+ # already completed
try:
self.transfer.cancel()
@@ -148,18 +206,23 @@ async def open_usb_transport(spec):
logger.debug('OUT transfer likely already completed')
class UsbPacketSource(asyncio.Protocol, ParserSource):
- def __init__(self, context, device):
+ def __init__(self, context, device, acl_in, events_in):
super().__init__()
- self.context = context
- self.device = device
- self.loop = asyncio.get_running_loop()
- self.queue = asyncio.Queue()
- self.closed = False
+ self.context = context
+ self.device = device
+ self.acl_in = acl_in
+ self.events_in = events_in
+ self.loop = asyncio.get_running_loop()
+ self.queue = asyncio.Queue()
+ self.dequeue_task = None
+ self.closed = False
self.event_loop_done = self.loop.create_future()
self.cancel_done = {
- hci.HCI_EVENT_PACKET: self.loop.create_future(),
- hci.HCI_ACL_DATA_PACKET: self.loop.create_future()
+ hci.HCI_EVENT_PACKET: self.loop.create_future(),
+ hci.HCI_ACL_DATA_PACKET: self.loop.create_future(),
}
+ self.events_in_transfer = None
+ self.acl_in_transfer = None
# Create a thread to process events
self.event_thread = threading.Thread(target=self.run)
@@ -168,19 +231,19 @@ async def open_usb_transport(spec):
# Set up transfer objects for input
self.events_in_transfer = device.getTransfer()
self.events_in_transfer.setInterrupt(
- USB_ENDPOINT_EVENTS_IN,
+ self.events_in,
READ_SIZE,
callback=self.on_packet_received,
- user_data=hci.HCI_EVENT_PACKET
+ user_data=hci.HCI_EVENT_PACKET,
)
self.events_in_transfer.submit()
self.acl_in_transfer = device.getTransfer()
self.acl_in_transfer.setBulk(
- USB_ENDPOINT_ACL_IN,
+ self.acl_in,
READ_SIZE,
callback=self.on_packet_received,
- user_data=hci.HCI_ACL_DATA_PACKET
+ user_data=hci.HCI_ACL_DATA_PACKET,
)
self.acl_in_transfer.submit()
@@ -190,16 +253,28 @@ async def open_usb_transport(spec):
def on_packet_received(self, transfer):
packet_type = transfer.getUserData()
status = transfer.getStatus()
- # logger.debug(f'<<< USB IN transfer callback: status={status} packet_type={packet_type}')
+ # logger.debug(
+ # f'<<< USB IN transfer callback: status={status} '
+ # f'packet_type={packet_type} '
+ # f'length={transfer.getActualLength()}'
+ # )
+ # pylint: disable=no-member
if status == usb1.TRANSFER_COMPLETED:
- packet = bytes([packet_type]) + transfer.getBuffer()[:transfer.getActualLength()]
+ packet = (
+ bytes([packet_type])
+ + transfer.getBuffer()[: transfer.getActualLength()]
+ )
self.loop.call_soon_threadsafe(self.queue.put_nowait, packet)
elif status == usb1.TRANSFER_CANCELLED:
- self.loop.call_soon_threadsafe(self.cancel_done[packet_type].set_result, None)
+ self.loop.call_soon_threadsafe(
+ self.cancel_done[packet_type].set_result, None
+ )
return
else:
- logger.warning(color(f'!!! transfer not completed: status={status}', 'red'))
+ logger.warning(
+ color(f'!!! transfer not completed: status={status}', 'red')
+ )
# Re-submit the transfer so we can receive more data
transfer.submit()
@@ -214,7 +289,11 @@ async def open_usb_transport(spec):
def run(self):
logger.debug('starting USB event loop')
- while self.events_in_transfer.isSubmitted() or self.acl_in_transfer.isSubmitted():
+ while (
+ self.events_in_transfer.isSubmitted()
+ or self.acl_in_transfer.isSubmitted()
+ ):
+ # pylint: disable=no-member
try:
self.context.handleEvents()
except usb1.USBErrorInterrupted:
@@ -223,75 +302,130 @@ async def open_usb_transport(spec):
logger.debug('USB event loop done')
self.loop.call_soon_threadsafe(self.event_loop_done.set_result, None)
- async def close(self):
+ def close(self):
self.closed = True
+
+ async def terminate(self):
+ if not self.closed:
+ self.close()
+
self.dequeue_task.cancel()
# Cancel the transfers
for transfer in (self.events_in_transfer, self.acl_in_transfer):
if transfer.isSubmitted():
- # Try to cancel the transfer, but that may fail because it may have already completed
+ # Try to cancel the transfer, but that may fail because it may have
+ # already completed
packet_type = transfer.getUserData()
try:
transfer.cancel()
- logger.debug(f'waiting for IN[{packet_type}] transfer cancellation to be done...')
+ logger.debug(
+ f'waiting for IN[{packet_type}] transfer cancellation '
+ 'to be done...'
+ )
await self.cancel_done[packet_type]
logger.debug(f'IN[{packet_type}] transfer cancellation done')
except usb1.USBError:
- logger.debug(f'IN[{packet_type}] transfer likely already completed')
+ logger.debug(
+ f'IN[{packet_type}] transfer likely already completed'
+ )
# Wait for the thread to terminate
await self.event_loop_done
class UsbTransport(Transport):
- def __init__(self, context, device, interface, source, sink):
+ def __init__(self, context, device, interface, setting, source, sink):
super().__init__(source, sink)
- self.context = context
- self.device = device
+ self.context = context
+ self.device = device
self.interface = interface
# Get exclusive access
device.claimInterface(interface)
+ # Set the alternate setting if not the default
+ if setting != 0:
+ device.setInterfaceAltSetting(interface, setting)
+
# The source and sink can now start
source.start()
sink.start()
async def close(self):
- await self.source.close()
- await self.sink.close()
+ self.source.close()
+ self.sink.close()
+ await self.source.terminate()
+ await self.sink.terminate()
self.device.releaseInterface(self.interface)
self.device.close()
self.context.close()
# Find the device according to the spec moniker
+ load_libusb()
context = usb1.USBContext()
context.open()
try:
found = None
+
+ if spec.endswith('!'):
+ spec = spec[:-1]
+ forced_mode = True
+ else:
+ forced_mode = False
+
if ':' in spec:
vendor_id, product_id = spec.split(':')
+ serial_number = None
+ device_index = 0
if '/' in product_id:
product_id, serial_number = product_id.split('/')
- for device in context.getDeviceIterator(skip_on_error=True):
- if (
- device.getVendorID() == int(vendor_id, 16) and
- device.getProductID() == int(product_id, 16) and
- device.getSerialNumber() == serial_number
- ):
+ elif '#' in product_id:
+ product_id, device_index_str = product_id.split('#')
+ device_index = int(device_index_str)
+
+ for device in context.getDeviceIterator(skip_on_error=True):
+ try:
+ device_serial_number = device.getSerialNumber()
+ except usb1.USBError:
+ device_serial_number = None
+ if (
+ device.getVendorID() == int(vendor_id, 16)
+ and device.getProductID() == int(product_id, 16)
+ and (serial_number is None or serial_number == device_serial_number)
+ ):
+ if device_index == 0:
found = device
break
- device.close()
- else:
- found = context.getByVendorIDAndProductID(int(vendor_id, 16), int(product_id, 16), skip_on_error=True)
+ device_index -= 1
+ device.close()
else:
+ # Look for a compatible device by index
+ def device_is_bluetooth_hci(device):
+ # Check if the device class indicates a match
+ if (
+ device.getDeviceClass(),
+ device.getDeviceSubClass(),
+ device.getDeviceProtocol(),
+ ) == USB_BT_HCI_CLASS_TUPLE:
+ return True
+
+ # If the device class is 'Device', look for a matching interface
+ if device.getDeviceClass() == USB_DEVICE_CLASS_DEVICE:
+ for configuration in device:
+ for interface in configuration:
+ for setting in interface:
+ if (
+ setting.getClass(),
+ setting.getSubClass(),
+ setting.getProtocol(),
+ ) == USB_BT_HCI_CLASS_TUPLE:
+ return True
+
+ return False
+
device_index = int(spec)
for device in context.getDeviceIterator(skip_on_error=True):
- if (
- device.getDeviceClass() == USB_DEVICE_CLASS_WIRELESS_CONTROLLER and
- device.getDeviceSubClass() == USB_DEVICE_SUBCLASS_RF_CONTROLLER and
- device.getDeviceProtocol() == USB_DEVICE_PROTOCOL_BLUETOOTH_PRIMARY_CONTROLLER
- ):
+ if device_is_bluetooth_hci(device):
if device_index == 0:
found = device
break
@@ -303,34 +437,107 @@ async def open_usb_transport(spec):
raise ValueError('device not found')
logger.debug(f'USB Device: {found}')
+
+ # Look for the first interface with the right class and endpoints
+ def find_endpoints(device):
+ # pylint: disable-next=too-many-nested-blocks
+ for (configuration_index, configuration) in enumerate(device):
+ interface = None
+ for interface in configuration:
+ setting = None
+ for setting in interface:
+ if (
+ not forced_mode
+ and (
+ setting.getClass(),
+ setting.getSubClass(),
+ setting.getProtocol(),
+ )
+ != USB_BT_HCI_CLASS_TUPLE
+ ):
+ continue
+
+ events_in = None
+ acl_in = None
+ acl_out = None
+ for endpoint in setting:
+ attributes = endpoint.getAttributes()
+ address = endpoint.getAddress()
+ if attributes & 0x03 == USB_ENDPOINT_TRANSFER_TYPE_BULK:
+ if address & USB_ENDPOINT_IN and acl_in is None:
+ acl_in = address
+ elif acl_out is None:
+ acl_out = address
+ elif (
+ attributes & 0x03
+ == USB_ENDPOINT_TRANSFER_TYPE_INTERRUPT
+ ):
+ if address & USB_ENDPOINT_IN and events_in is None:
+ events_in = address
+
+ # Return if we found all 3 endpoints
+ if (
+ acl_in is not None
+ and acl_out is not None
+ and events_in is not None
+ ):
+ return (
+ configuration_index + 1,
+ setting.getNumber(),
+ setting.getAlternateSetting(),
+ acl_in,
+ acl_out,
+ events_in,
+ )
+
+ logger.debug(
+ f'skipping configuration {configuration_index + 1} / '
+ f'interface {setting.getNumber()}'
+ )
+
+ return None
+
+ endpoints = find_endpoints(found)
+ if endpoints is None:
+ raise ValueError('no compatible interface found for device')
+ (configuration, interface, setting, acl_in, acl_out, events_in) = endpoints
+ logger.debug(
+ f'selected endpoints: configuration={configuration}, '
+ f'interface={interface}, '
+ f'setting={setting}, '
+ f'acl_in=0x{acl_in:02X}, '
+ f'acl_out=0x{acl_out:02X}, '
+ f'events_in=0x{events_in:02X}, '
+ )
+
device = found.open()
+ # Auto-detach the kernel driver if supported
+ # pylint: disable=no-member
+ if usb1.hasCapability(usb1.CAP_SUPPORTS_DETACH_KERNEL_DRIVER):
+ try:
+ logger.debug('auto-detaching kernel driver')
+ device.setAutoDetachKernelDriver(True)
+ except usb1.USBError as error:
+ logger.warning(f'unable to auto-detach kernel driver: {error}')
+
# Set the configuration if needed
try:
- configuration = device.getConfiguration()
- logger.debug(f'current configuration = {configuration}')
+ current_configuration = device.getConfiguration()
+ logger.debug(f'current configuration = {current_configuration}')
except usb1.USBError:
- try:
- logger.debug('setting configuration 1')
- device.setConfiguration(1)
- except usb1.USBError:
- logger.debug('failed to set configuration 1')
-
- # Use the first interface
- interface = 0
+ current_configuration = 0
- # Detach the kernel driver if supported and needed
- if usb1.hasCapability(usb1.CAP_SUPPORTS_DETACH_KERNEL_DRIVER):
+ if current_configuration != configuration:
try:
- if device.kernelDriverActive(interface):
- logger.debug("detaching kernel driver")
- device.detachKernelDriver(interface)
+ logger.debug(f'setting configuration {configuration}')
+ device.setConfiguration(configuration)
except usb1.USBError:
- pass
+ logger.warning('failed to set configuration')
- source = UsbPacketSource(context, device)
- sink = UsbPacketSink(device)
- return UsbTransport(context, device, interface, source, sink)
+ source = UsbPacketSource(context, device, acl_in, events_in)
+ sink = UsbPacketSink(device, acl_out)
+ return UsbTransport(context, device, interface, setting, source, sink)
except usb1.USBError as error:
logger.warning(color(f'!!! failed to open USB device: {error}', 'red'))
context.close()
diff --git a/bumble/transport/vhci.py b/bumble/transport/vhci.py
index 572c31d..ec61ab4 100644
--- a/bumble/transport/vhci.py
+++ b/bumble/transport/vhci.py
@@ -33,7 +33,7 @@ async def open_vhci_transport(spec):
path at /dev/vhci), or the path of a VHCI device
'''
- HCI_VENDOR_PKT = 0xff
+ HCI_VENDOR_PKT = 0xFF
HCI_BREDR = 0x00 # Controller type
# Open the VHCI device
@@ -56,4 +56,3 @@ async def open_vhci_transport(spec):
transport.sink.on_packet(bytes([HCI_VENDOR_PKT, HCI_BREDR]))
return transport
-
diff --git a/bumble/transport/ws_client.py b/bumble/transport/ws_client.py
index 9ee7e49..85f6e88 100644
--- a/bumble/transport/ws_client.py
+++ b/bumble/transport/ws_client.py
@@ -43,7 +43,7 @@ async def open_ws_client_transport(spec):
transport = PumpedTransport(
PumpedPacketSource(websocket.recv),
PumpedPacketSink(websocket.send),
- websocket.close
+ websocket.close,
)
transport.start()
return transport
diff --git a/bumble/transport/ws_server.py b/bumble/transport/ws_server.py
index 3b2d15e..c7b7c6e 100644
--- a/bumble/transport/ws_server.py
+++ b/bumble/transport/ws_server.py
@@ -41,30 +41,36 @@ async def open_ws_server_transport(spec):
class WsServerTransport(Transport):
def __init__(self):
- source = ParserSource()
- sink = PumpedPacketSink(self.send_packet)
+ source = ParserSource()
+ sink = PumpedPacketSink(self.send_packet)
self.connection = asyncio.get_running_loop().create_future()
+ self.server = None
super().__init__(source, sink)
async def serve(self, local_host, local_port):
self.sink.start()
+ # pylint: disable-next=no-member
self.server = await websockets.serve(
- ws_handler = self.on_connection,
- host = local_host if local_host != '_' else None,
- port = int(local_port)
+ ws_handler=self.on_connection,
+ host=local_host if local_host != '_' else None,
+ port=int(local_port),
)
logger.debug(f'websocket server ready on port {local_port}')
async def on_connection(self, connection):
- logger.debug(f'new connection on {connection.local_address} from {connection.remote_address}')
+ logger.debug(
+ f'new connection on {connection.local_address} '
+ f'from {connection.remote_address}'
+ )
self.connection.set_result(connection)
+ # pylint: disable=no-member
try:
async for packet in connection:
- if type(packet) is bytes:
+ if isinstance(packet, bytes):
self.source.parser.feed_data(packet)
else:
- logger.warn('discarding packet: not a BINARY frame')
+ logger.warning('discarding packet: not a BINARY frame')
except websockets.WebSocketException as error:
logger.debug(f'exception while receiving packet: {error}')
diff --git a/bumble/utils.py b/bumble/utils.py
index 1ab3fd7..8a55684 100644
--- a/bumble/utils.py
+++ b/bumble/utils.py
@@ -18,10 +18,13 @@
import asyncio
import logging
import traceback
+import collections
+import sys
+from typing import Awaitable, Set, TypeVar
from functools import wraps
-from colors import color
from pyee import EventEmitter
+from .colors import color
# -----------------------------------------------------------------------------
# Logging
@@ -33,6 +36,7 @@ logger = logging.getLogger(__name__)
def setup_event_forwarding(emitter, forwarder, event_name):
def emit(*args, **kwargs):
forwarder.emit(event_name, *args, **kwargs)
+
emitter.on(event_name, emit)
@@ -43,6 +47,8 @@ def composite_listener(cls):
registers/deregisters all methods named `on_<event_name>` as a listener for
the <event_name> event with an emitter.
"""
+ # pylint: disable=protected-access
+
def register(self, emitter):
for method_name in dir(cls):
if method_name.startswith('on_'):
@@ -53,13 +59,47 @@ def composite_listener(cls):
if method_name.startswith('on_'):
emitter.remove_listener(method_name[3:], getattr(self, method_name))
- cls._bumble_register_composite = register
+ cls._bumble_register_composite = register
cls._bumble_deregister_composite = deregister
return cls
# -----------------------------------------------------------------------------
-class CompositeEventEmitter(EventEmitter):
+_T = TypeVar('_T')
+
+
+class AbortableEventEmitter(EventEmitter):
+ def abort_on(self, event: str, awaitable: Awaitable[_T]) -> Awaitable[_T]:
+ """
+ Set a coroutine or future to abort when an event occur.
+ """
+ future = asyncio.ensure_future(awaitable)
+ if future.done():
+ return future
+
+ def on_event(*_):
+ if future.done():
+ return
+ msg = f'abort: {event} event occurred.'
+ if isinstance(future, asyncio.Task):
+ # python < 3.9 does not support passing a message on `Task.cancel`
+ if sys.version_info < (3, 9, 0):
+ future.cancel()
+ else:
+ future.cancel(msg)
+ else:
+ future.set_exception(asyncio.CancelledError(msg))
+
+ def on_done(_):
+ self.remove_listener(event, on_event)
+
+ self.on(event, on_event)
+ future.add_done_callback(on_done)
+ return future
+
+
+# -----------------------------------------------------------------------------
+class CompositeEventEmitter(AbortableEventEmitter):
def __init__(self):
super().__init__()
self._listener = None
@@ -70,6 +110,7 @@ class CompositeEventEmitter(EventEmitter):
@listener.setter
def listener(self, listener):
+ # pylint: disable=protected-access
if self._listener:
# Call the deregistration methods for each base class that has them
for cls in self._listener.__class__.mro():
@@ -109,11 +150,16 @@ class AsyncRunner:
try:
await item
except Exception as error:
- logger.warning(f'{color("!!! Exception in work queue:", "red")} {error}')
+ logger.warning(
+ f'{color("!!! Exception in work queue:", "red")} {error}'
+ )
# Shared default queue
default_queue = WorkQueue()
+ # Shared set of running tasks
+ running_tasks: Set[Awaitable] = set()
+
@staticmethod
def run_in_task(queue=None):
"""
@@ -130,7 +176,10 @@ class AsyncRunner:
try:
await coroutine
except Exception:
- logger.warning(f'{color("!!! Exception in wrapper:", "red")} {traceback.format_exc()}')
+ logger.warning(
+ f'{color("!!! Exception in wrapper:", "red")} '
+ f'{traceback.format_exc()}'
+ )
asyncio.create_task(run())
else:
@@ -140,3 +189,116 @@ class AsyncRunner:
return wrapper
return decorator
+
+ @staticmethod
+ def spawn(coroutine):
+ """
+ Spawn a task to run a coroutine in a "fire and forget" mode.
+
+ Using this method instead of just calling `asyncio.create_task(coroutine)`
+ is necessary when you don't keep a reference to the task, because `asyncio`
+ only keeps weak references to alive tasks.
+ """
+ task = asyncio.create_task(coroutine)
+ AsyncRunner.running_tasks.add(task)
+ task.add_done_callback(AsyncRunner.running_tasks.remove)
+
+
+# -----------------------------------------------------------------------------
+class FlowControlAsyncPipe:
+ """
+ Asyncio pipe with flow control. When writing to the pipe, the source is
+ paused (by calling a function passed in when the pipe is created) if the
+ amount of queued data exceeds a specified threshold.
+ """
+
+ def __init__(
+ self,
+ pause_source,
+ resume_source,
+ write_to_sink=None,
+ drain_sink=None,
+ threshold=0,
+ ):
+ self.pause_source = pause_source
+ self.resume_source = resume_source
+ self.write_to_sink = write_to_sink
+ self.drain_sink = drain_sink
+ self.threshold = threshold
+ self.queue = collections.deque() # Queue of packets
+ self.queued_bytes = 0 # Number of bytes in the queue
+ self.ready_to_pump = asyncio.Event()
+ self.paused = False
+ self.source_paused = False
+ self.pump_task = None
+
+ def start(self):
+ if self.pump_task is None:
+ self.pump_task = asyncio.create_task(self.pump())
+
+ self.check_pump()
+
+ def stop(self):
+ if self.pump_task is not None:
+ self.pump_task.cancel()
+ self.pump_task = None
+
+ def write(self, packet):
+ self.queued_bytes += len(packet)
+ self.queue.append(packet)
+
+ # Pause the source if we're over the threshold
+ if self.queued_bytes > self.threshold and not self.source_paused:
+ logger.debug(f'pausing source (queued={self.queued_bytes})')
+ self.pause_source()
+ self.source_paused = True
+
+ self.check_pump()
+
+ def pause(self):
+ if not self.paused:
+ self.paused = True
+ if not self.source_paused:
+ self.pause_source()
+ self.source_paused = True
+ self.check_pump()
+
+ def resume(self):
+ if self.paused:
+ self.paused = False
+ if self.source_paused:
+ self.resume_source()
+ self.source_paused = False
+ self.check_pump()
+
+ def can_pump(self):
+ return self.queue and not self.paused and self.write_to_sink is not None
+
+ def check_pump(self):
+ if self.can_pump():
+ self.ready_to_pump.set()
+ else:
+ self.ready_to_pump.clear()
+
+ async def pump(self):
+ while True:
+ # Wait until we can try to pump packets
+ await self.ready_to_pump.wait()
+
+ # Try to pump a packet
+ if self.can_pump():
+ packet = self.queue.pop()
+ self.write_to_sink(packet)
+ self.queued_bytes -= len(packet)
+
+ # Drain the sink if we can
+ if self.drain_sink:
+ await self.drain_sink()
+
+ # Check if we can accept more
+ if self.queued_bytes <= self.threshold and self.source_paused:
+ logger.debug(f'resuming source (queued={self.queued_bytes})')
+ self.source_paused = False
+ self.resume_source()
+
+ self.check_pump()
diff --git a/docs/README.md b/docs/README.md
index ca7d4c0..cf32226 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -2,7 +2,7 @@ Bumble Documentation
====================
The documentation consists of a collection of markdown text files, with the root of the file
-hierarchy at `docs/mkdocs/src`, starting with `docs/mkdocs/src/index.md`.
+hierarchy at `docs/mkdocs/src`, starting with `docs/mkdocs/src/index.md`.
You can read the documentation as text, with any text viewer or your favorite markdown viewer,
or generate a static HTML "site" using `mkdocs`, which you can then open with any browser.
@@ -14,9 +14,9 @@ The `mkdocs` directory contains all the data (actual documentation) and metadata
`mkdocs/mkdocs.yml` contains the site configuration.
`mkdocs/src/` is the directory where the actual documentation text, in markdown format, is located.
-To build, from the project's root directory:
+To build, from the project's root directory:
```
-$ mkdocs build -f docs/mkdocs/mkdocs.yml
+$ mkdocs build -f docs/mkdocs/mkdocs.yml
```
You can then open `docs/mkdocs/site/index.html` with any web browser.
diff --git a/docs/images/logo.vectornator/Artboard0.json b/docs/images/logo.vectornator/Artboard0.json
index eddf68a..f10d409 100644
--- a/docs/images/logo.vectornator/Artboard0.json
+++ b/docs/images/logo.vectornator/Artboard0.json
@@ -1 +1 @@
-{"layers":[{"elements":[{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[-5.882939210360405,25.513785542788241],"opacity":1,"blur":0,"isLocked":false,"gid":56,"smootheningRate":0,"initialPoint":[-5.882939210360405,25.513785542788241],"creationPoints":[],"group":{"elements":[{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[225.48442074400293,105.07566425478205],"opacity":1,"blur":0,"isLocked":false,"gid":27,"smootheningRate":0,"initialPoint":[225.48442074400293,105.07566425478205],"creationPoints":[],"group":{"elements":[{"elementDescription":"(rectangle)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[225.48442074400293,180.0751680461143],"reflectionModeOverride":0,"anchorPoint":[225.48442074400293,180.0751680461143],"cornerRadius":0,"prevPoint":[-2.4497734478039774,-990.41770428277562],"inPoint":[225.48442074400293,180.0751680461143],"nextPoint":[-2.4497734478039774,-990.41770428277562]},{"outPoint":[375.4834254415108,180.0751680461143],"reflectionModeOverride":0,"anchorPoint":[375.4834254415108,180.0751680461143],"cornerRadius":0,"prevPoint":[-2.4497734478039774,-990.41770428277562],"inPoint":[375.4834254415108,180.0751680461143],"nextPoint":[-2.4497734478039774,-990.41770428277562]},{"outPoint":[375.4834254415108,430.07351680205772],"reflectionModeOverride":0,"anchorPoint":[375.4834254415108,430.07351680205772],"cornerRadius":0,"prevPoint":[-2.4497734478039774,-990.41770428277562],"inPoint":[375.4834254415108,430.07351680205772],"nextPoint":[-2.4497734478039774,-990.41770428277562]},{"outPoint":[225.48442074400293,430.07351680205772],"reflectionModeOverride":0,"anchorPoint":[225.48442074400293,430.07351680205772],"cornerRadius":0,"prevPoint":[-2.4497734478039774,-990.41770428277562],"inPoint":[225.48442074400293,430.07351680205772],"nextPoint":[-2.4497734478039774,-990.41770428277562]}],"closed":true,"reversed":false}},"fillColor":{"b":0.9882352941176471,"s":1,"h":0.13822251558303833,"a":1},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":1,"width":20,"endArrow":"","startArrow":"","cap":0},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[375.4834254415108,430.07351680205772],"opacity":1,"blur":0,"isLocked":false,"gid":22,"smootheningRate":0,"initialPoint":[225.48442074400293,180.0751680461143],"creationPoints":[],"name":"(rectangle)"},{"elementDescription":"(oval)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[225.48442074400293,138.65412011223214],"reflectionModeOverride":0,"anchorPoint":[225.48442074400293,180.07518887113827],"cornerRadius":0,"prevPoint":[-235.35384472404451,-574.6867431949596],"inPoint":[225.48442074400293,221.49625763004531],"nextPoint":[-235.35384472404451,-574.6867431949596]},{"outPoint":[341.90501411926641,105.07566425478205],"reflectionModeOverride":0,"anchorPoint":[300.48394536035983,105.07566425478205],"cornerRadius":0,"prevPoint":[-235.35384472404451,-574.6867431949596],"inPoint":[259.06287660145324,105.07566425478205],"nextPoint":[-235.35384472404451,-574.6867431949596]},{"outPoint":[375.4834230115174,221.49625763004531],"reflectionModeOverride":0,"anchorPoint":[375.4834230115174,180.07518887113827],"cornerRadius":0,"prevPoint":[-235.35384472404451,-574.6867431949596],"inPoint":[375.4834230115174,138.65412011223214],"nextPoint":[-235.35384472404451,-574.6867431949596]},{"outPoint":[259.06287660145324,255.0746665222963],"reflectionModeOverride":0,"anchorPoint":[300.48394536035983,255.0746665222963],"cornerRadius":0,"prevPoint":[-235.35384472404451,-574.6867431949596],"inPoint":[341.90501411926641,255.0746665222963],"nextPoint":[-235.35384472404451,-574.6867431949596]}],"closed":true,"reversed":false}},"fillColor":{"b":0.9882352941176471,"s":1,"h":0.13822251558303833,"a":1},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":1,"width":20,"endArrow":"","startArrow":"","cap":0},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[-235.35384472404451,-574.6867431949596],"opacity":1,"blur":0,"isLocked":false,"gid":24,"smootheningRate":0,"initialPoint":[-235.35384472404451,-574.6867431949596],"creationPoints":[],"name":"(oval)"},{"elementDescription":"(oval)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[225.48442074400293,388.65246608333962],"reflectionModeOverride":0,"anchorPoint":[225.48442074400293,430.07353484224666],"cornerRadius":0,"prevPoint":[-235.35384472404451,-324.68839722385167],"inPoint":[225.48442074400293,471.49460360115279],"nextPoint":[-235.35384472404451,-324.68839722385167]},{"outPoint":[341.90501411926641,355.07401022588954],"reflectionModeOverride":0,"anchorPoint":[300.48394536035983,355.07401022588954],"cornerRadius":0,"prevPoint":[-235.35384472404451,-324.68839722385167],"inPoint":[259.06287660145324,355.07401022588954],"nextPoint":[-235.35384472404451,-324.68839722385167]},{"outPoint":[375.4834230115174,471.49460360115279],"reflectionModeOverride":0,"anchorPoint":[375.4834230115174,430.07353484224666],"cornerRadius":0,"prevPoint":[-235.35384472404451,-324.68839722385167],"inPoint":[375.4834230115174,388.65246608333962],"nextPoint":[-235.35384472404451,-324.68839722385167]},{"outPoint":[259.06287660145324,505.07301249340378],"reflectionModeOverride":0,"anchorPoint":[300.48394536035983,505.07301249340378],"cornerRadius":0,"prevPoint":[-235.35384472404451,-324.68839722385167],"inPoint":[341.90501411926641,505.07301249340378],"nextPoint":[-235.35384472404451,-324.68839722385167]}],"closed":true,"reversed":false}},"fillColor":{"b":0.9882352941176471,"s":1,"h":0.13822251558303833,"a":1},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":1,"width":20,"endArrow":"","startArrow":"","cap":0},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[-235.35384472404451,-324.68839722385167],"opacity":1,"blur":0,"isLocked":false,"gid":25,"smootheningRate":0,"initialPoint":[-235.35384472404451,-324.68839722385167],"creationPoints":[],"name":"(oval)"},{"elementDescription":"(rectangle)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[235.48435458284723,179.89237563632139],"reflectionModeOverride":0,"anchorPoint":[235.48435458284723,179.89237563632139],"cornerRadius":0,"prevPoint":[37.941384471822971,-990.60049669256784],"inPoint":[235.48435458284723,179.89237563632139],"nextPoint":[37.941384471822971,-990.60049669256784]},{"outPoint":[365.48349317943928,179.89237563632139],"reflectionModeOverride":0,"anchorPoint":[365.48349317943928,179.89237563632139],"cornerRadius":0,"prevPoint":[37.941384471822971,-990.60049669256784],"inPoint":[365.48349317943928,179.89237563632139],"nextPoint":[37.941384471822971,-990.60049669256784]},{"outPoint":[365.48349317943928,429.89072439226481],"reflectionModeOverride":0,"anchorPoint":[365.48349317943928,429.89072439226481],"cornerRadius":0,"prevPoint":[37.941384471822971,-990.60049669256784],"inPoint":[365.48349317943928,429.89072439226481],"nextPoint":[37.941384471822971,-990.60049669256784]},{"outPoint":[235.48435458284723,429.89072439226481],"reflectionModeOverride":0,"anchorPoint":[235.48435458284723,429.89072439226481],"cornerRadius":0,"prevPoint":[37.941384471822971,-990.60049669256784],"inPoint":[235.48435458284723,429.89072439226481],"nextPoint":[37.941384471822971,-990.60049669256784]}],"closed":true,"reversed":false}},"fillColor":{"b":0.9882352941176471,"s":1,"h":0.13822251558303833,"a":1},"strokeStyle":{"color":{"b":0.9882352941176471,"s":1,"h":0.5806878306878307,"a":1},"dashPattern":[],"join":1,"width":0.10000000149011612,"endArrow":"","startArrow":"","cap":0},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[365.48349317943928,429.89072439226481],"opacity":1,"blur":0,"isLocked":false,"gid":26,"smootheningRate":0,"initialPoint":[235.48435458284723,179.89237563632139],"creationPoints":[],"name":"(rectangle)"}]},"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[35.772159785141525,199.98637434514319],"reflectionModeOverride":0,"anchorPoint":[35.772159785141525,199.98637434514319],"cornerRadius":0,"prevPoint":[16.704525477792117,37.513706149401855],"inPoint":[35.772159785141525,199.98637434514319],"nextPoint":[16.704525477792117,37.513706149401855]},{"outPoint":[159.56661941832897,334.72204728763415],"reflectionModeOverride":0,"anchorPoint":[159.56661941832897,334.72204728763415],"cornerRadius":0,"prevPoint":[16.704525477792117,37.513706149401855],"inPoint":[159.56661941832897,334.72204728763415],"nextPoint":[16.704525477792117,37.513706149401855]},{"outPoint":[299.28226312627601,200.42272477566019],"reflectionModeOverride":0,"anchorPoint":[299.28226312627601,200.42272477566019],"cornerRadius":0,"prevPoint":[16.704525477792117,37.513706149401855],"inPoint":[299.28226312627601,200.42272477566019],"nextPoint":[16.704525477792117,37.513706149401855]}],"closed":true,"reversed":false}},"fillColor":{"b":0.9882352941176471,"s":1,"h":0.5806878306878307,"a":1},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":1,"width":0.10000000149011612,"endArrow":"","startArrow":"","cap":1},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[16.704525477792117,37.513706149401855],"opacity":1,"blur":0,"isLocked":false,"gid":29,"smootheningRate":0,"initialPoint":[16.704525477792117,37.513706149401855],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[316.02230657990947,197.89539868947611],"reflectionModeOverride":0,"anchorPoint":[316.02230657990947,197.89539868947611],"cornerRadius":0,"prevPoint":[296.695700377354,37.472065800512951],"inPoint":[316.02230657990947,197.89539868947611],"nextPoint":[296.695700377354,37.472065800512951]},{"outPoint":[441.49811195900963,330.9315945770885],"reflectionModeOverride":0,"anchorPoint":[441.49811195900963,330.9315945770885],"cornerRadius":0,"prevPoint":[296.695700377354,37.472065800512951],"inPoint":[441.49811195900963,330.9315945770885],"nextPoint":[296.695700377354,37.472065800512951]},{"outPoint":[583.11133899889126,198.32624525061453],"reflectionModeOverride":0,"anchorPoint":[583.11133899889126,198.32624525061453],"cornerRadius":0,"prevPoint":[296.695700377354,37.472065800512951],"inPoint":[583.11133899889126,198.32624525061453],"nextPoint":[296.695700377354,37.472065800512951]}],"closed":true,"reversed":false}},"fillColor":{"b":0.9882352941176471,"s":1,"h":0.5806878306878307,"a":1},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":1,"width":0.10000000149011612,"endArrow":"","startArrow":"","cap":1},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[296.695700377354,37.472065800512951],"opacity":1,"blur":0,"isLocked":false,"gid":30,"smootheningRate":0,"initialPoint":[296.695700377354,37.472065800512951],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[454.65560248608688,45.627293553562936],"reflectionModeOverride":0,"anchorPoint":[454.65560248608688,45.627293553562936],"cornerRadius":0,"prevPoint":[971.93140466738657,-224.79785180257943],"inPoint":[454.65560248608688,45.627293553562936],"nextPoint":[971.93140466738657,-224.79785180257943]},{"outPoint":[162.17037499378046,339.70097131047794],"reflectionModeOverride":0,"anchorPoint":[162.17037499378046,339.70097131047794],"cornerRadius":0,"prevPoint":[971.93140466738657,-224.79785180257943],"inPoint":[162.17037499378046,339.70097131047794],"nextPoint":[971.93140466738657,-224.79785180257943]},{"outPoint":[16.450758016910754,190.92333427643769],"reflectionModeOverride":0,"anchorPoint":[16.450758016910754,190.92333427643769],"cornerRadius":0,"prevPoint":[971.93140466738657,-224.79785180257943],"inPoint":[16.450758016910754,190.92333427643769],"nextPoint":[971.93140466738657,-224.79785180257943]},{"outPoint":[586.27726302866802,193.75471648932478],"reflectionModeOverride":0,"anchorPoint":[586.27726302866802,193.75471648932478],"cornerRadius":0,"prevPoint":[971.93140466738657,-224.79785180257943],"inPoint":[586.27726302866802,193.75471648932478],"nextPoint":[971.93140466738657,-224.79785180257943]},{"outPoint":[444.36970577266027,335.60394507941498],"reflectionModeOverride":0,"anchorPoint":[444.36970577266027,335.60394507941498],"cornerRadius":0,"prevPoint":[971.93140466738657,-224.79785180257943],"inPoint":[444.36970577266027,335.60394507941498],"nextPoint":[971.93140466738657,-224.79785180257943]},{"outPoint":[155.71179749272039,46.932845447085015],"reflectionModeOverride":0,"anchorPoint":[155.71179749272039,46.932845447085015],"cornerRadius":0,"prevPoint":[971.93140466738657,-224.79785180257943],"inPoint":[155.71179749272039,46.932845447085015],"nextPoint":[971.93140466738657,-224.79785180257943]}],"closed":false,"reversed":false}},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":1,"width":20,"endArrow":"","startArrow":"","cap":1},"maskedElements":[]},"angle":90,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[1132.6259120879768,-222.31407294998928],"opacity":1,"blur":0,"isLocked":false,"gid":21,"smootheningRate":0,"initialPoint":[1132.6259120879768,-222.31407294998928],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(line)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[228.4683004292159,309.55668062155007],"reflectionModeOverride":0,"anchorPoint":[228.4683004292159,309.55668062155007],"cornerRadius":0,"prevPoint":[16.704525477792117,37.513706149401855],"inPoint":[228.4683004292159,309.55668062155007],"nextPoint":[16.704525477792117,37.513706149401855]},{"outPoint":[371.51081106842264,309.55668062155007],"reflectionModeOverride":0,"anchorPoint":[371.51081106842264,309.55668062155007],"cornerRadius":0,"prevPoint":[16.704525477792117,37.513706149401855],"inPoint":[371.51081106842264,309.55668062155007],"nextPoint":[16.704525477792117,37.513706149401855]}],"closed":false,"reversed":false}},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":1,"width":61.869819641113281,"endArrow":"","startArrow":"","cap":0},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[16.704525477792117,37.513706149401855],"opacity":1,"blur":0,"isLocked":false,"gid":31,"smootheningRate":0,"initialPoint":[16.704525477792117,37.513706149401855],"creationPoints":[],"name":"(line)"},{"elementDescription":"(line)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[228.4683004292159,412.55599916164635],"reflectionModeOverride":0,"anchorPoint":[228.4683004292159,412.55599916164635],"cornerRadius":0,"prevPoint":[16.704525477792117,140.51302468949859],"inPoint":[228.4683004292159,412.55599916164635],"nextPoint":[16.704525477792117,140.51302468949859]},{"outPoint":[371.51081106842264,412.55599916164635],"reflectionModeOverride":0,"anchorPoint":[371.51081106842264,412.55599916164635],"cornerRadius":0,"prevPoint":[16.704525477792117,140.51302468949859],"inPoint":[371.51081106842264,412.55599916164635],"nextPoint":[16.704525477792117,140.51302468949859]}],"closed":false,"reversed":false}},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":1,"width":61.869819641113281,"endArrow":"","startArrow":"","cap":0},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[16.704525477792117,140.51302468949859],"opacity":1,"blur":0,"isLocked":false,"gid":32,"smootheningRate":0,"initialPoint":[16.704525477792117,140.51302468949859],"creationPoints":[],"name":"(line)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[2.7206907461103356,25.513785542788241],"opacity":1,"blur":0,"isLocked":false,"gid":55,"smootheningRate":0,"initialPoint":[2.7206907461103356,25.513785542788241],"creationPoints":[],"group":{"elements":[{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[300.38008332937886,557.84279577418272],"reflectionModeOverride":0,"anchorPoint":[300.38008332937886,557.84279577418272],"cornerRadius":0,"prevPoint":[4.8049994992771872,-1.0129103054042616],"inPoint":[300.87435644597588,529.50877422158635],"nextPoint":[4.8049994992771872,-1.0129103054042616]},{"outPoint":[300.43161232869249,507.2021517541192],"reflectionModeOverride":0,"anchorPoint":[300.43161232869249,507.2021517541192],"cornerRadius":0,"prevPoint":[-12.365577443621419,-27.342871697380019],"inPoint":[300.43161232869249,507.2021517541192],"nextPoint":[-12.365577443621419,-27.342871697380019]},{"outPoint":[315.7481814828169,517.26662181075551],"reflectionModeOverride":0,"anchorPoint":[336.28774305214836,507.15563112854068],"cornerRadius":0,"prevPoint":[2.7206907461103356,24.978316814837285],"inPoint":[336.28774305214836,507.15563112854068],"nextPoint":[2.7206907461103356,24.978316814837285]}],"closed":true,"reversed":false}},"fillColor":{"b":0,"s":0,"h":0,"a":1},"strokeStyle":{"color":{"b":0.9882352941176471,"s":1,"h":0.5806878306878307,"a":1},"dashPattern":[],"join":1,"width":0.10000000149011612,"endArrow":"","startArrow":"","cap":0},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[4.9686415433105822,12.610834591390244],"opacity":1,"blur":0,"isLocked":false,"gid":48,"smootheningRate":0,"initialPoint":[4.9686415433105822,12.610834591390244],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[300.44667602585685,557.84279577418272],"reflectionModeOverride":0,"anchorPoint":[300.44667602585685,557.84279577418272],"cornerRadius":0,"prevPoint":[596.02175985595829,-1.0129103054042616],"inPoint":[299.95240290925983,529.50877422158635],"nextPoint":[596.02175985595829,-1.0129103054042616]},{"outPoint":[300.39514702654321,507.2021517541192],"reflectionModeOverride":0,"anchorPoint":[300.39514702654321,507.2021517541192],"cornerRadius":0,"prevPoint":[613.1923367988569,-27.342871697380019],"inPoint":[300.39514702654321,507.2021517541192],"nextPoint":[613.1923367988569,-27.342871697380019]},{"outPoint":[285.07857787241835,517.26662181075551],"reflectionModeOverride":0,"anchorPoint":[264.53901630308735,507.15563112854068],"cornerRadius":0,"prevPoint":[598.10606860912537,24.978316814837285],"inPoint":[264.53901630308735,507.15563112854068],"nextPoint":[598.10606860912537,24.978316814837285]}],"closed":true,"reversed":false}},"fillColor":{"b":0,"s":0,"h":0,"a":1},"strokeStyle":{"color":{"b":0.9882352941176471,"s":1,"h":0.5806878306878307,"a":1},"dashPattern":[],"join":1,"width":0.10000000149011612,"endArrow":"","startArrow":"","cap":0},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[595.85811781192467,12.818230389370797],"opacity":1,"blur":0,"isLocked":false,"gid":54,"smootheningRate":0,"initialPoint":[595.85811781192467,12.818230389370797],"creationPoints":[],"name":"(curve)"}]},"name":"(curve)"}]},"name":"(curve)"}],"isExpanded":false,"isLocked":false,"isVisible":true,"opacity":1,"gid":4,"name":"Layer 1"}],"frame":{"y":0,"x":0,"width":600,"height":600},"title":"Mac App icon","activeLayerIndex":0,"settings":{"gridSpacing":20,"gridAngle":45,"backgroundColor":{"b":1,"s":0,"h":0,"a":1},"gridMode":0,"isGridVisible":false},"guideLayer":{"isExpanded":false,"elements":[],"isLocked":false,"defaultName":"Guides","isVisible":true,"opacity":1,"name":"Guides","gid":5},"gid":3} \ No newline at end of file
+{"layers":[{"elements":[{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[-5.882939210360405,25.513785542788241],"opacity":1,"blur":0,"isLocked":false,"gid":56,"smootheningRate":0,"initialPoint":[-5.882939210360405,25.513785542788241],"creationPoints":[],"group":{"elements":[{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[225.48442074400293,105.07566425478205],"opacity":1,"blur":0,"isLocked":false,"gid":27,"smootheningRate":0,"initialPoint":[225.48442074400293,105.07566425478205],"creationPoints":[],"group":{"elements":[{"elementDescription":"(rectangle)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[225.48442074400293,180.0751680461143],"reflectionModeOverride":0,"anchorPoint":[225.48442074400293,180.0751680461143],"cornerRadius":0,"prevPoint":[-2.4497734478039774,-990.41770428277562],"inPoint":[225.48442074400293,180.0751680461143],"nextPoint":[-2.4497734478039774,-990.41770428277562]},{"outPoint":[375.4834254415108,180.0751680461143],"reflectionModeOverride":0,"anchorPoint":[375.4834254415108,180.0751680461143],"cornerRadius":0,"prevPoint":[-2.4497734478039774,-990.41770428277562],"inPoint":[375.4834254415108,180.0751680461143],"nextPoint":[-2.4497734478039774,-990.41770428277562]},{"outPoint":[375.4834254415108,430.07351680205772],"reflectionModeOverride":0,"anchorPoint":[375.4834254415108,430.07351680205772],"cornerRadius":0,"prevPoint":[-2.4497734478039774,-990.41770428277562],"inPoint":[375.4834254415108,430.07351680205772],"nextPoint":[-2.4497734478039774,-990.41770428277562]},{"outPoint":[225.48442074400293,430.07351680205772],"reflectionModeOverride":0,"anchorPoint":[225.48442074400293,430.07351680205772],"cornerRadius":0,"prevPoint":[-2.4497734478039774,-990.41770428277562],"inPoint":[225.48442074400293,430.07351680205772],"nextPoint":[-2.4497734478039774,-990.41770428277562]}],"closed":true,"reversed":false}},"fillColor":{"b":0.9882352941176471,"s":1,"h":0.13822251558303833,"a":1},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":1,"width":20,"endArrow":"","startArrow":"","cap":0},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[375.4834254415108,430.07351680205772],"opacity":1,"blur":0,"isLocked":false,"gid":22,"smootheningRate":0,"initialPoint":[225.48442074400293,180.0751680461143],"creationPoints":[],"name":"(rectangle)"},{"elementDescription":"(oval)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[225.48442074400293,138.65412011223214],"reflectionModeOverride":0,"anchorPoint":[225.48442074400293,180.07518887113827],"cornerRadius":0,"prevPoint":[-235.35384472404451,-574.6867431949596],"inPoint":[225.48442074400293,221.49625763004531],"nextPoint":[-235.35384472404451,-574.6867431949596]},{"outPoint":[341.90501411926641,105.07566425478205],"reflectionModeOverride":0,"anchorPoint":[300.48394536035983,105.07566425478205],"cornerRadius":0,"prevPoint":[-235.35384472404451,-574.6867431949596],"inPoint":[259.06287660145324,105.07566425478205],"nextPoint":[-235.35384472404451,-574.6867431949596]},{"outPoint":[375.4834230115174,221.49625763004531],"reflectionModeOverride":0,"anchorPoint":[375.4834230115174,180.07518887113827],"cornerRadius":0,"prevPoint":[-235.35384472404451,-574.6867431949596],"inPoint":[375.4834230115174,138.65412011223214],"nextPoint":[-235.35384472404451,-574.6867431949596]},{"outPoint":[259.06287660145324,255.0746665222963],"reflectionModeOverride":0,"anchorPoint":[300.48394536035983,255.0746665222963],"cornerRadius":0,"prevPoint":[-235.35384472404451,-574.6867431949596],"inPoint":[341.90501411926641,255.0746665222963],"nextPoint":[-235.35384472404451,-574.6867431949596]}],"closed":true,"reversed":false}},"fillColor":{"b":0.9882352941176471,"s":1,"h":0.13822251558303833,"a":1},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":1,"width":20,"endArrow":"","startArrow":"","cap":0},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[-235.35384472404451,-574.6867431949596],"opacity":1,"blur":0,"isLocked":false,"gid":24,"smootheningRate":0,"initialPoint":[-235.35384472404451,-574.6867431949596],"creationPoints":[],"name":"(oval)"},{"elementDescription":"(oval)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[225.48442074400293,388.65246608333962],"reflectionModeOverride":0,"anchorPoint":[225.48442074400293,430.07353484224666],"cornerRadius":0,"prevPoint":[-235.35384472404451,-324.68839722385167],"inPoint":[225.48442074400293,471.49460360115279],"nextPoint":[-235.35384472404451,-324.68839722385167]},{"outPoint":[341.90501411926641,355.07401022588954],"reflectionModeOverride":0,"anchorPoint":[300.48394536035983,355.07401022588954],"cornerRadius":0,"prevPoint":[-235.35384472404451,-324.68839722385167],"inPoint":[259.06287660145324,355.07401022588954],"nextPoint":[-235.35384472404451,-324.68839722385167]},{"outPoint":[375.4834230115174,471.49460360115279],"reflectionModeOverride":0,"anchorPoint":[375.4834230115174,430.07353484224666],"cornerRadius":0,"prevPoint":[-235.35384472404451,-324.68839722385167],"inPoint":[375.4834230115174,388.65246608333962],"nextPoint":[-235.35384472404451,-324.68839722385167]},{"outPoint":[259.06287660145324,505.07301249340378],"reflectionModeOverride":0,"anchorPoint":[300.48394536035983,505.07301249340378],"cornerRadius":0,"prevPoint":[-235.35384472404451,-324.68839722385167],"inPoint":[341.90501411926641,505.07301249340378],"nextPoint":[-235.35384472404451,-324.68839722385167]}],"closed":true,"reversed":false}},"fillColor":{"b":0.9882352941176471,"s":1,"h":0.13822251558303833,"a":1},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":1,"width":20,"endArrow":"","startArrow":"","cap":0},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[-235.35384472404451,-324.68839722385167],"opacity":1,"blur":0,"isLocked":false,"gid":25,"smootheningRate":0,"initialPoint":[-235.35384472404451,-324.68839722385167],"creationPoints":[],"name":"(oval)"},{"elementDescription":"(rectangle)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[235.48435458284723,179.89237563632139],"reflectionModeOverride":0,"anchorPoint":[235.48435458284723,179.89237563632139],"cornerRadius":0,"prevPoint":[37.941384471822971,-990.60049669256784],"inPoint":[235.48435458284723,179.89237563632139],"nextPoint":[37.941384471822971,-990.60049669256784]},{"outPoint":[365.48349317943928,179.89237563632139],"reflectionModeOverride":0,"anchorPoint":[365.48349317943928,179.89237563632139],"cornerRadius":0,"prevPoint":[37.941384471822971,-990.60049669256784],"inPoint":[365.48349317943928,179.89237563632139],"nextPoint":[37.941384471822971,-990.60049669256784]},{"outPoint":[365.48349317943928,429.89072439226481],"reflectionModeOverride":0,"anchorPoint":[365.48349317943928,429.89072439226481],"cornerRadius":0,"prevPoint":[37.941384471822971,-990.60049669256784],"inPoint":[365.48349317943928,429.89072439226481],"nextPoint":[37.941384471822971,-990.60049669256784]},{"outPoint":[235.48435458284723,429.89072439226481],"reflectionModeOverride":0,"anchorPoint":[235.48435458284723,429.89072439226481],"cornerRadius":0,"prevPoint":[37.941384471822971,-990.60049669256784],"inPoint":[235.48435458284723,429.89072439226481],"nextPoint":[37.941384471822971,-990.60049669256784]}],"closed":true,"reversed":false}},"fillColor":{"b":0.9882352941176471,"s":1,"h":0.13822251558303833,"a":1},"strokeStyle":{"color":{"b":0.9882352941176471,"s":1,"h":0.5806878306878307,"a":1},"dashPattern":[],"join":1,"width":0.10000000149011612,"endArrow":"","startArrow":"","cap":0},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[365.48349317943928,429.89072439226481],"opacity":1,"blur":0,"isLocked":false,"gid":26,"smootheningRate":0,"initialPoint":[235.48435458284723,179.89237563632139],"creationPoints":[],"name":"(rectangle)"}]},"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[35.772159785141525,199.98637434514319],"reflectionModeOverride":0,"anchorPoint":[35.772159785141525,199.98637434514319],"cornerRadius":0,"prevPoint":[16.704525477792117,37.513706149401855],"inPoint":[35.772159785141525,199.98637434514319],"nextPoint":[16.704525477792117,37.513706149401855]},{"outPoint":[159.56661941832897,334.72204728763415],"reflectionModeOverride":0,"anchorPoint":[159.56661941832897,334.72204728763415],"cornerRadius":0,"prevPoint":[16.704525477792117,37.513706149401855],"inPoint":[159.56661941832897,334.72204728763415],"nextPoint":[16.704525477792117,37.513706149401855]},{"outPoint":[299.28226312627601,200.42272477566019],"reflectionModeOverride":0,"anchorPoint":[299.28226312627601,200.42272477566019],"cornerRadius":0,"prevPoint":[16.704525477792117,37.513706149401855],"inPoint":[299.28226312627601,200.42272477566019],"nextPoint":[16.704525477792117,37.513706149401855]}],"closed":true,"reversed":false}},"fillColor":{"b":0.9882352941176471,"s":1,"h":0.5806878306878307,"a":1},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":1,"width":0.10000000149011612,"endArrow":"","startArrow":"","cap":1},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[16.704525477792117,37.513706149401855],"opacity":1,"blur":0,"isLocked":false,"gid":29,"smootheningRate":0,"initialPoint":[16.704525477792117,37.513706149401855],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[316.02230657990947,197.89539868947611],"reflectionModeOverride":0,"anchorPoint":[316.02230657990947,197.89539868947611],"cornerRadius":0,"prevPoint":[296.695700377354,37.472065800512951],"inPoint":[316.02230657990947,197.89539868947611],"nextPoint":[296.695700377354,37.472065800512951]},{"outPoint":[441.49811195900963,330.9315945770885],"reflectionModeOverride":0,"anchorPoint":[441.49811195900963,330.9315945770885],"cornerRadius":0,"prevPoint":[296.695700377354,37.472065800512951],"inPoint":[441.49811195900963,330.9315945770885],"nextPoint":[296.695700377354,37.472065800512951]},{"outPoint":[583.11133899889126,198.32624525061453],"reflectionModeOverride":0,"anchorPoint":[583.11133899889126,198.32624525061453],"cornerRadius":0,"prevPoint":[296.695700377354,37.472065800512951],"inPoint":[583.11133899889126,198.32624525061453],"nextPoint":[296.695700377354,37.472065800512951]}],"closed":true,"reversed":false}},"fillColor":{"b":0.9882352941176471,"s":1,"h":0.5806878306878307,"a":1},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":1,"width":0.10000000149011612,"endArrow":"","startArrow":"","cap":1},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[296.695700377354,37.472065800512951],"opacity":1,"blur":0,"isLocked":false,"gid":30,"smootheningRate":0,"initialPoint":[296.695700377354,37.472065800512951],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[454.65560248608688,45.627293553562936],"reflectionModeOverride":0,"anchorPoint":[454.65560248608688,45.627293553562936],"cornerRadius":0,"prevPoint":[971.93140466738657,-224.79785180257943],"inPoint":[454.65560248608688,45.627293553562936],"nextPoint":[971.93140466738657,-224.79785180257943]},{"outPoint":[162.17037499378046,339.70097131047794],"reflectionModeOverride":0,"anchorPoint":[162.17037499378046,339.70097131047794],"cornerRadius":0,"prevPoint":[971.93140466738657,-224.79785180257943],"inPoint":[162.17037499378046,339.70097131047794],"nextPoint":[971.93140466738657,-224.79785180257943]},{"outPoint":[16.450758016910754,190.92333427643769],"reflectionModeOverride":0,"anchorPoint":[16.450758016910754,190.92333427643769],"cornerRadius":0,"prevPoint":[971.93140466738657,-224.79785180257943],"inPoint":[16.450758016910754,190.92333427643769],"nextPoint":[971.93140466738657,-224.79785180257943]},{"outPoint":[586.27726302866802,193.75471648932478],"reflectionModeOverride":0,"anchorPoint":[586.27726302866802,193.75471648932478],"cornerRadius":0,"prevPoint":[971.93140466738657,-224.79785180257943],"inPoint":[586.27726302866802,193.75471648932478],"nextPoint":[971.93140466738657,-224.79785180257943]},{"outPoint":[444.36970577266027,335.60394507941498],"reflectionModeOverride":0,"anchorPoint":[444.36970577266027,335.60394507941498],"cornerRadius":0,"prevPoint":[971.93140466738657,-224.79785180257943],"inPoint":[444.36970577266027,335.60394507941498],"nextPoint":[971.93140466738657,-224.79785180257943]},{"outPoint":[155.71179749272039,46.932845447085015],"reflectionModeOverride":0,"anchorPoint":[155.71179749272039,46.932845447085015],"cornerRadius":0,"prevPoint":[971.93140466738657,-224.79785180257943],"inPoint":[155.71179749272039,46.932845447085015],"nextPoint":[971.93140466738657,-224.79785180257943]}],"closed":false,"reversed":false}},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":1,"width":20,"endArrow":"","startArrow":"","cap":1},"maskedElements":[]},"angle":90,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[1132.6259120879768,-222.31407294998928],"opacity":1,"blur":0,"isLocked":false,"gid":21,"smootheningRate":0,"initialPoint":[1132.6259120879768,-222.31407294998928],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(line)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[228.4683004292159,309.55668062155007],"reflectionModeOverride":0,"anchorPoint":[228.4683004292159,309.55668062155007],"cornerRadius":0,"prevPoint":[16.704525477792117,37.513706149401855],"inPoint":[228.4683004292159,309.55668062155007],"nextPoint":[16.704525477792117,37.513706149401855]},{"outPoint":[371.51081106842264,309.55668062155007],"reflectionModeOverride":0,"anchorPoint":[371.51081106842264,309.55668062155007],"cornerRadius":0,"prevPoint":[16.704525477792117,37.513706149401855],"inPoint":[371.51081106842264,309.55668062155007],"nextPoint":[16.704525477792117,37.513706149401855]}],"closed":false,"reversed":false}},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":1,"width":61.869819641113281,"endArrow":"","startArrow":"","cap":0},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[16.704525477792117,37.513706149401855],"opacity":1,"blur":0,"isLocked":false,"gid":31,"smootheningRate":0,"initialPoint":[16.704525477792117,37.513706149401855],"creationPoints":[],"name":"(line)"},{"elementDescription":"(line)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[228.4683004292159,412.55599916164635],"reflectionModeOverride":0,"anchorPoint":[228.4683004292159,412.55599916164635],"cornerRadius":0,"prevPoint":[16.704525477792117,140.51302468949859],"inPoint":[228.4683004292159,412.55599916164635],"nextPoint":[16.704525477792117,140.51302468949859]},{"outPoint":[371.51081106842264,412.55599916164635],"reflectionModeOverride":0,"anchorPoint":[371.51081106842264,412.55599916164635],"cornerRadius":0,"prevPoint":[16.704525477792117,140.51302468949859],"inPoint":[371.51081106842264,412.55599916164635],"nextPoint":[16.704525477792117,140.51302468949859]}],"closed":false,"reversed":false}},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":1,"width":61.869819641113281,"endArrow":"","startArrow":"","cap":0},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[16.704525477792117,140.51302468949859],"opacity":1,"blur":0,"isLocked":false,"gid":32,"smootheningRate":0,"initialPoint":[16.704525477792117,140.51302468949859],"creationPoints":[],"name":"(line)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[2.7206907461103356,25.513785542788241],"opacity":1,"blur":0,"isLocked":false,"gid":55,"smootheningRate":0,"initialPoint":[2.7206907461103356,25.513785542788241],"creationPoints":[],"group":{"elements":[{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[300.38008332937886,557.84279577418272],"reflectionModeOverride":0,"anchorPoint":[300.38008332937886,557.84279577418272],"cornerRadius":0,"prevPoint":[4.8049994992771872,-1.0129103054042616],"inPoint":[300.87435644597588,529.50877422158635],"nextPoint":[4.8049994992771872,-1.0129103054042616]},{"outPoint":[300.43161232869249,507.2021517541192],"reflectionModeOverride":0,"anchorPoint":[300.43161232869249,507.2021517541192],"cornerRadius":0,"prevPoint":[-12.365577443621419,-27.342871697380019],"inPoint":[300.43161232869249,507.2021517541192],"nextPoint":[-12.365577443621419,-27.342871697380019]},{"outPoint":[315.7481814828169,517.26662181075551],"reflectionModeOverride":0,"anchorPoint":[336.28774305214836,507.15563112854068],"cornerRadius":0,"prevPoint":[2.7206907461103356,24.978316814837285],"inPoint":[336.28774305214836,507.15563112854068],"nextPoint":[2.7206907461103356,24.978316814837285]}],"closed":true,"reversed":false}},"fillColor":{"b":0,"s":0,"h":0,"a":1},"strokeStyle":{"color":{"b":0.9882352941176471,"s":1,"h":0.5806878306878307,"a":1},"dashPattern":[],"join":1,"width":0.10000000149011612,"endArrow":"","startArrow":"","cap":0},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[4.9686415433105822,12.610834591390244],"opacity":1,"blur":0,"isLocked":false,"gid":48,"smootheningRate":0,"initialPoint":[4.9686415433105822,12.610834591390244],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[300.44667602585685,557.84279577418272],"reflectionModeOverride":0,"anchorPoint":[300.44667602585685,557.84279577418272],"cornerRadius":0,"prevPoint":[596.02175985595829,-1.0129103054042616],"inPoint":[299.95240290925983,529.50877422158635],"nextPoint":[596.02175985595829,-1.0129103054042616]},{"outPoint":[300.39514702654321,507.2021517541192],"reflectionModeOverride":0,"anchorPoint":[300.39514702654321,507.2021517541192],"cornerRadius":0,"prevPoint":[613.1923367988569,-27.342871697380019],"inPoint":[300.39514702654321,507.2021517541192],"nextPoint":[613.1923367988569,-27.342871697380019]},{"outPoint":[285.07857787241835,517.26662181075551],"reflectionModeOverride":0,"anchorPoint":[264.53901630308735,507.15563112854068],"cornerRadius":0,"prevPoint":[598.10606860912537,24.978316814837285],"inPoint":[264.53901630308735,507.15563112854068],"nextPoint":[598.10606860912537,24.978316814837285]}],"closed":true,"reversed":false}},"fillColor":{"b":0,"s":0,"h":0,"a":1},"strokeStyle":{"color":{"b":0.9882352941176471,"s":1,"h":0.5806878306878307,"a":1},"dashPattern":[],"join":1,"width":0.10000000149011612,"endArrow":"","startArrow":"","cap":0},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[595.85811781192467,12.818230389370797],"opacity":1,"blur":0,"isLocked":false,"gid":54,"smootheningRate":0,"initialPoint":[595.85811781192467,12.818230389370797],"creationPoints":[],"name":"(curve)"}]},"name":"(curve)"}]},"name":"(curve)"}],"isExpanded":false,"isLocked":false,"isVisible":true,"opacity":1,"gid":4,"name":"Layer 1"}],"frame":{"y":0,"x":0,"width":600,"height":600},"title":"Mac App icon","activeLayerIndex":0,"settings":{"gridSpacing":20,"gridAngle":45,"backgroundColor":{"b":1,"s":0,"h":0,"a":1},"gridMode":0,"isGridVisible":false},"guideLayer":{"isExpanded":false,"elements":[],"isLocked":false,"defaultName":"Guides","isVisible":true,"opacity":1,"name":"Guides","gid":5},"gid":3}
diff --git a/docs/images/logo.vectornator/Document.json b/docs/images/logo.vectornator/Document.json
index ac7714f..6439b5c 100644
--- a/docs/images/logo.vectornator/Document.json
+++ b/docs/images/logo.vectornator/Document.json
@@ -1 +1 @@
-{"date":644900643.85054696,"appVersion":"4.1.5","drawing":{"modificationDate":644894800.328192,"activeArtboardIndex":0,"settings":{"outlineMode":false,"isolateActiveLayer":false,"snapToEdges":false,"snapToPoints":false,"guidesVisible":true,"snapToGrid":false,"units":"Pixels","dimensionsVisible":true,"dynamicGuides":false,"isCMYKColorPreviewEnabled":false,"undoHistoryDisabled":false,"snapToGuides":true,"drawOnlyUsingPencil":false,"whiteBackground":false,"rulersVisible":true,"isTimeLapseWatermarkDisabled":false},"artboardPaths":["Artboard0.json"],"documentVersion":"unknown"}} \ No newline at end of file
+{"date":644900643.85054696,"appVersion":"4.1.5","drawing":{"modificationDate":644894800.328192,"activeArtboardIndex":0,"settings":{"outlineMode":false,"isolateActiveLayer":false,"snapToEdges":false,"snapToPoints":false,"guidesVisible":true,"snapToGrid":false,"units":"Pixels","dimensionsVisible":true,"dynamicGuides":false,"isCMYKColorPreviewEnabled":false,"undoHistoryDisabled":false,"snapToGuides":true,"drawOnlyUsingPencil":false,"whiteBackground":false,"rulersVisible":true,"isTimeLapseWatermarkDisabled":false},"artboardPaths":["Artboard0.json"],"documentVersion":"unknown"}}
diff --git a/docs/images/logo.vectornator/Manifest.json b/docs/images/logo.vectornator/Manifest.json
index 0f80b78..8e897a0 100644
--- a/docs/images/logo.vectornator/Manifest.json
+++ b/docs/images/logo.vectornator/Manifest.json
@@ -1 +1 @@
-{"documentJSONFilename":"Document.json","undoHistoryJSONFilename":"UndoHistory.json","fileFormatVersion":0,"thumbnailImageFilename":"Thumbnail.png"} \ No newline at end of file
+{"documentJSONFilename":"Document.json","undoHistoryJSONFilename":"UndoHistory.json","fileFormatVersion":0,"thumbnailImageFilename":"Thumbnail.png"}
diff --git a/docs/images/logo.vectornator/UndoHistory.json b/docs/images/logo.vectornator/UndoHistory.json
index ead621d..e9379db 100644
--- a/docs/images/logo.vectornator/UndoHistory.json
+++ b/docs/images/logo.vectornator/UndoHistory.json
@@ -1 +1 @@
-{"cacheElements":[{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[320,664.0506297595],"reflectionModeOverride":0,"anchorPoint":[320,640],"cornerRadius":0,"prevPoint":[0,0],"inPoint":[320,580],"nextPoint":[0,0]},{"outPoint":[344.050612449646,595.89893977911322],"reflectionModeOverride":0,"anchorPoint":[337.34381007033926,612.48211711168926],"cornerRadius":0,"prevPoint":[0,0],"inPoint":[327.23039949003834,637.48844227310212],"nextPoint":[0,0]},{"outPoint":[380,580],"reflectionModeOverride":0,"anchorPoint":[360,580],"cornerRadius":0,"prevPoint":[0,0],"inPoint":[352.025306224823,580],"nextPoint":[0,0]},{"outPoint":[260,580],"reflectionModeOverride":0,"anchorPoint":[280,580],"cornerRadius":0,"prevPoint":[0,0],"inPoint":[300,580],"nextPoint":[0,0]}],"closed":true,"reversed":false}},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":2,"width":0.10000000149011612,"endArrow":"","startArrow":"","cap":1},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[0,0],"opacity":1,"blur":0,"isLocked":false,"gid":34,"smootheningRate":0,"initialPoint":[0,0],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"fillColor":{"b":0.98823529481887817,"s":1,"h":0.58068782582120682,"a":1},"maskedElements":[],"abstractPath":{"fillRule":0,"compoundPathData":{"subpaths":[{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[221.67257107604084,316.56452785377144],"reflectionModeOverride":0,"anchorPoint":[221.67257107604084,316.56452785377144],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[221.67257107604084,316.56452785377144],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[222.78002147975192,316.58196755365179],"reflectionModeOverride":0,"anchorPoint":[222.50257105935154,316.56452785377144],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[222.50257105935154,316.56452785377144],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[223.46754319256974,316.15798118973765],"reflectionModeOverride":0,"anchorPoint":[223.27257099819641,316.3245278149393],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[223.05416436926282,316.49652037792839],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[223.56257095468965,315.05452779244973],"reflectionModeOverride":0,"anchorPoint":[223.56257095468965,315.65452781629159],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[223.57458948209043,315.9106673969701],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[222.50257101191011,314.72452780913903],"reflectionModeOverride":0,"anchorPoint":[222.50257101191011,314.72452780913903],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[223.18257095945802,314.72452780913903],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[221.67257102859941,314.72452780913903],"reflectionModeOverride":0,"anchorPoint":[221.67257102859941,314.72452780913903],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[221.67257102859941,314.72452780913903],"nextPoint":[112.85257138121662,191.97453151588078]}],"closed":true,"reversed":false}},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[112.85257138121662,191.97453151588078],"opacity":1,"blur":0,"isLocked":false,"gid":7,"smootheningRate":0,"initialPoint":[112.85257138121662,191.97453151588078],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[223.39257110465107,318.92452774886726],"reflectionModeOverride":0,"anchorPoint":[223.39257110465107,318.92452774886726],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[223.39257110465107,318.92452774886726],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[222.33257116187153,317.04452775363563],"reflectionModeOverride":0,"anchorPoint":[222.33257116187153,317.04452775363563],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[222.33257116187153,317.04452775363563],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[221.67257113564548,317.04452775363563],"reflectionModeOverride":0,"anchorPoint":[221.67257113564548,317.04452775363563],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[221.67257113564548,317.04452775363563],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[221.67257113564548,318.97453151588081],"reflectionModeOverride":0,"anchorPoint":[221.67257113564548,318.97453151588081],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[221.67257113564548,318.97453151588081],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[221.06257112134037,318.97453151588081],"reflectionModeOverride":0,"anchorPoint":[221.06257112134037,318.97453151588081],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[221.06257112134037,318.97453151588081],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[221.06257112134037,314.29453168754219],"reflectionModeOverride":0,"anchorPoint":[221.06257112134037,314.29453168754219],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[221.06257112134037,314.29453168754219],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[222.85351610118363,314.2910670771638],"reflectionModeOverride":0,"anchorPoint":[222.64257116425571,314.29453168754219],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[222.64257116425571,314.29453168754219],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[223.44257068590508,314.46434348341825],"reflectionModeOverride":0,"anchorPoint":[223.26257121864279,314.39453162176318],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[223.06341253016012,314.32492145971571],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[223.8867055322342,314.82297152263595],"reflectionModeOverride":0,"anchorPoint":[223.75257125112995,314.69453165532451],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[223.60854628757448,314.56596123813961],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[224.15455094852729,315.31612333025106],"reflectionModeOverride":0,"anchorPoint":[224.07257117822328,315.14453165999419],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[223.99528738469252,314.97566482247669],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[224.19825083117667,315.9922372888982],"reflectionModeOverride":0,"anchorPoint":[224.19257122020886,315.69453168706491],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[224.19562660185056,315.50438689028209],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[223.7338072115908,316.75555373263109],"reflectionModeOverride":0,"anchorPoint":[223.91257119347284,316.51453168318102],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[224.09914577717603,316.28247388344346],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[223.19257120773227,317.01453168185151],"reflectionModeOverride":0,"anchorPoint":[223.19257120773227,317.01453168185151],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[223.48085346525613,316.9312160768892],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[222.99257120475204,317.08453168214953],"reflectionModeOverride":0,"anchorPoint":[222.99257120475204,317.08453168214953],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[222.99257120475204,317.08453168214953],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[224.0925712285939,318.97453166784442],"reflectionModeOverride":0,"anchorPoint":[224.0925712285939,318.97453166784442],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[224.0925712285939,318.97453166784442],"nextPoint":[112.85257138121662,191.97453151588078]}],"closed":true,"reversed":false}},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[112.85257138121662,191.97453151588078],"opacity":1,"blur":0,"isLocked":false,"gid":8,"smootheningRate":0,"initialPoint":[112.85257138121662,191.97453151588078],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[221.88165496610824,312.75214941635204],"reflectionModeOverride":0,"anchorPoint":[222.39257110465107,312.75452767257332],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[222.39257110465107,312.75452767257332],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[220.45378029794426,313.23854645592189],"reflectionModeOverride":0,"anchorPoint":[220.90257124445034,313.04452773196982],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[221.37529974656684,312.85070177480884],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[219.35876943156495,314.2208600575953],"reflectionModeOverride":0,"anchorPoint":[219.70257152159786,313.86452769906913],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[220.04640821090715,313.51691728007791],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[218.51848057480817,316.05954140545026],"reflectionModeOverride":0,"anchorPoint":[218.89257170245423,315.09452765536599],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[219.0841152815558,314.63792794299417],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[219.07885049250976,318.55391401613247],"reflectionModeOverride":0,"anchorPoint":[218.89257166857527,318.09452771720584],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[218.51848023468915,317.12951359608263],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[220.04640881460426,319.67213836278347],"reflectionModeOverride":0,"anchorPoint":[219.70257171508007,319.32452783266035],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[219.35412998721458,318.97193143333453],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[222.32887552639454,320.75534631866788],"reflectionModeOverride":0,"anchorPoint":[220.90257185775954,320.14452762388811],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[220.45378073087409,319.9505090873252],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[225.42747093525361,318.97720769048311],"reflectionModeOverride":0,"anchorPoint":[225.07257197531021,319.32452740981233],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[223.98375014972524,320.42992729161517],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[226.25666363710593,317.12951355179308],"reflectionModeOverride":0,"anchorPoint":[225.8825720147413,318.09452742555698],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[225.70369149262439,318.55776181404121],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[225.69870344883279,314.63387871118448],"reflectionModeOverride":0,"anchorPoint":[225.88257204862026,315.09452736371713],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[226.25666342066654,316.05954129932087],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[224.73054756988128,313.51475021332715],"reflectionModeOverride":0,"anchorPoint":[225.07257201185996,313.86452742080394],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[225.42312528062655,314.21540813724465],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[223.40302999066401,312.851739523118],"reflectionModeOverride":0,"anchorPoint":[223.87257194075443,313.04452740721484],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[224.32272320141846,313.23607014436448],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[222.39257194847221,312.754527354262],"reflectionModeOverride":0,"anchorPoint":[222.39257194847221,312.754527354262],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[222.90014945704277,312.7532021443493],"nextPoint":[112.85257138121662,191.97453151588078]}],"closed":false,"reversed":false}},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[112.85257138121662,191.97453151588078],"opacity":1,"blur":0,"isLocked":false,"gid":9,"smootheningRate":0,"initialPoint":[112.85257138121662,191.97453151588078],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[221.79793545229796,321.06845412941806],"reflectionModeOverride":0,"anchorPoint":[222.39257194847221,321.06452777387869],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[222.39257194847221,321.06452777387869],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[220.13630955687603,320.47368746402753],"reflectionModeOverride":0,"anchorPoint":[220.66257205810552,320.71452796827054],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[221.20891937561655,320.94928924957026],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[218.84008207185138,319.31458146286332],"reflectionModeOverride":0,"anchorPoint":[219.26257159607349,319.71452784560978],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[219.66107353858615,320.13423302542299],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[217.79637500761001,317.20177600727493],"reflectionModeOverride":0,"anchorPoint":[218.26257166453621,318.30452834140976],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[218.50031051375157,318.83550383670706],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[218.71657507260346,313.79480682341318],"reflectionModeOverride":0,"anchorPoint":[218.26257150938892,314.85452883246262],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[217.79637484257967,315.95728089190948],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[221.15964890699888,312.25319776201661],"reflectionModeOverride":0,"anchorPoint":[220.61257125382446,312.48452913388269],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[219.5567350056233,312.94749659064405],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[222.93948006388655,312.14028017121217],"reflectionModeOverride":0,"anchorPoint":[222.34257146546875,312.14452894709979],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[221.74863705025209,312.1374427227563],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[224.61118094730551,312.72639164873863],"reflectionModeOverride":0,"anchorPoint":[224.08257153232208,312.48452915920495],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[223.53116831317226,312.25589748063879],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[225.90916737355408,313.88955714821628],"reflectionModeOverride":0,"anchorPoint":[225.49257153005306,313.48452928232075],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[225.08951592668194,313.06563634089633],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[226.95876793869749,315.99728178436908],"reflectionModeOverride":0,"anchorPoint":[226.49257128177129,314.89452945023424],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[226.24808810980261,314.36743571685838],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[226.25070868333646,318.87313890226199],"reflectionModeOverride":0,"anchorPoint":[226.49257117287002,318.34452948727852],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[226.95876813673391,317.24177716378313],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[224.65955409863321,320.59420064219239],"reflectionModeOverride":0,"anchorPoint":[225.49257104975428,319.75452948500953],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[225.91146402567489,319.35147381264608],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[222.34257072457945,321.06452950412722],"reflectionModeOverride":0,"anchorPoint":[222.34257072457945,321.06452950412722],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[223.52534831488276,321.06588609892162],"nextPoint":[112.85257138121662,191.97453151588078]}],"closed":false,"reversed":false}},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[112.85257138121662,191.97453151588078],"opacity":1,"blur":0,"isLocked":false,"gid":10,"smootheningRate":0,"initialPoint":[112.85257138121662,191.97453151588078],"creationPoints":[],"name":"(curve)"}]}}},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[112.85257138121662,191.97453151588078],"opacity":1,"blur":0,"isLocked":false,"gid":6,"smootheningRate":0,"initialPoint":[112.85257138121662,191.97453151588078],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"fillColor":{"b":1,"s":0,"h":0,"a":1},"maskedElements":[],"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[189.49257363188801,253.97453151588081],"reflectionModeOverride":0,"anchorPoint":[189.49257363188801,253.97453151588081],"cornerRadius":0,"prevPoint":[112.85257138121662,152.97453151588078],"inPoint":[189.49257363188801,253.97453151588081],"nextPoint":[112.85257138121662,152.97453151588078]},{"outPoint":[198.97257317412434,244.48453174476265],"reflectionModeOverride":0,"anchorPoint":[198.97257317412434,244.48453174476265],"cornerRadius":0,"prevPoint":[112.85257138121662,152.97453151588078],"inPoint":[198.97257317412434,244.48453174476265],"nextPoint":[112.85257138121662,152.97453151588078]},{"outPoint":[189.49257363188801,235.01453147773384],"reflectionModeOverride":0,"anchorPoint":[189.49257363188801,235.01453147773384],"cornerRadius":0,"prevPoint":[112.85257138121662,152.97453151588078],"inPoint":[189.49257363188801,235.01453147773384],"nextPoint":[112.85257138121662,152.97453151588078]}],"closed":true,"reversed":false}}},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[112.85257138121662,152.97453151588078],"opacity":1,"blur":0,"isLocked":false,"gid":16,"smootheningRate":0,"initialPoint":[112.85257138121662,152.97453151588078],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[300,640],"reflectionModeOverride":0,"anchorPoint":[300,640],"cornerRadius":0,"prevPoint":[0,0],"inPoint":[300,640],"nextPoint":[0,0]},{"outPoint":[380,580],"reflectionModeOverride":0,"anchorPoint":[340,580],"cornerRadius":0,"prevPoint":[0,0],"inPoint":[300,580],"nextPoint":[0,0]}],"closed":false,"reversed":false}},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":2,"width":0.10000000149011612,"endArrow":"","startArrow":"","cap":1},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[0,0],"opacity":1,"blur":0,"isLocked":false,"gid":36,"smootheningRate":0,"initialPoint":[0,0],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[292.2196979967656,487.32457590003901],"reflectionModeOverride":0,"anchorPoint":[270.70254252087443,481.42866614307741],"cornerRadius":0,"prevPoint":[0,1.3634276556741725],"inPoint":[246.45876716860445,474.78563603599895],"nextPoint":[0,1.3634276556741725]},{"outPoint":[308.32019835237998,560.47255779544446],"reflectionModeOverride":0,"anchorPoint":[307.80961189523731,532.13830093176216],"cornerRadius":0,"prevPoint":[9.9345758586960642,16.47175369678871],"inPoint":[307.29902543809465,503.80404406807986],"nextPoint":[9.9345758586960642,16.47175369678871]}],"closed":false,"reversed":false}},"fillColor":{"b":0.9882352941176471,"s":1,"h":0.13822251558303833,"a":1},"strokeStyle":{"color":{"b":0.9882352941176471,"s":1,"h":0.5806878306878307,"a":1},"dashPattern":[],"join":1,"width":0.10000000149011612,"endArrow":"","startArrow":"","cap":0},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[9.9345758586960642,15.108326041114537],"opacity":1,"blur":0,"isLocked":false,"gid":44,"smootheningRate":0,"initialPoint":[9.9345758586960642,15.108326041114537],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(polygon)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[368.75294547403814,729.44134214300266],"reflectionModeOverride":0,"anchorPoint":[368.75294547403814,729.44134214300266],"cornerRadius":0,"prevPoint":[221.86289110820167,-279.40236718212691],"inPoint":[368.75294547403814,729.44134214300266],"nextPoint":[221.86289110820167,-279.40236718212691]},{"outPoint":[58.884741476317231,550.53885452571922],"reflectionModeOverride":0,"anchorPoint":[58.884741476317231,550.53885452571922],"cornerRadius":0,"prevPoint":[221.86289110820167,-279.40236718212691],"inPoint":[58.884741476317231,550.53885452571922],"nextPoint":[221.86289110820167,-279.40236718212691]},{"outPoint":[58.884771993693448,192.73377248033557],"reflectionModeOverride":0,"anchorPoint":[58.884771993693448,192.73377248033557],"cornerRadius":0,"prevPoint":[221.86289110820167,-279.40236718212691],"inPoint":[58.884771993693448,192.73377248033557],"nextPoint":[221.86289110820167,-279.40236718212691]},{"outPoint":[368.75296538097359,13.831330639116459],"reflectionModeOverride":0,"anchorPoint":[368.75296538097359,13.831330639116459],"cornerRadius":0,"prevPoint":[221.86289110820167,-279.40236718212691],"inPoint":[368.75296538097359,13.831330639116459],"nextPoint":[221.86289110820167,-279.40236718212691]},{"outPoint":[678.62124178681802,192.73392506721666],"reflectionModeOverride":0,"anchorPoint":[678.62124178681802,192.73392506721666],"cornerRadius":0,"prevPoint":[221.86289110820167,-279.40236718212691],"inPoint":[678.62124178681802,192.73392506721666],"nextPoint":[221.86289110820167,-279.40236718212691]},{"outPoint":[678.62118075206558,550.53885452571922],"reflectionModeOverride":0,"anchorPoint":[678.62118075206558,550.53885452571922],"cornerRadius":0,"prevPoint":[221.86289110820167,-279.40236718212691],"inPoint":[678.62118075206558,550.53885452571922],"nextPoint":[221.86289110820167,-279.40236718212691]}],"closed":true,"reversed":false}},"fillColor":{"b":0.9882352941176471,"s":1,"h":0.5806878306878307,"a":0.3074892778331435},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":1,"width":18.646402359008789,"endArrow":"","startArrow":"","cap":0},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[368.75296111419152,729.44134214300266],"opacity":1,"blur":0,"isLocked":false,"gid":57,"smootheningRate":0,"initialPoint":[368.75296111419152,371.63633639105956],"creationPoints":[],"name":"(polygon)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[340,700],"reflectionModeOverride":0,"anchorPoint":[340,660],"cornerRadius":0,"prevPoint":[0,0],"inPoint":[340,620],"nextPoint":[0,0]},{"outPoint":[340,600],"reflectionModeOverride":0,"anchorPoint":[380,600],"cornerRadius":0,"prevPoint":[0,0],"inPoint":[420,600],"nextPoint":[0,0]}],"closed":false,"reversed":false}},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":2,"width":0.10000000149011612,"endArrow":"","startArrow":"","cap":1},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[0,0],"opacity":1,"blur":0,"isLocked":false,"gid":35,"smootheningRate":0,"initialPoint":[0,0],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[345.33038784778722,480.48121812716067],"reflectionModeOverride":0,"anchorPoint":[345.33038784778722,480.48121812716067],"cornerRadius":0,"prevPoint":[86.563617484933189,-170.37985441312253],"inPoint":[308.36370636737951,480.48121812716067],"nextPoint":[86.563617484933189,-170.37985441312253]},{"outPoint":[271.39702488697174,480.48121812716067],"reflectionModeOverride":0,"anchorPoint":[271.39702488697174,480.48121812716067],"cornerRadius":0,"prevPoint":[86.563617484933189,-170.37985441312253],"inPoint":[271.39702488697174,480.48121812716067],"nextPoint":[86.563617484933189,-170.37985441312253]},{"outPoint":[345.33038784778722,480.48121812716067],"reflectionModeOverride":0,"anchorPoint":[345.33038784778722,480.48121812716067],"cornerRadius":0,"prevPoint":[86.563617484933189,-170.37985441312253],"inPoint":[345.33038784778722,480.48121812716067],"nextPoint":[86.563617484933189,-170.37985441312253]},{"outPoint":[308.36370636737951,480.48121812716067],"reflectionModeOverride":0,"anchorPoint":[271.39702488697174,480.48121812716067],"cornerRadius":0,"prevPoint":[86.563617484933189,-170.37985441312253],"inPoint":[271.39702488697174,480.48121812716067],"nextPoint":[86.563617484933189,-170.37985441312253]},{"outPoint":[308.36370636737951,547.81167390718997],"reflectionModeOverride":0,"anchorPoint":[308.36370636737951,547.81167390718997],"cornerRadius":0,"prevPoint":[86.563617484933189,-170.37985441312253],"inPoint":[308.36370636737951,547.81167390718997],"nextPoint":[86.563617484933189,-170.37985441312253]}],"closed":true,"reversed":true}},"fillColor":{"b":0,"s":0,"h":0,"a":1},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":2,"width":0.10000000149011612,"endArrow":"","startArrow":"","cap":1},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[579.21777967228218,-165.50118646031109],"opacity":1,"blur":0,"isLocked":false,"gid":37,"smootheningRate":0,"initialPoint":[579.21777967228218,-165.50118646031109],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(line)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[13.974435927889729,160.80268978822852],"reflectionModeOverride":0,"anchorPoint":[13.974435927889729,160.80268978822852],"cornerRadius":0,"prevPoint":[0,0],"inPoint":[13.974435927889729,160.80268978822852],"nextPoint":[0,0]},{"outPoint":[144.25556161242727,291.78142890790133],"reflectionModeOverride":0,"anchorPoint":[144.25556161242727,291.78142890790133],"cornerRadius":0,"prevPoint":[0,0],"inPoint":[144.25556161242727,291.78142890790133],"nextPoint":[0,0]}],"closed":false,"reversed":false}},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":1,"width":20,"endArrow":"","startArrow":"","cap":1},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[0,0],"opacity":1,"blur":0,"isLocked":false,"gid":28,"smootheningRate":0,"initialPoint":[0,0],"creationPoints":[],"name":"(line)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[323.38754763944246,487.32457590003901],"reflectionModeOverride":0,"anchorPoint":[344.90470311533363,481.42866614307741],"cornerRadius":0,"prevPoint":[615.60724563620806,1.3634276556741725],"inPoint":[369.14847846760358,474.78563603599895],"nextPoint":[615.60724563620806,1.3634276556741725]},{"outPoint":[307.28704728382809,560.47255779544446],"reflectionModeOverride":0,"anchorPoint":[307.79763374097075,532.13830093176216],"cornerRadius":0,"prevPoint":[605.67266977751206,16.47175369678871],"inPoint":[308.30822019811342,503.80404406807986],"nextPoint":[605.67266977751206,16.47175369678871]}],"closed":false,"reversed":false}},"fillColor":{"b":0.9882352941176471,"s":1,"h":0.13822251558303833,"a":1},"strokeStyle":{"color":{"b":0.9882352941176471,"s":1,"h":0.5806878306878307,"a":1},"dashPattern":[],"join":1,"width":0.10000000149011612,"endArrow":"","startArrow":"","cap":0},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[605.67266977751206,16.47175369678871],"opacity":1,"blur":0,"isLocked":false,"gid":45,"smootheningRate":0,"initialPoint":[605.67266977751206,16.47175369678871],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[307.98765662154068,497.22766759942954],"reflectionModeOverride":0,"anchorPoint":[307.98765662154068,526.40806463936553],"cornerRadius":0,"prevPoint":[0,0],"inPoint":[307.98765662154068,555.58846167930153],"nextPoint":[0,0]},{"outPoint":[347.07124677007465,468.5633046399771],"reflectionModeOverride":0,"anchorPoint":[331.56894097295356,478.9361833057668],"cornerRadius":0,"prevPoint":[0,0],"inPoint":[316.06663517583246,489.3090619715565],"nextPoint":[0,0]}],"closed":false,"reversed":false}},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":2,"width":20,"endArrow":"","startArrow":"","cap":1},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[0,0],"opacity":1,"blur":0,"isLocked":false,"gid":33,"smootheningRate":0,"initialPoint":[0,0],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"compoundPathData":{"subpaths":[{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[367.7690644381571,667.02363476289884],"reflectionModeOverride":0,"anchorPoint":[367.7690644381571,667.02363476289884],"cornerRadius":0,"prevPoint":[72.193980608055426,108.16792868331186],"inPoint":[368.26333755475412,638.68961321030247],"nextPoint":[72.193980608055426,108.16792868331186]},{"outPoint":[367.82059343747073,616.38299074283532],"reflectionModeOverride":0,"anchorPoint":[367.82059343747073,616.38299074283532],"cornerRadius":0,"prevPoint":[55.02340366515682,81.837967291336099],"inPoint":[367.82059343747073,616.38299074283532],"nextPoint":[55.02340366515682,81.837967291336099]},{"outPoint":[383.13716259159514,626.44746079947163],"reflectionModeOverride":0,"anchorPoint":[403.6767241609266,616.33647011725679],"cornerRadius":0,"prevPoint":[70.109671854888575,134.1591558035534],"inPoint":[403.6767241609266,616.33647011725679],"nextPoint":[70.109671854888575,134.1591558035534]}],"closed":true,"reversed":false}},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[72.357622652088821,121.79167358010636],"opacity":1,"blur":0,"isLocked":false,"gid":48,"smootheningRate":0,"initialPoint":[72.357622652088821,121.79167358010636],"creationPoints":[],"name":"(curve)"}]}},"fillColor":{"b":0.9882352941176471,"s":1,"h":0.13822251558303833,"a":1},"strokeStyle":{"color":{"b":0.9882352941176471,"s":1,"h":0.5806878306878307,"a":1},"dashPattern":[],"join":1,"width":0.10000000149011612,"endArrow":"","startArrow":"","cap":0},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[-2.4740749822735211,26.734403557988003],"opacity":1,"blur":0,"isLocked":false,"gid":46,"smootheningRate":0,"initialPoint":[-2.4740749822735211,26.734403557988003],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"fillColor":{"b":0.98823529481887817,"s":1,"h":0.58068782582120682,"a":1},"maskedElements":[],"abstractPath":{"fillRule":0,"compoundPathData":{"subpaths":[{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[-17.790763092914176,455.94130474918654],"reflectionModeOverride":0,"anchorPoint":[-17.790763092914176,455.94130474918654],"cornerRadius":0,"prevPoint":[-343.22817622315347,103.6410041510419],"inPoint":[-17.790763092914176,455.94130474918654],"nextPoint":[-343.22817622315347,103.6410041510419]},{"outPoint":[-118.14742861878335,355.38893101990755],"reflectionModeOverride":0,"anchorPoint":[-118.14742861878335,355.38893101990755],"cornerRadius":0,"prevPoint":[-343.22817622315347,103.6410041510419],"inPoint":[-118.14742861878335,355.38893101990755],"nextPoint":[-343.22817622315347,103.6410041510419]},{"outPoint":[-89.082653539453304,326.03057263672883],"reflectionModeOverride":0,"anchorPoint":[-89.082653539453304,326.03057263672883],"cornerRadius":0,"prevPoint":[-343.22817622315347,103.6410041510419],"inPoint":[-89.082653539453304,326.03057263672883],"nextPoint":[-343.22817622315347,103.6410041510419]},{"outPoint":[-9.0811227455444623,406.22781863362536],"reflectionModeOverride":0,"anchorPoint":[-9.0811227455444623,406.22781863362536],"cornerRadius":0,"prevPoint":[-343.22817622315347,103.6410041510419],"inPoint":[-9.0811227455444623,406.22781863362536],"nextPoint":[-343.22817622315347,103.6410041510419]},{"outPoint":[-9.0811227455444623,214.66453204993843],"reflectionModeOverride":0,"anchorPoint":[-9.0811227455444623,214.66453204993843],"cornerRadius":0,"prevPoint":[-343.22817622315347,103.6410041510419],"inPoint":[-9.0811227455444623,214.66453204993843],"nextPoint":[-343.22817622315347,103.6410041510419]},{"outPoint":[136.29167736876548,359.98840044701058],"reflectionModeOverride":0,"anchorPoint":[136.29167736876548,359.98840044701058],"cornerRadius":0,"prevPoint":[-343.22817622315347,103.6410041510419],"inPoint":[136.29167736876548,359.98840044701058],"nextPoint":[-343.22817622315347,103.6410041510419]},{"outPoint":[40.289832016581158,455.94130474918654],"reflectionModeOverride":0,"anchorPoint":[40.289832016581158,455.94130474918654],"cornerRadius":0,"prevPoint":[-343.22817622315347,103.6410041510419],"inPoint":[40.289832016581158,455.94130474918654],"nextPoint":[-343.22817622315347,103.6410041510419]},{"outPoint":[136.29167736876548,551.89420905136228],"reflectionModeOverride":0,"anchorPoint":[136.29167736876548,551.89420905136228],"cornerRadius":0,"prevPoint":[-343.22817622315347,103.6410041510419],"inPoint":[136.29167736876548,551.89420905136228],"nextPoint":[-343.22817622315347,103.6410041510419]},{"outPoint":[-9.0322003610774573,697.21808678120522],"reflectionModeOverride":0,"anchorPoint":[-9.0322003610774573,697.21808678120522],"cornerRadius":0,"prevPoint":[-343.22817622315347,103.6410041510419],"inPoint":[-9.0322003610774573,697.21808678120522],"nextPoint":[-343.22817622315347,103.6410041510419]},{"outPoint":[-9.0322003610774573,505.65480953028907],"reflectionModeOverride":0,"anchorPoint":[-9.0322003610774573,505.65480953028907],"cornerRadius":0,"prevPoint":[-343.22817622315347,103.6410041510419],"inPoint":[-9.0322003610774573,505.65480953028907],"nextPoint":[-343.22817622315347,103.6410041510419]},{"outPoint":[-88.78907023560464,585.60738760822585],"reflectionModeOverride":0,"anchorPoint":[-88.78907023560464,585.60738760822585],"cornerRadius":0,"prevPoint":[-343.22817622315347,103.6410041510419],"inPoint":[-88.78907023560464,585.60738760822585],"nextPoint":[-343.22817622315347,103.6410041510419]},{"outPoint":[-117.85384531493469,556.24902922504714],"reflectionModeOverride":0,"anchorPoint":[-117.85384531493469,556.24902922504714],"cornerRadius":0,"prevPoint":[-343.22817622315347,103.6410041510419],"inPoint":[-117.85384531493469,556.24902922504714],"nextPoint":[-343.22817622315347,103.6410041510419]}],"closed":true,"reversed":false}},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[-343.22817622315347,103.6410041510419],"opacity":1,"blur":0,"isLocked":false,"gid":13,"smootheningRate":0,"initialPoint":[-343.22817622315347,103.6410041510419],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[-87.50742636811205,292.97453151588081],"reflectionModeOverride":0,"anchorPoint":[-87.50742636811205,292.97453151588081],"cornerRadius":0,"prevPoint":[-164.14742861878338,191.97453151588081],"inPoint":[-87.50742636811205,292.97453151588081],"nextPoint":[-164.14742861878338,191.97453151588081]},{"outPoint":[-78.027426825875665,283.48453174476265],"reflectionModeOverride":0,"anchorPoint":[-78.027426825875665,283.48453174476265],"cornerRadius":0,"prevPoint":[-164.14742861878338,191.97453151588081],"inPoint":[-78.027426825875665,283.48453174476265],"nextPoint":[-164.14742861878338,191.97453151588081]},{"outPoint":[-87.507426368111936,274.01453147773384],"reflectionModeOverride":0,"anchorPoint":[-87.507426368111936,274.01453147773384],"cornerRadius":0,"prevPoint":[-164.14742861878338,191.97453151588081],"inPoint":[-87.507426368111936,274.01453147773384],"nextPoint":[-164.14742861878338,191.97453151588081]}],"closed":true,"reversed":false}},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[-164.14742861878338,191.97453151588081],"opacity":1,"blur":0,"isLocked":false,"gid":14,"smootheningRate":0,"initialPoint":[-164.14742861878338,191.97453151588081],"creationPoints":[],"name":"(curve)"}]}}},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[-164.14742861878338,191.97453151588078],"opacity":1,"blur":0,"isLocked":false,"gid":11,"smootheningRate":0,"initialPoint":[-164.14742861878338,191.97453151588078],"creationPoints":[],"name":"(curve)"}],"cacheLayers":[],"cacheArtboardPaths":[],"undoStack":[[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":6}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -20, -20]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11,6]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -29.209948435277369, -232.41660739687057]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[12]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[12,13,14,15]}","argumentGID":0}],"methodSignature":"setSubpaths:","targetGID":11},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11}],"methodSignature":"setSuperpath:","targetGID":12},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setFill:","targetGID":12},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":12},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setShadow:","targetGID":12},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11}],"methodSignature":"setSuperpath:","targetGID":13},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setFill:","targetGID":13},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":13},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setShadow:","targetGID":13},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11}],"methodSignature":"setSuperpath:","targetGID":14},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setFill:","targetGID":14},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":14},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setShadow:","targetGID":14}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":6},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":16}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -20, -20]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":16},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":16}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setFill:","targetGID":14}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setFill:","targetGID":16}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setFill:","targetGID":16}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.01450315572447696,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.93007444840156717,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.014503091068591101,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.93451308072143913,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.014503091068591101,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.93910701763028559,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.014503091068591101,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.94055809677531532,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.014503091068591101,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.94999337125602745,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.013467045153601698,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.95297621548706413,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.013467045153601698,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.95790068402842177,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.011044777045815676,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.96266052064980523,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.0088583736096398309,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.96911575815444173,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.0077646546444650423,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.97217928832645584,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.0032726223185911016,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.98016728703982747,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.0010851843882415254,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.98662352066719217,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.99307006473711057,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[0.20437110010339629, -0, -0, 0.20437110010339629, 126.38769661378409, 170.79330548171168]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[13]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[12,13,14]}","argumentGID":0}],"methodSignature":"setSubpaths:","targetGID":11},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11}],"methodSignature":"setSuperpath:","targetGID":13},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setFill:","targetGID":13},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":13},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setShadow:","targetGID":13},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11}],"methodSignature":"setSuperpath:","targetGID":14},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setFill:","targetGID":14},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":14},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setShadow:","targetGID":14}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":21}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":185.15633048630471,\"AnchorPoint_Y\":354.17149931944061,\"inPoint_Y\":354.17149931944061,\"OutPoint_X\":185.15633048630471,\"AnchorPoint_X\":185.15633048630471,\"OutPoint_Y\":354.17149931944061},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":185.15633048630471,\"AnchorPoint_Y\":354.17149931944061,\"inPoint_Y\":354.17149931944061,\"OutPoint_X\":185.15633048630471,\"AnchorPoint_X\":185.15633048630471,\"OutPoint_Y\":354.17149931944061},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":386.50447364412418,\"AnchorPoint_Y\":554.43203524141848,\"inPoint_Y\":554.43203524141848,\"OutPoint_X\":386.50447364412418,\"AnchorPoint_X\":386.50447364412418,\"OutPoint_Y\":554.43203524141848},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":185.15633048630471,\"AnchorPoint_Y\":354.17149931944061,\"inPoint_Y\":354.17149931944061,\"OutPoint_X\":185.15633048630471,\"AnchorPoint_X\":185.15633048630471,\"OutPoint_Y\":354.17149931944061},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":386.50447364412418,\"AnchorPoint_Y\":554.43203524141848,\"inPoint_Y\":554.43203524141848,\"OutPoint_X\":386.50447364412418,\"AnchorPoint_X\":386.50447364412418,\"OutPoint_Y\":554.43203524141848},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":284.63851065196616,\"AnchorPoint_Y\":654.20422348213651,\"inPoint_Y\":654.20422348213651,\"OutPoint_X\":284.63851065196616,\"AnchorPoint_X\":284.63851065196616,\"OutPoint_Y\":654.20422348213651},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":185.15633048630471,\"AnchorPoint_Y\":354.17149931944061,\"inPoint_Y\":354.17149931944061,\"OutPoint_X\":185.15633048630471,\"AnchorPoint_X\":185.15633048630471,\"OutPoint_Y\":354.17149931944061},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":386.50447364412418,\"AnchorPoint_Y\":554.43203524141848,\"inPoint_Y\":554.43203524141848,\"OutPoint_X\":386.50447364412418,\"AnchorPoint_X\":386.50447364412418,\"OutPoint_Y\":554.43203524141848},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":284.63851065196616,\"AnchorPoint_Y\":654.20422348213651,\"inPoint_Y\":654.20422348213651,\"OutPoint_X\":284.63851065196616,\"AnchorPoint_X\":284.63851065196616,\"OutPoint_Y\":654.20422348213651},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":286.57710140084737,\"AnchorPoint_Y\":264.05198470231699,\"inPoint_Y\":264.05198470231699,\"OutPoint_X\":286.57710140084737,\"AnchorPoint_X\":286.57710140084737,\"OutPoint_Y\":264.05198470231699},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":185.15633048630471,\"AnchorPoint_Y\":354.17149931944061,\"inPoint_Y\":354.17149931944061,\"OutPoint_X\":185.15633048630471,\"AnchorPoint_X\":185.15633048630471,\"OutPoint_Y\":354.17149931944061},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":386.50447364412418,\"AnchorPoint_Y\":554.43203524141848,\"inPoint_Y\":554.43203524141848,\"OutPoint_X\":386.50447364412418,\"AnchorPoint_X\":386.50447364412418,\"OutPoint_Y\":554.43203524141848},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":284.63851065196616,\"AnchorPoint_Y\":654.20422348213651,\"inPoint_Y\":654.20422348213651,\"OutPoint_X\":284.63851065196616,\"AnchorPoint_X\":284.63851065196616,\"OutPoint_Y\":654.20422348213651},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":286.57710140084737,\"AnchorPoint_Y\":264.05198470231699,\"inPoint_Y\":264.05198470231699,\"OutPoint_X\":286.57710140084737,\"AnchorPoint_X\":286.57710140084737,\"OutPoint_Y\":264.05198470231699},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":383.69928863669242,\"AnchorPoint_Y\":361.21410026752545,\"inPoint_Y\":361.21410026752545,\"OutPoint_X\":383.69928863669242,\"AnchorPoint_X\":383.69928863669242,\"OutPoint_Y\":361.21410026752545},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":1}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":1,\"WDHueKey\":0.5806878306878307,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":1}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":1,\"WDHueKey\":0.5806878306878307,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":37.148059844970703}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":1,\"WDHueKey\":0.5806878306878307,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":2,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":37.148059844970703}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":185.15633048630471,\"AnchorPoint_Y\":354.17149931944061,\"inPoint_Y\":354.17149931944061,\"OutPoint_X\":185.15633048630471,\"AnchorPoint_X\":185.15633048630471,\"OutPoint_Y\":354.17149931944061},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":386.50447364412418,\"AnchorPoint_Y\":554.43203524141848,\"inPoint_Y\":554.43203524141848,\"OutPoint_X\":386.50447364412418,\"AnchorPoint_X\":386.50447364412418,\"OutPoint_Y\":554.43203524141848},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":284.63851065196616,\"AnchorPoint_Y\":654.20422348213651,\"inPoint_Y\":654.20422348213651,\"OutPoint_X\":284.63851065196616,\"AnchorPoint_X\":284.63851065196616,\"OutPoint_Y\":654.20422348213651},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":286.57710140084737,\"AnchorPoint_Y\":264.05198470231699,\"inPoint_Y\":264.05198470231699,\"OutPoint_X\":286.57710140084737,\"AnchorPoint_X\":286.57710140084737,\"OutPoint_Y\":264.05198470231699},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":383.69928863669242,\"AnchorPoint_Y\":361.21410026752545,\"inPoint_Y\":361.21410026752545,\"OutPoint_X\":383.69928863669242,\"AnchorPoint_X\":383.69928863669242,\"OutPoint_Y\":361.21410026752545},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":186.05023255601679,\"AnchorPoint_Y\":558.85414169234264,\"inPoint_Y\":558.85414169234264,\"OutPoint_X\":186.05023255601679,\"AnchorPoint_X\":186.05023255601679,\"OutPoint_Y\":558.85414169234264},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":185.15633048630471,\"AnchorPoint_Y\":354.17149931944061,\"inPoint_Y\":354.17149931944061,\"OutPoint_X\":185.15633048630471,\"AnchorPoint_X\":185.15633048630471,\"OutPoint_Y\":354.17149931944061},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":386.50447364412418,\"AnchorPoint_Y\":554.43203524141848,\"inPoint_Y\":554.43203524141848,\"OutPoint_X\":386.50447364412418,\"AnchorPoint_X\":386.50447364412418,\"OutPoint_Y\":554.43203524141848},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":284.63851065196616,\"AnchorPoint_Y\":654.20422348213651,\"inPoint_Y\":654.20422348213651,\"OutPoint_X\":284.63851065196616,\"AnchorPoint_X\":284.63851065196616,\"OutPoint_Y\":654.20422348213651},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":286.57710140084737,\"AnchorPoint_Y\":264.05198470231699,\"inPoint_Y\":264.05198470231699,\"OutPoint_X\":286.57710140084737,\"AnchorPoint_X\":286.57710140084737,\"OutPoint_Y\":264.05198470231699},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":383.69928863669242,\"AnchorPoint_Y\":361.21410026752545,\"inPoint_Y\":361.21410026752545,\"OutPoint_X\":383.69928863669242,\"AnchorPoint_X\":383.69928863669242,\"OutPoint_Y\":361.21410026752545},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":1,\"NodePoints\":{\"inPoint_X\":235.46249740746129,\"AnchorPoint_Y\":558.85414169234264,\"inPoint_Y\":509.44413050490067,\"OutPoint_X\":136.6379677045723,\"AnchorPoint_X\":186.05023255601679,\"OutPoint_Y\":608.26415287978466},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782582120682,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.98823529481887817,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":16},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":1,\"WDHueKey\":0.5806878306878307,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":37.148059844970703}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":1,\"WDHueKey\":0.5806878306878307,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":37.148059844970703}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0.03408561318607653,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.016189711030229925,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":37.148059844970703}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0.029926881951800856,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.016189711030229925,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":37.148059844970703}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0.021585238181938561,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.012961911164688478,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":37.148059844970703}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0.011895648503707629,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.007872629590133573,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":37.148059844970703}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0.005957393322960804,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":37.148059844970703}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":37.148059844970703}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":37.148059844970703}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":21.344829559326172}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":21.344829559326172}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":20}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[-4.3711390001862419e-08, -0.99999999999999922, 0.99999999999999922, -4.3711390001862419e-08, -173.29768953296772, 744.95852622656867]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 8.2190355245806472, 176.90598115888827]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":22}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 0.55538688884063114, -0, 182.49084631957811]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[22]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":24}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 150.32620239929324, 36.081797695525552]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[24]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[24]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0.12249755187863798, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[24]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[0.64978701032960984, -0, -0, 0.64978701032960984, 52.531948450558538, 142.05406077476505]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[24]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -55.171276915352394, 196.69205141995428]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[24]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[0.65616231221472443, -0, -0, 0.65616231221472443, 51.425334356867019, 141.12771095949628]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[22]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -55.53221494113933, 129.60740108742715]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[22]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 205.17127691535239, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[24]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 205.09503537570964, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[22]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 208.92985571850454]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[24]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 130.84123782858848]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[22]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 75]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[22]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":25}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -20, -20]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[25]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 4.5418914390142788, -306.56258907512347]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[25]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[0.96223302635797447, -0, -0, 0.96223302635797447, -0, 2.8325230231519103]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[22]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1.0392493219135692, -0, -0, 1.0392493219135692, 0, -2.9436991435176969]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[22]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 0.96223302635797447, -0, 2.8325230231519103]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[22]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 15.458108560985721, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[25]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 26.562589075123469]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[25]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 25]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[25]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 50]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[25]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -25]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[25]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":22}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":26}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -20, -20]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":20}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":0.10000000149011612}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":1,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":0.10000000149011612}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 9.881426012744555, 0.91199734232554874]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -77.745954011856824, 28.270796276850916]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 67.864527999112269, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 10, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1.1538461432654479, -0, -0, 1, -1.5384614326544779, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -136.98574299882625, 7.8612196478959504]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":27}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":25},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":3}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":24},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":26},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":3}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":22},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setElements:","targetGID":27},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -53.141264363887032, -43.604121250556744]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -70.052055171480333, -2.5049969673447094]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 219.77475934149726, 163.57319520938375]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":27},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":27}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[0.6846814845770105, -0, -0, 0.6846814845770105, -0.080018108436871196, 3.1890182924268196]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -85.587957051898314, -21.453286888159028]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":20}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setShadow:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDShadowOffsetKey\":10,\"WDShadowAngleKey\":1.5707999467849731,\"WDShadowRadiusKey\":10,\"WDShadowColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":0.33300000000000002,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"$class\":\"WDShadow\"}}","argumentGID":0}],"methodSignature":"setShadow:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setShadow:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDShadowOffsetKey\":10,\"WDShadowAngleKey\":1.5707999467849731,\"WDShadowRadiusKey\":10,\"WDShadowColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":0.33300000000000002,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"$class\":\"WDShadow\"}}","argumentGID":0}],"methodSignature":"setShadow:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":20}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":28}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":28},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":29}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":29}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":19.067760461856238,\"AnchorPoint_Y\":162.4737431408027,\"inPoint_Y\":162.4737431408027,\"OutPoint_X\":19.067760461856238,\"AnchorPoint_X\":19.067760461856238,\"OutPoint_Y\":162.4737431408027},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":29}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":19.067760461856238,\"AnchorPoint_Y\":162.4737431408027,\"inPoint_Y\":162.4737431408027,\"OutPoint_X\":19.067760461856238,\"AnchorPoint_X\":19.067760461856238,\"OutPoint_Y\":162.4737431408027},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":142.86303913891427,\"AnchorPoint_Y\":297.21030751597522,\"inPoint_Y\":297.21030751597522,\"OutPoint_X\":142.86303913891427,\"AnchorPoint_X\":142.86303913891427,\"OutPoint_Y\":297.21030751597522},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":29}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":3,"argumentEncodedJsonString":"{\"Argument\":false}","argumentGID":0}],"methodSignature":"setClosed:","targetGID":29}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setFill:","targetGID":29}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782582120682,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.98823529481887817,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":29}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":30}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -20, -20]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -258.8309537310077, 14.790477788784642]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":21},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":21}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":21},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":3}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":21}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0}],"methodSignature":"exchangeObjectAtIndex:withObjectAtIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0}],"methodSignature":"exchangeObjectAtIndex:withObjectAtIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0}],"methodSignature":"exchangeObjectAtIndex:withObjectAtIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0}],"methodSignature":"exchangeObjectAtIndex:withObjectAtIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0}],"methodSignature":"exchangeObjectAtIndex:withObjectAtIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0}],"methodSignature":"exchangeObjectAtIndex:withObjectAtIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":3}","argumentGID":0}],"methodSignature":"exchangeObjectAtIndex:withObjectAtIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":1,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":20}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":30}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":1,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":20}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":29}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0}],"methodSignature":"exchangeObjectAtIndex:withObjectAtIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":3}","argumentGID":0}],"methodSignature":"exchangeObjectAtIndex:withObjectAtIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":3}","argumentGID":0},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0}],"methodSignature":"exchangeObjectAtIndex:withObjectAtIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0}],"methodSignature":"exchangeObjectAtIndex:withObjectAtIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[0.98660023945785613, -0, -0, 1.0127745463822073, 7.5897658853896965, -3.7483052243093384]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":3}","argumentGID":0},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0}],"methodSignature":"exchangeObjectAtIndex:withObjectAtIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":31}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":1,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":0.10000000149011612}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":31}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":1,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":27.568212509155273}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":31}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":27.568212509155273}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":31}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":1,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":29}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782582120682,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.98823529481887817,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782582120682,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.98823529481887817,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782582120682,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.98823529481887817,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782582120682,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.98823529481887817,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11623311042785645,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11623311042785645,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11623311042785645,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11623311042785645,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11518210172653198,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11518210172653198,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11518210172653198,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11518210172653198,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11062517762184143,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11062517762184143,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11062517762184143,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11062517762184143,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10827497392892838,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10827497392892838,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10827497392892838,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10827497392892838,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10599262267351151,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10599262267351151,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10599262267351151,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10599262267351151,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10487814247608185,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10487814247608185,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10487814247608185,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10487814247608185,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10140901058912277,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10140901058912277,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10140901058912277,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10140901058912277,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10024447739124298,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10024447739124298,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10024447739124298,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10024447739124298,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.0991511270403862,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.0991511270403862,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.0991511270403862,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.0991511270403862,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.095819912850856781,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.095819912850856781,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.095819912850856781,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.095819912850856781,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.093592062592506436,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.093592062592506436,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.093592062592506436,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.093592062592506436,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.091305255889892578,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.091305255889892578,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.091305255889892578,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.091305255889892578,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.086611531674861908,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.086611531674861908,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.086611531674861908,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.086611531674861908,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.084330290555953952,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.084330290555953952,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.084330290555953952,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.084330290555953952,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.082062393426895142,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.082062393426895142,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.082062393426895142,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.082062393426895142,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.080980166792869596,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.080980166792869596,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.080980166792869596,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.080980166792869596,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.078774556517601013,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.078774556517601013,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.078774556517601013,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.078774556517601013,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.079864569008350372,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.079864569008350372,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.079864569008350372,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.079864569008350372,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.084498241543769864,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.084498241543769864,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.084498241543769864,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.084498241543769864,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.090882599353790255,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.090882599353790255,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.090882599353790255,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.090882599353790255,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.09557187557220459,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.09557187557220459,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.09557187557220459,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.09557187557220459,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.0990910604596138,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.0990910604596138,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.0990910604596138,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.0990910604596138,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10261469334363937,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10261469334363937,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10261469334363937,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10261469334363937,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10601820796728134,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10601820796728134,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10601820796728134,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10601820796728134,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10719386488199234,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10719386488199234,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10719386488199234,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10719386488199234,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11685270816087723,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11685270816087723,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11685270816087723,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11685270816087723,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.12441384047269821,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.12441384047269821,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.12441384047269821,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.12441384047269821,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.12794080376625061,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.12794080376625061,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.12794080376625061,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.12794080376625061,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13263343274593353,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13263343274593353,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13263343274593353,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13263343274593353,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13615038990974426,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13615038990974426,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13615038990974426,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13615038990974426,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13955500721931458,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13955500721931458,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13955500721931458,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13955500721931458,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14536766707897186,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14536766707897186,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14536766707897186,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14536766707897186,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15242382884025574,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15242382884025574,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15242382884025574,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15242382884025574,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15580509603023529,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15580509603023529,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15580509603023529,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15580509603023529,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15815529227256775,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15815529227256775,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15815529227256775,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15815529227256775,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.16035088896751404,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.16035088896751404,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.16035088896751404,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.16035088896751404,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15694738924503326,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15694738924503326,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15694738924503326,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15694738924503326,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15200117230415344,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15200117230415344,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15200117230415344,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15200117230415344,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14730300009250641,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14730300009250641,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14730300009250641,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14730300009250641,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14378604292869568,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14378604292869568,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14378604292869568,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14378604292869568,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14143472909927368,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14143472909927368,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14143472909927368,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14143472909927368,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14034359157085419,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14034359157085419,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14034359157085419,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14034359157085419,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":1,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":30}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":32}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -20, -20]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":33}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":33}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":307.98765662154068,\"AnchorPoint_Y\":526.40806463936553,\"inPoint_Y\":555.58846167930153,\"OutPoint_X\":307.98765662154068,\"AnchorPoint_X\":307.98765662154068,\"OutPoint_Y\":497.22766759942954},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":33}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":1,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":20}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":33}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":33},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":9223372036854775807}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":34}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":34}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":320,\"AnchorPoint_Y\":640,\"inPoint_Y\":680,\"OutPoint_X\":320,\"AnchorPoint_X\":320,\"OutPoint_Y\":600},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":34}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":320,\"AnchorPoint_Y\":640,\"inPoint_Y\":680,\"OutPoint_X\":320,\"AnchorPoint_X\":320,\"OutPoint_Y\":600},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":340,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":380,\"AnchorPoint_X\":360,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":34}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":320,\"AnchorPoint_Y\":640,\"inPoint_Y\":680,\"OutPoint_X\":320,\"AnchorPoint_X\":320,\"OutPoint_Y\":600},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":340,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":380,\"AnchorPoint_X\":360,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":260,\"AnchorPoint_X\":280,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":34},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":3,"argumentEncodedJsonString":"{\"Argument\":false}","argumentGID":0}],"methodSignature":"setClosed:","targetGID":34}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":320,\"AnchorPoint_Y\":640,\"inPoint_Y\":580,\"OutPoint_X\":320,\"AnchorPoint_X\":320,\"OutPoint_Y\":680.00002878904479},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":340,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":380,\"AnchorPoint_X\":360,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":260,\"AnchorPoint_X\":280,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":34}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":34},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":6}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":35}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":35}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":340,\"AnchorPoint_Y\":660,\"inPoint_Y\":620,\"OutPoint_X\":340,\"AnchorPoint_X\":340,\"OutPoint_Y\":700},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":35}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":35},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":6}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":36}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":36}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":640,\"inPoint_Y\":640,\"OutPoint_X\":300,\"AnchorPoint_X\":300,\"OutPoint_Y\":640},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":36}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":37}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -20, -20]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 20, 20]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[-1, -0, 0, 1, 640, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"KeepNodesAfterTransformTransformOptionKey\":true}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 39, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":640,\"inPoint_Y\":640,\"OutPoint_X\":300,\"AnchorPoint_X\":300,\"OutPoint_Y\":640},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{600, 0}\",\"VNPrevPointForRadiusKey\":\"{600, 0}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":220,\"AnchorPoint_X\":260,\"OutPoint_Y\":580},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{600, 0}\",\"VNPrevPointForRadiusKey\":\"{600, 0}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":37}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":640,\"inPoint_Y\":640,\"OutPoint_X\":300,\"AnchorPoint_X\":300,\"OutPoint_Y\":640},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{600, 0}\",\"VNPrevPointForRadiusKey\":\"{600, 0}\",\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":260,\"AnchorPoint_X\":260,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":37}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":640,\"inPoint_Y\":640,\"OutPoint_X\":300,\"AnchorPoint_X\":300,\"OutPoint_Y\":640},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{600, 0}\",\"VNPrevPointForRadiusKey\":\"{600, 0}\",\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":260,\"AnchorPoint_X\":260,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":340,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":340,\"AnchorPoint_X\":340,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":37}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":640,\"inPoint_Y\":640,\"OutPoint_X\":300,\"AnchorPoint_X\":300,\"OutPoint_Y\":640},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{600, 0}\",\"VNPrevPointForRadiusKey\":\"{600, 0}\",\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":260,\"AnchorPoint_X\":260,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":340,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":340,\"AnchorPoint_X\":340,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":260,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":260,\"AnchorPoint_X\":260,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":37}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":640,\"inPoint_Y\":640,\"OutPoint_X\":300,\"AnchorPoint_X\":300,\"OutPoint_Y\":640},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{600, 0}\",\"VNPrevPointForRadiusKey\":\"{600, 0}\",\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":260,\"AnchorPoint_X\":260,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":340,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":340,\"AnchorPoint_X\":340,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":260,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":260,\"AnchorPoint_X\":260,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":340,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":340,\"AnchorPoint_X\":340,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":37}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 60, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":240,\"AnchorPoint_Y\":640,\"inPoint_Y\":640,\"OutPoint_X\":240,\"AnchorPoint_X\":240,\"OutPoint_Y\":640},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{540, 0}\",\"VNPrevPointForRadiusKey\":\"{540, 0}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":240,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":200,\"AnchorPoint_X\":200,\"OutPoint_Y\":580},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-60, 0}\",\"VNPrevPointForRadiusKey\":\"{-60, 0}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":280,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":280,\"AnchorPoint_X\":280,\"OutPoint_Y\":580},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-60, 0}\",\"VNPrevPointForRadiusKey\":\"{-60, 0}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":200,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":200,\"AnchorPoint_X\":200,\"OutPoint_Y\":580},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-60, 0}\",\"VNPrevPointForRadiusKey\":\"{-60, 0}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":280,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":300,\"AnchorPoint_X\":280,\"OutPoint_Y\":600},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-60, 0}\",\"VNPrevPointForRadiusKey\":\"{-60, 0}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":37},{"actionTypeRawValue":"proxy","methodArguments":[],"methodSignature":"reversePathDirection","targetGID":37}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":580,\"inPoint_Y\":600,\"OutPoint_X\":280,\"AnchorPoint_X\":280,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":200,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":200,\"AnchorPoint_X\":200,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":280,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":280,\"AnchorPoint_X\":280,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":200,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":240,\"AnchorPoint_X\":200,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":240,\"AnchorPoint_Y\":640,\"inPoint_Y\":640,\"OutPoint_X\":240,\"AnchorPoint_X\":240,\"OutPoint_Y\":640},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":37},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":3,"argumentEncodedJsonString":"{\"Argument\":false}","argumentGID":0}],"methodSignature":"setClosed:","targetGID":37}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":36},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":6}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -60, 100]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -8.3360061810856791, -0.18596575427056905]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setFill:","targetGID":37}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0.12624915594960839, -0.84513498021431133]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1.0820554726071352, -0, -0, 1, -28.572516179113212, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 3.7693360211719664, 0.58007166688469169]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 0.8911271920692454, -0, 58.840421083655528]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0.018101184397323777, -6.1834757589472247]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0.5616683932951787, -14.721591768371582]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1.4335340527209723, 13.544422687729025]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":37},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":6}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":43}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.10440918421369,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":598.11903819000008},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":314.21352490073997,\"AnchorPoint_Y\":480.08137659705397,\"inPoint_Y\":479.94813303079826,\"OutPoint_X\":366.0442444460744,\"AnchorPoint_X\":340.12888467340719,\"OutPoint_Y\":480.21462016330969},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":314.21352490073997,\"AnchorPoint_Y\":480.08137659705397,\"inPoint_Y\":479.94813303079826,\"OutPoint_X\":340.12888467340719,\"AnchorPoint_X\":340.12888467340719,\"OutPoint_Y\":480.08137659705397},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":314.21352490073997,\"AnchorPoint_Y\":480.08137659705397,\"inPoint_Y\":479.94813303079826,\"OutPoint_X\":340.12888467340719,\"AnchorPoint_X\":340.12888467340719,\"OutPoint_Y\":480.08137659705397},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":337.32713106884489,\"AnchorPoint_Y\":505.14299981511687,\"inPoint_Y\":505.14299981511687,\"OutPoint_X\":337.32713106884489,\"AnchorPoint_X\":337.32713106884489,\"OutPoint_Y\":505.14299981511687},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":314.21352490073997,\"AnchorPoint_Y\":480.08137659705397,\"inPoint_Y\":479.94813303079826,\"OutPoint_X\":340.12888467340719,\"AnchorPoint_X\":340.12888467340719,\"OutPoint_Y\":480.08137659705397},\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":268.41762507168443,\"AnchorPoint_Y\":478.86160216124927,\"inPoint_Y\":478.86160216124927,\"OutPoint_X\":268.41762507168443,\"AnchorPoint_X\":268.41762507168443,\"OutPoint_Y\":478.86160216124927},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-68.909505997160466, -26.2813976538676}\",\"VNPrevPointForRadiusKey\":\"{-68.909505997160466, -26.2813976538676}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":268.41762507168443,\"AnchorPoint_Y\":478.86160216124927,\"inPoint_Y\":478.86160216124927,\"OutPoint_X\":268.41762507168443,\"AnchorPoint_X\":268.41762507168443,\"OutPoint_Y\":478.86160216124927},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-68.909505997160466, -26.2813976538676}\",\"VNPrevPointForRadiusKey\":\"{-68.909505997160466, -26.2813976538676}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":282.38947067174871,\"AnchorPoint_Y\":502.68576551434728,\"inPoint_Y\":502.68576551434728,\"OutPoint_X\":282.38947067174871,\"AnchorPoint_X\":282.38947067174871,\"OutPoint_Y\":502.68576551434728},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.41762507168443,\"AnchorPoint_Y\":478.86160216124927,\"inPoint_Y\":478.86160216124927,\"OutPoint_X\":268.41762507168443,\"AnchorPoint_X\":268.41762507168443,\"OutPoint_Y\":478.86160216124927},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":333.80634908853523,\"AnchorPoint_Y\":479.14166624396699,\"inPoint_Y\":479.14166624396699,\"OutPoint_X\":333.80634908853523,\"AnchorPoint_X\":333.80634908853523,\"OutPoint_Y\":479.14166624396699},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{51.416878416786517, -23.544099270380286}\",\"VNPrevPointForRadiusKey\":\"{51.416878416786517, -23.544099270380286}\",\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.41762507168443,\"AnchorPoint_Y\":478.86160216124927,\"inPoint_Y\":478.86160216124927,\"OutPoint_X\":268.41762507168443,\"AnchorPoint_X\":268.41762507168443,\"OutPoint_Y\":478.86160216124927},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":342.99265545324346,\"AnchorPoint_Y\":479.14166624396699,\"inPoint_Y\":494.80574311033359,\"OutPoint_X\":324.620042723827,\"AnchorPoint_X\":333.80634908853523,\"OutPoint_Y\":463.4775893776004},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.41762507168443,\"AnchorPoint_Y\":478.86160216124927,\"inPoint_Y\":478.86160216124927,\"OutPoint_X\":268.41762507168443,\"AnchorPoint_X\":268.41762507168443,\"OutPoint_Y\":478.86160216124927},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":333.80634908853523,\"AnchorPoint_Y\":479.14166624396699,\"inPoint_Y\":479.14166624396699,\"OutPoint_X\":333.80634908853523,\"AnchorPoint_X\":333.80634908853523,\"OutPoint_Y\":479.14166624396699},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.41762507168443,\"AnchorPoint_Y\":478.86160216124927,\"inPoint_Y\":478.86160216124927,\"OutPoint_X\":268.41762507168443,\"AnchorPoint_X\":268.41762507168443,\"OutPoint_Y\":478.86160216124927},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":3,\"NodePoints\":{\"inPoint_X\":342.99265545324346,\"AnchorPoint_Y\":479.14166624396699,\"inPoint_Y\":494.80574311033359,\"OutPoint_X\":324.620042723827,\"AnchorPoint_X\":333.80634908853523,\"OutPoint_Y\":463.4775893776004},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.41762507168443,\"AnchorPoint_Y\":478.86160216124927,\"inPoint_Y\":478.86160216124927,\"OutPoint_X\":268.41762507168443,\"AnchorPoint_X\":268.41762507168443,\"OutPoint_Y\":478.86160216124927},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":3,\"NodePoints\":{\"inPoint_X\":342.99265545324346,\"AnchorPoint_Y\":479.14166624396699,\"inPoint_Y\":494.80574311033359,\"OutPoint_X\":333.79302393751607,\"AnchorPoint_X\":333.80634908853523,\"OutPoint_Y\":478.98295741265042},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.41762507168443,\"AnchorPoint_Y\":478.86160216124927,\"inPoint_Y\":478.86160216124927,\"OutPoint_X\":268.41762507168443,\"AnchorPoint_X\":268.41762507168443,\"OutPoint_Y\":478.86160216124927},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":3,\"NodePoints\":{\"inPoint_X\":303.99512941310888,\"AnchorPoint_Y\":479.14166624396699,\"inPoint_Y\":487.18557523329599,\"OutPoint_X\":333.79302393751607,\"AnchorPoint_X\":333.80634908853523,\"OutPoint_Y\":478.98295741265042},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.41762507168443,\"AnchorPoint_Y\":478.86160216124927,\"inPoint_Y\":478.86160216124927,\"OutPoint_X\":268.41762507168443,\"AnchorPoint_X\":268.41762507168443,\"OutPoint_Y\":478.86160216124927},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":44}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":44}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":249.48159496463126,\"AnchorPoint_Y\":480.06523848740324,\"inPoint_Y\":466.59075022213392,\"OutPoint_X\":291.92349007711761,\"AnchorPoint_X\":270.70254252087443,\"OutPoint_Y\":493.53972675267255},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":44}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":249.48159496463126,\"AnchorPoint_Y\":480.06523848740324,\"inPoint_Y\":466.59075022213392,\"OutPoint_X\":291.92349007711761,\"AnchorPoint_X\":270.70254252087443,\"OutPoint_Y\":493.53972675267255},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":297.36444957939858,\"AnchorPoint_Y\":515.66654723497345,\"inPoint_Y\":487.33229037129115,\"OutPoint_X\":298.38562249368391,\"AnchorPoint_X\":297.87503603654125,\"OutPoint_Y\":544.00080409865575},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":44}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":246.45876716860445,\"AnchorPoint_Y\":480.06523848740324,\"inPoint_Y\":473.42220838032478,\"OutPoint_X\":292.2196979967656,\"AnchorPoint_X\":270.70254252087443,\"OutPoint_Y\":485.96114824436484},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":297.36444957939858,\"AnchorPoint_Y\":515.66654723497345,\"inPoint_Y\":487.33229037129115,\"OutPoint_X\":298.38562249368391,\"AnchorPoint_X\":297.87503603654125,\"OutPoint_Y\":544.00080409865575},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":44}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":45}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":246.45876716860445,\"AnchorPoint_Y\":480.06523848740324,\"inPoint_Y\":473.42220838032478,\"OutPoint_X\":292.2196979967656,\"AnchorPoint_X\":270.70254252087443,\"OutPoint_Y\":485.96114824436484},\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":307.29902543809465,\"AnchorPoint_Y\":530.77487327608799,\"inPoint_Y\":502.44061641240569,\"OutPoint_X\":308.32019835237998,\"AnchorPoint_X\":307.80961189523731,\"OutPoint_Y\":559.10913013977029},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{9.9345758586960642, 15.108326041114537}\",\"VNPrevPointForRadiusKey\":\"{9.9345758586960642, 15.108326041114537}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":45}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[-1, -0, 0, 1, 618.5121544161118, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[45]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"KeepNodesAfterTransformTransformOptionKey\":true}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -17.095091220096265, 18.636572344325828]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[45]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":246.45876716860445,\"AnchorPoint_Y\":480.06523848740324,\"inPoint_Y\":473.42220838032478,\"OutPoint_X\":292.2196979967656,\"AnchorPoint_X\":270.70254252087443,\"OutPoint_Y\":485.96114824436484},\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":307.29902543809465,\"AnchorPoint_Y\":530.77487327608799,\"inPoint_Y\":502.44061641240569,\"OutPoint_X\":308.32019835237998,\"AnchorPoint_X\":307.80961189523731,\"OutPoint_Y\":559.10913013977029},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{9.9345758586960642, 15.108326041114537}\",\"VNPrevPointForRadiusKey\":\"{9.9345758586960642, 15.108326041114537}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":44}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":46}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":45},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":8}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":44},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":6}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 2.4740749822735211, -26.734403557988003]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[46]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":50}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":50}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":305.84902480507895,\"AnchorPoint_Y\":558.859403557988,\"inPoint_Y\":530.52519454298988,\"OutPoint_X\":305.33842501772648,\"AnchorPoint_X\":305.33842501772648,\"OutPoint_Y\":558.859403557988},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-2.4740749822735211, 26.734403557988003}\",\"VNPrevPointForRadiusKey\":\"{-2.4740749822735211, 26.734403557988003}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":342.43217501772648,\"AnchorPoint_Y\":508.171903557988,\"inPoint_Y\":508.171903557988,\"OutPoint_X\":320.91501841129599,\"AnchorPoint_X\":342.43217501772648,\"OutPoint_Y\":514.06781336097845},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-2.4740749822735211, 26.734403557988003}\",\"VNPrevPointForRadiusKey\":\"{-2.4740749822735211, 26.734403557988003}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":48}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.84902480507895,\"AnchorPoint_Y\":558.859403557988,\"inPoint_Y\":530.52519454298988,\"OutPoint_X\":305.33842501772648,\"AnchorPoint_X\":305.33842501772648,\"OutPoint_Y\":558.859403557988},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":323.12940602919167,\"AnchorPoint_Y\":534.54856008655031,\"inPoint_Y\":534.54856008655031,\"OutPoint_X\":323.12940602919167,\"AnchorPoint_X\":323.12940602919167,\"OutPoint_Y\":534.54856008655031},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":342.43217501772648,\"AnchorPoint_Y\":508.171903557988,\"inPoint_Y\":508.171903557988,\"OutPoint_X\":320.91501841129599,\"AnchorPoint_X\":342.43217501772648,\"OutPoint_Y\":514.06781336097845},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":48}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[47,48]}","argumentGID":0}],"methodSignature":"setSubpaths:","targetGID":46},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":46}],"methodSignature":"setSuperpath:","targetGID":48},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setFill:","targetGID":48},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":48},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setShadow:","targetGID":48},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":46}],"methodSignature":"setSuperpath:","targetGID":48},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":48},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setFill:","targetGID":48},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setShadow:","targetGID":48},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":48}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":46},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":7}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13822251558303833,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":48}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -2.1531569701203352, 25.991399082341331]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[48]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":308.00218177519929,\"AnchorPoint_Y\":532.86800447564667,\"inPoint_Y\":504.53379546064855,\"OutPoint_X\":307.49158198784681,\"AnchorPoint_X\":307.49158198784681,\"OutPoint_Y\":532.86800447564667},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{2.1531569701203352, -25.991399082341331}\",\"VNPrevPointForRadiusKey\":\"{2.1531569701203352, -25.991399082341331}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":307.54481307650724,\"AnchorPoint_Y\":482.22702540901258,\"inPoint_Y\":482.22702540901258,\"OutPoint_X\":307.54481307650724,\"AnchorPoint_X\":307.54481307650724,\"OutPoint_Y\":482.22702540901258},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-15.584592952684432, -52.321534677537727}\",\"VNPrevPointForRadiusKey\":\"{-15.584592952684432, -52.321534677537727}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":344.58533198784681,\"AnchorPoint_Y\":482.18050447564667,\"inPoint_Y\":482.18050447564667,\"OutPoint_X\":323.06817538141632,\"AnchorPoint_X\":344.58533198784681,\"OutPoint_Y\":488.07641427863712},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{2.1531569701203352, -25.991399082341331}\",\"VNPrevPointForRadiusKey\":\"{2.1531569701203352, -25.991399082341331}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":48}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[48]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[48]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[48]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[48]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 0.34003453224391933]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[48]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 0.1954377384541317]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[48]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":54}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -20, -20]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[54]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[-1, -0, 0, 1, 692.07691397569363, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[54]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"KeepNodesAfterTransformTransformOptionKey\":true}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 57.024957634971202, 19.792602829855639]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[54]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":307.04977456552314,\"AnchorPoint_Y\":532.53992937509292,\"inPoint_Y\":504.20572036009486,\"OutPoint_X\":307.56037435287561,\"AnchorPoint_X\":307.56037435287561,\"OutPoint_Y\":532.53992937509292},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{612.89879937060209, -26.319474182895021}\",\"VNPrevPointForRadiusKey\":\"{612.89879937060209, -26.319474182895021}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":307.50714326421519,\"AnchorPoint_Y\":481.89895030845889,\"inPoint_Y\":481.89895030845889,\"OutPoint_X\":307.50714326421519,\"AnchorPoint_X\":307.50714326421519,\"OutPoint_Y\":481.89895030845889},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{630.6365492934068, -52.649609778091417}\",\"VNPrevPointForRadiusKey\":\"{630.6365492934068, -52.649609778091417}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":270.46662435287561,\"AnchorPoint_Y\":481.85242937509298,\"inPoint_Y\":481.85242937509298,\"OutPoint_X\":291.68464211968808,\"AnchorPoint_X\":270.46662435287561,\"OutPoint_Y\":491.96348695323337},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{615.05195634072243, -0.32807510055368994}\",\"VNPrevPointForRadiusKey\":\"{615.05195634072243, -0.32807510055368994}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":54}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":55}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":54},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":8}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":48},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":6}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setElements:","targetGID":55},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":48},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":54}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1.0330248439984473, -0, -0, 0.99999999999999989, -11.379876833051835, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[55]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":56}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":55},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":7}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":21},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":3}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":30},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":32},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":3}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":27},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":29},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":31},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setElements:","targetGID":56},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":27},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":29},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":30},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":21},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":31},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":32},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":55}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":57}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -290.115478515625, 62.302734375]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.042222879700741525,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.89467432944640213,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.042222879700741525,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.90097236067321962,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.031593452065677957,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.91739226661025597,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.019517801575741518,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.93616537665754818,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.0091232041181144082,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.94328004740819738,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.0018620895127118644,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.95006183205443251,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.95531556443573817,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9587083584477003,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.96669617604784863,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.96977202191904677,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.97283138648692502,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.97731792325435829,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9818318081185089,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9863455118694362,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.99094089768406901,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.99553628349870182,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":1,\"WDHueKey\":0.5806878306878307,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":0.10000000149011612}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":0.10000000149011612}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -138.240478515625, -358.288818359375]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":56},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":56}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 10.2197265625, 7.887451171875]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1.73681640625, -1.3956298828125]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":1,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.5806878306878307,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.5806878306878307,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.96954748896640086,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.96362693977790437,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.95841712343394081,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.954131593465262,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.93934857275056949,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.83357840083997725,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.80253639308086555,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.76741239856207288,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.7565612097807517,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.73508462058656032,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.69529915290432798,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.68285743522209563,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.66214385499715267,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.64970324957289294,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.63305608449601369,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.62061547907175396,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.60169597095671978,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.59555519468963558,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.5870419721668565,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.57588046341116172,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.56733832218109337,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.5457271497722096,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.51220146996013671,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.45939702270785876,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.41278562784738043,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.38011749893223234,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.35006206399487472,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.33336373505125283,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.31040673049544421,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.29577720138097952,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.27499243664578588,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.25639993237471526,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.24782776017938496,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.23669294561503418,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.22722206897779043,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.22344372864464693,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.21991675861332574,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.21874110193621868,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.2197966347522779,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.23113499252562641,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.24180488325740318,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.2529452591116173,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.28146132901480636,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.29042946504840544,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.29303437322038722,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.30319262528473806,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.31050016016514809,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.31284924900341687,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.31402379342255127,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.31192273811218679,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.31087054207004555,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.30975717183940776,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.3074892778331435,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1.0000066161593433, -0, -0, 1.0000066161593433, -0.00084115369224984499, -0.0015278888873493538]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 106.25150911801597, 215.10157288799655]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {1024, 1024}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {1018.1834573966, 1022.316502396953}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {1008.5644489681886, 1015.9218488910001}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {1003.3383988868811, 1012.188740268123}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {959.56182404754463, 968.37466824766148}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {930.99873639690077, 938.04865943448704}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {883.88375480634159, 898.86742705675647}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {851.39277451811745, 876.13749149913815}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {807.42735481491377, 847.80421878677203}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {780.8131139470363, 833.66058405713125}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {758.18676120653936, 823.6793880913026}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {745.42543866806363, 820.26800024929958}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {738.45307691385142, 820.26800024929958}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {738.07015268029545, 820.26800024929958}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {738.07015268029545, 820.65313908147255}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {735.7456294412641, 820.1359296408807}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {734.20024226104533, 819.105537302637}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {730.82720724054207, 815.73250228213374}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {722.51078545309133, 807.41391622785272}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {715.22999050970566, 800.13291995732015}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {710.02528110597814, 794.3195482564854}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {708.99086222479468, 792.76802059828378}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {705.03881032957679, 786.83843280185465}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {703.71729893680003, 785.04591654871797}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {702.86608775936838, 784.19455437592615}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {701.16326275021129, 782.49188036212945}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {700.77188277648224, 782.10024872946656}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {699.97704320020512, 781.30550981676288}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {699.12865060283116, 780.87985389626033}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {698.70304501411556, 780.45414764397106}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {695.54100084364723, 776.8204946317021}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {693.70127337454369, 774.98056583545167}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {691.86235121402819, 772.67134345959084}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {689.97672115541332, 769.84279770809485}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {689.03491276184081, 768.90119064166925}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {686.67817717929256, 766.07264489017348}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {683.90469440249581, 763.76603976722345}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {682.53607245732564, 762.86897633206718}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {681.17026909221318, 762.39756881741346}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {678.95083862390538, 761.54620664462163}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {676.30580256688177, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {675.07408308165805, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {673.28025820206608, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {671.48603066818009, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {670.54341696601955, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {669.17600298373122, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {667.39103649860635, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {666.44842279644581, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {666.02281720772999, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {665.226367014277, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {663.57830298909857, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.7291050831368, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.92701772956843, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.54691207607016, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.15190821369538, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.15190821369538, 760.69429082217562}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.15190821369538, 760.30406847954168}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.15190821369538, 759.91817467056762}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.15190821369538, 759.52795232793369}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.15190821369538, 759.12605301077474}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.15190821369538, 758.73814593033103}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.15190821369538, 758.35446671997374}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.55134127330371, 758.35446671997374}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.55134127330371, 757.96107347477482}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.55134127330371, 757.57593464260208}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.97694686201953, 757.57593464260208}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.3896675133285, 757.18274272455005}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.3896675133285, 756.35493582795493}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 755.94518475206382}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 755.5517915068649}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 754.78614436689986}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 754.3960730196261}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 754.00237778370661}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 753.60918586565458}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 753.21065877820774}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 752.81701387407497}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 752.41430924832821}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 749.69714774089903}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 748.93285955917622}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 747.99004452986878}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 747.13868235707696}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.41906127678772, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.65522608114543, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.27149653900142, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {660.88132452815421, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {660.48793128295529, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {659.69429966956, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {659.30453031300658, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {659.68503862079888, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {660.0695734715307, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {660.47263041978476, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {660.86843959074758, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.25498771294906, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.63670398362319, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.02566803158879, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.83158060094979, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {664.08383545516563, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {665.7862578100287, 746.7378903392264}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {667.06307457617595, 747.16359659151567}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {669.70851328749336, 748.01490843252077}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {670.98533005364084, 748.44061468481004}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {672.66399580516031, 748.84437627807847}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {673.94081257130756, 749.26907589463281}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {675.19387273411121, 749.69478214692208}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {675.58525270784025, 749.69478214692208}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {675.20474440004818, 749.69478214692208}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {673.93235683113426, 749.26907589463281}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {672.1381292972485, 747.52296554887494}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {670.87500277709569, 747.09725929658589}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {670.47194582884163, 746.2471050866759}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {669.64368594616599, 745.41864387685314}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {669.24787677520317, 745.02308636482417}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {669.24787677520317, 744.6337699943515}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":287.2857717617394,\"AnchorPoint_Y\":289.25600703483042,\"inPoint_Y\":289.25600703483042,\"OutPoint_X\":287.2857717617394,\"AnchorPoint_X\":287.2857717617394,\"OutPoint_Y\":289.25600703483042},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{59.351577569932488, -881.2368652940595}\",\"VNPrevPointForRadiusKey\":\"{59.351577569932488, -881.2368652940595}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":437.28477645924727,\"AnchorPoint_Y\":289.25600703483042,\"inPoint_Y\":289.25600703483042,\"OutPoint_X\":437.28477645924727,\"AnchorPoint_X\":437.28477645924727,\"OutPoint_Y\":289.25600703483042},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{59.351577569932488, -881.2368652940595}\",\"VNPrevPointForRadiusKey\":\"{59.351577569932488, -881.2368652940595}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":437.28477645924727,\"AnchorPoint_Y\":539.25435579077384,\"inPoint_Y\":539.25435579077384,\"OutPoint_X\":437.28477645924727,\"AnchorPoint_X\":437.28477645924727,\"OutPoint_Y\":539.25435579077384},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{59.351577569932488, -881.2368652940595}\",\"VNPrevPointForRadiusKey\":\"{59.351577569932488, -881.2368652940595}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":287.2857717617394,\"AnchorPoint_Y\":539.25435579077384,\"inPoint_Y\":539.25435579077384,\"OutPoint_X\":287.2857717617394,\"AnchorPoint_X\":287.2857717617394,\"OutPoint_Y\":539.25435579077384},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{59.351577569932488, -881.2368652940595}\",\"VNPrevPointForRadiusKey\":\"{59.351577569932488, -881.2368652940595}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":287.2857717617394,\"AnchorPoint_Y\":289.25602785985438,\"inPoint_Y\":330.67709661876142,\"OutPoint_X\":287.2857717617394,\"AnchorPoint_X\":287.2857717617394,\"OutPoint_Y\":247.83495910094825},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-173.55249370630804, -465.50590420624349}\",\"VNPrevPointForRadiusKey\":\"{-173.55249370630804, -465.50590420624349}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":320.86422761918971,\"AnchorPoint_Y\":214.25650324349817,\"inPoint_Y\":214.25650324349817,\"OutPoint_X\":403.70636513700288,\"AnchorPoint_X\":362.28529637809629,\"OutPoint_Y\":214.25650324349817},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-173.55249370630804, -465.50590420624349}\",\"VNPrevPointForRadiusKey\":\"{-173.55249370630804, -465.50590420624349}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":437.28477402925387,\"AnchorPoint_Y\":289.25602785985438,\"inPoint_Y\":247.83495910094825,\"OutPoint_X\":437.28477402925387,\"AnchorPoint_X\":437.28477402925387,\"OutPoint_Y\":330.67709661876142},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-173.55249370630804, -465.50590420624349}\",\"VNPrevPointForRadiusKey\":\"{-173.55249370630804, -465.50590420624349}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":403.70636513700288,\"AnchorPoint_Y\":364.25550551101242,\"inPoint_Y\":364.25550551101242,\"OutPoint_X\":320.86422761918971,\"AnchorPoint_X\":362.28529637809629,\"OutPoint_Y\":364.25550551101242},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-173.55249370630804, -465.50590420624349}\",\"VNPrevPointForRadiusKey\":\"{-173.55249370630804, -465.50590420624349}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":287.2857717617394,\"AnchorPoint_Y\":539.25437383096278,\"inPoint_Y\":580.67544258986891,\"OutPoint_X\":287.2857717617394,\"AnchorPoint_X\":287.2857717617394,\"OutPoint_Y\":497.83330507205574},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-173.55249370630804, -215.50755823513555}\",\"VNPrevPointForRadiusKey\":\"{-173.55249370630804, -215.50755823513555}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":320.86422761918971,\"AnchorPoint_Y\":464.25484921460566,\"inPoint_Y\":464.25484921460566,\"OutPoint_X\":403.70636513700288,\"AnchorPoint_X\":362.28529637809629,\"OutPoint_Y\":464.25484921460566},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-173.55249370630804, -215.50755823513555}\",\"VNPrevPointForRadiusKey\":\"{-173.55249370630804, -215.50755823513555}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":437.28477402925387,\"AnchorPoint_Y\":539.25437383096278,\"inPoint_Y\":497.83330507205574,\"OutPoint_X\":437.28477402925387,\"AnchorPoint_X\":437.28477402925387,\"OutPoint_Y\":580.67544258986891},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-173.55249370630804, -215.50755823513555}\",\"VNPrevPointForRadiusKey\":\"{-173.55249370630804, -215.50755823513555}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":403.70636513700288,\"AnchorPoint_Y\":614.2538514821199,\"inPoint_Y\":614.2538514821199,\"OutPoint_X\":320.86422761918971,\"AnchorPoint_X\":362.28529637809629,\"OutPoint_Y\":614.2538514821199},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-173.55249370630804, -215.50755823513555}\",\"VNPrevPointForRadiusKey\":\"{-173.55249370630804, -215.50755823513555}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":297.2857056005837,\"AnchorPoint_Y\":289.07321462503751,\"inPoint_Y\":289.07321462503751,\"OutPoint_X\":297.2857056005837,\"AnchorPoint_X\":297.2857056005837,\"OutPoint_Y\":289.07321462503751},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{99.742735489559436, -881.41965770385173}\",\"VNPrevPointForRadiusKey\":\"{99.742735489559436, -881.41965770385173}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":427.28484419717574,\"AnchorPoint_Y\":289.07321462503751,\"inPoint_Y\":289.07321462503751,\"OutPoint_X\":427.28484419717574,\"AnchorPoint_X\":427.28484419717574,\"OutPoint_Y\":289.07321462503751},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{99.742735489559436, -881.41965770385173}\",\"VNPrevPointForRadiusKey\":\"{99.742735489559436, -881.41965770385173}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":427.28484419717574,\"AnchorPoint_Y\":539.07156338098093,\"inPoint_Y\":539.07156338098093,\"OutPoint_X\":427.28484419717574,\"AnchorPoint_X\":427.28484419717574,\"OutPoint_Y\":539.07156338098093},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{99.742735489559436, -881.41965770385173}\",\"VNPrevPointForRadiusKey\":\"{99.742735489559436, -881.41965770385173}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":297.2857056005837,\"AnchorPoint_Y\":539.07156338098093,\"inPoint_Y\":539.07156338098093,\"OutPoint_X\":297.2857056005837,\"AnchorPoint_X\":297.2857056005837,\"OutPoint_Y\":539.07156338098093},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{99.742735489559436, -881.41965770385173}\",\"VNPrevPointForRadiusKey\":\"{99.742735489559436, -881.41965770385173}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":97.57351080287799,\"AnchorPoint_Y\":309.16721333385931,\"inPoint_Y\":309.16721333385931,\"OutPoint_X\":97.57351080287799,\"AnchorPoint_X\":97.57351080287799,\"OutPoint_Y\":309.16721333385931},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{78.505876495528582, 146.69454513811797}\",\"VNPrevPointForRadiusKey\":\"{78.505876495528582, 146.69454513811797}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":221.36797043606543,\"AnchorPoint_Y\":443.90288627635027,\"inPoint_Y\":443.90288627635027,\"OutPoint_X\":221.36797043606543,\"AnchorPoint_X\":221.36797043606543,\"OutPoint_Y\":443.90288627635027},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{78.505876495528582, 146.69454513811797}\",\"VNPrevPointForRadiusKey\":\"{78.505876495528582, 146.69454513811797}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":361.08361414401247,\"AnchorPoint_Y\":309.6035637643763,\"inPoint_Y\":309.6035637643763,\"OutPoint_X\":361.08361414401247,\"AnchorPoint_X\":361.08361414401247,\"OutPoint_Y\":309.6035637643763},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{78.505876495528582, 146.69454513811797}\",\"VNPrevPointForRadiusKey\":\"{78.505876495528582, 146.69454513811797}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":29},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":377.82365759764593,\"AnchorPoint_Y\":307.07623767819223,\"inPoint_Y\":307.07623767819223,\"OutPoint_X\":377.82365759764593,\"AnchorPoint_X\":377.82365759764593,\"OutPoint_Y\":307.07623767819223},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{358.49705139509047, 146.65290478922907}\",\"VNPrevPointForRadiusKey\":\"{358.49705139509047, 146.65290478922907}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":503.2994629767461,\"AnchorPoint_Y\":440.11243356580462,\"inPoint_Y\":440.11243356580462,\"OutPoint_X\":503.2994629767461,\"AnchorPoint_X\":503.2994629767461,\"OutPoint_Y\":440.11243356580462},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{358.49705139509047, 146.65290478922907}\",\"VNPrevPointForRadiusKey\":\"{358.49705139509047, 146.65290478922907}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":644.91269001662772,\"AnchorPoint_Y\":307.50708423933065,\"inPoint_Y\":307.50708423933065,\"OutPoint_X\":644.91269001662772,\"AnchorPoint_X\":644.91269001662772,\"OutPoint_Y\":307.50708423933065},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{358.49705139509047, 146.65290478922907}\",\"VNPrevPointForRadiusKey\":\"{358.49705139509047, 146.65290478922907}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":30},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":516.45695350382334,\"AnchorPoint_Y\":154.80813254227905,\"inPoint_Y\":154.80813254227905,\"OutPoint_X\":516.45695350382334,\"AnchorPoint_X\":516.45695350382334,\"OutPoint_Y\":154.80813254227905},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{1033.732755685123, -115.61701281386331}\",\"VNPrevPointForRadiusKey\":\"{1033.732755685123, -115.61701281386331}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":223.97172601151692,\"AnchorPoint_Y\":448.88181029919406,\"inPoint_Y\":448.88181029919406,\"OutPoint_X\":223.97172601151692,\"AnchorPoint_X\":223.97172601151692,\"OutPoint_Y\":448.88181029919406},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{1033.732755685123, -115.61701281386331}\",\"VNPrevPointForRadiusKey\":\"{1033.732755685123, -115.61701281386331}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":78.252109034647219,\"AnchorPoint_Y\":300.1041732651538,\"inPoint_Y\":300.1041732651538,\"OutPoint_X\":78.252109034647219,\"AnchorPoint_X\":78.252109034647219,\"OutPoint_Y\":300.1041732651538},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{1033.732755685123, -115.61701281386331}\",\"VNPrevPointForRadiusKey\":\"{1033.732755685123, -115.61701281386331}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":648.07861404640448,\"AnchorPoint_Y\":302.9355554780409,\"inPoint_Y\":302.9355554780409,\"OutPoint_X\":648.07861404640448,\"AnchorPoint_X\":648.07861404640448,\"OutPoint_Y\":302.9355554780409},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{1033.732755685123, -115.61701281386331}\",\"VNPrevPointForRadiusKey\":\"{1033.732755685123, -115.61701281386331}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":506.17105679039673,\"AnchorPoint_Y\":444.7847840681311,\"inPoint_Y\":444.7847840681311,\"OutPoint_X\":506.17105679039673,\"AnchorPoint_X\":506.17105679039673,\"OutPoint_Y\":444.7847840681311},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{1033.732755685123, -115.61701281386331}\",\"VNPrevPointForRadiusKey\":\"{1033.732755685123, -115.61701281386331}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":217.51314851045686,\"AnchorPoint_Y\":156.11368443580113,\"inPoint_Y\":156.11368443580113,\"OutPoint_X\":217.51314851045686,\"AnchorPoint_X\":217.51314851045686,\"OutPoint_Y\":156.11368443580113},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{1033.732755685123, -115.61701281386331}\",\"VNPrevPointForRadiusKey\":\"{1033.732755685123, -115.61701281386331}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":21},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":290.26965144695237,\"AnchorPoint_Y\":418.73751961026619,\"inPoint_Y\":418.73751961026619,\"OutPoint_X\":290.26965144695237,\"AnchorPoint_X\":290.26965144695237,\"OutPoint_Y\":418.73751961026619},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{78.505876495528582, 146.69454513811797}\",\"VNPrevPointForRadiusKey\":\"{78.505876495528582, 146.69454513811797}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":433.31216208615911,\"AnchorPoint_Y\":418.73751961026619,\"inPoint_Y\":418.73751961026619,\"OutPoint_X\":433.31216208615911,\"AnchorPoint_X\":433.31216208615911,\"OutPoint_Y\":418.73751961026619},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{78.505876495528582, 146.69454513811797}\",\"VNPrevPointForRadiusKey\":\"{78.505876495528582, 146.69454513811797}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":31},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":290.26965144695237,\"AnchorPoint_Y\":521.73683815036247,\"inPoint_Y\":521.73683815036247,\"OutPoint_X\":290.26965144695237,\"AnchorPoint_X\":290.26965144695237,\"OutPoint_Y\":521.73683815036247},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{78.505876495528582, 249.69386367821471}\",\"VNPrevPointForRadiusKey\":\"{78.505876495528582, 249.69386367821471}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":433.31216208615911,\"AnchorPoint_Y\":521.73683815036247,\"inPoint_Y\":521.73683815036247,\"OutPoint_X\":433.31216208615911,\"AnchorPoint_X\":433.31216208615911,\"OutPoint_Y\":521.73683815036247},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{78.505876495528582, 249.69386367821471}\",\"VNPrevPointForRadiusKey\":\"{78.505876495528582, 249.69386367821471}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":32},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":362.67570746371234,\"AnchorPoint_Y\":667.02363476289884,\"inPoint_Y\":638.68961321030247,\"OutPoint_X\":362.18143434711533,\"AnchorPoint_X\":362.18143434711533,\"OutPoint_Y\":667.02363476289884},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{66.606350517013652, 108.16792868331186}\",\"VNPrevPointForRadiusKey\":\"{66.606350517013652, 108.16792868331186}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":362.23296334642896,\"AnchorPoint_Y\":616.38299074283532,\"inPoint_Y\":616.38299074283532,\"OutPoint_X\":362.23296334642896,\"AnchorPoint_X\":362.23296334642896,\"OutPoint_Y\":616.38299074283532},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{49.435773574115046, 81.837967291336099}\",\"VNPrevPointForRadiusKey\":\"{49.435773574115046, 81.837967291336099}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":398.08909406988482,\"AnchorPoint_Y\":616.33647011725679,\"inPoint_Y\":616.33647011725679,\"OutPoint_X\":377.54953250055337,\"AnchorPoint_X\":398.08909406988482,\"OutPoint_Y\":626.44746079947163},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{64.522041763846801, 134.1591558035534}\",\"VNPrevPointForRadiusKey\":\"{64.522041763846801, 134.1591558035534}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":48},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":361.7537539269963,\"AnchorPoint_Y\":667.02363476289884,\"inPoint_Y\":638.68961321030247,\"OutPoint_X\":362.24802704359331,\"AnchorPoint_X\":362.24802704359331,\"OutPoint_Y\":667.02363476289884},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{657.82311087369476, 108.16792868331186}\",\"VNPrevPointForRadiusKey\":\"{657.82311087369476, 108.16792868331186}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":362.19649804427968,\"AnchorPoint_Y\":616.38299074283532,\"inPoint_Y\":616.38299074283532,\"OutPoint_X\":362.19649804427968,\"AnchorPoint_X\":362.19649804427968,\"OutPoint_Y\":616.38299074283532},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{674.99368781659336, 81.837967291336099}\",\"VNPrevPointForRadiusKey\":\"{674.99368781659336, 81.837967291336099}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":326.34036732082382,\"AnchorPoint_Y\":616.33647011725679,\"inPoint_Y\":616.33647011725679,\"OutPoint_X\":346.87992889015482,\"AnchorPoint_X\":326.34036732082382,\"OutPoint_Y\":626.44746079947163},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{659.90741962686184, 134.1591558035534}\",\"VNPrevPointForRadiusKey\":\"{659.90741962686184, 134.1591558035534}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":54}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":\"Mac App icon\"}","argumentGID":0}],"methodSignature":"title","targetGID":3}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":57},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 51.701018329683393, 116.18082292683278]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {740, 744.6337699943515}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {736.35253901673036, 740.35218585345365}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {726.62032261171248, 732.07890244371663}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {706.29497285008392, 715.91557216276851}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {691.48129050959142, 702.64569380957585}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {676.51521301916046, 688.7168285032127}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {672.9666932377902, 683.82682021816697}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {667.51490451806353, 675.17444423582754}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {659.05376131978483, 661.73639796317264}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {652.798107458392, 653.69283161018325}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {646.24074717873964, 645.29847372318682}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {639.28068335784974, 635.32950515648088}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {636.62597526532704, 630.02008897143548}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {635.24953610331818, 624.67241338007113}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {634.94885764559763, 622.6021329778589}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {634.94885764559763, 621.53096597223009}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {634.94885764559763, 620.05992231684661}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {634.94885764559763, 617.99269367248519}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {634.94885764559763, 616.51850188795038}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {634.94885764559763, 616.24683119169595}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {634.94885764559763, 615.70516023506332}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {634.94885764559763, 615.17627453763725}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {634.94885764559763, 614.91966988803563}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {634.94885764559763, 614.41860337270202}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {634.94885764559763, 614.17012603611374}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {634.94885764559763, 613.92274090759827}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {635.49213479057289, 613.12141354351331}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {635.76223142225149, 612.8513490356014}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {636.57611917917507, 612.03746127867794}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {637.11913933401547, 611.49444112383765}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {637.39077790650299, 610.95251317707016}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {637.39077790650299, 609.88031821090215}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {637.39077790650299, 609.63566360256891}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {637.39077790650299, 609.14548704419769}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {637.39077790650299, 605.7312446082625}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {636.5843428634887, 599.34404392161696}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {636.5843428634887, 593.09060660013677}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {636.5843428634887, 589.48773340525565}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {636.5843428634887, 588.67320317299516}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {636.5843428634887, 588.41560268662124}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {636.5843428634887, 588.17014498411686}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {636.5843428634887, 587.37090566487711}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {636.5843428634887, 585.89687449917653}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {637.75570389792438, 583.82575887902624}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {638.35654683309554, 582.08108497761054}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {638.89982397807057, 581.53800057523642}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {638.89982397807057, 581.26632987898211}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {638.89982397807057, 580.49002692927365}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {638.89982397807057, 579.01760195191559}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {638.89982397807057, 577.54289618711107}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {638.89982397807057, 576.39787664149299}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {638.89982397807057, 574.98324232069888}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {637.49819978285086, 574.14796013505304}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {636.68559697660157, 573.33526095750301}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {635.54147689645515, 572.22030925765694}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {634.72784612966643, 571.9486064376357}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {633.91472934314743, 571.67857405349071}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {632.17002331796471, 571.67857405349071}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {630.76017543843136, 571.67857405349071}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {630.21689829345632, 571.67857405349071}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {629.95939417838304, 571.67857405349071}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {629.16606563224377, 571.67857405349071}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {627.41930368598264, 572.55198715038807}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {626.22070169725794, 573.15125602098351}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {624.65229090455068, 574.07519980313668}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {622.58506226018949, 575.54563310695005}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {622.31316669756711, 575.81730380320448}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {621.51598329940589, 576.35817166566585}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {621.75935295706495, 576.11476988423976}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {622.01171726944222, 576.11476988423976}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {622.79887805234603, 575.59915130252296}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {623.61379376980881, 574.78423558506029}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {625.35849979499153, 574.21346049566114}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {626.4990220132504, 573.64088647531833}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {627.02790771067657, 573.36995462570155}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {627.02790771067657, 573.12317984875619}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {627.02790771067657, 572.87576259647392}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {627.02790771067657, 572.62320554149551}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {627.02790771067657, 572.10858279655099}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {627.02790771067657, 571.85628273170744}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {626.48437357556668, 571.58695707043307}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {625.96371156245436, 571.06635930485447}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {625.71160424021173, 571.06635930485447}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {625.46360876012614, 571.06635930485447}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {625.21124444774887, 570.81418773507824}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {624.70805776380325, 570.81418773507824}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {624.18174196772497, 570.28806468160133}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {623.92449484278654, 570.01636186157998}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {623.11163504640217, 569.74465904155875}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {622.57632459560614, 569.20931646699569}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {622.31933446080234, 569.20931646699569}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {622.04743889817996, 568.93899496894903}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {622.04743889817996, 568.68393226015633}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {621.80252729971198, 568.68393226015633}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {621.80252729971198, 570.51884182265508}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {600, 570.51884182265508}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 15.687962779094846, 1.6061883343354566e-05]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}]],"isGroupingUndo":false,"currentUndoGroup":[],"currentRedoGroup":[],"isGroupingRedo":false,"redoStack":[],"nextGID":57} \ No newline at end of file
+{"cacheElements":[{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[320,664.0506297595],"reflectionModeOverride":0,"anchorPoint":[320,640],"cornerRadius":0,"prevPoint":[0,0],"inPoint":[320,580],"nextPoint":[0,0]},{"outPoint":[344.050612449646,595.89893977911322],"reflectionModeOverride":0,"anchorPoint":[337.34381007033926,612.48211711168926],"cornerRadius":0,"prevPoint":[0,0],"inPoint":[327.23039949003834,637.48844227310212],"nextPoint":[0,0]},{"outPoint":[380,580],"reflectionModeOverride":0,"anchorPoint":[360,580],"cornerRadius":0,"prevPoint":[0,0],"inPoint":[352.025306224823,580],"nextPoint":[0,0]},{"outPoint":[260,580],"reflectionModeOverride":0,"anchorPoint":[280,580],"cornerRadius":0,"prevPoint":[0,0],"inPoint":[300,580],"nextPoint":[0,0]}],"closed":true,"reversed":false}},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":2,"width":0.10000000149011612,"endArrow":"","startArrow":"","cap":1},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[0,0],"opacity":1,"blur":0,"isLocked":false,"gid":34,"smootheningRate":0,"initialPoint":[0,0],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"fillColor":{"b":0.98823529481887817,"s":1,"h":0.58068782582120682,"a":1},"maskedElements":[],"abstractPath":{"fillRule":0,"compoundPathData":{"subpaths":[{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[221.67257107604084,316.56452785377144],"reflectionModeOverride":0,"anchorPoint":[221.67257107604084,316.56452785377144],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[221.67257107604084,316.56452785377144],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[222.78002147975192,316.58196755365179],"reflectionModeOverride":0,"anchorPoint":[222.50257105935154,316.56452785377144],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[222.50257105935154,316.56452785377144],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[223.46754319256974,316.15798118973765],"reflectionModeOverride":0,"anchorPoint":[223.27257099819641,316.3245278149393],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[223.05416436926282,316.49652037792839],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[223.56257095468965,315.05452779244973],"reflectionModeOverride":0,"anchorPoint":[223.56257095468965,315.65452781629159],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[223.57458948209043,315.9106673969701],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[222.50257101191011,314.72452780913903],"reflectionModeOverride":0,"anchorPoint":[222.50257101191011,314.72452780913903],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[223.18257095945802,314.72452780913903],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[221.67257102859941,314.72452780913903],"reflectionModeOverride":0,"anchorPoint":[221.67257102859941,314.72452780913903],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[221.67257102859941,314.72452780913903],"nextPoint":[112.85257138121662,191.97453151588078]}],"closed":true,"reversed":false}},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[112.85257138121662,191.97453151588078],"opacity":1,"blur":0,"isLocked":false,"gid":7,"smootheningRate":0,"initialPoint":[112.85257138121662,191.97453151588078],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[223.39257110465107,318.92452774886726],"reflectionModeOverride":0,"anchorPoint":[223.39257110465107,318.92452774886726],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[223.39257110465107,318.92452774886726],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[222.33257116187153,317.04452775363563],"reflectionModeOverride":0,"anchorPoint":[222.33257116187153,317.04452775363563],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[222.33257116187153,317.04452775363563],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[221.67257113564548,317.04452775363563],"reflectionModeOverride":0,"anchorPoint":[221.67257113564548,317.04452775363563],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[221.67257113564548,317.04452775363563],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[221.67257113564548,318.97453151588081],"reflectionModeOverride":0,"anchorPoint":[221.67257113564548,318.97453151588081],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[221.67257113564548,318.97453151588081],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[221.06257112134037,318.97453151588081],"reflectionModeOverride":0,"anchorPoint":[221.06257112134037,318.97453151588081],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[221.06257112134037,318.97453151588081],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[221.06257112134037,314.29453168754219],"reflectionModeOverride":0,"anchorPoint":[221.06257112134037,314.29453168754219],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[221.06257112134037,314.29453168754219],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[222.85351610118363,314.2910670771638],"reflectionModeOverride":0,"anchorPoint":[222.64257116425571,314.29453168754219],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[222.64257116425571,314.29453168754219],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[223.44257068590508,314.46434348341825],"reflectionModeOverride":0,"anchorPoint":[223.26257121864279,314.39453162176318],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[223.06341253016012,314.32492145971571],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[223.8867055322342,314.82297152263595],"reflectionModeOverride":0,"anchorPoint":[223.75257125112995,314.69453165532451],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[223.60854628757448,314.56596123813961],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[224.15455094852729,315.31612333025106],"reflectionModeOverride":0,"anchorPoint":[224.07257117822328,315.14453165999419],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[223.99528738469252,314.97566482247669],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[224.19825083117667,315.9922372888982],"reflectionModeOverride":0,"anchorPoint":[224.19257122020886,315.69453168706491],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[224.19562660185056,315.50438689028209],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[223.7338072115908,316.75555373263109],"reflectionModeOverride":0,"anchorPoint":[223.91257119347284,316.51453168318102],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[224.09914577717603,316.28247388344346],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[223.19257120773227,317.01453168185151],"reflectionModeOverride":0,"anchorPoint":[223.19257120773227,317.01453168185151],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[223.48085346525613,316.9312160768892],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[222.99257120475204,317.08453168214953],"reflectionModeOverride":0,"anchorPoint":[222.99257120475204,317.08453168214953],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[222.99257120475204,317.08453168214953],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[224.0925712285939,318.97453166784442],"reflectionModeOverride":0,"anchorPoint":[224.0925712285939,318.97453166784442],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[224.0925712285939,318.97453166784442],"nextPoint":[112.85257138121662,191.97453151588078]}],"closed":true,"reversed":false}},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[112.85257138121662,191.97453151588078],"opacity":1,"blur":0,"isLocked":false,"gid":8,"smootheningRate":0,"initialPoint":[112.85257138121662,191.97453151588078],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[221.88165496610824,312.75214941635204],"reflectionModeOverride":0,"anchorPoint":[222.39257110465107,312.75452767257332],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[222.39257110465107,312.75452767257332],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[220.45378029794426,313.23854645592189],"reflectionModeOverride":0,"anchorPoint":[220.90257124445034,313.04452773196982],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[221.37529974656684,312.85070177480884],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[219.35876943156495,314.2208600575953],"reflectionModeOverride":0,"anchorPoint":[219.70257152159786,313.86452769906913],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[220.04640821090715,313.51691728007791],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[218.51848057480817,316.05954140545026],"reflectionModeOverride":0,"anchorPoint":[218.89257170245423,315.09452765536599],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[219.0841152815558,314.63792794299417],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[219.07885049250976,318.55391401613247],"reflectionModeOverride":0,"anchorPoint":[218.89257166857527,318.09452771720584],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[218.51848023468915,317.12951359608263],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[220.04640881460426,319.67213836278347],"reflectionModeOverride":0,"anchorPoint":[219.70257171508007,319.32452783266035],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[219.35412998721458,318.97193143333453],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[222.32887552639454,320.75534631866788],"reflectionModeOverride":0,"anchorPoint":[220.90257185775954,320.14452762388811],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[220.45378073087409,319.9505090873252],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[225.42747093525361,318.97720769048311],"reflectionModeOverride":0,"anchorPoint":[225.07257197531021,319.32452740981233],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[223.98375014972524,320.42992729161517],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[226.25666363710593,317.12951355179308],"reflectionModeOverride":0,"anchorPoint":[225.8825720147413,318.09452742555698],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[225.70369149262439,318.55776181404121],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[225.69870344883279,314.63387871118448],"reflectionModeOverride":0,"anchorPoint":[225.88257204862026,315.09452736371713],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[226.25666342066654,316.05954129932087],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[224.73054756988128,313.51475021332715],"reflectionModeOverride":0,"anchorPoint":[225.07257201185996,313.86452742080394],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[225.42312528062655,314.21540813724465],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[223.40302999066401,312.851739523118],"reflectionModeOverride":0,"anchorPoint":[223.87257194075443,313.04452740721484],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[224.32272320141846,313.23607014436448],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[222.39257194847221,312.754527354262],"reflectionModeOverride":0,"anchorPoint":[222.39257194847221,312.754527354262],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[222.90014945704277,312.7532021443493],"nextPoint":[112.85257138121662,191.97453151588078]}],"closed":false,"reversed":false}},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[112.85257138121662,191.97453151588078],"opacity":1,"blur":0,"isLocked":false,"gid":9,"smootheningRate":0,"initialPoint":[112.85257138121662,191.97453151588078],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[221.79793545229796,321.06845412941806],"reflectionModeOverride":0,"anchorPoint":[222.39257194847221,321.06452777387869],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[222.39257194847221,321.06452777387869],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[220.13630955687603,320.47368746402753],"reflectionModeOverride":0,"anchorPoint":[220.66257205810552,320.71452796827054],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[221.20891937561655,320.94928924957026],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[218.84008207185138,319.31458146286332],"reflectionModeOverride":0,"anchorPoint":[219.26257159607349,319.71452784560978],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[219.66107353858615,320.13423302542299],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[217.79637500761001,317.20177600727493],"reflectionModeOverride":0,"anchorPoint":[218.26257166453621,318.30452834140976],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[218.50031051375157,318.83550383670706],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[218.71657507260346,313.79480682341318],"reflectionModeOverride":0,"anchorPoint":[218.26257150938892,314.85452883246262],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[217.79637484257967,315.95728089190948],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[221.15964890699888,312.25319776201661],"reflectionModeOverride":0,"anchorPoint":[220.61257125382446,312.48452913388269],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[219.5567350056233,312.94749659064405],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[222.93948006388655,312.14028017121217],"reflectionModeOverride":0,"anchorPoint":[222.34257146546875,312.14452894709979],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[221.74863705025209,312.1374427227563],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[224.61118094730551,312.72639164873863],"reflectionModeOverride":0,"anchorPoint":[224.08257153232208,312.48452915920495],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[223.53116831317226,312.25589748063879],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[225.90916737355408,313.88955714821628],"reflectionModeOverride":0,"anchorPoint":[225.49257153005306,313.48452928232075],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[225.08951592668194,313.06563634089633],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[226.95876793869749,315.99728178436908],"reflectionModeOverride":0,"anchorPoint":[226.49257128177129,314.89452945023424],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[226.24808810980261,314.36743571685838],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[226.25070868333646,318.87313890226199],"reflectionModeOverride":0,"anchorPoint":[226.49257117287002,318.34452948727852],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[226.95876813673391,317.24177716378313],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[224.65955409863321,320.59420064219239],"reflectionModeOverride":0,"anchorPoint":[225.49257104975428,319.75452948500953],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[225.91146402567489,319.35147381264608],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[222.34257072457945,321.06452950412722],"reflectionModeOverride":0,"anchorPoint":[222.34257072457945,321.06452950412722],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[223.52534831488276,321.06588609892162],"nextPoint":[112.85257138121662,191.97453151588078]}],"closed":false,"reversed":false}},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[112.85257138121662,191.97453151588078],"opacity":1,"blur":0,"isLocked":false,"gid":10,"smootheningRate":0,"initialPoint":[112.85257138121662,191.97453151588078],"creationPoints":[],"name":"(curve)"}]}}},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[112.85257138121662,191.97453151588078],"opacity":1,"blur":0,"isLocked":false,"gid":6,"smootheningRate":0,"initialPoint":[112.85257138121662,191.97453151588078],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"fillColor":{"b":1,"s":0,"h":0,"a":1},"maskedElements":[],"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[189.49257363188801,253.97453151588081],"reflectionModeOverride":0,"anchorPoint":[189.49257363188801,253.97453151588081],"cornerRadius":0,"prevPoint":[112.85257138121662,152.97453151588078],"inPoint":[189.49257363188801,253.97453151588081],"nextPoint":[112.85257138121662,152.97453151588078]},{"outPoint":[198.97257317412434,244.48453174476265],"reflectionModeOverride":0,"anchorPoint":[198.97257317412434,244.48453174476265],"cornerRadius":0,"prevPoint":[112.85257138121662,152.97453151588078],"inPoint":[198.97257317412434,244.48453174476265],"nextPoint":[112.85257138121662,152.97453151588078]},{"outPoint":[189.49257363188801,235.01453147773384],"reflectionModeOverride":0,"anchorPoint":[189.49257363188801,235.01453147773384],"cornerRadius":0,"prevPoint":[112.85257138121662,152.97453151588078],"inPoint":[189.49257363188801,235.01453147773384],"nextPoint":[112.85257138121662,152.97453151588078]}],"closed":true,"reversed":false}}},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[112.85257138121662,152.97453151588078],"opacity":1,"blur":0,"isLocked":false,"gid":16,"smootheningRate":0,"initialPoint":[112.85257138121662,152.97453151588078],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[300,640],"reflectionModeOverride":0,"anchorPoint":[300,640],"cornerRadius":0,"prevPoint":[0,0],"inPoint":[300,640],"nextPoint":[0,0]},{"outPoint":[380,580],"reflectionModeOverride":0,"anchorPoint":[340,580],"cornerRadius":0,"prevPoint":[0,0],"inPoint":[300,580],"nextPoint":[0,0]}],"closed":false,"reversed":false}},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":2,"width":0.10000000149011612,"endArrow":"","startArrow":"","cap":1},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[0,0],"opacity":1,"blur":0,"isLocked":false,"gid":36,"smootheningRate":0,"initialPoint":[0,0],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[292.2196979967656,487.32457590003901],"reflectionModeOverride":0,"anchorPoint":[270.70254252087443,481.42866614307741],"cornerRadius":0,"prevPoint":[0,1.3634276556741725],"inPoint":[246.45876716860445,474.78563603599895],"nextPoint":[0,1.3634276556741725]},{"outPoint":[308.32019835237998,560.47255779544446],"reflectionModeOverride":0,"anchorPoint":[307.80961189523731,532.13830093176216],"cornerRadius":0,"prevPoint":[9.9345758586960642,16.47175369678871],"inPoint":[307.29902543809465,503.80404406807986],"nextPoint":[9.9345758586960642,16.47175369678871]}],"closed":false,"reversed":false}},"fillColor":{"b":0.9882352941176471,"s":1,"h":0.13822251558303833,"a":1},"strokeStyle":{"color":{"b":0.9882352941176471,"s":1,"h":0.5806878306878307,"a":1},"dashPattern":[],"join":1,"width":0.10000000149011612,"endArrow":"","startArrow":"","cap":0},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[9.9345758586960642,15.108326041114537],"opacity":1,"blur":0,"isLocked":false,"gid":44,"smootheningRate":0,"initialPoint":[9.9345758586960642,15.108326041114537],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(polygon)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[368.75294547403814,729.44134214300266],"reflectionModeOverride":0,"anchorPoint":[368.75294547403814,729.44134214300266],"cornerRadius":0,"prevPoint":[221.86289110820167,-279.40236718212691],"inPoint":[368.75294547403814,729.44134214300266],"nextPoint":[221.86289110820167,-279.40236718212691]},{"outPoint":[58.884741476317231,550.53885452571922],"reflectionModeOverride":0,"anchorPoint":[58.884741476317231,550.53885452571922],"cornerRadius":0,"prevPoint":[221.86289110820167,-279.40236718212691],"inPoint":[58.884741476317231,550.53885452571922],"nextPoint":[221.86289110820167,-279.40236718212691]},{"outPoint":[58.884771993693448,192.73377248033557],"reflectionModeOverride":0,"anchorPoint":[58.884771993693448,192.73377248033557],"cornerRadius":0,"prevPoint":[221.86289110820167,-279.40236718212691],"inPoint":[58.884771993693448,192.73377248033557],"nextPoint":[221.86289110820167,-279.40236718212691]},{"outPoint":[368.75296538097359,13.831330639116459],"reflectionModeOverride":0,"anchorPoint":[368.75296538097359,13.831330639116459],"cornerRadius":0,"prevPoint":[221.86289110820167,-279.40236718212691],"inPoint":[368.75296538097359,13.831330639116459],"nextPoint":[221.86289110820167,-279.40236718212691]},{"outPoint":[678.62124178681802,192.73392506721666],"reflectionModeOverride":0,"anchorPoint":[678.62124178681802,192.73392506721666],"cornerRadius":0,"prevPoint":[221.86289110820167,-279.40236718212691],"inPoint":[678.62124178681802,192.73392506721666],"nextPoint":[221.86289110820167,-279.40236718212691]},{"outPoint":[678.62118075206558,550.53885452571922],"reflectionModeOverride":0,"anchorPoint":[678.62118075206558,550.53885452571922],"cornerRadius":0,"prevPoint":[221.86289110820167,-279.40236718212691],"inPoint":[678.62118075206558,550.53885452571922],"nextPoint":[221.86289110820167,-279.40236718212691]}],"closed":true,"reversed":false}},"fillColor":{"b":0.9882352941176471,"s":1,"h":0.5806878306878307,"a":0.3074892778331435},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":1,"width":18.646402359008789,"endArrow":"","startArrow":"","cap":0},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[368.75296111419152,729.44134214300266],"opacity":1,"blur":0,"isLocked":false,"gid":57,"smootheningRate":0,"initialPoint":[368.75296111419152,371.63633639105956],"creationPoints":[],"name":"(polygon)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[340,700],"reflectionModeOverride":0,"anchorPoint":[340,660],"cornerRadius":0,"prevPoint":[0,0],"inPoint":[340,620],"nextPoint":[0,0]},{"outPoint":[340,600],"reflectionModeOverride":0,"anchorPoint":[380,600],"cornerRadius":0,"prevPoint":[0,0],"inPoint":[420,600],"nextPoint":[0,0]}],"closed":false,"reversed":false}},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":2,"width":0.10000000149011612,"endArrow":"","startArrow":"","cap":1},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[0,0],"opacity":1,"blur":0,"isLocked":false,"gid":35,"smootheningRate":0,"initialPoint":[0,0],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[345.33038784778722,480.48121812716067],"reflectionModeOverride":0,"anchorPoint":[345.33038784778722,480.48121812716067],"cornerRadius":0,"prevPoint":[86.563617484933189,-170.37985441312253],"inPoint":[308.36370636737951,480.48121812716067],"nextPoint":[86.563617484933189,-170.37985441312253]},{"outPoint":[271.39702488697174,480.48121812716067],"reflectionModeOverride":0,"anchorPoint":[271.39702488697174,480.48121812716067],"cornerRadius":0,"prevPoint":[86.563617484933189,-170.37985441312253],"inPoint":[271.39702488697174,480.48121812716067],"nextPoint":[86.563617484933189,-170.37985441312253]},{"outPoint":[345.33038784778722,480.48121812716067],"reflectionModeOverride":0,"anchorPoint":[345.33038784778722,480.48121812716067],"cornerRadius":0,"prevPoint":[86.563617484933189,-170.37985441312253],"inPoint":[345.33038784778722,480.48121812716067],"nextPoint":[86.563617484933189,-170.37985441312253]},{"outPoint":[308.36370636737951,480.48121812716067],"reflectionModeOverride":0,"anchorPoint":[271.39702488697174,480.48121812716067],"cornerRadius":0,"prevPoint":[86.563617484933189,-170.37985441312253],"inPoint":[271.39702488697174,480.48121812716067],"nextPoint":[86.563617484933189,-170.37985441312253]},{"outPoint":[308.36370636737951,547.81167390718997],"reflectionModeOverride":0,"anchorPoint":[308.36370636737951,547.81167390718997],"cornerRadius":0,"prevPoint":[86.563617484933189,-170.37985441312253],"inPoint":[308.36370636737951,547.81167390718997],"nextPoint":[86.563617484933189,-170.37985441312253]}],"closed":true,"reversed":true}},"fillColor":{"b":0,"s":0,"h":0,"a":1},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":2,"width":0.10000000149011612,"endArrow":"","startArrow":"","cap":1},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[579.21777967228218,-165.50118646031109],"opacity":1,"blur":0,"isLocked":false,"gid":37,"smootheningRate":0,"initialPoint":[579.21777967228218,-165.50118646031109],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(line)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[13.974435927889729,160.80268978822852],"reflectionModeOverride":0,"anchorPoint":[13.974435927889729,160.80268978822852],"cornerRadius":0,"prevPoint":[0,0],"inPoint":[13.974435927889729,160.80268978822852],"nextPoint":[0,0]},{"outPoint":[144.25556161242727,291.78142890790133],"reflectionModeOverride":0,"anchorPoint":[144.25556161242727,291.78142890790133],"cornerRadius":0,"prevPoint":[0,0],"inPoint":[144.25556161242727,291.78142890790133],"nextPoint":[0,0]}],"closed":false,"reversed":false}},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":1,"width":20,"endArrow":"","startArrow":"","cap":1},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[0,0],"opacity":1,"blur":0,"isLocked":false,"gid":28,"smootheningRate":0,"initialPoint":[0,0],"creationPoints":[],"name":"(line)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[323.38754763944246,487.32457590003901],"reflectionModeOverride":0,"anchorPoint":[344.90470311533363,481.42866614307741],"cornerRadius":0,"prevPoint":[615.60724563620806,1.3634276556741725],"inPoint":[369.14847846760358,474.78563603599895],"nextPoint":[615.60724563620806,1.3634276556741725]},{"outPoint":[307.28704728382809,560.47255779544446],"reflectionModeOverride":0,"anchorPoint":[307.79763374097075,532.13830093176216],"cornerRadius":0,"prevPoint":[605.67266977751206,16.47175369678871],"inPoint":[308.30822019811342,503.80404406807986],"nextPoint":[605.67266977751206,16.47175369678871]}],"closed":false,"reversed":false}},"fillColor":{"b":0.9882352941176471,"s":1,"h":0.13822251558303833,"a":1},"strokeStyle":{"color":{"b":0.9882352941176471,"s":1,"h":0.5806878306878307,"a":1},"dashPattern":[],"join":1,"width":0.10000000149011612,"endArrow":"","startArrow":"","cap":0},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[605.67266977751206,16.47175369678871],"opacity":1,"blur":0,"isLocked":false,"gid":45,"smootheningRate":0,"initialPoint":[605.67266977751206,16.47175369678871],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[307.98765662154068,497.22766759942954],"reflectionModeOverride":0,"anchorPoint":[307.98765662154068,526.40806463936553],"cornerRadius":0,"prevPoint":[0,0],"inPoint":[307.98765662154068,555.58846167930153],"nextPoint":[0,0]},{"outPoint":[347.07124677007465,468.5633046399771],"reflectionModeOverride":0,"anchorPoint":[331.56894097295356,478.9361833057668],"cornerRadius":0,"prevPoint":[0,0],"inPoint":[316.06663517583246,489.3090619715565],"nextPoint":[0,0]}],"closed":false,"reversed":false}},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":2,"width":20,"endArrow":"","startArrow":"","cap":1},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[0,0],"opacity":1,"blur":0,"isLocked":false,"gid":33,"smootheningRate":0,"initialPoint":[0,0],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"compoundPathData":{"subpaths":[{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[367.7690644381571,667.02363476289884],"reflectionModeOverride":0,"anchorPoint":[367.7690644381571,667.02363476289884],"cornerRadius":0,"prevPoint":[72.193980608055426,108.16792868331186],"inPoint":[368.26333755475412,638.68961321030247],"nextPoint":[72.193980608055426,108.16792868331186]},{"outPoint":[367.82059343747073,616.38299074283532],"reflectionModeOverride":0,"anchorPoint":[367.82059343747073,616.38299074283532],"cornerRadius":0,"prevPoint":[55.02340366515682,81.837967291336099],"inPoint":[367.82059343747073,616.38299074283532],"nextPoint":[55.02340366515682,81.837967291336099]},{"outPoint":[383.13716259159514,626.44746079947163],"reflectionModeOverride":0,"anchorPoint":[403.6767241609266,616.33647011725679],"cornerRadius":0,"prevPoint":[70.109671854888575,134.1591558035534],"inPoint":[403.6767241609266,616.33647011725679],"nextPoint":[70.109671854888575,134.1591558035534]}],"closed":true,"reversed":false}},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[72.357622652088821,121.79167358010636],"opacity":1,"blur":0,"isLocked":false,"gid":48,"smootheningRate":0,"initialPoint":[72.357622652088821,121.79167358010636],"creationPoints":[],"name":"(curve)"}]}},"fillColor":{"b":0.9882352941176471,"s":1,"h":0.13822251558303833,"a":1},"strokeStyle":{"color":{"b":0.9882352941176471,"s":1,"h":0.5806878306878307,"a":1},"dashPattern":[],"join":1,"width":0.10000000149011612,"endArrow":"","startArrow":"","cap":0},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[-2.4740749822735211,26.734403557988003],"opacity":1,"blur":0,"isLocked":false,"gid":46,"smootheningRate":0,"initialPoint":[-2.4740749822735211,26.734403557988003],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"fillColor":{"b":0.98823529481887817,"s":1,"h":0.58068782582120682,"a":1},"maskedElements":[],"abstractPath":{"fillRule":0,"compoundPathData":{"subpaths":[{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[-17.790763092914176,455.94130474918654],"reflectionModeOverride":0,"anchorPoint":[-17.790763092914176,455.94130474918654],"cornerRadius":0,"prevPoint":[-343.22817622315347,103.6410041510419],"inPoint":[-17.790763092914176,455.94130474918654],"nextPoint":[-343.22817622315347,103.6410041510419]},{"outPoint":[-118.14742861878335,355.38893101990755],"reflectionModeOverride":0,"anchorPoint":[-118.14742861878335,355.38893101990755],"cornerRadius":0,"prevPoint":[-343.22817622315347,103.6410041510419],"inPoint":[-118.14742861878335,355.38893101990755],"nextPoint":[-343.22817622315347,103.6410041510419]},{"outPoint":[-89.082653539453304,326.03057263672883],"reflectionModeOverride":0,"anchorPoint":[-89.082653539453304,326.03057263672883],"cornerRadius":0,"prevPoint":[-343.22817622315347,103.6410041510419],"inPoint":[-89.082653539453304,326.03057263672883],"nextPoint":[-343.22817622315347,103.6410041510419]},{"outPoint":[-9.0811227455444623,406.22781863362536],"reflectionModeOverride":0,"anchorPoint":[-9.0811227455444623,406.22781863362536],"cornerRadius":0,"prevPoint":[-343.22817622315347,103.6410041510419],"inPoint":[-9.0811227455444623,406.22781863362536],"nextPoint":[-343.22817622315347,103.6410041510419]},{"outPoint":[-9.0811227455444623,214.66453204993843],"reflectionModeOverride":0,"anchorPoint":[-9.0811227455444623,214.66453204993843],"cornerRadius":0,"prevPoint":[-343.22817622315347,103.6410041510419],"inPoint":[-9.0811227455444623,214.66453204993843],"nextPoint":[-343.22817622315347,103.6410041510419]},{"outPoint":[136.29167736876548,359.98840044701058],"reflectionModeOverride":0,"anchorPoint":[136.29167736876548,359.98840044701058],"cornerRadius":0,"prevPoint":[-343.22817622315347,103.6410041510419],"inPoint":[136.29167736876548,359.98840044701058],"nextPoint":[-343.22817622315347,103.6410041510419]},{"outPoint":[40.289832016581158,455.94130474918654],"reflectionModeOverride":0,"anchorPoint":[40.289832016581158,455.94130474918654],"cornerRadius":0,"prevPoint":[-343.22817622315347,103.6410041510419],"inPoint":[40.289832016581158,455.94130474918654],"nextPoint":[-343.22817622315347,103.6410041510419]},{"outPoint":[136.29167736876548,551.89420905136228],"reflectionModeOverride":0,"anchorPoint":[136.29167736876548,551.89420905136228],"cornerRadius":0,"prevPoint":[-343.22817622315347,103.6410041510419],"inPoint":[136.29167736876548,551.89420905136228],"nextPoint":[-343.22817622315347,103.6410041510419]},{"outPoint":[-9.0322003610774573,697.21808678120522],"reflectionModeOverride":0,"anchorPoint":[-9.0322003610774573,697.21808678120522],"cornerRadius":0,"prevPoint":[-343.22817622315347,103.6410041510419],"inPoint":[-9.0322003610774573,697.21808678120522],"nextPoint":[-343.22817622315347,103.6410041510419]},{"outPoint":[-9.0322003610774573,505.65480953028907],"reflectionModeOverride":0,"anchorPoint":[-9.0322003610774573,505.65480953028907],"cornerRadius":0,"prevPoint":[-343.22817622315347,103.6410041510419],"inPoint":[-9.0322003610774573,505.65480953028907],"nextPoint":[-343.22817622315347,103.6410041510419]},{"outPoint":[-88.78907023560464,585.60738760822585],"reflectionModeOverride":0,"anchorPoint":[-88.78907023560464,585.60738760822585],"cornerRadius":0,"prevPoint":[-343.22817622315347,103.6410041510419],"inPoint":[-88.78907023560464,585.60738760822585],"nextPoint":[-343.22817622315347,103.6410041510419]},{"outPoint":[-117.85384531493469,556.24902922504714],"reflectionModeOverride":0,"anchorPoint":[-117.85384531493469,556.24902922504714],"cornerRadius":0,"prevPoint":[-343.22817622315347,103.6410041510419],"inPoint":[-117.85384531493469,556.24902922504714],"nextPoint":[-343.22817622315347,103.6410041510419]}],"closed":true,"reversed":false}},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[-343.22817622315347,103.6410041510419],"opacity":1,"blur":0,"isLocked":false,"gid":13,"smootheningRate":0,"initialPoint":[-343.22817622315347,103.6410041510419],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[-87.50742636811205,292.97453151588081],"reflectionModeOverride":0,"anchorPoint":[-87.50742636811205,292.97453151588081],"cornerRadius":0,"prevPoint":[-164.14742861878338,191.97453151588081],"inPoint":[-87.50742636811205,292.97453151588081],"nextPoint":[-164.14742861878338,191.97453151588081]},{"outPoint":[-78.027426825875665,283.48453174476265],"reflectionModeOverride":0,"anchorPoint":[-78.027426825875665,283.48453174476265],"cornerRadius":0,"prevPoint":[-164.14742861878338,191.97453151588081],"inPoint":[-78.027426825875665,283.48453174476265],"nextPoint":[-164.14742861878338,191.97453151588081]},{"outPoint":[-87.507426368111936,274.01453147773384],"reflectionModeOverride":0,"anchorPoint":[-87.507426368111936,274.01453147773384],"cornerRadius":0,"prevPoint":[-164.14742861878338,191.97453151588081],"inPoint":[-87.507426368111936,274.01453147773384],"nextPoint":[-164.14742861878338,191.97453151588081]}],"closed":true,"reversed":false}},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[-164.14742861878338,191.97453151588081],"opacity":1,"blur":0,"isLocked":false,"gid":14,"smootheningRate":0,"initialPoint":[-164.14742861878338,191.97453151588081],"creationPoints":[],"name":"(curve)"}]}}},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[-164.14742861878338,191.97453151588078],"opacity":1,"blur":0,"isLocked":false,"gid":11,"smootheningRate":0,"initialPoint":[-164.14742861878338,191.97453151588078],"creationPoints":[],"name":"(curve)"}],"cacheLayers":[],"cacheArtboardPaths":[],"undoStack":[[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":6}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -20, -20]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11,6]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -29.209948435277369, -232.41660739687057]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[12]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[12,13,14,15]}","argumentGID":0}],"methodSignature":"setSubpaths:","targetGID":11},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11}],"methodSignature":"setSuperpath:","targetGID":12},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setFill:","targetGID":12},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":12},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setShadow:","targetGID":12},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11}],"methodSignature":"setSuperpath:","targetGID":13},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setFill:","targetGID":13},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":13},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setShadow:","targetGID":13},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11}],"methodSignature":"setSuperpath:","targetGID":14},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setFill:","targetGID":14},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":14},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setShadow:","targetGID":14}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":6},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":16}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -20, -20]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":16},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":16}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setFill:","targetGID":14}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setFill:","targetGID":16}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setFill:","targetGID":16}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.01450315572447696,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.93007444840156717,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.014503091068591101,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.93451308072143913,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.014503091068591101,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.93910701763028559,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.014503091068591101,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.94055809677531532,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.014503091068591101,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.94999337125602745,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.013467045153601698,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.95297621548706413,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.013467045153601698,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.95790068402842177,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.011044777045815676,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.96266052064980523,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.0088583736096398309,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.96911575815444173,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.0077646546444650423,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.97217928832645584,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.0032726223185911016,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.98016728703982747,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.0010851843882415254,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.98662352066719217,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.99307006473711057,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[0.20437110010339629, -0, -0, 0.20437110010339629, 126.38769661378409, 170.79330548171168]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[13]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[12,13,14]}","argumentGID":0}],"methodSignature":"setSubpaths:","targetGID":11},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11}],"methodSignature":"setSuperpath:","targetGID":13},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setFill:","targetGID":13},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":13},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setShadow:","targetGID":13},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11}],"methodSignature":"setSuperpath:","targetGID":14},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setFill:","targetGID":14},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":14},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setShadow:","targetGID":14}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":21}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":185.15633048630471,\"AnchorPoint_Y\":354.17149931944061,\"inPoint_Y\":354.17149931944061,\"OutPoint_X\":185.15633048630471,\"AnchorPoint_X\":185.15633048630471,\"OutPoint_Y\":354.17149931944061},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":185.15633048630471,\"AnchorPoint_Y\":354.17149931944061,\"inPoint_Y\":354.17149931944061,\"OutPoint_X\":185.15633048630471,\"AnchorPoint_X\":185.15633048630471,\"OutPoint_Y\":354.17149931944061},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":386.50447364412418,\"AnchorPoint_Y\":554.43203524141848,\"inPoint_Y\":554.43203524141848,\"OutPoint_X\":386.50447364412418,\"AnchorPoint_X\":386.50447364412418,\"OutPoint_Y\":554.43203524141848},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":185.15633048630471,\"AnchorPoint_Y\":354.17149931944061,\"inPoint_Y\":354.17149931944061,\"OutPoint_X\":185.15633048630471,\"AnchorPoint_X\":185.15633048630471,\"OutPoint_Y\":354.17149931944061},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":386.50447364412418,\"AnchorPoint_Y\":554.43203524141848,\"inPoint_Y\":554.43203524141848,\"OutPoint_X\":386.50447364412418,\"AnchorPoint_X\":386.50447364412418,\"OutPoint_Y\":554.43203524141848},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":284.63851065196616,\"AnchorPoint_Y\":654.20422348213651,\"inPoint_Y\":654.20422348213651,\"OutPoint_X\":284.63851065196616,\"AnchorPoint_X\":284.63851065196616,\"OutPoint_Y\":654.20422348213651},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":185.15633048630471,\"AnchorPoint_Y\":354.17149931944061,\"inPoint_Y\":354.17149931944061,\"OutPoint_X\":185.15633048630471,\"AnchorPoint_X\":185.15633048630471,\"OutPoint_Y\":354.17149931944061},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":386.50447364412418,\"AnchorPoint_Y\":554.43203524141848,\"inPoint_Y\":554.43203524141848,\"OutPoint_X\":386.50447364412418,\"AnchorPoint_X\":386.50447364412418,\"OutPoint_Y\":554.43203524141848},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":284.63851065196616,\"AnchorPoint_Y\":654.20422348213651,\"inPoint_Y\":654.20422348213651,\"OutPoint_X\":284.63851065196616,\"AnchorPoint_X\":284.63851065196616,\"OutPoint_Y\":654.20422348213651},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":286.57710140084737,\"AnchorPoint_Y\":264.05198470231699,\"inPoint_Y\":264.05198470231699,\"OutPoint_X\":286.57710140084737,\"AnchorPoint_X\":286.57710140084737,\"OutPoint_Y\":264.05198470231699},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":185.15633048630471,\"AnchorPoint_Y\":354.17149931944061,\"inPoint_Y\":354.17149931944061,\"OutPoint_X\":185.15633048630471,\"AnchorPoint_X\":185.15633048630471,\"OutPoint_Y\":354.17149931944061},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":386.50447364412418,\"AnchorPoint_Y\":554.43203524141848,\"inPoint_Y\":554.43203524141848,\"OutPoint_X\":386.50447364412418,\"AnchorPoint_X\":386.50447364412418,\"OutPoint_Y\":554.43203524141848},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":284.63851065196616,\"AnchorPoint_Y\":654.20422348213651,\"inPoint_Y\":654.20422348213651,\"OutPoint_X\":284.63851065196616,\"AnchorPoint_X\":284.63851065196616,\"OutPoint_Y\":654.20422348213651},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":286.57710140084737,\"AnchorPoint_Y\":264.05198470231699,\"inPoint_Y\":264.05198470231699,\"OutPoint_X\":286.57710140084737,\"AnchorPoint_X\":286.57710140084737,\"OutPoint_Y\":264.05198470231699},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":383.69928863669242,\"AnchorPoint_Y\":361.21410026752545,\"inPoint_Y\":361.21410026752545,\"OutPoint_X\":383.69928863669242,\"AnchorPoint_X\":383.69928863669242,\"OutPoint_Y\":361.21410026752545},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":1}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":1,\"WDHueKey\":0.5806878306878307,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":1}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":1,\"WDHueKey\":0.5806878306878307,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":37.148059844970703}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":1,\"WDHueKey\":0.5806878306878307,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":2,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":37.148059844970703}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":185.15633048630471,\"AnchorPoint_Y\":354.17149931944061,\"inPoint_Y\":354.17149931944061,\"OutPoint_X\":185.15633048630471,\"AnchorPoint_X\":185.15633048630471,\"OutPoint_Y\":354.17149931944061},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":386.50447364412418,\"AnchorPoint_Y\":554.43203524141848,\"inPoint_Y\":554.43203524141848,\"OutPoint_X\":386.50447364412418,\"AnchorPoint_X\":386.50447364412418,\"OutPoint_Y\":554.43203524141848},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":284.63851065196616,\"AnchorPoint_Y\":654.20422348213651,\"inPoint_Y\":654.20422348213651,\"OutPoint_X\":284.63851065196616,\"AnchorPoint_X\":284.63851065196616,\"OutPoint_Y\":654.20422348213651},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":286.57710140084737,\"AnchorPoint_Y\":264.05198470231699,\"inPoint_Y\":264.05198470231699,\"OutPoint_X\":286.57710140084737,\"AnchorPoint_X\":286.57710140084737,\"OutPoint_Y\":264.05198470231699},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":383.69928863669242,\"AnchorPoint_Y\":361.21410026752545,\"inPoint_Y\":361.21410026752545,\"OutPoint_X\":383.69928863669242,\"AnchorPoint_X\":383.69928863669242,\"OutPoint_Y\":361.21410026752545},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":186.05023255601679,\"AnchorPoint_Y\":558.85414169234264,\"inPoint_Y\":558.85414169234264,\"OutPoint_X\":186.05023255601679,\"AnchorPoint_X\":186.05023255601679,\"OutPoint_Y\":558.85414169234264},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":185.15633048630471,\"AnchorPoint_Y\":354.17149931944061,\"inPoint_Y\":354.17149931944061,\"OutPoint_X\":185.15633048630471,\"AnchorPoint_X\":185.15633048630471,\"OutPoint_Y\":354.17149931944061},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":386.50447364412418,\"AnchorPoint_Y\":554.43203524141848,\"inPoint_Y\":554.43203524141848,\"OutPoint_X\":386.50447364412418,\"AnchorPoint_X\":386.50447364412418,\"OutPoint_Y\":554.43203524141848},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":284.63851065196616,\"AnchorPoint_Y\":654.20422348213651,\"inPoint_Y\":654.20422348213651,\"OutPoint_X\":284.63851065196616,\"AnchorPoint_X\":284.63851065196616,\"OutPoint_Y\":654.20422348213651},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":286.57710140084737,\"AnchorPoint_Y\":264.05198470231699,\"inPoint_Y\":264.05198470231699,\"OutPoint_X\":286.57710140084737,\"AnchorPoint_X\":286.57710140084737,\"OutPoint_Y\":264.05198470231699},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":383.69928863669242,\"AnchorPoint_Y\":361.21410026752545,\"inPoint_Y\":361.21410026752545,\"OutPoint_X\":383.69928863669242,\"AnchorPoint_X\":383.69928863669242,\"OutPoint_Y\":361.21410026752545},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":1,\"NodePoints\":{\"inPoint_X\":235.46249740746129,\"AnchorPoint_Y\":558.85414169234264,\"inPoint_Y\":509.44413050490067,\"OutPoint_X\":136.6379677045723,\"AnchorPoint_X\":186.05023255601679,\"OutPoint_Y\":608.26415287978466},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782582120682,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.98823529481887817,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":16},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":1,\"WDHueKey\":0.5806878306878307,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":37.148059844970703}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":1,\"WDHueKey\":0.5806878306878307,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":37.148059844970703}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0.03408561318607653,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.016189711030229925,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":37.148059844970703}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0.029926881951800856,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.016189711030229925,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":37.148059844970703}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0.021585238181938561,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.012961911164688478,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":37.148059844970703}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0.011895648503707629,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.007872629590133573,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":37.148059844970703}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0.005957393322960804,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":37.148059844970703}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":37.148059844970703}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":37.148059844970703}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":21.344829559326172}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":21.344829559326172}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":20}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[-4.3711390001862419e-08, -0.99999999999999922, 0.99999999999999922, -4.3711390001862419e-08, -173.29768953296772, 744.95852622656867]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 8.2190355245806472, 176.90598115888827]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":22}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 0.55538688884063114, -0, 182.49084631957811]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[22]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":24}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 150.32620239929324, 36.081797695525552]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[24]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[24]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0.12249755187863798, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[24]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[0.64978701032960984, -0, -0, 0.64978701032960984, 52.531948450558538, 142.05406077476505]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[24]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -55.171276915352394, 196.69205141995428]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[24]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[0.65616231221472443, -0, -0, 0.65616231221472443, 51.425334356867019, 141.12771095949628]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[22]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -55.53221494113933, 129.60740108742715]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[22]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 205.17127691535239, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[24]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 205.09503537570964, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[22]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 208.92985571850454]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[24]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 130.84123782858848]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[22]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 75]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[22]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":25}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -20, -20]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[25]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 4.5418914390142788, -306.56258907512347]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[25]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[0.96223302635797447, -0, -0, 0.96223302635797447, -0, 2.8325230231519103]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[22]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1.0392493219135692, -0, -0, 1.0392493219135692, 0, -2.9436991435176969]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[22]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 0.96223302635797447, -0, 2.8325230231519103]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[22]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 15.458108560985721, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[25]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 26.562589075123469]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[25]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 25]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[25]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 50]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[25]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -25]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[25]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":22}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":26}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -20, -20]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":20}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":0.10000000149011612}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":1,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":0.10000000149011612}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 9.881426012744555, 0.91199734232554874]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -77.745954011856824, 28.270796276850916]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 67.864527999112269, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 10, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1.1538461432654479, -0, -0, 1, -1.5384614326544779, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -136.98574299882625, 7.8612196478959504]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":27}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":25},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":3}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":24},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":26},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":3}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":22},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setElements:","targetGID":27},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -53.141264363887032, -43.604121250556744]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -70.052055171480333, -2.5049969673447094]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 219.77475934149726, 163.57319520938375]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":27},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":27}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[0.6846814845770105, -0, -0, 0.6846814845770105, -0.080018108436871196, 3.1890182924268196]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -85.587957051898314, -21.453286888159028]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":20}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setShadow:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDShadowOffsetKey\":10,\"WDShadowAngleKey\":1.5707999467849731,\"WDShadowRadiusKey\":10,\"WDShadowColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":0.33300000000000002,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"$class\":\"WDShadow\"}}","argumentGID":0}],"methodSignature":"setShadow:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setShadow:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDShadowOffsetKey\":10,\"WDShadowAngleKey\":1.5707999467849731,\"WDShadowRadiusKey\":10,\"WDShadowColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":0.33300000000000002,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"$class\":\"WDShadow\"}}","argumentGID":0}],"methodSignature":"setShadow:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":20}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":28}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":28},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":29}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":29}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":19.067760461856238,\"AnchorPoint_Y\":162.4737431408027,\"inPoint_Y\":162.4737431408027,\"OutPoint_X\":19.067760461856238,\"AnchorPoint_X\":19.067760461856238,\"OutPoint_Y\":162.4737431408027},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":29}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":19.067760461856238,\"AnchorPoint_Y\":162.4737431408027,\"inPoint_Y\":162.4737431408027,\"OutPoint_X\":19.067760461856238,\"AnchorPoint_X\":19.067760461856238,\"OutPoint_Y\":162.4737431408027},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":142.86303913891427,\"AnchorPoint_Y\":297.21030751597522,\"inPoint_Y\":297.21030751597522,\"OutPoint_X\":142.86303913891427,\"AnchorPoint_X\":142.86303913891427,\"OutPoint_Y\":297.21030751597522},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":29}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":3,"argumentEncodedJsonString":"{\"Argument\":false}","argumentGID":0}],"methodSignature":"setClosed:","targetGID":29}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setFill:","targetGID":29}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782582120682,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.98823529481887817,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":29}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":30}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -20, -20]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -258.8309537310077, 14.790477788784642]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":21},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":21}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":21},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":3}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":21}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0}],"methodSignature":"exchangeObjectAtIndex:withObjectAtIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0}],"methodSignature":"exchangeObjectAtIndex:withObjectAtIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0}],"methodSignature":"exchangeObjectAtIndex:withObjectAtIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0}],"methodSignature":"exchangeObjectAtIndex:withObjectAtIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0}],"methodSignature":"exchangeObjectAtIndex:withObjectAtIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0}],"methodSignature":"exchangeObjectAtIndex:withObjectAtIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":3}","argumentGID":0}],"methodSignature":"exchangeObjectAtIndex:withObjectAtIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":1,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":20}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":30}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":1,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":20}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":29}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0}],"methodSignature":"exchangeObjectAtIndex:withObjectAtIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":3}","argumentGID":0}],"methodSignature":"exchangeObjectAtIndex:withObjectAtIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":3}","argumentGID":0},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0}],"methodSignature":"exchangeObjectAtIndex:withObjectAtIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0}],"methodSignature":"exchangeObjectAtIndex:withObjectAtIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[0.98660023945785613, -0, -0, 1.0127745463822073, 7.5897658853896965, -3.7483052243093384]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":3}","argumentGID":0},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0}],"methodSignature":"exchangeObjectAtIndex:withObjectAtIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":31}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":1,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":0.10000000149011612}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":31}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":1,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":27.568212509155273}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":31}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":27.568212509155273}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":31}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":1,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":29}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782582120682,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.98823529481887817,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782582120682,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.98823529481887817,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782582120682,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.98823529481887817,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782582120682,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.98823529481887817,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11623311042785645,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11623311042785645,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11623311042785645,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11623311042785645,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11518210172653198,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11518210172653198,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11518210172653198,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11518210172653198,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11062517762184143,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11062517762184143,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11062517762184143,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11062517762184143,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10827497392892838,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10827497392892838,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10827497392892838,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10827497392892838,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10599262267351151,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10599262267351151,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10599262267351151,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10599262267351151,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10487814247608185,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10487814247608185,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10487814247608185,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10487814247608185,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10140901058912277,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10140901058912277,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10140901058912277,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10140901058912277,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10024447739124298,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10024447739124298,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10024447739124298,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10024447739124298,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.0991511270403862,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.0991511270403862,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.0991511270403862,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.0991511270403862,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.095819912850856781,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.095819912850856781,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.095819912850856781,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.095819912850856781,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.093592062592506436,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.093592062592506436,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.093592062592506436,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.093592062592506436,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.091305255889892578,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.091305255889892578,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.091305255889892578,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.091305255889892578,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.086611531674861908,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.086611531674861908,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.086611531674861908,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.086611531674861908,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.084330290555953952,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.084330290555953952,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.084330290555953952,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.084330290555953952,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.082062393426895142,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.082062393426895142,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.082062393426895142,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.082062393426895142,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.080980166792869596,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.080980166792869596,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.080980166792869596,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.080980166792869596,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.078774556517601013,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.078774556517601013,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.078774556517601013,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.078774556517601013,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.079864569008350372,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.079864569008350372,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.079864569008350372,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.079864569008350372,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.084498241543769864,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.084498241543769864,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.084498241543769864,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.084498241543769864,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.090882599353790255,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.090882599353790255,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.090882599353790255,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.090882599353790255,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.09557187557220459,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.09557187557220459,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.09557187557220459,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.09557187557220459,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.0990910604596138,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.0990910604596138,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.0990910604596138,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.0990910604596138,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10261469334363937,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10261469334363937,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10261469334363937,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10261469334363937,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10601820796728134,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10601820796728134,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10601820796728134,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10601820796728134,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10719386488199234,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10719386488199234,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10719386488199234,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10719386488199234,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11685270816087723,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11685270816087723,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11685270816087723,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11685270816087723,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.12441384047269821,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.12441384047269821,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.12441384047269821,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.12441384047269821,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.12794080376625061,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.12794080376625061,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.12794080376625061,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.12794080376625061,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13263343274593353,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13263343274593353,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13263343274593353,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13263343274593353,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13615038990974426,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13615038990974426,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13615038990974426,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13615038990974426,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13955500721931458,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13955500721931458,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13955500721931458,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13955500721931458,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14536766707897186,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14536766707897186,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14536766707897186,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14536766707897186,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15242382884025574,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15242382884025574,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15242382884025574,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15242382884025574,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15580509603023529,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15580509603023529,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15580509603023529,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15580509603023529,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15815529227256775,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15815529227256775,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15815529227256775,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15815529227256775,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.16035088896751404,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.16035088896751404,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.16035088896751404,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.16035088896751404,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15694738924503326,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15694738924503326,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15694738924503326,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15694738924503326,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15200117230415344,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15200117230415344,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15200117230415344,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15200117230415344,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14730300009250641,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14730300009250641,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14730300009250641,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14730300009250641,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14378604292869568,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14378604292869568,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14378604292869568,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14378604292869568,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14143472909927368,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14143472909927368,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14143472909927368,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14143472909927368,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14034359157085419,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14034359157085419,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14034359157085419,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14034359157085419,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":1,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":30}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":32}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -20, -20]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":33}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":33}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":307.98765662154068,\"AnchorPoint_Y\":526.40806463936553,\"inPoint_Y\":555.58846167930153,\"OutPoint_X\":307.98765662154068,\"AnchorPoint_X\":307.98765662154068,\"OutPoint_Y\":497.22766759942954},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":33}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":1,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":20}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":33}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":33},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":9223372036854775807}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":34}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":34}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":320,\"AnchorPoint_Y\":640,\"inPoint_Y\":680,\"OutPoint_X\":320,\"AnchorPoint_X\":320,\"OutPoint_Y\":600},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":34}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":320,\"AnchorPoint_Y\":640,\"inPoint_Y\":680,\"OutPoint_X\":320,\"AnchorPoint_X\":320,\"OutPoint_Y\":600},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":340,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":380,\"AnchorPoint_X\":360,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":34}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":320,\"AnchorPoint_Y\":640,\"inPoint_Y\":680,\"OutPoint_X\":320,\"AnchorPoint_X\":320,\"OutPoint_Y\":600},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":340,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":380,\"AnchorPoint_X\":360,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":260,\"AnchorPoint_X\":280,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":34},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":3,"argumentEncodedJsonString":"{\"Argument\":false}","argumentGID":0}],"methodSignature":"setClosed:","targetGID":34}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":320,\"AnchorPoint_Y\":640,\"inPoint_Y\":580,\"OutPoint_X\":320,\"AnchorPoint_X\":320,\"OutPoint_Y\":680.00002878904479},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":340,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":380,\"AnchorPoint_X\":360,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":260,\"AnchorPoint_X\":280,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":34}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":34},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":6}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":35}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":35}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":340,\"AnchorPoint_Y\":660,\"inPoint_Y\":620,\"OutPoint_X\":340,\"AnchorPoint_X\":340,\"OutPoint_Y\":700},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":35}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":35},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":6}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":36}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":36}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":640,\"inPoint_Y\":640,\"OutPoint_X\":300,\"AnchorPoint_X\":300,\"OutPoint_Y\":640},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":36}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":37}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -20, -20]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 20, 20]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[-1, -0, 0, 1, 640, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"KeepNodesAfterTransformTransformOptionKey\":true}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 39, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":640,\"inPoint_Y\":640,\"OutPoint_X\":300,\"AnchorPoint_X\":300,\"OutPoint_Y\":640},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{600, 0}\",\"VNPrevPointForRadiusKey\":\"{600, 0}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":220,\"AnchorPoint_X\":260,\"OutPoint_Y\":580},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{600, 0}\",\"VNPrevPointForRadiusKey\":\"{600, 0}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":37}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":640,\"inPoint_Y\":640,\"OutPoint_X\":300,\"AnchorPoint_X\":300,\"OutPoint_Y\":640},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{600, 0}\",\"VNPrevPointForRadiusKey\":\"{600, 0}\",\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":260,\"AnchorPoint_X\":260,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":37}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":640,\"inPoint_Y\":640,\"OutPoint_X\":300,\"AnchorPoint_X\":300,\"OutPoint_Y\":640},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{600, 0}\",\"VNPrevPointForRadiusKey\":\"{600, 0}\",\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":260,\"AnchorPoint_X\":260,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":340,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":340,\"AnchorPoint_X\":340,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":37}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":640,\"inPoint_Y\":640,\"OutPoint_X\":300,\"AnchorPoint_X\":300,\"OutPoint_Y\":640},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{600, 0}\",\"VNPrevPointForRadiusKey\":\"{600, 0}\",\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":260,\"AnchorPoint_X\":260,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":340,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":340,\"AnchorPoint_X\":340,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":260,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":260,\"AnchorPoint_X\":260,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":37}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":640,\"inPoint_Y\":640,\"OutPoint_X\":300,\"AnchorPoint_X\":300,\"OutPoint_Y\":640},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{600, 0}\",\"VNPrevPointForRadiusKey\":\"{600, 0}\",\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":260,\"AnchorPoint_X\":260,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":340,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":340,\"AnchorPoint_X\":340,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":260,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":260,\"AnchorPoint_X\":260,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":340,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":340,\"AnchorPoint_X\":340,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":37}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 60, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":240,\"AnchorPoint_Y\":640,\"inPoint_Y\":640,\"OutPoint_X\":240,\"AnchorPoint_X\":240,\"OutPoint_Y\":640},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{540, 0}\",\"VNPrevPointForRadiusKey\":\"{540, 0}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":240,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":200,\"AnchorPoint_X\":200,\"OutPoint_Y\":580},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-60, 0}\",\"VNPrevPointForRadiusKey\":\"{-60, 0}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":280,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":280,\"AnchorPoint_X\":280,\"OutPoint_Y\":580},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-60, 0}\",\"VNPrevPointForRadiusKey\":\"{-60, 0}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":200,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":200,\"AnchorPoint_X\":200,\"OutPoint_Y\":580},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-60, 0}\",\"VNPrevPointForRadiusKey\":\"{-60, 0}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":280,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":300,\"AnchorPoint_X\":280,\"OutPoint_Y\":600},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-60, 0}\",\"VNPrevPointForRadiusKey\":\"{-60, 0}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":37},{"actionTypeRawValue":"proxy","methodArguments":[],"methodSignature":"reversePathDirection","targetGID":37}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":580,\"inPoint_Y\":600,\"OutPoint_X\":280,\"AnchorPoint_X\":280,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":200,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":200,\"AnchorPoint_X\":200,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":280,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":280,\"AnchorPoint_X\":280,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":200,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":240,\"AnchorPoint_X\":200,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":240,\"AnchorPoint_Y\":640,\"inPoint_Y\":640,\"OutPoint_X\":240,\"AnchorPoint_X\":240,\"OutPoint_Y\":640},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":37},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":3,"argumentEncodedJsonString":"{\"Argument\":false}","argumentGID":0}],"methodSignature":"setClosed:","targetGID":37}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":36},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":6}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -60, 100]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -8.3360061810856791, -0.18596575427056905]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setFill:","targetGID":37}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0.12624915594960839, -0.84513498021431133]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1.0820554726071352, -0, -0, 1, -28.572516179113212, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 3.7693360211719664, 0.58007166688469169]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 0.8911271920692454, -0, 58.840421083655528]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0.018101184397323777, -6.1834757589472247]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0.5616683932951787, -14.721591768371582]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1.4335340527209723, 13.544422687729025]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":37},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":6}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":43}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.10440918421369,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":598.11903819000008},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":314.21352490073997,\"AnchorPoint_Y\":480.08137659705397,\"inPoint_Y\":479.94813303079826,\"OutPoint_X\":366.0442444460744,\"AnchorPoint_X\":340.12888467340719,\"OutPoint_Y\":480.21462016330969},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":314.21352490073997,\"AnchorPoint_Y\":480.08137659705397,\"inPoint_Y\":479.94813303079826,\"OutPoint_X\":340.12888467340719,\"AnchorPoint_X\":340.12888467340719,\"OutPoint_Y\":480.08137659705397},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":314.21352490073997,\"AnchorPoint_Y\":480.08137659705397,\"inPoint_Y\":479.94813303079826,\"OutPoint_X\":340.12888467340719,\"AnchorPoint_X\":340.12888467340719,\"OutPoint_Y\":480.08137659705397},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":337.32713106884489,\"AnchorPoint_Y\":505.14299981511687,\"inPoint_Y\":505.14299981511687,\"OutPoint_X\":337.32713106884489,\"AnchorPoint_X\":337.32713106884489,\"OutPoint_Y\":505.14299981511687},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":314.21352490073997,\"AnchorPoint_Y\":480.08137659705397,\"inPoint_Y\":479.94813303079826,\"OutPoint_X\":340.12888467340719,\"AnchorPoint_X\":340.12888467340719,\"OutPoint_Y\":480.08137659705397},\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":268.41762507168443,\"AnchorPoint_Y\":478.86160216124927,\"inPoint_Y\":478.86160216124927,\"OutPoint_X\":268.41762507168443,\"AnchorPoint_X\":268.41762507168443,\"OutPoint_Y\":478.86160216124927},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-68.909505997160466, -26.2813976538676}\",\"VNPrevPointForRadiusKey\":\"{-68.909505997160466, -26.2813976538676}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":268.41762507168443,\"AnchorPoint_Y\":478.86160216124927,\"inPoint_Y\":478.86160216124927,\"OutPoint_X\":268.41762507168443,\"AnchorPoint_X\":268.41762507168443,\"OutPoint_Y\":478.86160216124927},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-68.909505997160466, -26.2813976538676}\",\"VNPrevPointForRadiusKey\":\"{-68.909505997160466, -26.2813976538676}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":282.38947067174871,\"AnchorPoint_Y\":502.68576551434728,\"inPoint_Y\":502.68576551434728,\"OutPoint_X\":282.38947067174871,\"AnchorPoint_X\":282.38947067174871,\"OutPoint_Y\":502.68576551434728},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.41762507168443,\"AnchorPoint_Y\":478.86160216124927,\"inPoint_Y\":478.86160216124927,\"OutPoint_X\":268.41762507168443,\"AnchorPoint_X\":268.41762507168443,\"OutPoint_Y\":478.86160216124927},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":333.80634908853523,\"AnchorPoint_Y\":479.14166624396699,\"inPoint_Y\":479.14166624396699,\"OutPoint_X\":333.80634908853523,\"AnchorPoint_X\":333.80634908853523,\"OutPoint_Y\":479.14166624396699},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{51.416878416786517, -23.544099270380286}\",\"VNPrevPointForRadiusKey\":\"{51.416878416786517, -23.544099270380286}\",\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.41762507168443,\"AnchorPoint_Y\":478.86160216124927,\"inPoint_Y\":478.86160216124927,\"OutPoint_X\":268.41762507168443,\"AnchorPoint_X\":268.41762507168443,\"OutPoint_Y\":478.86160216124927},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":342.99265545324346,\"AnchorPoint_Y\":479.14166624396699,\"inPoint_Y\":494.80574311033359,\"OutPoint_X\":324.620042723827,\"AnchorPoint_X\":333.80634908853523,\"OutPoint_Y\":463.4775893776004},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.41762507168443,\"AnchorPoint_Y\":478.86160216124927,\"inPoint_Y\":478.86160216124927,\"OutPoint_X\":268.41762507168443,\"AnchorPoint_X\":268.41762507168443,\"OutPoint_Y\":478.86160216124927},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":333.80634908853523,\"AnchorPoint_Y\":479.14166624396699,\"inPoint_Y\":479.14166624396699,\"OutPoint_X\":333.80634908853523,\"AnchorPoint_X\":333.80634908853523,\"OutPoint_Y\":479.14166624396699},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.41762507168443,\"AnchorPoint_Y\":478.86160216124927,\"inPoint_Y\":478.86160216124927,\"OutPoint_X\":268.41762507168443,\"AnchorPoint_X\":268.41762507168443,\"OutPoint_Y\":478.86160216124927},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":3,\"NodePoints\":{\"inPoint_X\":342.99265545324346,\"AnchorPoint_Y\":479.14166624396699,\"inPoint_Y\":494.80574311033359,\"OutPoint_X\":324.620042723827,\"AnchorPoint_X\":333.80634908853523,\"OutPoint_Y\":463.4775893776004},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.41762507168443,\"AnchorPoint_Y\":478.86160216124927,\"inPoint_Y\":478.86160216124927,\"OutPoint_X\":268.41762507168443,\"AnchorPoint_X\":268.41762507168443,\"OutPoint_Y\":478.86160216124927},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":3,\"NodePoints\":{\"inPoint_X\":342.99265545324346,\"AnchorPoint_Y\":479.14166624396699,\"inPoint_Y\":494.80574311033359,\"OutPoint_X\":333.79302393751607,\"AnchorPoint_X\":333.80634908853523,\"OutPoint_Y\":478.98295741265042},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.41762507168443,\"AnchorPoint_Y\":478.86160216124927,\"inPoint_Y\":478.86160216124927,\"OutPoint_X\":268.41762507168443,\"AnchorPoint_X\":268.41762507168443,\"OutPoint_Y\":478.86160216124927},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":3,\"NodePoints\":{\"inPoint_X\":303.99512941310888,\"AnchorPoint_Y\":479.14166624396699,\"inPoint_Y\":487.18557523329599,\"OutPoint_X\":333.79302393751607,\"AnchorPoint_X\":333.80634908853523,\"OutPoint_Y\":478.98295741265042},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.41762507168443,\"AnchorPoint_Y\":478.86160216124927,\"inPoint_Y\":478.86160216124927,\"OutPoint_X\":268.41762507168443,\"AnchorPoint_X\":268.41762507168443,\"OutPoint_Y\":478.86160216124927},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":44}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":44}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":249.48159496463126,\"AnchorPoint_Y\":480.06523848740324,\"inPoint_Y\":466.59075022213392,\"OutPoint_X\":291.92349007711761,\"AnchorPoint_X\":270.70254252087443,\"OutPoint_Y\":493.53972675267255},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":44}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":249.48159496463126,\"AnchorPoint_Y\":480.06523848740324,\"inPoint_Y\":466.59075022213392,\"OutPoint_X\":291.92349007711761,\"AnchorPoint_X\":270.70254252087443,\"OutPoint_Y\":493.53972675267255},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":297.36444957939858,\"AnchorPoint_Y\":515.66654723497345,\"inPoint_Y\":487.33229037129115,\"OutPoint_X\":298.38562249368391,\"AnchorPoint_X\":297.87503603654125,\"OutPoint_Y\":544.00080409865575},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":44}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":246.45876716860445,\"AnchorPoint_Y\":480.06523848740324,\"inPoint_Y\":473.42220838032478,\"OutPoint_X\":292.2196979967656,\"AnchorPoint_X\":270.70254252087443,\"OutPoint_Y\":485.96114824436484},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":297.36444957939858,\"AnchorPoint_Y\":515.66654723497345,\"inPoint_Y\":487.33229037129115,\"OutPoint_X\":298.38562249368391,\"AnchorPoint_X\":297.87503603654125,\"OutPoint_Y\":544.00080409865575},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":44}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":45}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":246.45876716860445,\"AnchorPoint_Y\":480.06523848740324,\"inPoint_Y\":473.42220838032478,\"OutPoint_X\":292.2196979967656,\"AnchorPoint_X\":270.70254252087443,\"OutPoint_Y\":485.96114824436484},\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":307.29902543809465,\"AnchorPoint_Y\":530.77487327608799,\"inPoint_Y\":502.44061641240569,\"OutPoint_X\":308.32019835237998,\"AnchorPoint_X\":307.80961189523731,\"OutPoint_Y\":559.10913013977029},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{9.9345758586960642, 15.108326041114537}\",\"VNPrevPointForRadiusKey\":\"{9.9345758586960642, 15.108326041114537}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":45}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[-1, -0, 0, 1, 618.5121544161118, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[45]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"KeepNodesAfterTransformTransformOptionKey\":true}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -17.095091220096265, 18.636572344325828]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[45]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":246.45876716860445,\"AnchorPoint_Y\":480.06523848740324,\"inPoint_Y\":473.42220838032478,\"OutPoint_X\":292.2196979967656,\"AnchorPoint_X\":270.70254252087443,\"OutPoint_Y\":485.96114824436484},\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":307.29902543809465,\"AnchorPoint_Y\":530.77487327608799,\"inPoint_Y\":502.44061641240569,\"OutPoint_X\":308.32019835237998,\"AnchorPoint_X\":307.80961189523731,\"OutPoint_Y\":559.10913013977029},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{9.9345758586960642, 15.108326041114537}\",\"VNPrevPointForRadiusKey\":\"{9.9345758586960642, 15.108326041114537}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":44}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":46}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":45},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":8}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":44},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":6}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 2.4740749822735211, -26.734403557988003]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[46]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":50}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":50}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":305.84902480507895,\"AnchorPoint_Y\":558.859403557988,\"inPoint_Y\":530.52519454298988,\"OutPoint_X\":305.33842501772648,\"AnchorPoint_X\":305.33842501772648,\"OutPoint_Y\":558.859403557988},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-2.4740749822735211, 26.734403557988003}\",\"VNPrevPointForRadiusKey\":\"{-2.4740749822735211, 26.734403557988003}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":342.43217501772648,\"AnchorPoint_Y\":508.171903557988,\"inPoint_Y\":508.171903557988,\"OutPoint_X\":320.91501841129599,\"AnchorPoint_X\":342.43217501772648,\"OutPoint_Y\":514.06781336097845},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-2.4740749822735211, 26.734403557988003}\",\"VNPrevPointForRadiusKey\":\"{-2.4740749822735211, 26.734403557988003}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":48}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.84902480507895,\"AnchorPoint_Y\":558.859403557988,\"inPoint_Y\":530.52519454298988,\"OutPoint_X\":305.33842501772648,\"AnchorPoint_X\":305.33842501772648,\"OutPoint_Y\":558.859403557988},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":323.12940602919167,\"AnchorPoint_Y\":534.54856008655031,\"inPoint_Y\":534.54856008655031,\"OutPoint_X\":323.12940602919167,\"AnchorPoint_X\":323.12940602919167,\"OutPoint_Y\":534.54856008655031},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":342.43217501772648,\"AnchorPoint_Y\":508.171903557988,\"inPoint_Y\":508.171903557988,\"OutPoint_X\":320.91501841129599,\"AnchorPoint_X\":342.43217501772648,\"OutPoint_Y\":514.06781336097845},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":48}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[47,48]}","argumentGID":0}],"methodSignature":"setSubpaths:","targetGID":46},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":46}],"methodSignature":"setSuperpath:","targetGID":48},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setFill:","targetGID":48},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":48},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setShadow:","targetGID":48},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":46}],"methodSignature":"setSuperpath:","targetGID":48},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":48},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setFill:","targetGID":48},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setShadow:","targetGID":48},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":48}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":46},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":7}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13822251558303833,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":48}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -2.1531569701203352, 25.991399082341331]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[48]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":308.00218177519929,\"AnchorPoint_Y\":532.86800447564667,\"inPoint_Y\":504.53379546064855,\"OutPoint_X\":307.49158198784681,\"AnchorPoint_X\":307.49158198784681,\"OutPoint_Y\":532.86800447564667},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{2.1531569701203352, -25.991399082341331}\",\"VNPrevPointForRadiusKey\":\"{2.1531569701203352, -25.991399082341331}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":307.54481307650724,\"AnchorPoint_Y\":482.22702540901258,\"inPoint_Y\":482.22702540901258,\"OutPoint_X\":307.54481307650724,\"AnchorPoint_X\":307.54481307650724,\"OutPoint_Y\":482.22702540901258},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-15.584592952684432, -52.321534677537727}\",\"VNPrevPointForRadiusKey\":\"{-15.584592952684432, -52.321534677537727}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":344.58533198784681,\"AnchorPoint_Y\":482.18050447564667,\"inPoint_Y\":482.18050447564667,\"OutPoint_X\":323.06817538141632,\"AnchorPoint_X\":344.58533198784681,\"OutPoint_Y\":488.07641427863712},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{2.1531569701203352, -25.991399082341331}\",\"VNPrevPointForRadiusKey\":\"{2.1531569701203352, -25.991399082341331}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":48}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[48]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[48]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[48]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[48]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 0.34003453224391933]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[48]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 0.1954377384541317]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[48]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":54}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -20, -20]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[54]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[-1, -0, 0, 1, 692.07691397569363, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[54]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"KeepNodesAfterTransformTransformOptionKey\":true}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 57.024957634971202, 19.792602829855639]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[54]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":307.04977456552314,\"AnchorPoint_Y\":532.53992937509292,\"inPoint_Y\":504.20572036009486,\"OutPoint_X\":307.56037435287561,\"AnchorPoint_X\":307.56037435287561,\"OutPoint_Y\":532.53992937509292},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{612.89879937060209, -26.319474182895021}\",\"VNPrevPointForRadiusKey\":\"{612.89879937060209, -26.319474182895021}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":307.50714326421519,\"AnchorPoint_Y\":481.89895030845889,\"inPoint_Y\":481.89895030845889,\"OutPoint_X\":307.50714326421519,\"AnchorPoint_X\":307.50714326421519,\"OutPoint_Y\":481.89895030845889},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{630.6365492934068, -52.649609778091417}\",\"VNPrevPointForRadiusKey\":\"{630.6365492934068, -52.649609778091417}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":270.46662435287561,\"AnchorPoint_Y\":481.85242937509298,\"inPoint_Y\":481.85242937509298,\"OutPoint_X\":291.68464211968808,\"AnchorPoint_X\":270.46662435287561,\"OutPoint_Y\":491.96348695323337},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{615.05195634072243, -0.32807510055368994}\",\"VNPrevPointForRadiusKey\":\"{615.05195634072243, -0.32807510055368994}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":54}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":55}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":54},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":8}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":48},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":6}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setElements:","targetGID":55},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":48},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":54}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1.0330248439984473, -0, -0, 0.99999999999999989, -11.379876833051835, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[55]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":56}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":55},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":7}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":21},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":3}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":30},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":32},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":3}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":27},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":29},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":31},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setElements:","targetGID":56},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":27},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":29},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":30},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":21},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":31},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":32},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":55}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":57}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -290.115478515625, 62.302734375]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.042222879700741525,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.89467432944640213,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.042222879700741525,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.90097236067321962,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.031593452065677957,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.91739226661025597,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.019517801575741518,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.93616537665754818,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.0091232041181144082,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.94328004740819738,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.0018620895127118644,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.95006183205443251,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.95531556443573817,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9587083584477003,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.96669617604784863,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.96977202191904677,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.97283138648692502,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.97731792325435829,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9818318081185089,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9863455118694362,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.99094089768406901,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.99553628349870182,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":1,\"WDHueKey\":0.5806878306878307,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":0.10000000149011612}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":0.10000000149011612}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -138.240478515625, -358.288818359375]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":56},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":56}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 10.2197265625, 7.887451171875]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1.73681640625, -1.3956298828125]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":1,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.5806878306878307,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.5806878306878307,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.96954748896640086,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.96362693977790437,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.95841712343394081,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.954131593465262,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.93934857275056949,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.83357840083997725,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.80253639308086555,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.76741239856207288,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.7565612097807517,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.73508462058656032,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.69529915290432798,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.68285743522209563,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.66214385499715267,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.64970324957289294,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.63305608449601369,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.62061547907175396,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.60169597095671978,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.59555519468963558,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.5870419721668565,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.57588046341116172,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.56733832218109337,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.5457271497722096,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.51220146996013671,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.45939702270785876,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.41278562784738043,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.38011749893223234,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.35006206399487472,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.33336373505125283,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.31040673049544421,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.29577720138097952,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.27499243664578588,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.25639993237471526,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.24782776017938496,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.23669294561503418,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.22722206897779043,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.22344372864464693,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.21991675861332574,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.21874110193621868,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.2197966347522779,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.23113499252562641,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.24180488325740318,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.2529452591116173,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.28146132901480636,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.29042946504840544,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.29303437322038722,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.30319262528473806,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.31050016016514809,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.31284924900341687,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.31402379342255127,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.31192273811218679,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.31087054207004555,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.30975717183940776,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.3074892778331435,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1.0000066161593433, -0, -0, 1.0000066161593433, -0.00084115369224984499, -0.0015278888873493538]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 106.25150911801597, 215.10157288799655]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {1024, 1024}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {1018.1834573966, 1022.316502396953}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {1008.5644489681886, 1015.9218488910001}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {1003.3383988868811, 1012.188740268123}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {959.56182404754463, 968.37466824766148}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {930.99873639690077, 938.04865943448704}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {883.88375480634159, 898.86742705675647}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {851.39277451811745, 876.13749149913815}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {807.42735481491377, 847.80421878677203}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {780.8131139470363, 833.66058405713125}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {758.18676120653936, 823.6793880913026}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {745.42543866806363, 820.26800024929958}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {738.45307691385142, 820.26800024929958}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {738.07015268029545, 820.26800024929958}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {738.07015268029545, 820.65313908147255}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {735.7456294412641, 820.1359296408807}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {734.20024226104533, 819.105537302637}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {730.82720724054207, 815.73250228213374}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {722.51078545309133, 807.41391622785272}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {715.22999050970566, 800.13291995732015}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {710.02528110597814, 794.3195482564854}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {708.99086222479468, 792.76802059828378}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {705.03881032957679, 786.83843280185465}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {703.71729893680003, 785.04591654871797}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {702.86608775936838, 784.19455437592615}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {701.16326275021129, 782.49188036212945}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {700.77188277648224, 782.10024872946656}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {699.97704320020512, 781.30550981676288}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {699.12865060283116, 780.87985389626033}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {698.70304501411556, 780.45414764397106}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {695.54100084364723, 776.8204946317021}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {693.70127337454369, 774.98056583545167}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {691.86235121402819, 772.67134345959084}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {689.97672115541332, 769.84279770809485}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {689.03491276184081, 768.90119064166925}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {686.67817717929256, 766.07264489017348}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {683.90469440249581, 763.76603976722345}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {682.53607245732564, 762.86897633206718}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {681.17026909221318, 762.39756881741346}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {678.95083862390538, 761.54620664462163}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {676.30580256688177, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {675.07408308165805, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {673.28025820206608, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {671.48603066818009, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {670.54341696601955, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {669.17600298373122, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {667.39103649860635, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {666.44842279644581, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {666.02281720772999, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {665.226367014277, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {663.57830298909857, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.7291050831368, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.92701772956843, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.54691207607016, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.15190821369538, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.15190821369538, 760.69429082217562}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.15190821369538, 760.30406847954168}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.15190821369538, 759.91817467056762}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.15190821369538, 759.52795232793369}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.15190821369538, 759.12605301077474}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.15190821369538, 758.73814593033103}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.15190821369538, 758.35446671997374}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.55134127330371, 758.35446671997374}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.55134127330371, 757.96107347477482}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.55134127330371, 757.57593464260208}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.97694686201953, 757.57593464260208}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.3896675133285, 757.18274272455005}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.3896675133285, 756.35493582795493}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 755.94518475206382}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 755.5517915068649}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 754.78614436689986}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 754.3960730196261}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 754.00237778370661}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 753.60918586565458}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 753.21065877820774}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 752.81701387407497}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 752.41430924832821}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 749.69714774089903}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 748.93285955917622}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 747.99004452986878}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 747.13868235707696}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.41906127678772, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.65522608114543, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.27149653900142, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {660.88132452815421, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {660.48793128295529, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {659.69429966956, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {659.30453031300658, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {659.68503862079888, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {660.0695734715307, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {660.47263041978476, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {660.86843959074758, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.25498771294906, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.63670398362319, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.02566803158879, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.83158060094979, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {664.08383545516563, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {665.7862578100287, 746.7378903392264}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {667.06307457617595, 747.16359659151567}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {669.70851328749336, 748.01490843252077}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {670.98533005364084, 748.44061468481004}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {672.66399580516031, 748.84437627807847}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {673.94081257130756, 749.26907589463281}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {675.19387273411121, 749.69478214692208}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {675.58525270784025, 749.69478214692208}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {675.20474440004818, 749.69478214692208}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {673.93235683113426, 749.26907589463281}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {672.1381292972485, 747.52296554887494}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {670.87500277709569, 747.09725929658589}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {670.47194582884163, 746.2471050866759}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {669.64368594616599, 745.41864387685314}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {669.24787677520317, 745.02308636482417}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {669.24787677520317, 744.6337699943515}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":287.2857717617394,\"AnchorPoint_Y\":289.25600703483042,\"inPoint_Y\":289.25600703483042,\"OutPoint_X\":287.2857717617394,\"AnchorPoint_X\":287.2857717617394,\"OutPoint_Y\":289.25600703483042},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{59.351577569932488, -881.2368652940595}\",\"VNPrevPointForRadiusKey\":\"{59.351577569932488, -881.2368652940595}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":437.28477645924727,\"AnchorPoint_Y\":289.25600703483042,\"inPoint_Y\":289.25600703483042,\"OutPoint_X\":437.28477645924727,\"AnchorPoint_X\":437.28477645924727,\"OutPoint_Y\":289.25600703483042},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{59.351577569932488, -881.2368652940595}\",\"VNPrevPointForRadiusKey\":\"{59.351577569932488, -881.2368652940595}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":437.28477645924727,\"AnchorPoint_Y\":539.25435579077384,\"inPoint_Y\":539.25435579077384,\"OutPoint_X\":437.28477645924727,\"AnchorPoint_X\":437.28477645924727,\"OutPoint_Y\":539.25435579077384},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{59.351577569932488, -881.2368652940595}\",\"VNPrevPointForRadiusKey\":\"{59.351577569932488, -881.2368652940595}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":287.2857717617394,\"AnchorPoint_Y\":539.25435579077384,\"inPoint_Y\":539.25435579077384,\"OutPoint_X\":287.2857717617394,\"AnchorPoint_X\":287.2857717617394,\"OutPoint_Y\":539.25435579077384},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{59.351577569932488, -881.2368652940595}\",\"VNPrevPointForRadiusKey\":\"{59.351577569932488, -881.2368652940595}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":287.2857717617394,\"AnchorPoint_Y\":289.25602785985438,\"inPoint_Y\":330.67709661876142,\"OutPoint_X\":287.2857717617394,\"AnchorPoint_X\":287.2857717617394,\"OutPoint_Y\":247.83495910094825},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-173.55249370630804, -465.50590420624349}\",\"VNPrevPointForRadiusKey\":\"{-173.55249370630804, -465.50590420624349}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":320.86422761918971,\"AnchorPoint_Y\":214.25650324349817,\"inPoint_Y\":214.25650324349817,\"OutPoint_X\":403.70636513700288,\"AnchorPoint_X\":362.28529637809629,\"OutPoint_Y\":214.25650324349817},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-173.55249370630804, -465.50590420624349}\",\"VNPrevPointForRadiusKey\":\"{-173.55249370630804, -465.50590420624349}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":437.28477402925387,\"AnchorPoint_Y\":289.25602785985438,\"inPoint_Y\":247.83495910094825,\"OutPoint_X\":437.28477402925387,\"AnchorPoint_X\":437.28477402925387,\"OutPoint_Y\":330.67709661876142},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-173.55249370630804, -465.50590420624349}\",\"VNPrevPointForRadiusKey\":\"{-173.55249370630804, -465.50590420624349}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":403.70636513700288,\"AnchorPoint_Y\":364.25550551101242,\"inPoint_Y\":364.25550551101242,\"OutPoint_X\":320.86422761918971,\"AnchorPoint_X\":362.28529637809629,\"OutPoint_Y\":364.25550551101242},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-173.55249370630804, -465.50590420624349}\",\"VNPrevPointForRadiusKey\":\"{-173.55249370630804, -465.50590420624349}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":287.2857717617394,\"AnchorPoint_Y\":539.25437383096278,\"inPoint_Y\":580.67544258986891,\"OutPoint_X\":287.2857717617394,\"AnchorPoint_X\":287.2857717617394,\"OutPoint_Y\":497.83330507205574},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-173.55249370630804, -215.50755823513555}\",\"VNPrevPointForRadiusKey\":\"{-173.55249370630804, -215.50755823513555}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":320.86422761918971,\"AnchorPoint_Y\":464.25484921460566,\"inPoint_Y\":464.25484921460566,\"OutPoint_X\":403.70636513700288,\"AnchorPoint_X\":362.28529637809629,\"OutPoint_Y\":464.25484921460566},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-173.55249370630804, -215.50755823513555}\",\"VNPrevPointForRadiusKey\":\"{-173.55249370630804, -215.50755823513555}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":437.28477402925387,\"AnchorPoint_Y\":539.25437383096278,\"inPoint_Y\":497.83330507205574,\"OutPoint_X\":437.28477402925387,\"AnchorPoint_X\":437.28477402925387,\"OutPoint_Y\":580.67544258986891},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-173.55249370630804, -215.50755823513555}\",\"VNPrevPointForRadiusKey\":\"{-173.55249370630804, -215.50755823513555}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":403.70636513700288,\"AnchorPoint_Y\":614.2538514821199,\"inPoint_Y\":614.2538514821199,\"OutPoint_X\":320.86422761918971,\"AnchorPoint_X\":362.28529637809629,\"OutPoint_Y\":614.2538514821199},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-173.55249370630804, -215.50755823513555}\",\"VNPrevPointForRadiusKey\":\"{-173.55249370630804, -215.50755823513555}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":297.2857056005837,\"AnchorPoint_Y\":289.07321462503751,\"inPoint_Y\":289.07321462503751,\"OutPoint_X\":297.2857056005837,\"AnchorPoint_X\":297.2857056005837,\"OutPoint_Y\":289.07321462503751},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{99.742735489559436, -881.41965770385173}\",\"VNPrevPointForRadiusKey\":\"{99.742735489559436, -881.41965770385173}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":427.28484419717574,\"AnchorPoint_Y\":289.07321462503751,\"inPoint_Y\":289.07321462503751,\"OutPoint_X\":427.28484419717574,\"AnchorPoint_X\":427.28484419717574,\"OutPoint_Y\":289.07321462503751},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{99.742735489559436, -881.41965770385173}\",\"VNPrevPointForRadiusKey\":\"{99.742735489559436, -881.41965770385173}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":427.28484419717574,\"AnchorPoint_Y\":539.07156338098093,\"inPoint_Y\":539.07156338098093,\"OutPoint_X\":427.28484419717574,\"AnchorPoint_X\":427.28484419717574,\"OutPoint_Y\":539.07156338098093},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{99.742735489559436, -881.41965770385173}\",\"VNPrevPointForRadiusKey\":\"{99.742735489559436, -881.41965770385173}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":297.2857056005837,\"AnchorPoint_Y\":539.07156338098093,\"inPoint_Y\":539.07156338098093,\"OutPoint_X\":297.2857056005837,\"AnchorPoint_X\":297.2857056005837,\"OutPoint_Y\":539.07156338098093},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{99.742735489559436, -881.41965770385173}\",\"VNPrevPointForRadiusKey\":\"{99.742735489559436, -881.41965770385173}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":97.57351080287799,\"AnchorPoint_Y\":309.16721333385931,\"inPoint_Y\":309.16721333385931,\"OutPoint_X\":97.57351080287799,\"AnchorPoint_X\":97.57351080287799,\"OutPoint_Y\":309.16721333385931},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{78.505876495528582, 146.69454513811797}\",\"VNPrevPointForRadiusKey\":\"{78.505876495528582, 146.69454513811797}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":221.36797043606543,\"AnchorPoint_Y\":443.90288627635027,\"inPoint_Y\":443.90288627635027,\"OutPoint_X\":221.36797043606543,\"AnchorPoint_X\":221.36797043606543,\"OutPoint_Y\":443.90288627635027},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{78.505876495528582, 146.69454513811797}\",\"VNPrevPointForRadiusKey\":\"{78.505876495528582, 146.69454513811797}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":361.08361414401247,\"AnchorPoint_Y\":309.6035637643763,\"inPoint_Y\":309.6035637643763,\"OutPoint_X\":361.08361414401247,\"AnchorPoint_X\":361.08361414401247,\"OutPoint_Y\":309.6035637643763},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{78.505876495528582, 146.69454513811797}\",\"VNPrevPointForRadiusKey\":\"{78.505876495528582, 146.69454513811797}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":29},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":377.82365759764593,\"AnchorPoint_Y\":307.07623767819223,\"inPoint_Y\":307.07623767819223,\"OutPoint_X\":377.82365759764593,\"AnchorPoint_X\":377.82365759764593,\"OutPoint_Y\":307.07623767819223},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{358.49705139509047, 146.65290478922907}\",\"VNPrevPointForRadiusKey\":\"{358.49705139509047, 146.65290478922907}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":503.2994629767461,\"AnchorPoint_Y\":440.11243356580462,\"inPoint_Y\":440.11243356580462,\"OutPoint_X\":503.2994629767461,\"AnchorPoint_X\":503.2994629767461,\"OutPoint_Y\":440.11243356580462},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{358.49705139509047, 146.65290478922907}\",\"VNPrevPointForRadiusKey\":\"{358.49705139509047, 146.65290478922907}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":644.91269001662772,\"AnchorPoint_Y\":307.50708423933065,\"inPoint_Y\":307.50708423933065,\"OutPoint_X\":644.91269001662772,\"AnchorPoint_X\":644.91269001662772,\"OutPoint_Y\":307.50708423933065},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{358.49705139509047, 146.65290478922907}\",\"VNPrevPointForRadiusKey\":\"{358.49705139509047, 146.65290478922907}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":30},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":516.45695350382334,\"AnchorPoint_Y\":154.80813254227905,\"inPoint_Y\":154.80813254227905,\"OutPoint_X\":516.45695350382334,\"AnchorPoint_X\":516.45695350382334,\"OutPoint_Y\":154.80813254227905},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{1033.732755685123, -115.61701281386331}\",\"VNPrevPointForRadiusKey\":\"{1033.732755685123, -115.61701281386331}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":223.97172601151692,\"AnchorPoint_Y\":448.88181029919406,\"inPoint_Y\":448.88181029919406,\"OutPoint_X\":223.97172601151692,\"AnchorPoint_X\":223.97172601151692,\"OutPoint_Y\":448.88181029919406},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{1033.732755685123, -115.61701281386331}\",\"VNPrevPointForRadiusKey\":\"{1033.732755685123, -115.61701281386331}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":78.252109034647219,\"AnchorPoint_Y\":300.1041732651538,\"inPoint_Y\":300.1041732651538,\"OutPoint_X\":78.252109034647219,\"AnchorPoint_X\":78.252109034647219,\"OutPoint_Y\":300.1041732651538},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{1033.732755685123, -115.61701281386331}\",\"VNPrevPointForRadiusKey\":\"{1033.732755685123, -115.61701281386331}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":648.07861404640448,\"AnchorPoint_Y\":302.9355554780409,\"inPoint_Y\":302.9355554780409,\"OutPoint_X\":648.07861404640448,\"AnchorPoint_X\":648.07861404640448,\"OutPoint_Y\":302.9355554780409},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{1033.732755685123, -115.61701281386331}\",\"VNPrevPointForRadiusKey\":\"{1033.732755685123, -115.61701281386331}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":506.17105679039673,\"AnchorPoint_Y\":444.7847840681311,\"inPoint_Y\":444.7847840681311,\"OutPoint_X\":506.17105679039673,\"AnchorPoint_X\":506.17105679039673,\"OutPoint_Y\":444.7847840681311},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{1033.732755685123, -115.61701281386331}\",\"VNPrevPointForRadiusKey\":\"{1033.732755685123, -115.61701281386331}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":217.51314851045686,\"AnchorPoint_Y\":156.11368443580113,\"inPoint_Y\":156.11368443580113,\"OutPoint_X\":217.51314851045686,\"AnchorPoint_X\":217.51314851045686,\"OutPoint_Y\":156.11368443580113},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{1033.732755685123, -115.61701281386331}\",\"VNPrevPointForRadiusKey\":\"{1033.732755685123, -115.61701281386331}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":21},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":290.26965144695237,\"AnchorPoint_Y\":418.73751961026619,\"inPoint_Y\":418.73751961026619,\"OutPoint_X\":290.26965144695237,\"AnchorPoint_X\":290.26965144695237,\"OutPoint_Y\":418.73751961026619},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{78.505876495528582, 146.69454513811797}\",\"VNPrevPointForRadiusKey\":\"{78.505876495528582, 146.69454513811797}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":433.31216208615911,\"AnchorPoint_Y\":418.73751961026619,\"inPoint_Y\":418.73751961026619,\"OutPoint_X\":433.31216208615911,\"AnchorPoint_X\":433.31216208615911,\"OutPoint_Y\":418.73751961026619},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{78.505876495528582, 146.69454513811797}\",\"VNPrevPointForRadiusKey\":\"{78.505876495528582, 146.69454513811797}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":31},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":290.26965144695237,\"AnchorPoint_Y\":521.73683815036247,\"inPoint_Y\":521.73683815036247,\"OutPoint_X\":290.26965144695237,\"AnchorPoint_X\":290.26965144695237,\"OutPoint_Y\":521.73683815036247},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{78.505876495528582, 249.69386367821471}\",\"VNPrevPointForRadiusKey\":\"{78.505876495528582, 249.69386367821471}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":433.31216208615911,\"AnchorPoint_Y\":521.73683815036247,\"inPoint_Y\":521.73683815036247,\"OutPoint_X\":433.31216208615911,\"AnchorPoint_X\":433.31216208615911,\"OutPoint_Y\":521.73683815036247},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{78.505876495528582, 249.69386367821471}\",\"VNPrevPointForRadiusKey\":\"{78.505876495528582, 249.69386367821471}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":32},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":362.67570746371234,\"AnchorPoint_Y\":667.02363476289884,\"inPoint_Y\":638.68961321030247,\"OutPoint_X\":362.18143434711533,\"AnchorPoint_X\":362.18143434711533,\"OutPoint_Y\":667.02363476289884},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{66.606350517013652, 108.16792868331186}\",\"VNPrevPointForRadiusKey\":\"{66.606350517013652, 108.16792868331186}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":362.23296334642896,\"AnchorPoint_Y\":616.38299074283532,\"inPoint_Y\":616.38299074283532,\"OutPoint_X\":362.23296334642896,\"AnchorPoint_X\":362.23296334642896,\"OutPoint_Y\":616.38299074283532},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{49.435773574115046, 81.837967291336099}\",\"VNPrevPointForRadiusKey\":\"{49.435773574115046, 81.837967291336099}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":398.08909406988482,\"AnchorPoint_Y\":616.33647011725679,\"inPoint_Y\":616.33647011725679,\"OutPoint_X\":377.54953250055337,\"AnchorPoint_X\":398.08909406988482,\"OutPoint_Y\":626.44746079947163},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{64.522041763846801, 134.1591558035534}\",\"VNPrevPointForRadiusKey\":\"{64.522041763846801, 134.1591558035534}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":48},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":361.7537539269963,\"AnchorPoint_Y\":667.02363476289884,\"inPoint_Y\":638.68961321030247,\"OutPoint_X\":362.24802704359331,\"AnchorPoint_X\":362.24802704359331,\"OutPoint_Y\":667.02363476289884},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{657.82311087369476, 108.16792868331186}\",\"VNPrevPointForRadiusKey\":\"{657.82311087369476, 108.16792868331186}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":362.19649804427968,\"AnchorPoint_Y\":616.38299074283532,\"inPoint_Y\":616.38299074283532,\"OutPoint_X\":362.19649804427968,\"AnchorPoint_X\":362.19649804427968,\"OutPoint_Y\":616.38299074283532},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{674.99368781659336, 81.837967291336099}\",\"VNPrevPointForRadiusKey\":\"{674.99368781659336, 81.837967291336099}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":326.34036732082382,\"AnchorPoint_Y\":616.33647011725679,\"inPoint_Y\":616.33647011725679,\"OutPoint_X\":346.87992889015482,\"AnchorPoint_X\":326.34036732082382,\"OutPoint_Y\":626.44746079947163},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{659.90741962686184, 134.1591558035534}\",\"VNPrevPointForRadiusKey\":\"{659.90741962686184, 134.1591558035534}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":54}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":\"Mac App icon\"}","argumentGID":0}],"methodSignature":"title","targetGID":3}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":57},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 51.701018329683393, 116.18082292683278]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {740, 744.6337699943515}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {736.35253901673036, 740.35218585345365}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {726.62032261171248, 732.07890244371663}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {706.29497285008392, 715.91557216276851}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {691.48129050959142, 702.64569380957585}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {676.51521301916046, 688.7168285032127}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {672.9666932377902, 683.82682021816697}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {667.51490451806353, 675.17444423582754}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {659.05376131978483, 661.73639796317264}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {652.798107458392, 653.69283161018325}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {646.24074717873964, 645.29847372318682}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {639.28068335784974, 635.32950515648088}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {636.62597526532704, 630.02008897143548}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {635.24953610331818, 624.67241338007113}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {634.94885764559763, 622.6021329778589}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {634.94885764559763, 621.53096597223009}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {634.94885764559763, 620.05992231684661}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {634.94885764559763, 617.99269367248519}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {634.94885764559763, 616.51850188795038}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {634.94885764559763, 616.24683119169595}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {634.94885764559763, 615.70516023506332}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {634.94885764559763, 615.17627453763725}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {634.94885764559763, 614.91966988803563}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {634.94885764559763, 614.41860337270202}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {634.94885764559763, 614.17012603611374}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {634.94885764559763, 613.92274090759827}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {635.49213479057289, 613.12141354351331}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {635.76223142225149, 612.8513490356014}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {636.57611917917507, 612.03746127867794}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {637.11913933401547, 611.49444112383765}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {637.39077790650299, 610.95251317707016}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {637.39077790650299, 609.88031821090215}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {637.39077790650299, 609.63566360256891}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {637.39077790650299, 609.14548704419769}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {637.39077790650299, 605.7312446082625}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {636.5843428634887, 599.34404392161696}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {636.5843428634887, 593.09060660013677}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {636.5843428634887, 589.48773340525565}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {636.5843428634887, 588.67320317299516}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {636.5843428634887, 588.41560268662124}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {636.5843428634887, 588.17014498411686}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {636.5843428634887, 587.37090566487711}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {636.5843428634887, 585.89687449917653}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {637.75570389792438, 583.82575887902624}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {638.35654683309554, 582.08108497761054}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {638.89982397807057, 581.53800057523642}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {638.89982397807057, 581.26632987898211}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {638.89982397807057, 580.49002692927365}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {638.89982397807057, 579.01760195191559}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {638.89982397807057, 577.54289618711107}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {638.89982397807057, 576.39787664149299}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {638.89982397807057, 574.98324232069888}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {637.49819978285086, 574.14796013505304}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {636.68559697660157, 573.33526095750301}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {635.54147689645515, 572.22030925765694}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {634.72784612966643, 571.9486064376357}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {633.91472934314743, 571.67857405349071}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {632.17002331796471, 571.67857405349071}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {630.76017543843136, 571.67857405349071}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {630.21689829345632, 571.67857405349071}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {629.95939417838304, 571.67857405349071}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {629.16606563224377, 571.67857405349071}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {627.41930368598264, 572.55198715038807}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {626.22070169725794, 573.15125602098351}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {624.65229090455068, 574.07519980313668}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {622.58506226018949, 575.54563310695005}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {622.31316669756711, 575.81730380320448}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {621.51598329940589, 576.35817166566585}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {621.75935295706495, 576.11476988423976}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {622.01171726944222, 576.11476988423976}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {622.79887805234603, 575.59915130252296}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {623.61379376980881, 574.78423558506029}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {625.35849979499153, 574.21346049566114}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {626.4990220132504, 573.64088647531833}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {627.02790771067657, 573.36995462570155}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {627.02790771067657, 573.12317984875619}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {627.02790771067657, 572.87576259647392}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {627.02790771067657, 572.62320554149551}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {627.02790771067657, 572.10858279655099}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {627.02790771067657, 571.85628273170744}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {626.48437357556668, 571.58695707043307}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {625.96371156245436, 571.06635930485447}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {625.71160424021173, 571.06635930485447}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {625.46360876012614, 571.06635930485447}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {625.21124444774887, 570.81418773507824}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {624.70805776380325, 570.81418773507824}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {624.18174196772497, 570.28806468160133}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {623.92449484278654, 570.01636186157998}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {623.11163504640217, 569.74465904155875}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {622.57632459560614, 569.20931646699569}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {622.31933446080234, 569.20931646699569}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {622.04743889817996, 568.93899496894903}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {622.04743889817996, 568.68393226015633}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {621.80252729971198, 568.68393226015633}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {621.80252729971198, 570.51884182265508}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {600, 570.51884182265508}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 15.687962779094846, 1.6061883343354566e-05]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}]],"isGroupingUndo":false,"currentUndoGroup":[],"currentRedoGroup":[],"isGroupingRedo":false,"redoStack":[],"nextGID":57}
diff --git a/docs/images/logo_framed.vectornator/Artboard0.json b/docs/images/logo_framed.vectornator/Artboard0.json
index 7a365f7..a4e4bb4 100644
--- a/docs/images/logo_framed.vectornator/Artboard0.json
+++ b/docs/images/logo_framed.vectornator/Artboard0.json
@@ -1 +1 @@
-{"layers":[{"elements":[{"elementDescription":"(polygon)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[368.75294547403814,729.44134214300266],"reflectionModeOverride":0,"anchorPoint":[368.75294547403814,729.44134214300266],"cornerRadius":0,"prevPoint":[221.86289110820167,-279.40236718212691],"inPoint":[368.75294547403814,729.44134214300266],"nextPoint":[221.86289110820167,-279.40236718212691]},{"outPoint":[58.884741476317231,550.53885452571922],"reflectionModeOverride":0,"anchorPoint":[58.884741476317231,550.53885452571922],"cornerRadius":0,"prevPoint":[221.86289110820167,-279.40236718212691],"inPoint":[58.884741476317231,550.53885452571922],"nextPoint":[221.86289110820167,-279.40236718212691]},{"outPoint":[58.884771993693448,192.73377248033557],"reflectionModeOverride":0,"anchorPoint":[58.884771993693448,192.73377248033557],"cornerRadius":0,"prevPoint":[221.86289110820167,-279.40236718212691],"inPoint":[58.884771993693448,192.73377248033557],"nextPoint":[221.86289110820167,-279.40236718212691]},{"outPoint":[368.75296538097359,13.831330639116459],"reflectionModeOverride":0,"anchorPoint":[368.75296538097359,13.831330639116459],"cornerRadius":0,"prevPoint":[221.86289110820167,-279.40236718212691],"inPoint":[368.75296538097359,13.831330639116459],"nextPoint":[221.86289110820167,-279.40236718212691]},{"outPoint":[678.62124178681802,192.73392506721666],"reflectionModeOverride":0,"anchorPoint":[678.62124178681802,192.73392506721666],"cornerRadius":0,"prevPoint":[221.86289110820167,-279.40236718212691],"inPoint":[678.62124178681802,192.73392506721666],"nextPoint":[221.86289110820167,-279.40236718212691]},{"outPoint":[678.62118075206558,550.53885452571922],"reflectionModeOverride":0,"anchorPoint":[678.62118075206558,550.53885452571922],"cornerRadius":0,"prevPoint":[221.86289110820167,-279.40236718212691],"inPoint":[678.62118075206558,550.53885452571922],"nextPoint":[221.86289110820167,-279.40236718212691]}],"closed":true,"reversed":false}},"fillColor":{"b":0.9882352941176471,"s":1,"h":0.5806878306878307,"a":0.3074892778331435},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":1,"width":18.646402359008789,"endArrow":"","startArrow":"","cap":0},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[368.75296111419152,729.44134214300266],"opacity":1,"blur":0,"isLocked":false,"gid":57,"smootheningRate":0,"initialPoint":[368.75296111419152,371.63633639105956],"creationPoints":[],"name":"(polygon)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[61.506041898417834,134.69462453150436],"opacity":1,"blur":0,"isLocked":false,"gid":56,"smootheningRate":0,"initialPoint":[61.506041898417834,134.69462453150436],"creationPoints":[],"group":{"elements":[{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[292.87340185278117,214.25650324349817],"opacity":1,"blur":0,"isLocked":false,"gid":27,"smootheningRate":0,"initialPoint":[292.87340185278117,214.25650324349817],"creationPoints":[],"group":{"elements":[{"elementDescription":"(rectangle)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[292.87340185278117,289.25600703483042],"reflectionModeOverride":0,"anchorPoint":[292.87340185278117,289.25600703483042],"cornerRadius":0,"prevPoint":[64.939207660974262,-881.2368652940595],"inPoint":[292.87340185278117,289.25600703483042],"nextPoint":[64.939207660974262,-881.2368652940595]},{"outPoint":[442.87240655028904,289.25600703483042],"reflectionModeOverride":0,"anchorPoint":[442.87240655028904,289.25600703483042],"cornerRadius":0,"prevPoint":[64.939207660974262,-881.2368652940595],"inPoint":[442.87240655028904,289.25600703483042],"nextPoint":[64.939207660974262,-881.2368652940595]},{"outPoint":[442.87240655028904,539.25435579077384],"reflectionModeOverride":0,"anchorPoint":[442.87240655028904,539.25435579077384],"cornerRadius":0,"prevPoint":[64.939207660974262,-881.2368652940595],"inPoint":[442.87240655028904,539.25435579077384],"nextPoint":[64.939207660974262,-881.2368652940595]},{"outPoint":[292.87340185278117,539.25435579077384],"reflectionModeOverride":0,"anchorPoint":[292.87340185278117,539.25435579077384],"cornerRadius":0,"prevPoint":[64.939207660974262,-881.2368652940595],"inPoint":[292.87340185278117,539.25435579077384],"nextPoint":[64.939207660974262,-881.2368652940595]}],"closed":true,"reversed":false}},"fillColor":{"b":0.9882352941176471,"s":1,"h":0.13822251558303833,"a":1},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":1,"width":20,"endArrow":"","startArrow":"","cap":0},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[442.87240655028904,539.25435579077384],"opacity":1,"blur":0,"isLocked":false,"gid":22,"smootheningRate":0,"initialPoint":[292.87340185278117,289.25600703483042],"creationPoints":[],"name":"(rectangle)"},{"elementDescription":"(oval)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[292.87340185278117,247.83495910094825],"reflectionModeOverride":0,"anchorPoint":[292.87340185278117,289.25602785985438],"cornerRadius":0,"prevPoint":[-167.96486361526627,-465.50590420624349],"inPoint":[292.87340185278117,330.67709661876142],"nextPoint":[-167.96486361526627,-465.50590420624349]},{"outPoint":[409.29399522804465,214.25650324349817],"reflectionModeOverride":0,"anchorPoint":[367.87292646913806,214.25650324349817],"cornerRadius":0,"prevPoint":[-167.96486361526627,-465.50590420624349],"inPoint":[326.45185771023148,214.25650324349817],"nextPoint":[-167.96486361526627,-465.50590420624349]},{"outPoint":[442.87240412029564,330.67709661876142],"reflectionModeOverride":0,"anchorPoint":[442.87240412029564,289.25602785985438],"cornerRadius":0,"prevPoint":[-167.96486361526627,-465.50590420624349],"inPoint":[442.87240412029564,247.83495910094825],"nextPoint":[-167.96486361526627,-465.50590420624349]},{"outPoint":[326.45185771023148,364.25550551101242],"reflectionModeOverride":0,"anchorPoint":[367.87292646913806,364.25550551101242],"cornerRadius":0,"prevPoint":[-167.96486361526627,-465.50590420624349],"inPoint":[409.29399522804465,364.25550551101242],"nextPoint":[-167.96486361526627,-465.50590420624349]}],"closed":true,"reversed":false}},"fillColor":{"b":0.9882352941176471,"s":1,"h":0.13822251558303833,"a":1},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":1,"width":20,"endArrow":"","startArrow":"","cap":0},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[-167.96486361526627,-465.50590420624349],"opacity":1,"blur":0,"isLocked":false,"gid":24,"smootheningRate":0,"initialPoint":[-167.96486361526627,-465.50590420624349],"creationPoints":[],"name":"(oval)"},{"elementDescription":"(oval)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[292.87340185278117,497.83330507205574],"reflectionModeOverride":0,"anchorPoint":[292.87340185278117,539.25437383096278],"cornerRadius":0,"prevPoint":[-167.96486361526627,-215.50755823513555],"inPoint":[292.87340185278117,580.67544258986891],"nextPoint":[-167.96486361526627,-215.50755823513555]},{"outPoint":[409.29399522804465,464.25484921460566],"reflectionModeOverride":0,"anchorPoint":[367.87292646913806,464.25484921460566],"cornerRadius":0,"prevPoint":[-167.96486361526627,-215.50755823513555],"inPoint":[326.45185771023148,464.25484921460566],"nextPoint":[-167.96486361526627,-215.50755823513555]},{"outPoint":[442.87240412029564,580.67544258986891],"reflectionModeOverride":0,"anchorPoint":[442.87240412029564,539.25437383096278],"cornerRadius":0,"prevPoint":[-167.96486361526627,-215.50755823513555],"inPoint":[442.87240412029564,497.83330507205574],"nextPoint":[-167.96486361526627,-215.50755823513555]},{"outPoint":[326.45185771023148,614.2538514821199],"reflectionModeOverride":0,"anchorPoint":[367.87292646913806,614.2538514821199],"cornerRadius":0,"prevPoint":[-167.96486361526627,-215.50755823513555],"inPoint":[409.29399522804465,614.2538514821199],"nextPoint":[-167.96486361526627,-215.50755823513555]}],"closed":true,"reversed":false}},"fillColor":{"b":0.9882352941176471,"s":1,"h":0.13822251558303833,"a":1},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":1,"width":20,"endArrow":"","startArrow":"","cap":0},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[-167.96486361526627,-215.50755823513555],"opacity":1,"blur":0,"isLocked":false,"gid":25,"smootheningRate":0,"initialPoint":[-167.96486361526627,-215.50755823513555],"creationPoints":[],"name":"(oval)"},{"elementDescription":"(rectangle)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[302.87333569162547,289.07321462503751],"reflectionModeOverride":0,"anchorPoint":[302.87333569162547,289.07321462503751],"cornerRadius":0,"prevPoint":[105.33036558060121,-881.41965770385173],"inPoint":[302.87333569162547,289.07321462503751],"nextPoint":[105.33036558060121,-881.41965770385173]},{"outPoint":[432.87247428821752,289.07321462503751],"reflectionModeOverride":0,"anchorPoint":[432.87247428821752,289.07321462503751],"cornerRadius":0,"prevPoint":[105.33036558060121,-881.41965770385173],"inPoint":[432.87247428821752,289.07321462503751],"nextPoint":[105.33036558060121,-881.41965770385173]},{"outPoint":[432.87247428821752,539.07156338098093],"reflectionModeOverride":0,"anchorPoint":[432.87247428821752,539.07156338098093],"cornerRadius":0,"prevPoint":[105.33036558060121,-881.41965770385173],"inPoint":[432.87247428821752,539.07156338098093],"nextPoint":[105.33036558060121,-881.41965770385173]},{"outPoint":[302.87333569162547,539.07156338098093],"reflectionModeOverride":0,"anchorPoint":[302.87333569162547,539.07156338098093],"cornerRadius":0,"prevPoint":[105.33036558060121,-881.41965770385173],"inPoint":[302.87333569162547,539.07156338098093],"nextPoint":[105.33036558060121,-881.41965770385173]}],"closed":true,"reversed":false}},"fillColor":{"b":0.9882352941176471,"s":1,"h":0.13822251558303833,"a":1},"strokeStyle":{"color":{"b":0.9882352941176471,"s":1,"h":0.5806878306878307,"a":1},"dashPattern":[],"join":1,"width":0.10000000149011612,"endArrow":"","startArrow":"","cap":0},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[432.87247428821752,539.07156338098093],"opacity":1,"blur":0,"isLocked":false,"gid":26,"smootheningRate":0,"initialPoint":[302.87333569162547,289.07321462503751],"creationPoints":[],"name":"(rectangle)"}]},"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[103.16114089391976,309.16721333385931],"reflectionModeOverride":0,"anchorPoint":[103.16114089391976,309.16721333385931],"cornerRadius":0,"prevPoint":[84.093506586570356,146.69454513811797],"inPoint":[103.16114089391976,309.16721333385931],"nextPoint":[84.093506586570356,146.69454513811797]},{"outPoint":[226.95560052710721,443.90288627635027],"reflectionModeOverride":0,"anchorPoint":[226.95560052710721,443.90288627635027],"cornerRadius":0,"prevPoint":[84.093506586570356,146.69454513811797],"inPoint":[226.95560052710721,443.90288627635027],"nextPoint":[84.093506586570356,146.69454513811797]},{"outPoint":[366.67124423505425,309.6035637643763],"reflectionModeOverride":0,"anchorPoint":[366.67124423505425,309.6035637643763],"cornerRadius":0,"prevPoint":[84.093506586570356,146.69454513811797],"inPoint":[366.67124423505425,309.6035637643763],"nextPoint":[84.093506586570356,146.69454513811797]}],"closed":true,"reversed":false}},"fillColor":{"b":0.9882352941176471,"s":1,"h":0.5806878306878307,"a":1},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":1,"width":0.10000000149011612,"endArrow":"","startArrow":"","cap":1},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[84.093506586570356,146.69454513811797],"opacity":1,"blur":0,"isLocked":false,"gid":29,"smootheningRate":0,"initialPoint":[84.093506586570356,146.69454513811797],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[383.41128768868771,307.07623767819223],"reflectionModeOverride":0,"anchorPoint":[383.41128768868771,307.07623767819223],"cornerRadius":0,"prevPoint":[364.08468148613224,146.65290478922907],"inPoint":[383.41128768868771,307.07623767819223],"nextPoint":[364.08468148613224,146.65290478922907]},{"outPoint":[508.88709306778787,440.11243356580462],"reflectionModeOverride":0,"anchorPoint":[508.88709306778787,440.11243356580462],"cornerRadius":0,"prevPoint":[364.08468148613224,146.65290478922907],"inPoint":[508.88709306778787,440.11243356580462],"nextPoint":[364.08468148613224,146.65290478922907]},{"outPoint":[650.50032010766949,307.50708423933065],"reflectionModeOverride":0,"anchorPoint":[650.50032010766949,307.50708423933065],"cornerRadius":0,"prevPoint":[364.08468148613224,146.65290478922907],"inPoint":[650.50032010766949,307.50708423933065],"nextPoint":[364.08468148613224,146.65290478922907]}],"closed":true,"reversed":false}},"fillColor":{"b":0.9882352941176471,"s":1,"h":0.5806878306878307,"a":1},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":1,"width":0.10000000149011612,"endArrow":"","startArrow":"","cap":1},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[364.08468148613224,146.65290478922907],"opacity":1,"blur":0,"isLocked":false,"gid":30,"smootheningRate":0,"initialPoint":[364.08468148613224,146.65290478922907],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[522.04458359486512,154.80813254227905],"reflectionModeOverride":0,"anchorPoint":[522.04458359486512,154.80813254227905],"cornerRadius":0,"prevPoint":[1039.3203857761648,-115.61701281386331],"inPoint":[522.04458359486512,154.80813254227905],"nextPoint":[1039.3203857761648,-115.61701281386331]},{"outPoint":[229.5593561025587,448.88181029919406],"reflectionModeOverride":0,"anchorPoint":[229.5593561025587,448.88181029919406],"cornerRadius":0,"prevPoint":[1039.3203857761648,-115.61701281386331],"inPoint":[229.5593561025587,448.88181029919406],"nextPoint":[1039.3203857761648,-115.61701281386331]},{"outPoint":[83.839739125688993,300.1041732651538],"reflectionModeOverride":0,"anchorPoint":[83.839739125688993,300.1041732651538],"cornerRadius":0,"prevPoint":[1039.3203857761648,-115.61701281386331],"inPoint":[83.839739125688993,300.1041732651538],"nextPoint":[1039.3203857761648,-115.61701281386331]},{"outPoint":[653.66624413744626,302.9355554780409],"reflectionModeOverride":0,"anchorPoint":[653.66624413744626,302.9355554780409],"cornerRadius":0,"prevPoint":[1039.3203857761648,-115.61701281386331],"inPoint":[653.66624413744626,302.9355554780409],"nextPoint":[1039.3203857761648,-115.61701281386331]},{"outPoint":[511.75868688143851,444.7847840681311],"reflectionModeOverride":0,"anchorPoint":[511.75868688143851,444.7847840681311],"cornerRadius":0,"prevPoint":[1039.3203857761648,-115.61701281386331],"inPoint":[511.75868688143851,444.7847840681311],"nextPoint":[1039.3203857761648,-115.61701281386331]},{"outPoint":[223.10077860149863,156.11368443580113],"reflectionModeOverride":0,"anchorPoint":[223.10077860149863,156.11368443580113],"cornerRadius":0,"prevPoint":[1039.3203857761648,-115.61701281386331],"inPoint":[223.10077860149863,156.11368443580113],"nextPoint":[1039.3203857761648,-115.61701281386331]}],"closed":false,"reversed":false}},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":1,"width":20,"endArrow":"","startArrow":"","cap":1},"maskedElements":[]},"angle":90,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[1200.0148931967549,-113.13323396127316],"opacity":1,"blur":0,"isLocked":false,"gid":21,"smootheningRate":0,"initialPoint":[1200.0148931967549,-113.13323396127316],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(line)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[295.85728153799414,418.73751961026619],"reflectionModeOverride":0,"anchorPoint":[295.85728153799414,418.73751961026619],"cornerRadius":0,"prevPoint":[84.093506586570356,146.69454513811797],"inPoint":[295.85728153799414,418.73751961026619],"nextPoint":[84.093506586570356,146.69454513811797]},{"outPoint":[438.89979217720088,418.73751961026619],"reflectionModeOverride":0,"anchorPoint":[438.89979217720088,418.73751961026619],"cornerRadius":0,"prevPoint":[84.093506586570356,146.69454513811797],"inPoint":[438.89979217720088,418.73751961026619],"nextPoint":[84.093506586570356,146.69454513811797]}],"closed":false,"reversed":false}},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":1,"width":61.869819641113281,"endArrow":"","startArrow":"","cap":0},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[84.093506586570356,146.69454513811797],"opacity":1,"blur":0,"isLocked":false,"gid":31,"smootheningRate":0,"initialPoint":[84.093506586570356,146.69454513811797],"creationPoints":[],"name":"(line)"},{"elementDescription":"(line)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[295.85728153799414,521.73683815036247],"reflectionModeOverride":0,"anchorPoint":[295.85728153799414,521.73683815036247],"cornerRadius":0,"prevPoint":[84.093506586570356,249.69386367821471],"inPoint":[295.85728153799414,521.73683815036247],"nextPoint":[84.093506586570356,249.69386367821471]},{"outPoint":[438.89979217720088,521.73683815036247],"reflectionModeOverride":0,"anchorPoint":[438.89979217720088,521.73683815036247],"cornerRadius":0,"prevPoint":[84.093506586570356,249.69386367821471],"inPoint":[438.89979217720088,521.73683815036247],"nextPoint":[84.093506586570356,249.69386367821471]}],"closed":false,"reversed":false}},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":1,"width":61.869819641113281,"endArrow":"","startArrow":"","cap":0},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[84.093506586570356,249.69386367821471],"opacity":1,"blur":0,"isLocked":false,"gid":32,"smootheningRate":0,"initialPoint":[84.093506586570356,249.69386367821471],"creationPoints":[],"name":"(line)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[70.109671854888575,134.69462453150436],"opacity":1,"blur":0,"isLocked":false,"gid":55,"smootheningRate":0,"initialPoint":[70.109671854888575,134.69462453150436],"creationPoints":[],"group":{"elements":[{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[367.7690644381571,667.02363476289884],"reflectionModeOverride":0,"anchorPoint":[367.7690644381571,667.02363476289884],"cornerRadius":0,"prevPoint":[72.193980608055426,108.16792868331186],"inPoint":[368.26333755475412,638.68961321030247],"nextPoint":[72.193980608055426,108.16792868331186]},{"outPoint":[367.82059343747073,616.38299074283532],"reflectionModeOverride":0,"anchorPoint":[367.82059343747073,616.38299074283532],"cornerRadius":0,"prevPoint":[55.02340366515682,81.837967291336099],"inPoint":[367.82059343747073,616.38299074283532],"nextPoint":[55.02340366515682,81.837967291336099]},{"outPoint":[383.13716259159514,626.44746079947163],"reflectionModeOverride":0,"anchorPoint":[403.6767241609266,616.33647011725679],"cornerRadius":0,"prevPoint":[70.109671854888575,134.1591558035534],"inPoint":[403.6767241609266,616.33647011725679],"nextPoint":[70.109671854888575,134.1591558035534]}],"closed":true,"reversed":false}},"fillColor":{"b":0,"s":0,"h":0,"a":1},"strokeStyle":{"color":{"b":0.9882352941176471,"s":1,"h":0.5806878306878307,"a":1},"dashPattern":[],"join":1,"width":0.10000000149011612,"endArrow":"","startArrow":"","cap":0},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[72.357622652088821,121.79167358010636],"opacity":1,"blur":0,"isLocked":false,"gid":48,"smootheningRate":0,"initialPoint":[72.357622652088821,121.79167358010636],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[367.83565713463508,667.02363476289884],"reflectionModeOverride":0,"anchorPoint":[367.83565713463508,667.02363476289884],"cornerRadius":0,"prevPoint":[663.41074096473653,108.16792868331186],"inPoint":[367.34138401803807,638.68961321030247],"nextPoint":[663.41074096473653,108.16792868331186]},{"outPoint":[367.78412813532145,616.38299074283532],"reflectionModeOverride":0,"anchorPoint":[367.78412813532145,616.38299074283532],"cornerRadius":0,"prevPoint":[680.58131790763514,81.837967291336099],"inPoint":[367.78412813532145,616.38299074283532],"nextPoint":[680.58131790763514,81.837967291336099]},{"outPoint":[352.46755898119659,626.44746079947163],"reflectionModeOverride":0,"anchorPoint":[331.92799741186559,616.33647011725679],"cornerRadius":0,"prevPoint":[665.49504971790361,134.1591558035534],"inPoint":[331.92799741186559,616.33647011725679],"nextPoint":[665.49504971790361,134.1591558035534]}],"closed":true,"reversed":false}},"fillColor":{"b":0,"s":0,"h":0,"a":1},"strokeStyle":{"color":{"b":0.9882352941176471,"s":1,"h":0.5806878306878307,"a":1},"dashPattern":[],"join":1,"width":0.10000000149011612,"endArrow":"","startArrow":"","cap":0},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[663.24709892070291,121.99906937808692],"opacity":1,"blur":0,"isLocked":false,"gid":54,"smootheningRate":0,"initialPoint":[663.24709892070291,121.99906937808692],"creationPoints":[],"name":"(curve)"}]},"name":"(curve)"}]},"name":"(curve)"}],"isExpanded":false,"isLocked":false,"isVisible":true,"opacity":1,"gid":4,"name":"Layer 1"}],"frame":{"y":0,"x":0,"width":745,"height":744.6337699943515},"title":"Mac App icon","activeLayerIndex":0,"settings":{"gridSpacing":20,"gridAngle":45,"backgroundColor":{"b":1,"s":0,"h":0,"a":1},"gridMode":0,"isGridVisible":false},"guideLayer":{"isExpanded":false,"elements":[],"isLocked":false,"defaultName":"Guides","isVisible":true,"opacity":1,"name":"Guides","gid":5},"gid":3} \ No newline at end of file
+{"layers":[{"elements":[{"elementDescription":"(polygon)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[368.75294547403814,729.44134214300266],"reflectionModeOverride":0,"anchorPoint":[368.75294547403814,729.44134214300266],"cornerRadius":0,"prevPoint":[221.86289110820167,-279.40236718212691],"inPoint":[368.75294547403814,729.44134214300266],"nextPoint":[221.86289110820167,-279.40236718212691]},{"outPoint":[58.884741476317231,550.53885452571922],"reflectionModeOverride":0,"anchorPoint":[58.884741476317231,550.53885452571922],"cornerRadius":0,"prevPoint":[221.86289110820167,-279.40236718212691],"inPoint":[58.884741476317231,550.53885452571922],"nextPoint":[221.86289110820167,-279.40236718212691]},{"outPoint":[58.884771993693448,192.73377248033557],"reflectionModeOverride":0,"anchorPoint":[58.884771993693448,192.73377248033557],"cornerRadius":0,"prevPoint":[221.86289110820167,-279.40236718212691],"inPoint":[58.884771993693448,192.73377248033557],"nextPoint":[221.86289110820167,-279.40236718212691]},{"outPoint":[368.75296538097359,13.831330639116459],"reflectionModeOverride":0,"anchorPoint":[368.75296538097359,13.831330639116459],"cornerRadius":0,"prevPoint":[221.86289110820167,-279.40236718212691],"inPoint":[368.75296538097359,13.831330639116459],"nextPoint":[221.86289110820167,-279.40236718212691]},{"outPoint":[678.62124178681802,192.73392506721666],"reflectionModeOverride":0,"anchorPoint":[678.62124178681802,192.73392506721666],"cornerRadius":0,"prevPoint":[221.86289110820167,-279.40236718212691],"inPoint":[678.62124178681802,192.73392506721666],"nextPoint":[221.86289110820167,-279.40236718212691]},{"outPoint":[678.62118075206558,550.53885452571922],"reflectionModeOverride":0,"anchorPoint":[678.62118075206558,550.53885452571922],"cornerRadius":0,"prevPoint":[221.86289110820167,-279.40236718212691],"inPoint":[678.62118075206558,550.53885452571922],"nextPoint":[221.86289110820167,-279.40236718212691]}],"closed":true,"reversed":false}},"fillColor":{"b":0.9882352941176471,"s":1,"h":0.5806878306878307,"a":0.3074892778331435},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":1,"width":18.646402359008789,"endArrow":"","startArrow":"","cap":0},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[368.75296111419152,729.44134214300266],"opacity":1,"blur":0,"isLocked":false,"gid":57,"smootheningRate":0,"initialPoint":[368.75296111419152,371.63633639105956],"creationPoints":[],"name":"(polygon)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[61.506041898417834,134.69462453150436],"opacity":1,"blur":0,"isLocked":false,"gid":56,"smootheningRate":0,"initialPoint":[61.506041898417834,134.69462453150436],"creationPoints":[],"group":{"elements":[{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[292.87340185278117,214.25650324349817],"opacity":1,"blur":0,"isLocked":false,"gid":27,"smootheningRate":0,"initialPoint":[292.87340185278117,214.25650324349817],"creationPoints":[],"group":{"elements":[{"elementDescription":"(rectangle)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[292.87340185278117,289.25600703483042],"reflectionModeOverride":0,"anchorPoint":[292.87340185278117,289.25600703483042],"cornerRadius":0,"prevPoint":[64.939207660974262,-881.2368652940595],"inPoint":[292.87340185278117,289.25600703483042],"nextPoint":[64.939207660974262,-881.2368652940595]},{"outPoint":[442.87240655028904,289.25600703483042],"reflectionModeOverride":0,"anchorPoint":[442.87240655028904,289.25600703483042],"cornerRadius":0,"prevPoint":[64.939207660974262,-881.2368652940595],"inPoint":[442.87240655028904,289.25600703483042],"nextPoint":[64.939207660974262,-881.2368652940595]},{"outPoint":[442.87240655028904,539.25435579077384],"reflectionModeOverride":0,"anchorPoint":[442.87240655028904,539.25435579077384],"cornerRadius":0,"prevPoint":[64.939207660974262,-881.2368652940595],"inPoint":[442.87240655028904,539.25435579077384],"nextPoint":[64.939207660974262,-881.2368652940595]},{"outPoint":[292.87340185278117,539.25435579077384],"reflectionModeOverride":0,"anchorPoint":[292.87340185278117,539.25435579077384],"cornerRadius":0,"prevPoint":[64.939207660974262,-881.2368652940595],"inPoint":[292.87340185278117,539.25435579077384],"nextPoint":[64.939207660974262,-881.2368652940595]}],"closed":true,"reversed":false}},"fillColor":{"b":0.9882352941176471,"s":1,"h":0.13822251558303833,"a":1},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":1,"width":20,"endArrow":"","startArrow":"","cap":0},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[442.87240655028904,539.25435579077384],"opacity":1,"blur":0,"isLocked":false,"gid":22,"smootheningRate":0,"initialPoint":[292.87340185278117,289.25600703483042],"creationPoints":[],"name":"(rectangle)"},{"elementDescription":"(oval)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[292.87340185278117,247.83495910094825],"reflectionModeOverride":0,"anchorPoint":[292.87340185278117,289.25602785985438],"cornerRadius":0,"prevPoint":[-167.96486361526627,-465.50590420624349],"inPoint":[292.87340185278117,330.67709661876142],"nextPoint":[-167.96486361526627,-465.50590420624349]},{"outPoint":[409.29399522804465,214.25650324349817],"reflectionModeOverride":0,"anchorPoint":[367.87292646913806,214.25650324349817],"cornerRadius":0,"prevPoint":[-167.96486361526627,-465.50590420624349],"inPoint":[326.45185771023148,214.25650324349817],"nextPoint":[-167.96486361526627,-465.50590420624349]},{"outPoint":[442.87240412029564,330.67709661876142],"reflectionModeOverride":0,"anchorPoint":[442.87240412029564,289.25602785985438],"cornerRadius":0,"prevPoint":[-167.96486361526627,-465.50590420624349],"inPoint":[442.87240412029564,247.83495910094825],"nextPoint":[-167.96486361526627,-465.50590420624349]},{"outPoint":[326.45185771023148,364.25550551101242],"reflectionModeOverride":0,"anchorPoint":[367.87292646913806,364.25550551101242],"cornerRadius":0,"prevPoint":[-167.96486361526627,-465.50590420624349],"inPoint":[409.29399522804465,364.25550551101242],"nextPoint":[-167.96486361526627,-465.50590420624349]}],"closed":true,"reversed":false}},"fillColor":{"b":0.9882352941176471,"s":1,"h":0.13822251558303833,"a":1},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":1,"width":20,"endArrow":"","startArrow":"","cap":0},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[-167.96486361526627,-465.50590420624349],"opacity":1,"blur":0,"isLocked":false,"gid":24,"smootheningRate":0,"initialPoint":[-167.96486361526627,-465.50590420624349],"creationPoints":[],"name":"(oval)"},{"elementDescription":"(oval)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[292.87340185278117,497.83330507205574],"reflectionModeOverride":0,"anchorPoint":[292.87340185278117,539.25437383096278],"cornerRadius":0,"prevPoint":[-167.96486361526627,-215.50755823513555],"inPoint":[292.87340185278117,580.67544258986891],"nextPoint":[-167.96486361526627,-215.50755823513555]},{"outPoint":[409.29399522804465,464.25484921460566],"reflectionModeOverride":0,"anchorPoint":[367.87292646913806,464.25484921460566],"cornerRadius":0,"prevPoint":[-167.96486361526627,-215.50755823513555],"inPoint":[326.45185771023148,464.25484921460566],"nextPoint":[-167.96486361526627,-215.50755823513555]},{"outPoint":[442.87240412029564,580.67544258986891],"reflectionModeOverride":0,"anchorPoint":[442.87240412029564,539.25437383096278],"cornerRadius":0,"prevPoint":[-167.96486361526627,-215.50755823513555],"inPoint":[442.87240412029564,497.83330507205574],"nextPoint":[-167.96486361526627,-215.50755823513555]},{"outPoint":[326.45185771023148,614.2538514821199],"reflectionModeOverride":0,"anchorPoint":[367.87292646913806,614.2538514821199],"cornerRadius":0,"prevPoint":[-167.96486361526627,-215.50755823513555],"inPoint":[409.29399522804465,614.2538514821199],"nextPoint":[-167.96486361526627,-215.50755823513555]}],"closed":true,"reversed":false}},"fillColor":{"b":0.9882352941176471,"s":1,"h":0.13822251558303833,"a":1},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":1,"width":20,"endArrow":"","startArrow":"","cap":0},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[-167.96486361526627,-215.50755823513555],"opacity":1,"blur":0,"isLocked":false,"gid":25,"smootheningRate":0,"initialPoint":[-167.96486361526627,-215.50755823513555],"creationPoints":[],"name":"(oval)"},{"elementDescription":"(rectangle)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[302.87333569162547,289.07321462503751],"reflectionModeOverride":0,"anchorPoint":[302.87333569162547,289.07321462503751],"cornerRadius":0,"prevPoint":[105.33036558060121,-881.41965770385173],"inPoint":[302.87333569162547,289.07321462503751],"nextPoint":[105.33036558060121,-881.41965770385173]},{"outPoint":[432.87247428821752,289.07321462503751],"reflectionModeOverride":0,"anchorPoint":[432.87247428821752,289.07321462503751],"cornerRadius":0,"prevPoint":[105.33036558060121,-881.41965770385173],"inPoint":[432.87247428821752,289.07321462503751],"nextPoint":[105.33036558060121,-881.41965770385173]},{"outPoint":[432.87247428821752,539.07156338098093],"reflectionModeOverride":0,"anchorPoint":[432.87247428821752,539.07156338098093],"cornerRadius":0,"prevPoint":[105.33036558060121,-881.41965770385173],"inPoint":[432.87247428821752,539.07156338098093],"nextPoint":[105.33036558060121,-881.41965770385173]},{"outPoint":[302.87333569162547,539.07156338098093],"reflectionModeOverride":0,"anchorPoint":[302.87333569162547,539.07156338098093],"cornerRadius":0,"prevPoint":[105.33036558060121,-881.41965770385173],"inPoint":[302.87333569162547,539.07156338098093],"nextPoint":[105.33036558060121,-881.41965770385173]}],"closed":true,"reversed":false}},"fillColor":{"b":0.9882352941176471,"s":1,"h":0.13822251558303833,"a":1},"strokeStyle":{"color":{"b":0.9882352941176471,"s":1,"h":0.5806878306878307,"a":1},"dashPattern":[],"join":1,"width":0.10000000149011612,"endArrow":"","startArrow":"","cap":0},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[432.87247428821752,539.07156338098093],"opacity":1,"blur":0,"isLocked":false,"gid":26,"smootheningRate":0,"initialPoint":[302.87333569162547,289.07321462503751],"creationPoints":[],"name":"(rectangle)"}]},"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[103.16114089391976,309.16721333385931],"reflectionModeOverride":0,"anchorPoint":[103.16114089391976,309.16721333385931],"cornerRadius":0,"prevPoint":[84.093506586570356,146.69454513811797],"inPoint":[103.16114089391976,309.16721333385931],"nextPoint":[84.093506586570356,146.69454513811797]},{"outPoint":[226.95560052710721,443.90288627635027],"reflectionModeOverride":0,"anchorPoint":[226.95560052710721,443.90288627635027],"cornerRadius":0,"prevPoint":[84.093506586570356,146.69454513811797],"inPoint":[226.95560052710721,443.90288627635027],"nextPoint":[84.093506586570356,146.69454513811797]},{"outPoint":[366.67124423505425,309.6035637643763],"reflectionModeOverride":0,"anchorPoint":[366.67124423505425,309.6035637643763],"cornerRadius":0,"prevPoint":[84.093506586570356,146.69454513811797],"inPoint":[366.67124423505425,309.6035637643763],"nextPoint":[84.093506586570356,146.69454513811797]}],"closed":true,"reversed":false}},"fillColor":{"b":0.9882352941176471,"s":1,"h":0.5806878306878307,"a":1},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":1,"width":0.10000000149011612,"endArrow":"","startArrow":"","cap":1},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[84.093506586570356,146.69454513811797],"opacity":1,"blur":0,"isLocked":false,"gid":29,"smootheningRate":0,"initialPoint":[84.093506586570356,146.69454513811797],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[383.41128768868771,307.07623767819223],"reflectionModeOverride":0,"anchorPoint":[383.41128768868771,307.07623767819223],"cornerRadius":0,"prevPoint":[364.08468148613224,146.65290478922907],"inPoint":[383.41128768868771,307.07623767819223],"nextPoint":[364.08468148613224,146.65290478922907]},{"outPoint":[508.88709306778787,440.11243356580462],"reflectionModeOverride":0,"anchorPoint":[508.88709306778787,440.11243356580462],"cornerRadius":0,"prevPoint":[364.08468148613224,146.65290478922907],"inPoint":[508.88709306778787,440.11243356580462],"nextPoint":[364.08468148613224,146.65290478922907]},{"outPoint":[650.50032010766949,307.50708423933065],"reflectionModeOverride":0,"anchorPoint":[650.50032010766949,307.50708423933065],"cornerRadius":0,"prevPoint":[364.08468148613224,146.65290478922907],"inPoint":[650.50032010766949,307.50708423933065],"nextPoint":[364.08468148613224,146.65290478922907]}],"closed":true,"reversed":false}},"fillColor":{"b":0.9882352941176471,"s":1,"h":0.5806878306878307,"a":1},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":1,"width":0.10000000149011612,"endArrow":"","startArrow":"","cap":1},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[364.08468148613224,146.65290478922907],"opacity":1,"blur":0,"isLocked":false,"gid":30,"smootheningRate":0,"initialPoint":[364.08468148613224,146.65290478922907],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[522.04458359486512,154.80813254227905],"reflectionModeOverride":0,"anchorPoint":[522.04458359486512,154.80813254227905],"cornerRadius":0,"prevPoint":[1039.3203857761648,-115.61701281386331],"inPoint":[522.04458359486512,154.80813254227905],"nextPoint":[1039.3203857761648,-115.61701281386331]},{"outPoint":[229.5593561025587,448.88181029919406],"reflectionModeOverride":0,"anchorPoint":[229.5593561025587,448.88181029919406],"cornerRadius":0,"prevPoint":[1039.3203857761648,-115.61701281386331],"inPoint":[229.5593561025587,448.88181029919406],"nextPoint":[1039.3203857761648,-115.61701281386331]},{"outPoint":[83.839739125688993,300.1041732651538],"reflectionModeOverride":0,"anchorPoint":[83.839739125688993,300.1041732651538],"cornerRadius":0,"prevPoint":[1039.3203857761648,-115.61701281386331],"inPoint":[83.839739125688993,300.1041732651538],"nextPoint":[1039.3203857761648,-115.61701281386331]},{"outPoint":[653.66624413744626,302.9355554780409],"reflectionModeOverride":0,"anchorPoint":[653.66624413744626,302.9355554780409],"cornerRadius":0,"prevPoint":[1039.3203857761648,-115.61701281386331],"inPoint":[653.66624413744626,302.9355554780409],"nextPoint":[1039.3203857761648,-115.61701281386331]},{"outPoint":[511.75868688143851,444.7847840681311],"reflectionModeOverride":0,"anchorPoint":[511.75868688143851,444.7847840681311],"cornerRadius":0,"prevPoint":[1039.3203857761648,-115.61701281386331],"inPoint":[511.75868688143851,444.7847840681311],"nextPoint":[1039.3203857761648,-115.61701281386331]},{"outPoint":[223.10077860149863,156.11368443580113],"reflectionModeOverride":0,"anchorPoint":[223.10077860149863,156.11368443580113],"cornerRadius":0,"prevPoint":[1039.3203857761648,-115.61701281386331],"inPoint":[223.10077860149863,156.11368443580113],"nextPoint":[1039.3203857761648,-115.61701281386331]}],"closed":false,"reversed":false}},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":1,"width":20,"endArrow":"","startArrow":"","cap":1},"maskedElements":[]},"angle":90,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[1200.0148931967549,-113.13323396127316],"opacity":1,"blur":0,"isLocked":false,"gid":21,"smootheningRate":0,"initialPoint":[1200.0148931967549,-113.13323396127316],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(line)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[295.85728153799414,418.73751961026619],"reflectionModeOverride":0,"anchorPoint":[295.85728153799414,418.73751961026619],"cornerRadius":0,"prevPoint":[84.093506586570356,146.69454513811797],"inPoint":[295.85728153799414,418.73751961026619],"nextPoint":[84.093506586570356,146.69454513811797]},{"outPoint":[438.89979217720088,418.73751961026619],"reflectionModeOverride":0,"anchorPoint":[438.89979217720088,418.73751961026619],"cornerRadius":0,"prevPoint":[84.093506586570356,146.69454513811797],"inPoint":[438.89979217720088,418.73751961026619],"nextPoint":[84.093506586570356,146.69454513811797]}],"closed":false,"reversed":false}},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":1,"width":61.869819641113281,"endArrow":"","startArrow":"","cap":0},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[84.093506586570356,146.69454513811797],"opacity":1,"blur":0,"isLocked":false,"gid":31,"smootheningRate":0,"initialPoint":[84.093506586570356,146.69454513811797],"creationPoints":[],"name":"(line)"},{"elementDescription":"(line)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[295.85728153799414,521.73683815036247],"reflectionModeOverride":0,"anchorPoint":[295.85728153799414,521.73683815036247],"cornerRadius":0,"prevPoint":[84.093506586570356,249.69386367821471],"inPoint":[295.85728153799414,521.73683815036247],"nextPoint":[84.093506586570356,249.69386367821471]},{"outPoint":[438.89979217720088,521.73683815036247],"reflectionModeOverride":0,"anchorPoint":[438.89979217720088,521.73683815036247],"cornerRadius":0,"prevPoint":[84.093506586570356,249.69386367821471],"inPoint":[438.89979217720088,521.73683815036247],"nextPoint":[84.093506586570356,249.69386367821471]}],"closed":false,"reversed":false}},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":1,"width":61.869819641113281,"endArrow":"","startArrow":"","cap":0},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[84.093506586570356,249.69386367821471],"opacity":1,"blur":0,"isLocked":false,"gid":32,"smootheningRate":0,"initialPoint":[84.093506586570356,249.69386367821471],"creationPoints":[],"name":"(line)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[70.109671854888575,134.69462453150436],"opacity":1,"blur":0,"isLocked":false,"gid":55,"smootheningRate":0,"initialPoint":[70.109671854888575,134.69462453150436],"creationPoints":[],"group":{"elements":[{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[367.7690644381571,667.02363476289884],"reflectionModeOverride":0,"anchorPoint":[367.7690644381571,667.02363476289884],"cornerRadius":0,"prevPoint":[72.193980608055426,108.16792868331186],"inPoint":[368.26333755475412,638.68961321030247],"nextPoint":[72.193980608055426,108.16792868331186]},{"outPoint":[367.82059343747073,616.38299074283532],"reflectionModeOverride":0,"anchorPoint":[367.82059343747073,616.38299074283532],"cornerRadius":0,"prevPoint":[55.02340366515682,81.837967291336099],"inPoint":[367.82059343747073,616.38299074283532],"nextPoint":[55.02340366515682,81.837967291336099]},{"outPoint":[383.13716259159514,626.44746079947163],"reflectionModeOverride":0,"anchorPoint":[403.6767241609266,616.33647011725679],"cornerRadius":0,"prevPoint":[70.109671854888575,134.1591558035534],"inPoint":[403.6767241609266,616.33647011725679],"nextPoint":[70.109671854888575,134.1591558035534]}],"closed":true,"reversed":false}},"fillColor":{"b":0,"s":0,"h":0,"a":1},"strokeStyle":{"color":{"b":0.9882352941176471,"s":1,"h":0.5806878306878307,"a":1},"dashPattern":[],"join":1,"width":0.10000000149011612,"endArrow":"","startArrow":"","cap":0},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[72.357622652088821,121.79167358010636],"opacity":1,"blur":0,"isLocked":false,"gid":48,"smootheningRate":0,"initialPoint":[72.357622652088821,121.79167358010636],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[367.83565713463508,667.02363476289884],"reflectionModeOverride":0,"anchorPoint":[367.83565713463508,667.02363476289884],"cornerRadius":0,"prevPoint":[663.41074096473653,108.16792868331186],"inPoint":[367.34138401803807,638.68961321030247],"nextPoint":[663.41074096473653,108.16792868331186]},{"outPoint":[367.78412813532145,616.38299074283532],"reflectionModeOverride":0,"anchorPoint":[367.78412813532145,616.38299074283532],"cornerRadius":0,"prevPoint":[680.58131790763514,81.837967291336099],"inPoint":[367.78412813532145,616.38299074283532],"nextPoint":[680.58131790763514,81.837967291336099]},{"outPoint":[352.46755898119659,626.44746079947163],"reflectionModeOverride":0,"anchorPoint":[331.92799741186559,616.33647011725679],"cornerRadius":0,"prevPoint":[665.49504971790361,134.1591558035534],"inPoint":[331.92799741186559,616.33647011725679],"nextPoint":[665.49504971790361,134.1591558035534]}],"closed":true,"reversed":false}},"fillColor":{"b":0,"s":0,"h":0,"a":1},"strokeStyle":{"color":{"b":0.9882352941176471,"s":1,"h":0.5806878306878307,"a":1},"dashPattern":[],"join":1,"width":0.10000000149011612,"endArrow":"","startArrow":"","cap":0},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[663.24709892070291,121.99906937808692],"opacity":1,"blur":0,"isLocked":false,"gid":54,"smootheningRate":0,"initialPoint":[663.24709892070291,121.99906937808692],"creationPoints":[],"name":"(curve)"}]},"name":"(curve)"}]},"name":"(curve)"}],"isExpanded":false,"isLocked":false,"isVisible":true,"opacity":1,"gid":4,"name":"Layer 1"}],"frame":{"y":0,"x":0,"width":745,"height":744.6337699943515},"title":"Mac App icon","activeLayerIndex":0,"settings":{"gridSpacing":20,"gridAngle":45,"backgroundColor":{"b":1,"s":0,"h":0,"a":1},"gridMode":0,"isGridVisible":false},"guideLayer":{"isExpanded":false,"elements":[],"isLocked":false,"defaultName":"Guides","isVisible":true,"opacity":1,"name":"Guides","gid":5},"gid":3}
diff --git a/docs/images/logo_framed.vectornator/Document.json b/docs/images/logo_framed.vectornator/Document.json
index 974df2c..a2f614f 100644
--- a/docs/images/logo_framed.vectornator/Document.json
+++ b/docs/images/logo_framed.vectornator/Document.json
@@ -1 +1 @@
-{"date":644900741.09290397,"appVersion":"4.1.5","drawing":{"modificationDate":644894800.328192,"activeArtboardIndex":0,"settings":{"outlineMode":false,"isolateActiveLayer":false,"snapToEdges":false,"snapToPoints":false,"guidesVisible":true,"snapToGrid":false,"units":"Pixels","dimensionsVisible":true,"dynamicGuides":false,"isCMYKColorPreviewEnabled":false,"undoHistoryDisabled":false,"snapToGuides":true,"drawOnlyUsingPencil":false,"whiteBackground":false,"rulersVisible":true,"isTimeLapseWatermarkDisabled":false},"artboardPaths":["Artboard0.json"],"documentVersion":"unknown"}} \ No newline at end of file
+{"date":644900741.09290397,"appVersion":"4.1.5","drawing":{"modificationDate":644894800.328192,"activeArtboardIndex":0,"settings":{"outlineMode":false,"isolateActiveLayer":false,"snapToEdges":false,"snapToPoints":false,"guidesVisible":true,"snapToGrid":false,"units":"Pixels","dimensionsVisible":true,"dynamicGuides":false,"isCMYKColorPreviewEnabled":false,"undoHistoryDisabled":false,"snapToGuides":true,"drawOnlyUsingPencil":false,"whiteBackground":false,"rulersVisible":true,"isTimeLapseWatermarkDisabled":false},"artboardPaths":["Artboard0.json"],"documentVersion":"unknown"}}
diff --git a/docs/images/logo_framed.vectornator/Manifest.json b/docs/images/logo_framed.vectornator/Manifest.json
index 0f80b78..8e897a0 100644
--- a/docs/images/logo_framed.vectornator/Manifest.json
+++ b/docs/images/logo_framed.vectornator/Manifest.json
@@ -1 +1 @@
-{"documentJSONFilename":"Document.json","undoHistoryJSONFilename":"UndoHistory.json","fileFormatVersion":0,"thumbnailImageFilename":"Thumbnail.png"} \ No newline at end of file
+{"documentJSONFilename":"Document.json","undoHistoryJSONFilename":"UndoHistory.json","fileFormatVersion":0,"thumbnailImageFilename":"Thumbnail.png"}
diff --git a/docs/images/logo_framed.vectornator/UndoHistory.json b/docs/images/logo_framed.vectornator/UndoHistory.json
index 0238dd1..b0f4385 100644
--- a/docs/images/logo_framed.vectornator/UndoHistory.json
+++ b/docs/images/logo_framed.vectornator/UndoHistory.json
@@ -1 +1 @@
-{"cacheElements":[{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"fillColor":{"b":0.98823529481887817,"s":1,"h":0.58068782582120682,"a":1},"maskedElements":[],"abstractPath":{"fillRule":0,"compoundPathData":{"subpaths":[{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[-17.790763092914176,455.94130474918654],"reflectionModeOverride":0,"anchorPoint":[-17.790763092914176,455.94130474918654],"cornerRadius":0,"prevPoint":[-343.22817622315347,103.6410041510419],"inPoint":[-17.790763092914176,455.94130474918654],"nextPoint":[-343.22817622315347,103.6410041510419]},{"outPoint":[-118.14742861878335,355.38893101990755],"reflectionModeOverride":0,"anchorPoint":[-118.14742861878335,355.38893101990755],"cornerRadius":0,"prevPoint":[-343.22817622315347,103.6410041510419],"inPoint":[-118.14742861878335,355.38893101990755],"nextPoint":[-343.22817622315347,103.6410041510419]},{"outPoint":[-89.082653539453304,326.03057263672883],"reflectionModeOverride":0,"anchorPoint":[-89.082653539453304,326.03057263672883],"cornerRadius":0,"prevPoint":[-343.22817622315347,103.6410041510419],"inPoint":[-89.082653539453304,326.03057263672883],"nextPoint":[-343.22817622315347,103.6410041510419]},{"outPoint":[-9.0811227455444623,406.22781863362536],"reflectionModeOverride":0,"anchorPoint":[-9.0811227455444623,406.22781863362536],"cornerRadius":0,"prevPoint":[-343.22817622315347,103.6410041510419],"inPoint":[-9.0811227455444623,406.22781863362536],"nextPoint":[-343.22817622315347,103.6410041510419]},{"outPoint":[-9.0811227455444623,214.66453204993843],"reflectionModeOverride":0,"anchorPoint":[-9.0811227455444623,214.66453204993843],"cornerRadius":0,"prevPoint":[-343.22817622315347,103.6410041510419],"inPoint":[-9.0811227455444623,214.66453204993843],"nextPoint":[-343.22817622315347,103.6410041510419]},{"outPoint":[136.29167736876548,359.98840044701058],"reflectionModeOverride":0,"anchorPoint":[136.29167736876548,359.98840044701058],"cornerRadius":0,"prevPoint":[-343.22817622315347,103.6410041510419],"inPoint":[136.29167736876548,359.98840044701058],"nextPoint":[-343.22817622315347,103.6410041510419]},{"outPoint":[40.289832016581158,455.94130474918654],"reflectionModeOverride":0,"anchorPoint":[40.289832016581158,455.94130474918654],"cornerRadius":0,"prevPoint":[-343.22817622315347,103.6410041510419],"inPoint":[40.289832016581158,455.94130474918654],"nextPoint":[-343.22817622315347,103.6410041510419]},{"outPoint":[136.29167736876548,551.89420905136228],"reflectionModeOverride":0,"anchorPoint":[136.29167736876548,551.89420905136228],"cornerRadius":0,"prevPoint":[-343.22817622315347,103.6410041510419],"inPoint":[136.29167736876548,551.89420905136228],"nextPoint":[-343.22817622315347,103.6410041510419]},{"outPoint":[-9.0322003610774573,697.21808678120522],"reflectionModeOverride":0,"anchorPoint":[-9.0322003610774573,697.21808678120522],"cornerRadius":0,"prevPoint":[-343.22817622315347,103.6410041510419],"inPoint":[-9.0322003610774573,697.21808678120522],"nextPoint":[-343.22817622315347,103.6410041510419]},{"outPoint":[-9.0322003610774573,505.65480953028907],"reflectionModeOverride":0,"anchorPoint":[-9.0322003610774573,505.65480953028907],"cornerRadius":0,"prevPoint":[-343.22817622315347,103.6410041510419],"inPoint":[-9.0322003610774573,505.65480953028907],"nextPoint":[-343.22817622315347,103.6410041510419]},{"outPoint":[-88.78907023560464,585.60738760822585],"reflectionModeOverride":0,"anchorPoint":[-88.78907023560464,585.60738760822585],"cornerRadius":0,"prevPoint":[-343.22817622315347,103.6410041510419],"inPoint":[-88.78907023560464,585.60738760822585],"nextPoint":[-343.22817622315347,103.6410041510419]},{"outPoint":[-117.85384531493469,556.24902922504714],"reflectionModeOverride":0,"anchorPoint":[-117.85384531493469,556.24902922504714],"cornerRadius":0,"prevPoint":[-343.22817622315347,103.6410041510419],"inPoint":[-117.85384531493469,556.24902922504714],"nextPoint":[-343.22817622315347,103.6410041510419]}],"closed":true,"reversed":false}},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[-343.22817622315347,103.6410041510419],"opacity":1,"blur":0,"isLocked":false,"gid":13,"smootheningRate":0,"initialPoint":[-343.22817622315347,103.6410041510419],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[-87.50742636811205,292.97453151588081],"reflectionModeOverride":0,"anchorPoint":[-87.50742636811205,292.97453151588081],"cornerRadius":0,"prevPoint":[-164.14742861878338,191.97453151588081],"inPoint":[-87.50742636811205,292.97453151588081],"nextPoint":[-164.14742861878338,191.97453151588081]},{"outPoint":[-78.027426825875665,283.48453174476265],"reflectionModeOverride":0,"anchorPoint":[-78.027426825875665,283.48453174476265],"cornerRadius":0,"prevPoint":[-164.14742861878338,191.97453151588081],"inPoint":[-78.027426825875665,283.48453174476265],"nextPoint":[-164.14742861878338,191.97453151588081]},{"outPoint":[-87.507426368111936,274.01453147773384],"reflectionModeOverride":0,"anchorPoint":[-87.507426368111936,274.01453147773384],"cornerRadius":0,"prevPoint":[-164.14742861878338,191.97453151588081],"inPoint":[-87.507426368111936,274.01453147773384],"nextPoint":[-164.14742861878338,191.97453151588081]}],"closed":true,"reversed":false}},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[-164.14742861878338,191.97453151588081],"opacity":1,"blur":0,"isLocked":false,"gid":14,"smootheningRate":0,"initialPoint":[-164.14742861878338,191.97453151588081],"creationPoints":[],"name":"(curve)"}]}}},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[-164.14742861878338,191.97453151588078],"opacity":1,"blur":0,"isLocked":false,"gid":11,"smootheningRate":0,"initialPoint":[-164.14742861878338,191.97453151588078],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[340,700],"reflectionModeOverride":0,"anchorPoint":[340,660],"cornerRadius":0,"prevPoint":[0,0],"inPoint":[340,620],"nextPoint":[0,0]},{"outPoint":[340,600],"reflectionModeOverride":0,"anchorPoint":[380,600],"cornerRadius":0,"prevPoint":[0,0],"inPoint":[420,600],"nextPoint":[0,0]}],"closed":false,"reversed":false}},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":2,"width":0.10000000149011612,"endArrow":"","startArrow":"","cap":1},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[0,0],"opacity":1,"blur":0,"isLocked":false,"gid":35,"smootheningRate":0,"initialPoint":[0,0],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"fillColor":{"b":0.98823529481887817,"s":1,"h":0.58068782582120682,"a":1},"maskedElements":[],"abstractPath":{"fillRule":0,"compoundPathData":{"subpaths":[{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[221.67257107604084,316.56452785377144],"reflectionModeOverride":0,"anchorPoint":[221.67257107604084,316.56452785377144],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[221.67257107604084,316.56452785377144],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[222.78002147975192,316.58196755365179],"reflectionModeOverride":0,"anchorPoint":[222.50257105935154,316.56452785377144],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[222.50257105935154,316.56452785377144],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[223.46754319256974,316.15798118973765],"reflectionModeOverride":0,"anchorPoint":[223.27257099819641,316.3245278149393],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[223.05416436926282,316.49652037792839],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[223.56257095468965,315.05452779244973],"reflectionModeOverride":0,"anchorPoint":[223.56257095468965,315.65452781629159],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[223.57458948209043,315.9106673969701],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[222.50257101191011,314.72452780913903],"reflectionModeOverride":0,"anchorPoint":[222.50257101191011,314.72452780913903],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[223.18257095945802,314.72452780913903],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[221.67257102859941,314.72452780913903],"reflectionModeOverride":0,"anchorPoint":[221.67257102859941,314.72452780913903],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[221.67257102859941,314.72452780913903],"nextPoint":[112.85257138121662,191.97453151588078]}],"closed":true,"reversed":false}},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[112.85257138121662,191.97453151588078],"opacity":1,"blur":0,"isLocked":false,"gid":7,"smootheningRate":0,"initialPoint":[112.85257138121662,191.97453151588078],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[223.39257110465107,318.92452774886726],"reflectionModeOverride":0,"anchorPoint":[223.39257110465107,318.92452774886726],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[223.39257110465107,318.92452774886726],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[222.33257116187153,317.04452775363563],"reflectionModeOverride":0,"anchorPoint":[222.33257116187153,317.04452775363563],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[222.33257116187153,317.04452775363563],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[221.67257113564548,317.04452775363563],"reflectionModeOverride":0,"anchorPoint":[221.67257113564548,317.04452775363563],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[221.67257113564548,317.04452775363563],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[221.67257113564548,318.97453151588081],"reflectionModeOverride":0,"anchorPoint":[221.67257113564548,318.97453151588081],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[221.67257113564548,318.97453151588081],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[221.06257112134037,318.97453151588081],"reflectionModeOverride":0,"anchorPoint":[221.06257112134037,318.97453151588081],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[221.06257112134037,318.97453151588081],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[221.06257112134037,314.29453168754219],"reflectionModeOverride":0,"anchorPoint":[221.06257112134037,314.29453168754219],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[221.06257112134037,314.29453168754219],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[222.85351610118363,314.2910670771638],"reflectionModeOverride":0,"anchorPoint":[222.64257116425571,314.29453168754219],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[222.64257116425571,314.29453168754219],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[223.44257068590508,314.46434348341825],"reflectionModeOverride":0,"anchorPoint":[223.26257121864279,314.39453162176318],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[223.06341253016012,314.32492145971571],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[223.8867055322342,314.82297152263595],"reflectionModeOverride":0,"anchorPoint":[223.75257125112995,314.69453165532451],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[223.60854628757448,314.56596123813961],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[224.15455094852729,315.31612333025106],"reflectionModeOverride":0,"anchorPoint":[224.07257117822328,315.14453165999419],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[223.99528738469252,314.97566482247669],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[224.19825083117667,315.9922372888982],"reflectionModeOverride":0,"anchorPoint":[224.19257122020886,315.69453168706491],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[224.19562660185056,315.50438689028209],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[223.7338072115908,316.75555373263109],"reflectionModeOverride":0,"anchorPoint":[223.91257119347284,316.51453168318102],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[224.09914577717603,316.28247388344346],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[223.19257120773227,317.01453168185151],"reflectionModeOverride":0,"anchorPoint":[223.19257120773227,317.01453168185151],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[223.48085346525613,316.9312160768892],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[222.99257120475204,317.08453168214953],"reflectionModeOverride":0,"anchorPoint":[222.99257120475204,317.08453168214953],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[222.99257120475204,317.08453168214953],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[224.0925712285939,318.97453166784442],"reflectionModeOverride":0,"anchorPoint":[224.0925712285939,318.97453166784442],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[224.0925712285939,318.97453166784442],"nextPoint":[112.85257138121662,191.97453151588078]}],"closed":true,"reversed":false}},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[112.85257138121662,191.97453151588078],"opacity":1,"blur":0,"isLocked":false,"gid":8,"smootheningRate":0,"initialPoint":[112.85257138121662,191.97453151588078],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[221.88165496610824,312.75214941635204],"reflectionModeOverride":0,"anchorPoint":[222.39257110465107,312.75452767257332],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[222.39257110465107,312.75452767257332],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[220.45378029794426,313.23854645592189],"reflectionModeOverride":0,"anchorPoint":[220.90257124445034,313.04452773196982],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[221.37529974656684,312.85070177480884],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[219.35876943156495,314.2208600575953],"reflectionModeOverride":0,"anchorPoint":[219.70257152159786,313.86452769906913],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[220.04640821090715,313.51691728007791],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[218.51848057480817,316.05954140545026],"reflectionModeOverride":0,"anchorPoint":[218.89257170245423,315.09452765536599],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[219.0841152815558,314.63792794299417],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[219.07885049250976,318.55391401613247],"reflectionModeOverride":0,"anchorPoint":[218.89257166857527,318.09452771720584],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[218.51848023468915,317.12951359608263],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[220.04640881460426,319.67213836278347],"reflectionModeOverride":0,"anchorPoint":[219.70257171508007,319.32452783266035],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[219.35412998721458,318.97193143333453],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[222.32887552639454,320.75534631866788],"reflectionModeOverride":0,"anchorPoint":[220.90257185775954,320.14452762388811],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[220.45378073087409,319.9505090873252],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[225.42747093525361,318.97720769048311],"reflectionModeOverride":0,"anchorPoint":[225.07257197531021,319.32452740981233],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[223.98375014972524,320.42992729161517],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[226.25666363710593,317.12951355179308],"reflectionModeOverride":0,"anchorPoint":[225.8825720147413,318.09452742555698],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[225.70369149262439,318.55776181404121],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[225.69870344883279,314.63387871118448],"reflectionModeOverride":0,"anchorPoint":[225.88257204862026,315.09452736371713],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[226.25666342066654,316.05954129932087],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[224.73054756988128,313.51475021332715],"reflectionModeOverride":0,"anchorPoint":[225.07257201185996,313.86452742080394],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[225.42312528062655,314.21540813724465],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[223.40302999066401,312.851739523118],"reflectionModeOverride":0,"anchorPoint":[223.87257194075443,313.04452740721484],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[224.32272320141846,313.23607014436448],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[222.39257194847221,312.754527354262],"reflectionModeOverride":0,"anchorPoint":[222.39257194847221,312.754527354262],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[222.90014945704277,312.7532021443493],"nextPoint":[112.85257138121662,191.97453151588078]}],"closed":false,"reversed":false}},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[112.85257138121662,191.97453151588078],"opacity":1,"blur":0,"isLocked":false,"gid":9,"smootheningRate":0,"initialPoint":[112.85257138121662,191.97453151588078],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[221.79793545229796,321.06845412941806],"reflectionModeOverride":0,"anchorPoint":[222.39257194847221,321.06452777387869],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[222.39257194847221,321.06452777387869],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[220.13630955687603,320.47368746402753],"reflectionModeOverride":0,"anchorPoint":[220.66257205810552,320.71452796827054],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[221.20891937561655,320.94928924957026],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[218.84008207185138,319.31458146286332],"reflectionModeOverride":0,"anchorPoint":[219.26257159607349,319.71452784560978],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[219.66107353858615,320.13423302542299],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[217.79637500761001,317.20177600727493],"reflectionModeOverride":0,"anchorPoint":[218.26257166453621,318.30452834140976],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[218.50031051375157,318.83550383670706],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[218.71657507260346,313.79480682341318],"reflectionModeOverride":0,"anchorPoint":[218.26257150938892,314.85452883246262],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[217.79637484257967,315.95728089190948],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[221.15964890699888,312.25319776201661],"reflectionModeOverride":0,"anchorPoint":[220.61257125382446,312.48452913388269],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[219.5567350056233,312.94749659064405],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[222.93948006388655,312.14028017121217],"reflectionModeOverride":0,"anchorPoint":[222.34257146546875,312.14452894709979],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[221.74863705025209,312.1374427227563],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[224.61118094730551,312.72639164873863],"reflectionModeOverride":0,"anchorPoint":[224.08257153232208,312.48452915920495],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[223.53116831317226,312.25589748063879],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[225.90916737355408,313.88955714821628],"reflectionModeOverride":0,"anchorPoint":[225.49257153005306,313.48452928232075],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[225.08951592668194,313.06563634089633],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[226.95876793869749,315.99728178436908],"reflectionModeOverride":0,"anchorPoint":[226.49257128177129,314.89452945023424],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[226.24808810980261,314.36743571685838],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[226.25070868333646,318.87313890226199],"reflectionModeOverride":0,"anchorPoint":[226.49257117287002,318.34452948727852],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[226.95876813673391,317.24177716378313],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[224.65955409863321,320.59420064219239],"reflectionModeOverride":0,"anchorPoint":[225.49257104975428,319.75452948500953],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[225.91146402567489,319.35147381264608],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[222.34257072457945,321.06452950412722],"reflectionModeOverride":0,"anchorPoint":[222.34257072457945,321.06452950412722],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[223.52534831488276,321.06588609892162],"nextPoint":[112.85257138121662,191.97453151588078]}],"closed":false,"reversed":false}},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[112.85257138121662,191.97453151588078],"opacity":1,"blur":0,"isLocked":false,"gid":10,"smootheningRate":0,"initialPoint":[112.85257138121662,191.97453151588078],"creationPoints":[],"name":"(curve)"}]}}},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[112.85257138121662,191.97453151588078],"opacity":1,"blur":0,"isLocked":false,"gid":6,"smootheningRate":0,"initialPoint":[112.85257138121662,191.97453151588078],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[292.2196979967656,487.32457590003901],"reflectionModeOverride":0,"anchorPoint":[270.70254252087443,481.42866614307741],"cornerRadius":0,"prevPoint":[0,1.3634276556741725],"inPoint":[246.45876716860445,474.78563603599895],"nextPoint":[0,1.3634276556741725]},{"outPoint":[308.32019835237998,560.47255779544446],"reflectionModeOverride":0,"anchorPoint":[307.80961189523731,532.13830093176216],"cornerRadius":0,"prevPoint":[9.9345758586960642,16.47175369678871],"inPoint":[307.29902543809465,503.80404406807986],"nextPoint":[9.9345758586960642,16.47175369678871]}],"closed":false,"reversed":false}},"fillColor":{"b":0.9882352941176471,"s":1,"h":0.13822251558303833,"a":1},"strokeStyle":{"color":{"b":0.9882352941176471,"s":1,"h":0.5806878306878307,"a":1},"dashPattern":[],"join":1,"width":0.10000000149011612,"endArrow":"","startArrow":"","cap":0},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[9.9345758586960642,15.108326041114537],"opacity":1,"blur":0,"isLocked":false,"gid":44,"smootheningRate":0,"initialPoint":[9.9345758586960642,15.108326041114537],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[345.33038784778722,480.48121812716067],"reflectionModeOverride":0,"anchorPoint":[345.33038784778722,480.48121812716067],"cornerRadius":0,"prevPoint":[86.563617484933189,-170.37985441312253],"inPoint":[308.36370636737951,480.48121812716067],"nextPoint":[86.563617484933189,-170.37985441312253]},{"outPoint":[271.39702488697174,480.48121812716067],"reflectionModeOverride":0,"anchorPoint":[271.39702488697174,480.48121812716067],"cornerRadius":0,"prevPoint":[86.563617484933189,-170.37985441312253],"inPoint":[271.39702488697174,480.48121812716067],"nextPoint":[86.563617484933189,-170.37985441312253]},{"outPoint":[345.33038784778722,480.48121812716067],"reflectionModeOverride":0,"anchorPoint":[345.33038784778722,480.48121812716067],"cornerRadius":0,"prevPoint":[86.563617484933189,-170.37985441312253],"inPoint":[345.33038784778722,480.48121812716067],"nextPoint":[86.563617484933189,-170.37985441312253]},{"outPoint":[308.36370636737951,480.48121812716067],"reflectionModeOverride":0,"anchorPoint":[271.39702488697174,480.48121812716067],"cornerRadius":0,"prevPoint":[86.563617484933189,-170.37985441312253],"inPoint":[271.39702488697174,480.48121812716067],"nextPoint":[86.563617484933189,-170.37985441312253]},{"outPoint":[308.36370636737951,547.81167390718997],"reflectionModeOverride":0,"anchorPoint":[308.36370636737951,547.81167390718997],"cornerRadius":0,"prevPoint":[86.563617484933189,-170.37985441312253],"inPoint":[308.36370636737951,547.81167390718997],"nextPoint":[86.563617484933189,-170.37985441312253]}],"closed":true,"reversed":true}},"fillColor":{"b":0,"s":0,"h":0,"a":1},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":2,"width":0.10000000149011612,"endArrow":"","startArrow":"","cap":1},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[579.21777967228218,-165.50118646031109],"opacity":1,"blur":0,"isLocked":false,"gid":37,"smootheningRate":0,"initialPoint":[579.21777967228218,-165.50118646031109],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[307.98765662154068,497.22766759942954],"reflectionModeOverride":0,"anchorPoint":[307.98765662154068,526.40806463936553],"cornerRadius":0,"prevPoint":[0,0],"inPoint":[307.98765662154068,555.58846167930153],"nextPoint":[0,0]},{"outPoint":[347.07124677007465,468.5633046399771],"reflectionModeOverride":0,"anchorPoint":[331.56894097295356,478.9361833057668],"cornerRadius":0,"prevPoint":[0,0],"inPoint":[316.06663517583246,489.3090619715565],"nextPoint":[0,0]}],"closed":false,"reversed":false}},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":2,"width":20,"endArrow":"","startArrow":"","cap":1},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[0,0],"opacity":1,"blur":0,"isLocked":false,"gid":33,"smootheningRate":0,"initialPoint":[0,0],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"compoundPathData":{"subpaths":[{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[367.7690644381571,667.02363476289884],"reflectionModeOverride":0,"anchorPoint":[367.7690644381571,667.02363476289884],"cornerRadius":0,"prevPoint":[72.193980608055426,108.16792868331186],"inPoint":[368.26333755475412,638.68961321030247],"nextPoint":[72.193980608055426,108.16792868331186]},{"outPoint":[367.82059343747073,616.38299074283532],"reflectionModeOverride":0,"anchorPoint":[367.82059343747073,616.38299074283532],"cornerRadius":0,"prevPoint":[55.02340366515682,81.837967291336099],"inPoint":[367.82059343747073,616.38299074283532],"nextPoint":[55.02340366515682,81.837967291336099]},{"outPoint":[383.13716259159514,626.44746079947163],"reflectionModeOverride":0,"anchorPoint":[403.6767241609266,616.33647011725679],"cornerRadius":0,"prevPoint":[70.109671854888575,134.1591558035534],"inPoint":[403.6767241609266,616.33647011725679],"nextPoint":[70.109671854888575,134.1591558035534]}],"closed":true,"reversed":false}},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[72.357622652088821,121.79167358010636],"opacity":1,"blur":0,"isLocked":false,"gid":48,"smootheningRate":0,"initialPoint":[72.357622652088821,121.79167358010636],"creationPoints":[],"name":"(curve)"}]}},"fillColor":{"b":0.9882352941176471,"s":1,"h":0.13822251558303833,"a":1},"strokeStyle":{"color":{"b":0.9882352941176471,"s":1,"h":0.5806878306878307,"a":1},"dashPattern":[],"join":1,"width":0.10000000149011612,"endArrow":"","startArrow":"","cap":0},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[-2.4740749822735211,26.734403557988003],"opacity":1,"blur":0,"isLocked":false,"gid":46,"smootheningRate":0,"initialPoint":[-2.4740749822735211,26.734403557988003],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"fillColor":{"b":1,"s":0,"h":0,"a":1},"maskedElements":[],"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[189.49257363188801,253.97453151588081],"reflectionModeOverride":0,"anchorPoint":[189.49257363188801,253.97453151588081],"cornerRadius":0,"prevPoint":[112.85257138121662,152.97453151588078],"inPoint":[189.49257363188801,253.97453151588081],"nextPoint":[112.85257138121662,152.97453151588078]},{"outPoint":[198.97257317412434,244.48453174476265],"reflectionModeOverride":0,"anchorPoint":[198.97257317412434,244.48453174476265],"cornerRadius":0,"prevPoint":[112.85257138121662,152.97453151588078],"inPoint":[198.97257317412434,244.48453174476265],"nextPoint":[112.85257138121662,152.97453151588078]},{"outPoint":[189.49257363188801,235.01453147773384],"reflectionModeOverride":0,"anchorPoint":[189.49257363188801,235.01453147773384],"cornerRadius":0,"prevPoint":[112.85257138121662,152.97453151588078],"inPoint":[189.49257363188801,235.01453147773384],"nextPoint":[112.85257138121662,152.97453151588078]}],"closed":true,"reversed":false}}},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[112.85257138121662,152.97453151588078],"opacity":1,"blur":0,"isLocked":false,"gid":16,"smootheningRate":0,"initialPoint":[112.85257138121662,152.97453151588078],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[323.38754763944246,487.32457590003901],"reflectionModeOverride":0,"anchorPoint":[344.90470311533363,481.42866614307741],"cornerRadius":0,"prevPoint":[615.60724563620806,1.3634276556741725],"inPoint":[369.14847846760358,474.78563603599895],"nextPoint":[615.60724563620806,1.3634276556741725]},{"outPoint":[307.28704728382809,560.47255779544446],"reflectionModeOverride":0,"anchorPoint":[307.79763374097075,532.13830093176216],"cornerRadius":0,"prevPoint":[605.67266977751206,16.47175369678871],"inPoint":[308.30822019811342,503.80404406807986],"nextPoint":[605.67266977751206,16.47175369678871]}],"closed":false,"reversed":false}},"fillColor":{"b":0.9882352941176471,"s":1,"h":0.13822251558303833,"a":1},"strokeStyle":{"color":{"b":0.9882352941176471,"s":1,"h":0.5806878306878307,"a":1},"dashPattern":[],"join":1,"width":0.10000000149011612,"endArrow":"","startArrow":"","cap":0},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[605.67266977751206,16.47175369678871],"opacity":1,"blur":0,"isLocked":false,"gid":45,"smootheningRate":0,"initialPoint":[605.67266977751206,16.47175369678871],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(line)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[13.974435927889729,160.80268978822852],"reflectionModeOverride":0,"anchorPoint":[13.974435927889729,160.80268978822852],"cornerRadius":0,"prevPoint":[0,0],"inPoint":[13.974435927889729,160.80268978822852],"nextPoint":[0,0]},{"outPoint":[144.25556161242727,291.78142890790133],"reflectionModeOverride":0,"anchorPoint":[144.25556161242727,291.78142890790133],"cornerRadius":0,"prevPoint":[0,0],"inPoint":[144.25556161242727,291.78142890790133],"nextPoint":[0,0]}],"closed":false,"reversed":false}},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":1,"width":20,"endArrow":"","startArrow":"","cap":1},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[0,0],"opacity":1,"blur":0,"isLocked":false,"gid":28,"smootheningRate":0,"initialPoint":[0,0],"creationPoints":[],"name":"(line)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[320,664.0506297595],"reflectionModeOverride":0,"anchorPoint":[320,640],"cornerRadius":0,"prevPoint":[0,0],"inPoint":[320,580],"nextPoint":[0,0]},{"outPoint":[344.050612449646,595.89893977911322],"reflectionModeOverride":0,"anchorPoint":[337.34381007033926,612.48211711168926],"cornerRadius":0,"prevPoint":[0,0],"inPoint":[327.23039949003834,637.48844227310212],"nextPoint":[0,0]},{"outPoint":[380,580],"reflectionModeOverride":0,"anchorPoint":[360,580],"cornerRadius":0,"prevPoint":[0,0],"inPoint":[352.025306224823,580],"nextPoint":[0,0]},{"outPoint":[260,580],"reflectionModeOverride":0,"anchorPoint":[280,580],"cornerRadius":0,"prevPoint":[0,0],"inPoint":[300,580],"nextPoint":[0,0]}],"closed":true,"reversed":false}},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":2,"width":0.10000000149011612,"endArrow":"","startArrow":"","cap":1},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[0,0],"opacity":1,"blur":0,"isLocked":false,"gid":34,"smootheningRate":0,"initialPoint":[0,0],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[300,640],"reflectionModeOverride":0,"anchorPoint":[300,640],"cornerRadius":0,"prevPoint":[0,0],"inPoint":[300,640],"nextPoint":[0,0]},{"outPoint":[380,580],"reflectionModeOverride":0,"anchorPoint":[340,580],"cornerRadius":0,"prevPoint":[0,0],"inPoint":[300,580],"nextPoint":[0,0]}],"closed":false,"reversed":false}},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":2,"width":0.10000000149011612,"endArrow":"","startArrow":"","cap":1},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[0,0],"opacity":1,"blur":0,"isLocked":false,"gid":36,"smootheningRate":0,"initialPoint":[0,0],"creationPoints":[],"name":"(curve)"}],"cacheLayers":[],"cacheArtboardPaths":[],"undoStack":[[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":6}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -20, -20]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11,6]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -29.209948435277369, -232.41660739687057]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[12]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[12,13,14,15]}","argumentGID":0}],"methodSignature":"setSubpaths:","targetGID":11},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11}],"methodSignature":"setSuperpath:","targetGID":12},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setFill:","targetGID":12},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":12},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setShadow:","targetGID":12},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11}],"methodSignature":"setSuperpath:","targetGID":13},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setFill:","targetGID":13},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":13},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setShadow:","targetGID":13},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11}],"methodSignature":"setSuperpath:","targetGID":14},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setFill:","targetGID":14},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":14},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setShadow:","targetGID":14}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":6},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":16}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -20, -20]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":16},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":16}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setFill:","targetGID":14}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setFill:","targetGID":16}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setFill:","targetGID":16}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.01450315572447696,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.93007444840156717,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.014503091068591101,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.93451308072143913,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.014503091068591101,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.93910701763028559,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.014503091068591101,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.94055809677531532,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.014503091068591101,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.94999337125602745,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.013467045153601698,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.95297621548706413,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.013467045153601698,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.95790068402842177,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.011044777045815676,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.96266052064980523,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.0088583736096398309,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.96911575815444173,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.0077646546444650423,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.97217928832645584,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.0032726223185911016,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.98016728703982747,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.0010851843882415254,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.98662352066719217,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.99307006473711057,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[0.20437110010339629, -0, -0, 0.20437110010339629, 126.38769661378409, 170.79330548171168]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[13]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[12,13,14]}","argumentGID":0}],"methodSignature":"setSubpaths:","targetGID":11},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11}],"methodSignature":"setSuperpath:","targetGID":13},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setFill:","targetGID":13},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":13},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setShadow:","targetGID":13},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11}],"methodSignature":"setSuperpath:","targetGID":14},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setFill:","targetGID":14},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":14},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setShadow:","targetGID":14}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":21}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":185.15633048630471,\"AnchorPoint_Y\":354.17149931944061,\"inPoint_Y\":354.17149931944061,\"OutPoint_X\":185.15633048630471,\"AnchorPoint_X\":185.15633048630471,\"OutPoint_Y\":354.17149931944061},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":185.15633048630471,\"AnchorPoint_Y\":354.17149931944061,\"inPoint_Y\":354.17149931944061,\"OutPoint_X\":185.15633048630471,\"AnchorPoint_X\":185.15633048630471,\"OutPoint_Y\":354.17149931944061},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":386.50447364412418,\"AnchorPoint_Y\":554.43203524141848,\"inPoint_Y\":554.43203524141848,\"OutPoint_X\":386.50447364412418,\"AnchorPoint_X\":386.50447364412418,\"OutPoint_Y\":554.43203524141848},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":185.15633048630471,\"AnchorPoint_Y\":354.17149931944061,\"inPoint_Y\":354.17149931944061,\"OutPoint_X\":185.15633048630471,\"AnchorPoint_X\":185.15633048630471,\"OutPoint_Y\":354.17149931944061},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":386.50447364412418,\"AnchorPoint_Y\":554.43203524141848,\"inPoint_Y\":554.43203524141848,\"OutPoint_X\":386.50447364412418,\"AnchorPoint_X\":386.50447364412418,\"OutPoint_Y\":554.43203524141848},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":284.63851065196616,\"AnchorPoint_Y\":654.20422348213651,\"inPoint_Y\":654.20422348213651,\"OutPoint_X\":284.63851065196616,\"AnchorPoint_X\":284.63851065196616,\"OutPoint_Y\":654.20422348213651},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":185.15633048630471,\"AnchorPoint_Y\":354.17149931944061,\"inPoint_Y\":354.17149931944061,\"OutPoint_X\":185.15633048630471,\"AnchorPoint_X\":185.15633048630471,\"OutPoint_Y\":354.17149931944061},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":386.50447364412418,\"AnchorPoint_Y\":554.43203524141848,\"inPoint_Y\":554.43203524141848,\"OutPoint_X\":386.50447364412418,\"AnchorPoint_X\":386.50447364412418,\"OutPoint_Y\":554.43203524141848},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":284.63851065196616,\"AnchorPoint_Y\":654.20422348213651,\"inPoint_Y\":654.20422348213651,\"OutPoint_X\":284.63851065196616,\"AnchorPoint_X\":284.63851065196616,\"OutPoint_Y\":654.20422348213651},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":286.57710140084737,\"AnchorPoint_Y\":264.05198470231699,\"inPoint_Y\":264.05198470231699,\"OutPoint_X\":286.57710140084737,\"AnchorPoint_X\":286.57710140084737,\"OutPoint_Y\":264.05198470231699},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":185.15633048630471,\"AnchorPoint_Y\":354.17149931944061,\"inPoint_Y\":354.17149931944061,\"OutPoint_X\":185.15633048630471,\"AnchorPoint_X\":185.15633048630471,\"OutPoint_Y\":354.17149931944061},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":386.50447364412418,\"AnchorPoint_Y\":554.43203524141848,\"inPoint_Y\":554.43203524141848,\"OutPoint_X\":386.50447364412418,\"AnchorPoint_X\":386.50447364412418,\"OutPoint_Y\":554.43203524141848},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":284.63851065196616,\"AnchorPoint_Y\":654.20422348213651,\"inPoint_Y\":654.20422348213651,\"OutPoint_X\":284.63851065196616,\"AnchorPoint_X\":284.63851065196616,\"OutPoint_Y\":654.20422348213651},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":286.57710140084737,\"AnchorPoint_Y\":264.05198470231699,\"inPoint_Y\":264.05198470231699,\"OutPoint_X\":286.57710140084737,\"AnchorPoint_X\":286.57710140084737,\"OutPoint_Y\":264.05198470231699},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":383.69928863669242,\"AnchorPoint_Y\":361.21410026752545,\"inPoint_Y\":361.21410026752545,\"OutPoint_X\":383.69928863669242,\"AnchorPoint_X\":383.69928863669242,\"OutPoint_Y\":361.21410026752545},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":1}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":1,\"WDHueKey\":0.5806878306878307,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":1}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":1,\"WDHueKey\":0.5806878306878307,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":37.148059844970703}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":1,\"WDHueKey\":0.5806878306878307,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":2,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":37.148059844970703}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":185.15633048630471,\"AnchorPoint_Y\":354.17149931944061,\"inPoint_Y\":354.17149931944061,\"OutPoint_X\":185.15633048630471,\"AnchorPoint_X\":185.15633048630471,\"OutPoint_Y\":354.17149931944061},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":386.50447364412418,\"AnchorPoint_Y\":554.43203524141848,\"inPoint_Y\":554.43203524141848,\"OutPoint_X\":386.50447364412418,\"AnchorPoint_X\":386.50447364412418,\"OutPoint_Y\":554.43203524141848},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":284.63851065196616,\"AnchorPoint_Y\":654.20422348213651,\"inPoint_Y\":654.20422348213651,\"OutPoint_X\":284.63851065196616,\"AnchorPoint_X\":284.63851065196616,\"OutPoint_Y\":654.20422348213651},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":286.57710140084737,\"AnchorPoint_Y\":264.05198470231699,\"inPoint_Y\":264.05198470231699,\"OutPoint_X\":286.57710140084737,\"AnchorPoint_X\":286.57710140084737,\"OutPoint_Y\":264.05198470231699},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":383.69928863669242,\"AnchorPoint_Y\":361.21410026752545,\"inPoint_Y\":361.21410026752545,\"OutPoint_X\":383.69928863669242,\"AnchorPoint_X\":383.69928863669242,\"OutPoint_Y\":361.21410026752545},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":186.05023255601679,\"AnchorPoint_Y\":558.85414169234264,\"inPoint_Y\":558.85414169234264,\"OutPoint_X\":186.05023255601679,\"AnchorPoint_X\":186.05023255601679,\"OutPoint_Y\":558.85414169234264},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":185.15633048630471,\"AnchorPoint_Y\":354.17149931944061,\"inPoint_Y\":354.17149931944061,\"OutPoint_X\":185.15633048630471,\"AnchorPoint_X\":185.15633048630471,\"OutPoint_Y\":354.17149931944061},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":386.50447364412418,\"AnchorPoint_Y\":554.43203524141848,\"inPoint_Y\":554.43203524141848,\"OutPoint_X\":386.50447364412418,\"AnchorPoint_X\":386.50447364412418,\"OutPoint_Y\":554.43203524141848},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":284.63851065196616,\"AnchorPoint_Y\":654.20422348213651,\"inPoint_Y\":654.20422348213651,\"OutPoint_X\":284.63851065196616,\"AnchorPoint_X\":284.63851065196616,\"OutPoint_Y\":654.20422348213651},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":286.57710140084737,\"AnchorPoint_Y\":264.05198470231699,\"inPoint_Y\":264.05198470231699,\"OutPoint_X\":286.57710140084737,\"AnchorPoint_X\":286.57710140084737,\"OutPoint_Y\":264.05198470231699},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":383.69928863669242,\"AnchorPoint_Y\":361.21410026752545,\"inPoint_Y\":361.21410026752545,\"OutPoint_X\":383.69928863669242,\"AnchorPoint_X\":383.69928863669242,\"OutPoint_Y\":361.21410026752545},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":1,\"NodePoints\":{\"inPoint_X\":235.46249740746129,\"AnchorPoint_Y\":558.85414169234264,\"inPoint_Y\":509.44413050490067,\"OutPoint_X\":136.6379677045723,\"AnchorPoint_X\":186.05023255601679,\"OutPoint_Y\":608.26415287978466},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782582120682,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.98823529481887817,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":16},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":1,\"WDHueKey\":0.5806878306878307,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":37.148059844970703}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":1,\"WDHueKey\":0.5806878306878307,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":37.148059844970703}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0.03408561318607653,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.016189711030229925,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":37.148059844970703}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0.029926881951800856,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.016189711030229925,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":37.148059844970703}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0.021585238181938561,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.012961911164688478,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":37.148059844970703}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0.011895648503707629,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.007872629590133573,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":37.148059844970703}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0.005957393322960804,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":37.148059844970703}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":37.148059844970703}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":37.148059844970703}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":21.344829559326172}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":21.344829559326172}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":20}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[-4.3711390001862419e-08, -0.99999999999999922, 0.99999999999999922, -4.3711390001862419e-08, -173.29768953296772, 744.95852622656867]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 8.2190355245806472, 176.90598115888827]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":22}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 0.55538688884063114, -0, 182.49084631957811]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[22]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":24}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 150.32620239929324, 36.081797695525552]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[24]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[24]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0.12249755187863798, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[24]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[0.64978701032960984, -0, -0, 0.64978701032960984, 52.531948450558538, 142.05406077476505]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[24]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -55.171276915352394, 196.69205141995428]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[24]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[0.65616231221472443, -0, -0, 0.65616231221472443, 51.425334356867019, 141.12771095949628]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[22]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -55.53221494113933, 129.60740108742715]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[22]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 205.17127691535239, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[24]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 205.09503537570964, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[22]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 208.92985571850454]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[24]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 130.84123782858848]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[22]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 75]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[22]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":25}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -20, -20]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[25]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 4.5418914390142788, -306.56258907512347]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[25]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[0.96223302635797447, -0, -0, 0.96223302635797447, -0, 2.8325230231519103]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[22]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1.0392493219135692, -0, -0, 1.0392493219135692, 0, -2.9436991435176969]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[22]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 0.96223302635797447, -0, 2.8325230231519103]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[22]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 15.458108560985721, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[25]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 26.562589075123469]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[25]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 25]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[25]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 50]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[25]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -25]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[25]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":22}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":26}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -20, -20]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":20}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":0.10000000149011612}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":1,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":0.10000000149011612}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 9.881426012744555, 0.91199734232554874]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -77.745954011856824, 28.270796276850916]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 67.864527999112269, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 10, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1.1538461432654479, -0, -0, 1, -1.5384614326544779, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -136.98574299882625, 7.8612196478959504]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":27}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":25},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":3}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":24},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":26},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":3}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":22},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setElements:","targetGID":27},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -53.141264363887032, -43.604121250556744]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -70.052055171480333, -2.5049969673447094]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 219.77475934149726, 163.57319520938375]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":27},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":27}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[0.6846814845770105, -0, -0, 0.6846814845770105, -0.080018108436871196, 3.1890182924268196]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -85.587957051898314, -21.453286888159028]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":20}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setShadow:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDShadowOffsetKey\":10,\"WDShadowAngleKey\":1.5707999467849731,\"WDShadowRadiusKey\":10,\"WDShadowColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":0.33300000000000002,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"$class\":\"WDShadow\"}}","argumentGID":0}],"methodSignature":"setShadow:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setShadow:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDShadowOffsetKey\":10,\"WDShadowAngleKey\":1.5707999467849731,\"WDShadowRadiusKey\":10,\"WDShadowColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":0.33300000000000002,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"$class\":\"WDShadow\"}}","argumentGID":0}],"methodSignature":"setShadow:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":20}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":28}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":28},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":29}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":29}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":19.067760461856238,\"AnchorPoint_Y\":162.4737431408027,\"inPoint_Y\":162.4737431408027,\"OutPoint_X\":19.067760461856238,\"AnchorPoint_X\":19.067760461856238,\"OutPoint_Y\":162.4737431408027},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":29}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":19.067760461856238,\"AnchorPoint_Y\":162.4737431408027,\"inPoint_Y\":162.4737431408027,\"OutPoint_X\":19.067760461856238,\"AnchorPoint_X\":19.067760461856238,\"OutPoint_Y\":162.4737431408027},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":142.86303913891427,\"AnchorPoint_Y\":297.21030751597522,\"inPoint_Y\":297.21030751597522,\"OutPoint_X\":142.86303913891427,\"AnchorPoint_X\":142.86303913891427,\"OutPoint_Y\":297.21030751597522},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":29}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":3,"argumentEncodedJsonString":"{\"Argument\":false}","argumentGID":0}],"methodSignature":"setClosed:","targetGID":29}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setFill:","targetGID":29}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782582120682,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.98823529481887817,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":29}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":30}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -20, -20]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -258.8309537310077, 14.790477788784642]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":21},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":21}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":21},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":3}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":21}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0}],"methodSignature":"exchangeObjectAtIndex:withObjectAtIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0}],"methodSignature":"exchangeObjectAtIndex:withObjectAtIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0}],"methodSignature":"exchangeObjectAtIndex:withObjectAtIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0}],"methodSignature":"exchangeObjectAtIndex:withObjectAtIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0}],"methodSignature":"exchangeObjectAtIndex:withObjectAtIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0}],"methodSignature":"exchangeObjectAtIndex:withObjectAtIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":3}","argumentGID":0}],"methodSignature":"exchangeObjectAtIndex:withObjectAtIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":1,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":20}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":30}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":1,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":20}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":29}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0}],"methodSignature":"exchangeObjectAtIndex:withObjectAtIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":3}","argumentGID":0}],"methodSignature":"exchangeObjectAtIndex:withObjectAtIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":3}","argumentGID":0},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0}],"methodSignature":"exchangeObjectAtIndex:withObjectAtIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0}],"methodSignature":"exchangeObjectAtIndex:withObjectAtIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[0.98660023945785613, -0, -0, 1.0127745463822073, 7.5897658853896965, -3.7483052243093384]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":3}","argumentGID":0},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0}],"methodSignature":"exchangeObjectAtIndex:withObjectAtIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":31}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":1,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":0.10000000149011612}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":31}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":1,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":27.568212509155273}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":31}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":27.568212509155273}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":31}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":1,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":29}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782582120682,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.98823529481887817,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782582120682,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.98823529481887817,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782582120682,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.98823529481887817,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782582120682,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.98823529481887817,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11623311042785645,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11623311042785645,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11623311042785645,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11623311042785645,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11518210172653198,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11518210172653198,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11518210172653198,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11518210172653198,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11062517762184143,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11062517762184143,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11062517762184143,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11062517762184143,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10827497392892838,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10827497392892838,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10827497392892838,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10827497392892838,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10599262267351151,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10599262267351151,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10599262267351151,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10599262267351151,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10487814247608185,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10487814247608185,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10487814247608185,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10487814247608185,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10140901058912277,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10140901058912277,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10140901058912277,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10140901058912277,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10024447739124298,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10024447739124298,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10024447739124298,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10024447739124298,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.0991511270403862,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.0991511270403862,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.0991511270403862,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.0991511270403862,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.095819912850856781,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.095819912850856781,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.095819912850856781,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.095819912850856781,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.093592062592506436,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.093592062592506436,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.093592062592506436,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.093592062592506436,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.091305255889892578,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.091305255889892578,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.091305255889892578,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.091305255889892578,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.086611531674861908,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.086611531674861908,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.086611531674861908,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.086611531674861908,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.084330290555953952,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.084330290555953952,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.084330290555953952,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.084330290555953952,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.082062393426895142,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.082062393426895142,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.082062393426895142,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.082062393426895142,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.080980166792869596,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.080980166792869596,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.080980166792869596,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.080980166792869596,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.078774556517601013,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.078774556517601013,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.078774556517601013,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.078774556517601013,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.079864569008350372,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.079864569008350372,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.079864569008350372,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.079864569008350372,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.084498241543769864,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.084498241543769864,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.084498241543769864,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.084498241543769864,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.090882599353790255,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.090882599353790255,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.090882599353790255,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.090882599353790255,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.09557187557220459,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.09557187557220459,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.09557187557220459,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.09557187557220459,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.0990910604596138,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.0990910604596138,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.0990910604596138,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.0990910604596138,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10261469334363937,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10261469334363937,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10261469334363937,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10261469334363937,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10601820796728134,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10601820796728134,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10601820796728134,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10601820796728134,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10719386488199234,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10719386488199234,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10719386488199234,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10719386488199234,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11685270816087723,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11685270816087723,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11685270816087723,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11685270816087723,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.12441384047269821,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.12441384047269821,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.12441384047269821,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.12441384047269821,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.12794080376625061,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.12794080376625061,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.12794080376625061,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.12794080376625061,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13263343274593353,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13263343274593353,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13263343274593353,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13263343274593353,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13615038990974426,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13615038990974426,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13615038990974426,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13615038990974426,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13955500721931458,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13955500721931458,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13955500721931458,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13955500721931458,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14536766707897186,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14536766707897186,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14536766707897186,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14536766707897186,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15242382884025574,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15242382884025574,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15242382884025574,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15242382884025574,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15580509603023529,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15580509603023529,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15580509603023529,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15580509603023529,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15815529227256775,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15815529227256775,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15815529227256775,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15815529227256775,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.16035088896751404,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.16035088896751404,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.16035088896751404,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.16035088896751404,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15694738924503326,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15694738924503326,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15694738924503326,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15694738924503326,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15200117230415344,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15200117230415344,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15200117230415344,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15200117230415344,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14730300009250641,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14730300009250641,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14730300009250641,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14730300009250641,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14378604292869568,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14378604292869568,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14378604292869568,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14378604292869568,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14143472909927368,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14143472909927368,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14143472909927368,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14143472909927368,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14034359157085419,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14034359157085419,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14034359157085419,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14034359157085419,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":1,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":30}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":32}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -20, -20]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":33}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":33}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":307.98765662154068,\"AnchorPoint_Y\":526.40806463936553,\"inPoint_Y\":555.58846167930153,\"OutPoint_X\":307.98765662154068,\"AnchorPoint_X\":307.98765662154068,\"OutPoint_Y\":497.22766759942954},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":33}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":1,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":20}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":33}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":33},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":9223372036854775807}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":34}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":34}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":320,\"AnchorPoint_Y\":640,\"inPoint_Y\":680,\"OutPoint_X\":320,\"AnchorPoint_X\":320,\"OutPoint_Y\":600},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":34}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":320,\"AnchorPoint_Y\":640,\"inPoint_Y\":680,\"OutPoint_X\":320,\"AnchorPoint_X\":320,\"OutPoint_Y\":600},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":340,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":380,\"AnchorPoint_X\":360,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":34}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":320,\"AnchorPoint_Y\":640,\"inPoint_Y\":680,\"OutPoint_X\":320,\"AnchorPoint_X\":320,\"OutPoint_Y\":600},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":340,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":380,\"AnchorPoint_X\":360,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":260,\"AnchorPoint_X\":280,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":34},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":3,"argumentEncodedJsonString":"{\"Argument\":false}","argumentGID":0}],"methodSignature":"setClosed:","targetGID":34}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":320,\"AnchorPoint_Y\":640,\"inPoint_Y\":580,\"OutPoint_X\":320,\"AnchorPoint_X\":320,\"OutPoint_Y\":680.00002878904479},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":340,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":380,\"AnchorPoint_X\":360,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":260,\"AnchorPoint_X\":280,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":34}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":34},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":6}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":35}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":35}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":340,\"AnchorPoint_Y\":660,\"inPoint_Y\":620,\"OutPoint_X\":340,\"AnchorPoint_X\":340,\"OutPoint_Y\":700},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":35}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":35},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":6}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":36}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":36}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":640,\"inPoint_Y\":640,\"OutPoint_X\":300,\"AnchorPoint_X\":300,\"OutPoint_Y\":640},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":36}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":37}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -20, -20]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 20, 20]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[-1, -0, 0, 1, 640, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"KeepNodesAfterTransformTransformOptionKey\":true}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 39, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":640,\"inPoint_Y\":640,\"OutPoint_X\":300,\"AnchorPoint_X\":300,\"OutPoint_Y\":640},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{600, 0}\",\"VNPrevPointForRadiusKey\":\"{600, 0}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":220,\"AnchorPoint_X\":260,\"OutPoint_Y\":580},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{600, 0}\",\"VNPrevPointForRadiusKey\":\"{600, 0}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":37}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":640,\"inPoint_Y\":640,\"OutPoint_X\":300,\"AnchorPoint_X\":300,\"OutPoint_Y\":640},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{600, 0}\",\"VNPrevPointForRadiusKey\":\"{600, 0}\",\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":260,\"AnchorPoint_X\":260,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":37}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":640,\"inPoint_Y\":640,\"OutPoint_X\":300,\"AnchorPoint_X\":300,\"OutPoint_Y\":640},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{600, 0}\",\"VNPrevPointForRadiusKey\":\"{600, 0}\",\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":260,\"AnchorPoint_X\":260,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":340,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":340,\"AnchorPoint_X\":340,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":37}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":640,\"inPoint_Y\":640,\"OutPoint_X\":300,\"AnchorPoint_X\":300,\"OutPoint_Y\":640},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{600, 0}\",\"VNPrevPointForRadiusKey\":\"{600, 0}\",\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":260,\"AnchorPoint_X\":260,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":340,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":340,\"AnchorPoint_X\":340,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":260,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":260,\"AnchorPoint_X\":260,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":37}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":640,\"inPoint_Y\":640,\"OutPoint_X\":300,\"AnchorPoint_X\":300,\"OutPoint_Y\":640},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{600, 0}\",\"VNPrevPointForRadiusKey\":\"{600, 0}\",\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":260,\"AnchorPoint_X\":260,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":340,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":340,\"AnchorPoint_X\":340,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":260,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":260,\"AnchorPoint_X\":260,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":340,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":340,\"AnchorPoint_X\":340,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":37}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 60, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":240,\"AnchorPoint_Y\":640,\"inPoint_Y\":640,\"OutPoint_X\":240,\"AnchorPoint_X\":240,\"OutPoint_Y\":640},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{540, 0}\",\"VNPrevPointForRadiusKey\":\"{540, 0}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":240,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":200,\"AnchorPoint_X\":200,\"OutPoint_Y\":580},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-60, 0}\",\"VNPrevPointForRadiusKey\":\"{-60, 0}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":280,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":280,\"AnchorPoint_X\":280,\"OutPoint_Y\":580},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-60, 0}\",\"VNPrevPointForRadiusKey\":\"{-60, 0}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":200,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":200,\"AnchorPoint_X\":200,\"OutPoint_Y\":580},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-60, 0}\",\"VNPrevPointForRadiusKey\":\"{-60, 0}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":280,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":300,\"AnchorPoint_X\":280,\"OutPoint_Y\":600},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-60, 0}\",\"VNPrevPointForRadiusKey\":\"{-60, 0}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":37},{"actionTypeRawValue":"proxy","methodArguments":[],"methodSignature":"reversePathDirection","targetGID":37}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":580,\"inPoint_Y\":600,\"OutPoint_X\":280,\"AnchorPoint_X\":280,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":200,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":200,\"AnchorPoint_X\":200,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":280,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":280,\"AnchorPoint_X\":280,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":200,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":240,\"AnchorPoint_X\":200,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":240,\"AnchorPoint_Y\":640,\"inPoint_Y\":640,\"OutPoint_X\":240,\"AnchorPoint_X\":240,\"OutPoint_Y\":640},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":37},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":3,"argumentEncodedJsonString":"{\"Argument\":false}","argumentGID":0}],"methodSignature":"setClosed:","targetGID":37}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":36},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":6}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -60, 100]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -8.3360061810856791, -0.18596575427056905]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setFill:","targetGID":37}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0.12624915594960839, -0.84513498021431133]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1.0820554726071352, -0, -0, 1, -28.572516179113212, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 3.7693360211719664, 0.58007166688469169]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 0.8911271920692454, -0, 58.840421083655528]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0.018101184397323777, -6.1834757589472247]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0.5616683932951787, -14.721591768371582]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1.4335340527209723, 13.544422687729025]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":37},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":6}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":43}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.10440918421369,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":598.11903819000008},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":314.21352490073997,\"AnchorPoint_Y\":480.08137659705397,\"inPoint_Y\":479.94813303079826,\"OutPoint_X\":366.0442444460744,\"AnchorPoint_X\":340.12888467340719,\"OutPoint_Y\":480.21462016330969},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":314.21352490073997,\"AnchorPoint_Y\":480.08137659705397,\"inPoint_Y\":479.94813303079826,\"OutPoint_X\":340.12888467340719,\"AnchorPoint_X\":340.12888467340719,\"OutPoint_Y\":480.08137659705397},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":314.21352490073997,\"AnchorPoint_Y\":480.08137659705397,\"inPoint_Y\":479.94813303079826,\"OutPoint_X\":340.12888467340719,\"AnchorPoint_X\":340.12888467340719,\"OutPoint_Y\":480.08137659705397},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":337.32713106884489,\"AnchorPoint_Y\":505.14299981511687,\"inPoint_Y\":505.14299981511687,\"OutPoint_X\":337.32713106884489,\"AnchorPoint_X\":337.32713106884489,\"OutPoint_Y\":505.14299981511687},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":314.21352490073997,\"AnchorPoint_Y\":480.08137659705397,\"inPoint_Y\":479.94813303079826,\"OutPoint_X\":340.12888467340719,\"AnchorPoint_X\":340.12888467340719,\"OutPoint_Y\":480.08137659705397},\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":268.41762507168443,\"AnchorPoint_Y\":478.86160216124927,\"inPoint_Y\":478.86160216124927,\"OutPoint_X\":268.41762507168443,\"AnchorPoint_X\":268.41762507168443,\"OutPoint_Y\":478.86160216124927},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-68.909505997160466, -26.2813976538676}\",\"VNPrevPointForRadiusKey\":\"{-68.909505997160466, -26.2813976538676}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":268.41762507168443,\"AnchorPoint_Y\":478.86160216124927,\"inPoint_Y\":478.86160216124927,\"OutPoint_X\":268.41762507168443,\"AnchorPoint_X\":268.41762507168443,\"OutPoint_Y\":478.86160216124927},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-68.909505997160466, -26.2813976538676}\",\"VNPrevPointForRadiusKey\":\"{-68.909505997160466, -26.2813976538676}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":282.38947067174871,\"AnchorPoint_Y\":502.68576551434728,\"inPoint_Y\":502.68576551434728,\"OutPoint_X\":282.38947067174871,\"AnchorPoint_X\":282.38947067174871,\"OutPoint_Y\":502.68576551434728},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.41762507168443,\"AnchorPoint_Y\":478.86160216124927,\"inPoint_Y\":478.86160216124927,\"OutPoint_X\":268.41762507168443,\"AnchorPoint_X\":268.41762507168443,\"OutPoint_Y\":478.86160216124927},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":333.80634908853523,\"AnchorPoint_Y\":479.14166624396699,\"inPoint_Y\":479.14166624396699,\"OutPoint_X\":333.80634908853523,\"AnchorPoint_X\":333.80634908853523,\"OutPoint_Y\":479.14166624396699},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{51.416878416786517, -23.544099270380286}\",\"VNPrevPointForRadiusKey\":\"{51.416878416786517, -23.544099270380286}\",\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.41762507168443,\"AnchorPoint_Y\":478.86160216124927,\"inPoint_Y\":478.86160216124927,\"OutPoint_X\":268.41762507168443,\"AnchorPoint_X\":268.41762507168443,\"OutPoint_Y\":478.86160216124927},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":342.99265545324346,\"AnchorPoint_Y\":479.14166624396699,\"inPoint_Y\":494.80574311033359,\"OutPoint_X\":324.620042723827,\"AnchorPoint_X\":333.80634908853523,\"OutPoint_Y\":463.4775893776004},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.41762507168443,\"AnchorPoint_Y\":478.86160216124927,\"inPoint_Y\":478.86160216124927,\"OutPoint_X\":268.41762507168443,\"AnchorPoint_X\":268.41762507168443,\"OutPoint_Y\":478.86160216124927},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":333.80634908853523,\"AnchorPoint_Y\":479.14166624396699,\"inPoint_Y\":479.14166624396699,\"OutPoint_X\":333.80634908853523,\"AnchorPoint_X\":333.80634908853523,\"OutPoint_Y\":479.14166624396699},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.41762507168443,\"AnchorPoint_Y\":478.86160216124927,\"inPoint_Y\":478.86160216124927,\"OutPoint_X\":268.41762507168443,\"AnchorPoint_X\":268.41762507168443,\"OutPoint_Y\":478.86160216124927},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":3,\"NodePoints\":{\"inPoint_X\":342.99265545324346,\"AnchorPoint_Y\":479.14166624396699,\"inPoint_Y\":494.80574311033359,\"OutPoint_X\":324.620042723827,\"AnchorPoint_X\":333.80634908853523,\"OutPoint_Y\":463.4775893776004},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.41762507168443,\"AnchorPoint_Y\":478.86160216124927,\"inPoint_Y\":478.86160216124927,\"OutPoint_X\":268.41762507168443,\"AnchorPoint_X\":268.41762507168443,\"OutPoint_Y\":478.86160216124927},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":3,\"NodePoints\":{\"inPoint_X\":342.99265545324346,\"AnchorPoint_Y\":479.14166624396699,\"inPoint_Y\":494.80574311033359,\"OutPoint_X\":333.79302393751607,\"AnchorPoint_X\":333.80634908853523,\"OutPoint_Y\":478.98295741265042},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.41762507168443,\"AnchorPoint_Y\":478.86160216124927,\"inPoint_Y\":478.86160216124927,\"OutPoint_X\":268.41762507168443,\"AnchorPoint_X\":268.41762507168443,\"OutPoint_Y\":478.86160216124927},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":3,\"NodePoints\":{\"inPoint_X\":303.99512941310888,\"AnchorPoint_Y\":479.14166624396699,\"inPoint_Y\":487.18557523329599,\"OutPoint_X\":333.79302393751607,\"AnchorPoint_X\":333.80634908853523,\"OutPoint_Y\":478.98295741265042},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.41762507168443,\"AnchorPoint_Y\":478.86160216124927,\"inPoint_Y\":478.86160216124927,\"OutPoint_X\":268.41762507168443,\"AnchorPoint_X\":268.41762507168443,\"OutPoint_Y\":478.86160216124927},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":44}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":44}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":249.48159496463126,\"AnchorPoint_Y\":480.06523848740324,\"inPoint_Y\":466.59075022213392,\"OutPoint_X\":291.92349007711761,\"AnchorPoint_X\":270.70254252087443,\"OutPoint_Y\":493.53972675267255},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":44}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":249.48159496463126,\"AnchorPoint_Y\":480.06523848740324,\"inPoint_Y\":466.59075022213392,\"OutPoint_X\":291.92349007711761,\"AnchorPoint_X\":270.70254252087443,\"OutPoint_Y\":493.53972675267255},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":297.36444957939858,\"AnchorPoint_Y\":515.66654723497345,\"inPoint_Y\":487.33229037129115,\"OutPoint_X\":298.38562249368391,\"AnchorPoint_X\":297.87503603654125,\"OutPoint_Y\":544.00080409865575},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":44}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":246.45876716860445,\"AnchorPoint_Y\":480.06523848740324,\"inPoint_Y\":473.42220838032478,\"OutPoint_X\":292.2196979967656,\"AnchorPoint_X\":270.70254252087443,\"OutPoint_Y\":485.96114824436484},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":297.36444957939858,\"AnchorPoint_Y\":515.66654723497345,\"inPoint_Y\":487.33229037129115,\"OutPoint_X\":298.38562249368391,\"AnchorPoint_X\":297.87503603654125,\"OutPoint_Y\":544.00080409865575},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":44}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":45}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":246.45876716860445,\"AnchorPoint_Y\":480.06523848740324,\"inPoint_Y\":473.42220838032478,\"OutPoint_X\":292.2196979967656,\"AnchorPoint_X\":270.70254252087443,\"OutPoint_Y\":485.96114824436484},\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":307.29902543809465,\"AnchorPoint_Y\":530.77487327608799,\"inPoint_Y\":502.44061641240569,\"OutPoint_X\":308.32019835237998,\"AnchorPoint_X\":307.80961189523731,\"OutPoint_Y\":559.10913013977029},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{9.9345758586960642, 15.108326041114537}\",\"VNPrevPointForRadiusKey\":\"{9.9345758586960642, 15.108326041114537}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":45}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[-1, -0, 0, 1, 618.5121544161118, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[45]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"KeepNodesAfterTransformTransformOptionKey\":true}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -17.095091220096265, 18.636572344325828]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[45]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":246.45876716860445,\"AnchorPoint_Y\":480.06523848740324,\"inPoint_Y\":473.42220838032478,\"OutPoint_X\":292.2196979967656,\"AnchorPoint_X\":270.70254252087443,\"OutPoint_Y\":485.96114824436484},\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":307.29902543809465,\"AnchorPoint_Y\":530.77487327608799,\"inPoint_Y\":502.44061641240569,\"OutPoint_X\":308.32019835237998,\"AnchorPoint_X\":307.80961189523731,\"OutPoint_Y\":559.10913013977029},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{9.9345758586960642, 15.108326041114537}\",\"VNPrevPointForRadiusKey\":\"{9.9345758586960642, 15.108326041114537}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":44}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":46}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":45},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":8}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":44},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":6}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 2.4740749822735211, -26.734403557988003]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[46]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":50}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":50}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":305.84902480507895,\"AnchorPoint_Y\":558.859403557988,\"inPoint_Y\":530.52519454298988,\"OutPoint_X\":305.33842501772648,\"AnchorPoint_X\":305.33842501772648,\"OutPoint_Y\":558.859403557988},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-2.4740749822735211, 26.734403557988003}\",\"VNPrevPointForRadiusKey\":\"{-2.4740749822735211, 26.734403557988003}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":342.43217501772648,\"AnchorPoint_Y\":508.171903557988,\"inPoint_Y\":508.171903557988,\"OutPoint_X\":320.91501841129599,\"AnchorPoint_X\":342.43217501772648,\"OutPoint_Y\":514.06781336097845},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-2.4740749822735211, 26.734403557988003}\",\"VNPrevPointForRadiusKey\":\"{-2.4740749822735211, 26.734403557988003}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":48}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.84902480507895,\"AnchorPoint_Y\":558.859403557988,\"inPoint_Y\":530.52519454298988,\"OutPoint_X\":305.33842501772648,\"AnchorPoint_X\":305.33842501772648,\"OutPoint_Y\":558.859403557988},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":323.12940602919167,\"AnchorPoint_Y\":534.54856008655031,\"inPoint_Y\":534.54856008655031,\"OutPoint_X\":323.12940602919167,\"AnchorPoint_X\":323.12940602919167,\"OutPoint_Y\":534.54856008655031},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":342.43217501772648,\"AnchorPoint_Y\":508.171903557988,\"inPoint_Y\":508.171903557988,\"OutPoint_X\":320.91501841129599,\"AnchorPoint_X\":342.43217501772648,\"OutPoint_Y\":514.06781336097845},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":48}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[47,48]}","argumentGID":0}],"methodSignature":"setSubpaths:","targetGID":46},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":46}],"methodSignature":"setSuperpath:","targetGID":48},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setFill:","targetGID":48},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":48},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setShadow:","targetGID":48},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":46}],"methodSignature":"setSuperpath:","targetGID":48},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":48},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setFill:","targetGID":48},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setShadow:","targetGID":48},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":48}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":46},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":7}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13822251558303833,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":48}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -2.1531569701203352, 25.991399082341331]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[48]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":308.00218177519929,\"AnchorPoint_Y\":532.86800447564667,\"inPoint_Y\":504.53379546064855,\"OutPoint_X\":307.49158198784681,\"AnchorPoint_X\":307.49158198784681,\"OutPoint_Y\":532.86800447564667},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{2.1531569701203352, -25.991399082341331}\",\"VNPrevPointForRadiusKey\":\"{2.1531569701203352, -25.991399082341331}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":307.54481307650724,\"AnchorPoint_Y\":482.22702540901258,\"inPoint_Y\":482.22702540901258,\"OutPoint_X\":307.54481307650724,\"AnchorPoint_X\":307.54481307650724,\"OutPoint_Y\":482.22702540901258},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-15.584592952684432, -52.321534677537727}\",\"VNPrevPointForRadiusKey\":\"{-15.584592952684432, -52.321534677537727}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":344.58533198784681,\"AnchorPoint_Y\":482.18050447564667,\"inPoint_Y\":482.18050447564667,\"OutPoint_X\":323.06817538141632,\"AnchorPoint_X\":344.58533198784681,\"OutPoint_Y\":488.07641427863712},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{2.1531569701203352, -25.991399082341331}\",\"VNPrevPointForRadiusKey\":\"{2.1531569701203352, -25.991399082341331}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":48}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[48]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[48]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[48]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[48]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 0.34003453224391933]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[48]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 0.1954377384541317]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[48]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":54}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -20, -20]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[54]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[-1, -0, 0, 1, 692.07691397569363, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[54]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"KeepNodesAfterTransformTransformOptionKey\":true}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 57.024957634971202, 19.792602829855639]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[54]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":307.04977456552314,\"AnchorPoint_Y\":532.53992937509292,\"inPoint_Y\":504.20572036009486,\"OutPoint_X\":307.56037435287561,\"AnchorPoint_X\":307.56037435287561,\"OutPoint_Y\":532.53992937509292},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{612.89879937060209, -26.319474182895021}\",\"VNPrevPointForRadiusKey\":\"{612.89879937060209, -26.319474182895021}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":307.50714326421519,\"AnchorPoint_Y\":481.89895030845889,\"inPoint_Y\":481.89895030845889,\"OutPoint_X\":307.50714326421519,\"AnchorPoint_X\":307.50714326421519,\"OutPoint_Y\":481.89895030845889},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{630.6365492934068, -52.649609778091417}\",\"VNPrevPointForRadiusKey\":\"{630.6365492934068, -52.649609778091417}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":270.46662435287561,\"AnchorPoint_Y\":481.85242937509298,\"inPoint_Y\":481.85242937509298,\"OutPoint_X\":291.68464211968808,\"AnchorPoint_X\":270.46662435287561,\"OutPoint_Y\":491.96348695323337},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{615.05195634072243, -0.32807510055368994}\",\"VNPrevPointForRadiusKey\":\"{615.05195634072243, -0.32807510055368994}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":54}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":55}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":54},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":8}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":48},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":6}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setElements:","targetGID":55},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":48},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":54}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1.0330248439984473, -0, -0, 0.99999999999999989, -11.379876833051835, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[55]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":56}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":55},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":7}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":21},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":3}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":30},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":32},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":3}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":27},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":29},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":31},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setElements:","targetGID":56},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":27},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":29},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":30},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":21},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":31},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":32},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":55}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":57}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -290.115478515625, 62.302734375]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.042222879700741525,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.89467432944640213,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.042222879700741525,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.90097236067321962,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.031593452065677957,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.91739226661025597,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.019517801575741518,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.93616537665754818,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.0091232041181144082,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.94328004740819738,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.0018620895127118644,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.95006183205443251,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.95531556443573817,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9587083584477003,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.96669617604784863,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.96977202191904677,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.97283138648692502,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.97731792325435829,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9818318081185089,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9863455118694362,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.99094089768406901,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.99553628349870182,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":1,\"WDHueKey\":0.5806878306878307,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":0.10000000149011612}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":0.10000000149011612}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -138.240478515625, -358.288818359375]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":56},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":56}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 10.2197265625, 7.887451171875]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1.73681640625, -1.3956298828125]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":1,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.5806878306878307,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.5806878306878307,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.96954748896640086,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.96362693977790437,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.95841712343394081,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.954131593465262,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.93934857275056949,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.83357840083997725,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.80253639308086555,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.76741239856207288,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.7565612097807517,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.73508462058656032,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.69529915290432798,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.68285743522209563,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.66214385499715267,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.64970324957289294,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.63305608449601369,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.62061547907175396,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.60169597095671978,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.59555519468963558,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.5870419721668565,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.57588046341116172,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.56733832218109337,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.5457271497722096,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.51220146996013671,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.45939702270785876,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.41278562784738043,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.38011749893223234,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.35006206399487472,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.33336373505125283,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.31040673049544421,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.29577720138097952,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.27499243664578588,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.25639993237471526,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.24782776017938496,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.23669294561503418,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.22722206897779043,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.22344372864464693,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.21991675861332574,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.21874110193621868,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.2197966347522779,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.23113499252562641,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.24180488325740318,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.2529452591116173,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.28146132901480636,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.29042946504840544,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.29303437322038722,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.30319262528473806,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.31050016016514809,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.31284924900341687,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.31402379342255127,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.31192273811218679,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.31087054207004555,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.30975717183940776,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.3074892778331435,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1.0000066161593433, -0, -0, 1.0000066161593433, -0.00084115369224984499, -0.0015278888873493538]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 106.25150911801597, 215.10157288799655]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {1024, 1024}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {1018.1834573966, 1022.316502396953}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {1008.5644489681886, 1015.9218488910001}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {1003.3383988868811, 1012.188740268123}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {959.56182404754463, 968.37466824766148}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {930.99873639690077, 938.04865943448704}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {883.88375480634159, 898.86742705675647}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {851.39277451811745, 876.13749149913815}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {807.42735481491377, 847.80421878677203}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {780.8131139470363, 833.66058405713125}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {758.18676120653936, 823.6793880913026}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {745.42543866806363, 820.26800024929958}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {738.45307691385142, 820.26800024929958}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {738.07015268029545, 820.26800024929958}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {738.07015268029545, 820.65313908147255}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {735.7456294412641, 820.1359296408807}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {734.20024226104533, 819.105537302637}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {730.82720724054207, 815.73250228213374}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {722.51078545309133, 807.41391622785272}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {715.22999050970566, 800.13291995732015}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {710.02528110597814, 794.3195482564854}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {708.99086222479468, 792.76802059828378}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {705.03881032957679, 786.83843280185465}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {703.71729893680003, 785.04591654871797}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {702.86608775936838, 784.19455437592615}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {701.16326275021129, 782.49188036212945}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {700.77188277648224, 782.10024872946656}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {699.97704320020512, 781.30550981676288}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {699.12865060283116, 780.87985389626033}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {698.70304501411556, 780.45414764397106}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {695.54100084364723, 776.8204946317021}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {693.70127337454369, 774.98056583545167}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {691.86235121402819, 772.67134345959084}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {689.97672115541332, 769.84279770809485}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {689.03491276184081, 768.90119064166925}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {686.67817717929256, 766.07264489017348}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {683.90469440249581, 763.76603976722345}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {682.53607245732564, 762.86897633206718}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {681.17026909221318, 762.39756881741346}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {678.95083862390538, 761.54620664462163}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {676.30580256688177, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {675.07408308165805, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {673.28025820206608, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {671.48603066818009, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {670.54341696601955, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {669.17600298373122, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {667.39103649860635, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {666.44842279644581, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {666.02281720772999, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {665.226367014277, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {663.57830298909857, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.7291050831368, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.92701772956843, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.54691207607016, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.15190821369538, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.15190821369538, 760.69429082217562}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.15190821369538, 760.30406847954168}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.15190821369538, 759.91817467056762}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.15190821369538, 759.52795232793369}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.15190821369538, 759.12605301077474}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.15190821369538, 758.73814593033103}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.15190821369538, 758.35446671997374}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.55134127330371, 758.35446671997374}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.55134127330371, 757.96107347477482}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.55134127330371, 757.57593464260208}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.97694686201953, 757.57593464260208}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.3896675133285, 757.18274272455005}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.3896675133285, 756.35493582795493}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 755.94518475206382}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 755.5517915068649}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 754.78614436689986}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 754.3960730196261}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 754.00237778370661}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 753.60918586565458}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 753.21065877820774}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 752.81701387407497}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 752.41430924832821}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 749.69714774089903}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 748.93285955917622}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 747.99004452986878}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 747.13868235707696}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.41906127678772, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.65522608114543, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.27149653900142, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {660.88132452815421, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {660.48793128295529, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {659.69429966956, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {659.30453031300658, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {659.68503862079888, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {660.0695734715307, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {660.47263041978476, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {660.86843959074758, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.25498771294906, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.63670398362319, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.02566803158879, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.83158060094979, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {664.08383545516563, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {665.7862578100287, 746.7378903392264}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {667.06307457617595, 747.16359659151567}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {669.70851328749336, 748.01490843252077}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {670.98533005364084, 748.44061468481004}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {672.66399580516031, 748.84437627807847}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {673.94081257130756, 749.26907589463281}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {675.19387273411121, 749.69478214692208}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {675.58525270784025, 749.69478214692208}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {675.20474440004818, 749.69478214692208}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {673.93235683113426, 749.26907589463281}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {672.1381292972485, 747.52296554887494}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {670.87500277709569, 747.09725929658589}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {670.47194582884163, 746.2471050866759}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {669.64368594616599, 745.41864387685314}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {669.24787677520317, 745.02308636482417}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {669.24787677520317, 744.6337699943515}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":287.2857717617394,\"AnchorPoint_Y\":289.25600703483042,\"inPoint_Y\":289.25600703483042,\"OutPoint_X\":287.2857717617394,\"AnchorPoint_X\":287.2857717617394,\"OutPoint_Y\":289.25600703483042},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{59.351577569932488, -881.2368652940595}\",\"VNPrevPointForRadiusKey\":\"{59.351577569932488, -881.2368652940595}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":437.28477645924727,\"AnchorPoint_Y\":289.25600703483042,\"inPoint_Y\":289.25600703483042,\"OutPoint_X\":437.28477645924727,\"AnchorPoint_X\":437.28477645924727,\"OutPoint_Y\":289.25600703483042},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{59.351577569932488, -881.2368652940595}\",\"VNPrevPointForRadiusKey\":\"{59.351577569932488, -881.2368652940595}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":437.28477645924727,\"AnchorPoint_Y\":539.25435579077384,\"inPoint_Y\":539.25435579077384,\"OutPoint_X\":437.28477645924727,\"AnchorPoint_X\":437.28477645924727,\"OutPoint_Y\":539.25435579077384},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{59.351577569932488, -881.2368652940595}\",\"VNPrevPointForRadiusKey\":\"{59.351577569932488, -881.2368652940595}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":287.2857717617394,\"AnchorPoint_Y\":539.25435579077384,\"inPoint_Y\":539.25435579077384,\"OutPoint_X\":287.2857717617394,\"AnchorPoint_X\":287.2857717617394,\"OutPoint_Y\":539.25435579077384},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{59.351577569932488, -881.2368652940595}\",\"VNPrevPointForRadiusKey\":\"{59.351577569932488, -881.2368652940595}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":287.2857717617394,\"AnchorPoint_Y\":289.25602785985438,\"inPoint_Y\":330.67709661876142,\"OutPoint_X\":287.2857717617394,\"AnchorPoint_X\":287.2857717617394,\"OutPoint_Y\":247.83495910094825},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-173.55249370630804, -465.50590420624349}\",\"VNPrevPointForRadiusKey\":\"{-173.55249370630804, -465.50590420624349}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":320.86422761918971,\"AnchorPoint_Y\":214.25650324349817,\"inPoint_Y\":214.25650324349817,\"OutPoint_X\":403.70636513700288,\"AnchorPoint_X\":362.28529637809629,\"OutPoint_Y\":214.25650324349817},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-173.55249370630804, -465.50590420624349}\",\"VNPrevPointForRadiusKey\":\"{-173.55249370630804, -465.50590420624349}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":437.28477402925387,\"AnchorPoint_Y\":289.25602785985438,\"inPoint_Y\":247.83495910094825,\"OutPoint_X\":437.28477402925387,\"AnchorPoint_X\":437.28477402925387,\"OutPoint_Y\":330.67709661876142},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-173.55249370630804, -465.50590420624349}\",\"VNPrevPointForRadiusKey\":\"{-173.55249370630804, -465.50590420624349}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":403.70636513700288,\"AnchorPoint_Y\":364.25550551101242,\"inPoint_Y\":364.25550551101242,\"OutPoint_X\":320.86422761918971,\"AnchorPoint_X\":362.28529637809629,\"OutPoint_Y\":364.25550551101242},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-173.55249370630804, -465.50590420624349}\",\"VNPrevPointForRadiusKey\":\"{-173.55249370630804, -465.50590420624349}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":287.2857717617394,\"AnchorPoint_Y\":539.25437383096278,\"inPoint_Y\":580.67544258986891,\"OutPoint_X\":287.2857717617394,\"AnchorPoint_X\":287.2857717617394,\"OutPoint_Y\":497.83330507205574},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-173.55249370630804, -215.50755823513555}\",\"VNPrevPointForRadiusKey\":\"{-173.55249370630804, -215.50755823513555}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":320.86422761918971,\"AnchorPoint_Y\":464.25484921460566,\"inPoint_Y\":464.25484921460566,\"OutPoint_X\":403.70636513700288,\"AnchorPoint_X\":362.28529637809629,\"OutPoint_Y\":464.25484921460566},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-173.55249370630804, -215.50755823513555}\",\"VNPrevPointForRadiusKey\":\"{-173.55249370630804, -215.50755823513555}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":437.28477402925387,\"AnchorPoint_Y\":539.25437383096278,\"inPoint_Y\":497.83330507205574,\"OutPoint_X\":437.28477402925387,\"AnchorPoint_X\":437.28477402925387,\"OutPoint_Y\":580.67544258986891},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-173.55249370630804, -215.50755823513555}\",\"VNPrevPointForRadiusKey\":\"{-173.55249370630804, -215.50755823513555}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":403.70636513700288,\"AnchorPoint_Y\":614.2538514821199,\"inPoint_Y\":614.2538514821199,\"OutPoint_X\":320.86422761918971,\"AnchorPoint_X\":362.28529637809629,\"OutPoint_Y\":614.2538514821199},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-173.55249370630804, -215.50755823513555}\",\"VNPrevPointForRadiusKey\":\"{-173.55249370630804, -215.50755823513555}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":297.2857056005837,\"AnchorPoint_Y\":289.07321462503751,\"inPoint_Y\":289.07321462503751,\"OutPoint_X\":297.2857056005837,\"AnchorPoint_X\":297.2857056005837,\"OutPoint_Y\":289.07321462503751},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{99.742735489559436, -881.41965770385173}\",\"VNPrevPointForRadiusKey\":\"{99.742735489559436, -881.41965770385173}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":427.28484419717574,\"AnchorPoint_Y\":289.07321462503751,\"inPoint_Y\":289.07321462503751,\"OutPoint_X\":427.28484419717574,\"AnchorPoint_X\":427.28484419717574,\"OutPoint_Y\":289.07321462503751},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{99.742735489559436, -881.41965770385173}\",\"VNPrevPointForRadiusKey\":\"{99.742735489559436, -881.41965770385173}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":427.28484419717574,\"AnchorPoint_Y\":539.07156338098093,\"inPoint_Y\":539.07156338098093,\"OutPoint_X\":427.28484419717574,\"AnchorPoint_X\":427.28484419717574,\"OutPoint_Y\":539.07156338098093},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{99.742735489559436, -881.41965770385173}\",\"VNPrevPointForRadiusKey\":\"{99.742735489559436, -881.41965770385173}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":297.2857056005837,\"AnchorPoint_Y\":539.07156338098093,\"inPoint_Y\":539.07156338098093,\"OutPoint_X\":297.2857056005837,\"AnchorPoint_X\":297.2857056005837,\"OutPoint_Y\":539.07156338098093},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{99.742735489559436, -881.41965770385173}\",\"VNPrevPointForRadiusKey\":\"{99.742735489559436, -881.41965770385173}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":97.57351080287799,\"AnchorPoint_Y\":309.16721333385931,\"inPoint_Y\":309.16721333385931,\"OutPoint_X\":97.57351080287799,\"AnchorPoint_X\":97.57351080287799,\"OutPoint_Y\":309.16721333385931},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{78.505876495528582, 146.69454513811797}\",\"VNPrevPointForRadiusKey\":\"{78.505876495528582, 146.69454513811797}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":221.36797043606543,\"AnchorPoint_Y\":443.90288627635027,\"inPoint_Y\":443.90288627635027,\"OutPoint_X\":221.36797043606543,\"AnchorPoint_X\":221.36797043606543,\"OutPoint_Y\":443.90288627635027},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{78.505876495528582, 146.69454513811797}\",\"VNPrevPointForRadiusKey\":\"{78.505876495528582, 146.69454513811797}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":361.08361414401247,\"AnchorPoint_Y\":309.6035637643763,\"inPoint_Y\":309.6035637643763,\"OutPoint_X\":361.08361414401247,\"AnchorPoint_X\":361.08361414401247,\"OutPoint_Y\":309.6035637643763},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{78.505876495528582, 146.69454513811797}\",\"VNPrevPointForRadiusKey\":\"{78.505876495528582, 146.69454513811797}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":29},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":377.82365759764593,\"AnchorPoint_Y\":307.07623767819223,\"inPoint_Y\":307.07623767819223,\"OutPoint_X\":377.82365759764593,\"AnchorPoint_X\":377.82365759764593,\"OutPoint_Y\":307.07623767819223},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{358.49705139509047, 146.65290478922907}\",\"VNPrevPointForRadiusKey\":\"{358.49705139509047, 146.65290478922907}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":503.2994629767461,\"AnchorPoint_Y\":440.11243356580462,\"inPoint_Y\":440.11243356580462,\"OutPoint_X\":503.2994629767461,\"AnchorPoint_X\":503.2994629767461,\"OutPoint_Y\":440.11243356580462},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{358.49705139509047, 146.65290478922907}\",\"VNPrevPointForRadiusKey\":\"{358.49705139509047, 146.65290478922907}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":644.91269001662772,\"AnchorPoint_Y\":307.50708423933065,\"inPoint_Y\":307.50708423933065,\"OutPoint_X\":644.91269001662772,\"AnchorPoint_X\":644.91269001662772,\"OutPoint_Y\":307.50708423933065},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{358.49705139509047, 146.65290478922907}\",\"VNPrevPointForRadiusKey\":\"{358.49705139509047, 146.65290478922907}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":30},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":516.45695350382334,\"AnchorPoint_Y\":154.80813254227905,\"inPoint_Y\":154.80813254227905,\"OutPoint_X\":516.45695350382334,\"AnchorPoint_X\":516.45695350382334,\"OutPoint_Y\":154.80813254227905},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{1033.732755685123, -115.61701281386331}\",\"VNPrevPointForRadiusKey\":\"{1033.732755685123, -115.61701281386331}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":223.97172601151692,\"AnchorPoint_Y\":448.88181029919406,\"inPoint_Y\":448.88181029919406,\"OutPoint_X\":223.97172601151692,\"AnchorPoint_X\":223.97172601151692,\"OutPoint_Y\":448.88181029919406},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{1033.732755685123, -115.61701281386331}\",\"VNPrevPointForRadiusKey\":\"{1033.732755685123, -115.61701281386331}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":78.252109034647219,\"AnchorPoint_Y\":300.1041732651538,\"inPoint_Y\":300.1041732651538,\"OutPoint_X\":78.252109034647219,\"AnchorPoint_X\":78.252109034647219,\"OutPoint_Y\":300.1041732651538},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{1033.732755685123, -115.61701281386331}\",\"VNPrevPointForRadiusKey\":\"{1033.732755685123, -115.61701281386331}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":648.07861404640448,\"AnchorPoint_Y\":302.9355554780409,\"inPoint_Y\":302.9355554780409,\"OutPoint_X\":648.07861404640448,\"AnchorPoint_X\":648.07861404640448,\"OutPoint_Y\":302.9355554780409},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{1033.732755685123, -115.61701281386331}\",\"VNPrevPointForRadiusKey\":\"{1033.732755685123, -115.61701281386331}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":506.17105679039673,\"AnchorPoint_Y\":444.7847840681311,\"inPoint_Y\":444.7847840681311,\"OutPoint_X\":506.17105679039673,\"AnchorPoint_X\":506.17105679039673,\"OutPoint_Y\":444.7847840681311},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{1033.732755685123, -115.61701281386331}\",\"VNPrevPointForRadiusKey\":\"{1033.732755685123, -115.61701281386331}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":217.51314851045686,\"AnchorPoint_Y\":156.11368443580113,\"inPoint_Y\":156.11368443580113,\"OutPoint_X\":217.51314851045686,\"AnchorPoint_X\":217.51314851045686,\"OutPoint_Y\":156.11368443580113},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{1033.732755685123, -115.61701281386331}\",\"VNPrevPointForRadiusKey\":\"{1033.732755685123, -115.61701281386331}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":21},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":290.26965144695237,\"AnchorPoint_Y\":418.73751961026619,\"inPoint_Y\":418.73751961026619,\"OutPoint_X\":290.26965144695237,\"AnchorPoint_X\":290.26965144695237,\"OutPoint_Y\":418.73751961026619},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{78.505876495528582, 146.69454513811797}\",\"VNPrevPointForRadiusKey\":\"{78.505876495528582, 146.69454513811797}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":433.31216208615911,\"AnchorPoint_Y\":418.73751961026619,\"inPoint_Y\":418.73751961026619,\"OutPoint_X\":433.31216208615911,\"AnchorPoint_X\":433.31216208615911,\"OutPoint_Y\":418.73751961026619},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{78.505876495528582, 146.69454513811797}\",\"VNPrevPointForRadiusKey\":\"{78.505876495528582, 146.69454513811797}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":31},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":290.26965144695237,\"AnchorPoint_Y\":521.73683815036247,\"inPoint_Y\":521.73683815036247,\"OutPoint_X\":290.26965144695237,\"AnchorPoint_X\":290.26965144695237,\"OutPoint_Y\":521.73683815036247},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{78.505876495528582, 249.69386367821471}\",\"VNPrevPointForRadiusKey\":\"{78.505876495528582, 249.69386367821471}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":433.31216208615911,\"AnchorPoint_Y\":521.73683815036247,\"inPoint_Y\":521.73683815036247,\"OutPoint_X\":433.31216208615911,\"AnchorPoint_X\":433.31216208615911,\"OutPoint_Y\":521.73683815036247},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{78.505876495528582, 249.69386367821471}\",\"VNPrevPointForRadiusKey\":\"{78.505876495528582, 249.69386367821471}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":32},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":362.67570746371234,\"AnchorPoint_Y\":667.02363476289884,\"inPoint_Y\":638.68961321030247,\"OutPoint_X\":362.18143434711533,\"AnchorPoint_X\":362.18143434711533,\"OutPoint_Y\":667.02363476289884},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{66.606350517013652, 108.16792868331186}\",\"VNPrevPointForRadiusKey\":\"{66.606350517013652, 108.16792868331186}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":362.23296334642896,\"AnchorPoint_Y\":616.38299074283532,\"inPoint_Y\":616.38299074283532,\"OutPoint_X\":362.23296334642896,\"AnchorPoint_X\":362.23296334642896,\"OutPoint_Y\":616.38299074283532},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{49.435773574115046, 81.837967291336099}\",\"VNPrevPointForRadiusKey\":\"{49.435773574115046, 81.837967291336099}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":398.08909406988482,\"AnchorPoint_Y\":616.33647011725679,\"inPoint_Y\":616.33647011725679,\"OutPoint_X\":377.54953250055337,\"AnchorPoint_X\":398.08909406988482,\"OutPoint_Y\":626.44746079947163},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{64.522041763846801, 134.1591558035534}\",\"VNPrevPointForRadiusKey\":\"{64.522041763846801, 134.1591558035534}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":48},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":361.7537539269963,\"AnchorPoint_Y\":667.02363476289884,\"inPoint_Y\":638.68961321030247,\"OutPoint_X\":362.24802704359331,\"AnchorPoint_X\":362.24802704359331,\"OutPoint_Y\":667.02363476289884},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{657.82311087369476, 108.16792868331186}\",\"VNPrevPointForRadiusKey\":\"{657.82311087369476, 108.16792868331186}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":362.19649804427968,\"AnchorPoint_Y\":616.38299074283532,\"inPoint_Y\":616.38299074283532,\"OutPoint_X\":362.19649804427968,\"AnchorPoint_X\":362.19649804427968,\"OutPoint_Y\":616.38299074283532},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{674.99368781659336, 81.837967291336099}\",\"VNPrevPointForRadiusKey\":\"{674.99368781659336, 81.837967291336099}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":326.34036732082382,\"AnchorPoint_Y\":616.33647011725679,\"inPoint_Y\":616.33647011725679,\"OutPoint_X\":346.87992889015482,\"AnchorPoint_X\":326.34036732082382,\"OutPoint_Y\":626.44746079947163},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{659.90741962686184, 134.1591558035534}\",\"VNPrevPointForRadiusKey\":\"{659.90741962686184, 134.1591558035534}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":54}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":\"Mac App icon\"}","argumentGID":0}],"methodSignature":"title","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {740, 744.6337699943515}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {745, 744.6337699943515}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}]],"isGroupingUndo":false,"currentUndoGroup":[],"currentRedoGroup":[],"isGroupingRedo":false,"redoStack":[],"nextGID":57} \ No newline at end of file
+{"cacheElements":[{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"fillColor":{"b":0.98823529481887817,"s":1,"h":0.58068782582120682,"a":1},"maskedElements":[],"abstractPath":{"fillRule":0,"compoundPathData":{"subpaths":[{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[-17.790763092914176,455.94130474918654],"reflectionModeOverride":0,"anchorPoint":[-17.790763092914176,455.94130474918654],"cornerRadius":0,"prevPoint":[-343.22817622315347,103.6410041510419],"inPoint":[-17.790763092914176,455.94130474918654],"nextPoint":[-343.22817622315347,103.6410041510419]},{"outPoint":[-118.14742861878335,355.38893101990755],"reflectionModeOverride":0,"anchorPoint":[-118.14742861878335,355.38893101990755],"cornerRadius":0,"prevPoint":[-343.22817622315347,103.6410041510419],"inPoint":[-118.14742861878335,355.38893101990755],"nextPoint":[-343.22817622315347,103.6410041510419]},{"outPoint":[-89.082653539453304,326.03057263672883],"reflectionModeOverride":0,"anchorPoint":[-89.082653539453304,326.03057263672883],"cornerRadius":0,"prevPoint":[-343.22817622315347,103.6410041510419],"inPoint":[-89.082653539453304,326.03057263672883],"nextPoint":[-343.22817622315347,103.6410041510419]},{"outPoint":[-9.0811227455444623,406.22781863362536],"reflectionModeOverride":0,"anchorPoint":[-9.0811227455444623,406.22781863362536],"cornerRadius":0,"prevPoint":[-343.22817622315347,103.6410041510419],"inPoint":[-9.0811227455444623,406.22781863362536],"nextPoint":[-343.22817622315347,103.6410041510419]},{"outPoint":[-9.0811227455444623,214.66453204993843],"reflectionModeOverride":0,"anchorPoint":[-9.0811227455444623,214.66453204993843],"cornerRadius":0,"prevPoint":[-343.22817622315347,103.6410041510419],"inPoint":[-9.0811227455444623,214.66453204993843],"nextPoint":[-343.22817622315347,103.6410041510419]},{"outPoint":[136.29167736876548,359.98840044701058],"reflectionModeOverride":0,"anchorPoint":[136.29167736876548,359.98840044701058],"cornerRadius":0,"prevPoint":[-343.22817622315347,103.6410041510419],"inPoint":[136.29167736876548,359.98840044701058],"nextPoint":[-343.22817622315347,103.6410041510419]},{"outPoint":[40.289832016581158,455.94130474918654],"reflectionModeOverride":0,"anchorPoint":[40.289832016581158,455.94130474918654],"cornerRadius":0,"prevPoint":[-343.22817622315347,103.6410041510419],"inPoint":[40.289832016581158,455.94130474918654],"nextPoint":[-343.22817622315347,103.6410041510419]},{"outPoint":[136.29167736876548,551.89420905136228],"reflectionModeOverride":0,"anchorPoint":[136.29167736876548,551.89420905136228],"cornerRadius":0,"prevPoint":[-343.22817622315347,103.6410041510419],"inPoint":[136.29167736876548,551.89420905136228],"nextPoint":[-343.22817622315347,103.6410041510419]},{"outPoint":[-9.0322003610774573,697.21808678120522],"reflectionModeOverride":0,"anchorPoint":[-9.0322003610774573,697.21808678120522],"cornerRadius":0,"prevPoint":[-343.22817622315347,103.6410041510419],"inPoint":[-9.0322003610774573,697.21808678120522],"nextPoint":[-343.22817622315347,103.6410041510419]},{"outPoint":[-9.0322003610774573,505.65480953028907],"reflectionModeOverride":0,"anchorPoint":[-9.0322003610774573,505.65480953028907],"cornerRadius":0,"prevPoint":[-343.22817622315347,103.6410041510419],"inPoint":[-9.0322003610774573,505.65480953028907],"nextPoint":[-343.22817622315347,103.6410041510419]},{"outPoint":[-88.78907023560464,585.60738760822585],"reflectionModeOverride":0,"anchorPoint":[-88.78907023560464,585.60738760822585],"cornerRadius":0,"prevPoint":[-343.22817622315347,103.6410041510419],"inPoint":[-88.78907023560464,585.60738760822585],"nextPoint":[-343.22817622315347,103.6410041510419]},{"outPoint":[-117.85384531493469,556.24902922504714],"reflectionModeOverride":0,"anchorPoint":[-117.85384531493469,556.24902922504714],"cornerRadius":0,"prevPoint":[-343.22817622315347,103.6410041510419],"inPoint":[-117.85384531493469,556.24902922504714],"nextPoint":[-343.22817622315347,103.6410041510419]}],"closed":true,"reversed":false}},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[-343.22817622315347,103.6410041510419],"opacity":1,"blur":0,"isLocked":false,"gid":13,"smootheningRate":0,"initialPoint":[-343.22817622315347,103.6410041510419],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[-87.50742636811205,292.97453151588081],"reflectionModeOverride":0,"anchorPoint":[-87.50742636811205,292.97453151588081],"cornerRadius":0,"prevPoint":[-164.14742861878338,191.97453151588081],"inPoint":[-87.50742636811205,292.97453151588081],"nextPoint":[-164.14742861878338,191.97453151588081]},{"outPoint":[-78.027426825875665,283.48453174476265],"reflectionModeOverride":0,"anchorPoint":[-78.027426825875665,283.48453174476265],"cornerRadius":0,"prevPoint":[-164.14742861878338,191.97453151588081],"inPoint":[-78.027426825875665,283.48453174476265],"nextPoint":[-164.14742861878338,191.97453151588081]},{"outPoint":[-87.507426368111936,274.01453147773384],"reflectionModeOverride":0,"anchorPoint":[-87.507426368111936,274.01453147773384],"cornerRadius":0,"prevPoint":[-164.14742861878338,191.97453151588081],"inPoint":[-87.507426368111936,274.01453147773384],"nextPoint":[-164.14742861878338,191.97453151588081]}],"closed":true,"reversed":false}},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[-164.14742861878338,191.97453151588081],"opacity":1,"blur":0,"isLocked":false,"gid":14,"smootheningRate":0,"initialPoint":[-164.14742861878338,191.97453151588081],"creationPoints":[],"name":"(curve)"}]}}},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[-164.14742861878338,191.97453151588078],"opacity":1,"blur":0,"isLocked":false,"gid":11,"smootheningRate":0,"initialPoint":[-164.14742861878338,191.97453151588078],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[340,700],"reflectionModeOverride":0,"anchorPoint":[340,660],"cornerRadius":0,"prevPoint":[0,0],"inPoint":[340,620],"nextPoint":[0,0]},{"outPoint":[340,600],"reflectionModeOverride":0,"anchorPoint":[380,600],"cornerRadius":0,"prevPoint":[0,0],"inPoint":[420,600],"nextPoint":[0,0]}],"closed":false,"reversed":false}},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":2,"width":0.10000000149011612,"endArrow":"","startArrow":"","cap":1},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[0,0],"opacity":1,"blur":0,"isLocked":false,"gid":35,"smootheningRate":0,"initialPoint":[0,0],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"fillColor":{"b":0.98823529481887817,"s":1,"h":0.58068782582120682,"a":1},"maskedElements":[],"abstractPath":{"fillRule":0,"compoundPathData":{"subpaths":[{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[221.67257107604084,316.56452785377144],"reflectionModeOverride":0,"anchorPoint":[221.67257107604084,316.56452785377144],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[221.67257107604084,316.56452785377144],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[222.78002147975192,316.58196755365179],"reflectionModeOverride":0,"anchorPoint":[222.50257105935154,316.56452785377144],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[222.50257105935154,316.56452785377144],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[223.46754319256974,316.15798118973765],"reflectionModeOverride":0,"anchorPoint":[223.27257099819641,316.3245278149393],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[223.05416436926282,316.49652037792839],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[223.56257095468965,315.05452779244973],"reflectionModeOverride":0,"anchorPoint":[223.56257095468965,315.65452781629159],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[223.57458948209043,315.9106673969701],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[222.50257101191011,314.72452780913903],"reflectionModeOverride":0,"anchorPoint":[222.50257101191011,314.72452780913903],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[223.18257095945802,314.72452780913903],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[221.67257102859941,314.72452780913903],"reflectionModeOverride":0,"anchorPoint":[221.67257102859941,314.72452780913903],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[221.67257102859941,314.72452780913903],"nextPoint":[112.85257138121662,191.97453151588078]}],"closed":true,"reversed":false}},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[112.85257138121662,191.97453151588078],"opacity":1,"blur":0,"isLocked":false,"gid":7,"smootheningRate":0,"initialPoint":[112.85257138121662,191.97453151588078],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[223.39257110465107,318.92452774886726],"reflectionModeOverride":0,"anchorPoint":[223.39257110465107,318.92452774886726],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[223.39257110465107,318.92452774886726],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[222.33257116187153,317.04452775363563],"reflectionModeOverride":0,"anchorPoint":[222.33257116187153,317.04452775363563],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[222.33257116187153,317.04452775363563],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[221.67257113564548,317.04452775363563],"reflectionModeOverride":0,"anchorPoint":[221.67257113564548,317.04452775363563],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[221.67257113564548,317.04452775363563],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[221.67257113564548,318.97453151588081],"reflectionModeOverride":0,"anchorPoint":[221.67257113564548,318.97453151588081],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[221.67257113564548,318.97453151588081],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[221.06257112134037,318.97453151588081],"reflectionModeOverride":0,"anchorPoint":[221.06257112134037,318.97453151588081],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[221.06257112134037,318.97453151588081],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[221.06257112134037,314.29453168754219],"reflectionModeOverride":0,"anchorPoint":[221.06257112134037,314.29453168754219],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[221.06257112134037,314.29453168754219],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[222.85351610118363,314.2910670771638],"reflectionModeOverride":0,"anchorPoint":[222.64257116425571,314.29453168754219],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[222.64257116425571,314.29453168754219],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[223.44257068590508,314.46434348341825],"reflectionModeOverride":0,"anchorPoint":[223.26257121864279,314.39453162176318],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[223.06341253016012,314.32492145971571],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[223.8867055322342,314.82297152263595],"reflectionModeOverride":0,"anchorPoint":[223.75257125112995,314.69453165532451],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[223.60854628757448,314.56596123813961],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[224.15455094852729,315.31612333025106],"reflectionModeOverride":0,"anchorPoint":[224.07257117822328,315.14453165999419],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[223.99528738469252,314.97566482247669],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[224.19825083117667,315.9922372888982],"reflectionModeOverride":0,"anchorPoint":[224.19257122020886,315.69453168706491],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[224.19562660185056,315.50438689028209],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[223.7338072115908,316.75555373263109],"reflectionModeOverride":0,"anchorPoint":[223.91257119347284,316.51453168318102],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[224.09914577717603,316.28247388344346],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[223.19257120773227,317.01453168185151],"reflectionModeOverride":0,"anchorPoint":[223.19257120773227,317.01453168185151],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[223.48085346525613,316.9312160768892],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[222.99257120475204,317.08453168214953],"reflectionModeOverride":0,"anchorPoint":[222.99257120475204,317.08453168214953],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[222.99257120475204,317.08453168214953],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[224.0925712285939,318.97453166784442],"reflectionModeOverride":0,"anchorPoint":[224.0925712285939,318.97453166784442],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[224.0925712285939,318.97453166784442],"nextPoint":[112.85257138121662,191.97453151588078]}],"closed":true,"reversed":false}},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[112.85257138121662,191.97453151588078],"opacity":1,"blur":0,"isLocked":false,"gid":8,"smootheningRate":0,"initialPoint":[112.85257138121662,191.97453151588078],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[221.88165496610824,312.75214941635204],"reflectionModeOverride":0,"anchorPoint":[222.39257110465107,312.75452767257332],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[222.39257110465107,312.75452767257332],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[220.45378029794426,313.23854645592189],"reflectionModeOverride":0,"anchorPoint":[220.90257124445034,313.04452773196982],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[221.37529974656684,312.85070177480884],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[219.35876943156495,314.2208600575953],"reflectionModeOverride":0,"anchorPoint":[219.70257152159786,313.86452769906913],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[220.04640821090715,313.51691728007791],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[218.51848057480817,316.05954140545026],"reflectionModeOverride":0,"anchorPoint":[218.89257170245423,315.09452765536599],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[219.0841152815558,314.63792794299417],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[219.07885049250976,318.55391401613247],"reflectionModeOverride":0,"anchorPoint":[218.89257166857527,318.09452771720584],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[218.51848023468915,317.12951359608263],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[220.04640881460426,319.67213836278347],"reflectionModeOverride":0,"anchorPoint":[219.70257171508007,319.32452783266035],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[219.35412998721458,318.97193143333453],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[222.32887552639454,320.75534631866788],"reflectionModeOverride":0,"anchorPoint":[220.90257185775954,320.14452762388811],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[220.45378073087409,319.9505090873252],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[225.42747093525361,318.97720769048311],"reflectionModeOverride":0,"anchorPoint":[225.07257197531021,319.32452740981233],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[223.98375014972524,320.42992729161517],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[226.25666363710593,317.12951355179308],"reflectionModeOverride":0,"anchorPoint":[225.8825720147413,318.09452742555698],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[225.70369149262439,318.55776181404121],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[225.69870344883279,314.63387871118448],"reflectionModeOverride":0,"anchorPoint":[225.88257204862026,315.09452736371713],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[226.25666342066654,316.05954129932087],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[224.73054756988128,313.51475021332715],"reflectionModeOverride":0,"anchorPoint":[225.07257201185996,313.86452742080394],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[225.42312528062655,314.21540813724465],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[223.40302999066401,312.851739523118],"reflectionModeOverride":0,"anchorPoint":[223.87257194075443,313.04452740721484],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[224.32272320141846,313.23607014436448],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[222.39257194847221,312.754527354262],"reflectionModeOverride":0,"anchorPoint":[222.39257194847221,312.754527354262],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[222.90014945704277,312.7532021443493],"nextPoint":[112.85257138121662,191.97453151588078]}],"closed":false,"reversed":false}},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[112.85257138121662,191.97453151588078],"opacity":1,"blur":0,"isLocked":false,"gid":9,"smootheningRate":0,"initialPoint":[112.85257138121662,191.97453151588078],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[221.79793545229796,321.06845412941806],"reflectionModeOverride":0,"anchorPoint":[222.39257194847221,321.06452777387869],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[222.39257194847221,321.06452777387869],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[220.13630955687603,320.47368746402753],"reflectionModeOverride":0,"anchorPoint":[220.66257205810552,320.71452796827054],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[221.20891937561655,320.94928924957026],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[218.84008207185138,319.31458146286332],"reflectionModeOverride":0,"anchorPoint":[219.26257159607349,319.71452784560978],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[219.66107353858615,320.13423302542299],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[217.79637500761001,317.20177600727493],"reflectionModeOverride":0,"anchorPoint":[218.26257166453621,318.30452834140976],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[218.50031051375157,318.83550383670706],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[218.71657507260346,313.79480682341318],"reflectionModeOverride":0,"anchorPoint":[218.26257150938892,314.85452883246262],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[217.79637484257967,315.95728089190948],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[221.15964890699888,312.25319776201661],"reflectionModeOverride":0,"anchorPoint":[220.61257125382446,312.48452913388269],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[219.5567350056233,312.94749659064405],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[222.93948006388655,312.14028017121217],"reflectionModeOverride":0,"anchorPoint":[222.34257146546875,312.14452894709979],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[221.74863705025209,312.1374427227563],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[224.61118094730551,312.72639164873863],"reflectionModeOverride":0,"anchorPoint":[224.08257153232208,312.48452915920495],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[223.53116831317226,312.25589748063879],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[225.90916737355408,313.88955714821628],"reflectionModeOverride":0,"anchorPoint":[225.49257153005306,313.48452928232075],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[225.08951592668194,313.06563634089633],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[226.95876793869749,315.99728178436908],"reflectionModeOverride":0,"anchorPoint":[226.49257128177129,314.89452945023424],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[226.24808810980261,314.36743571685838],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[226.25070868333646,318.87313890226199],"reflectionModeOverride":0,"anchorPoint":[226.49257117287002,318.34452948727852],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[226.95876813673391,317.24177716378313],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[224.65955409863321,320.59420064219239],"reflectionModeOverride":0,"anchorPoint":[225.49257104975428,319.75452948500953],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[225.91146402567489,319.35147381264608],"nextPoint":[112.85257138121662,191.97453151588078]},{"outPoint":[222.34257072457945,321.06452950412722],"reflectionModeOverride":0,"anchorPoint":[222.34257072457945,321.06452950412722],"cornerRadius":0,"prevPoint":[112.85257138121662,191.97453151588078],"inPoint":[223.52534831488276,321.06588609892162],"nextPoint":[112.85257138121662,191.97453151588078]}],"closed":false,"reversed":false}},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[112.85257138121662,191.97453151588078],"opacity":1,"blur":0,"isLocked":false,"gid":10,"smootheningRate":0,"initialPoint":[112.85257138121662,191.97453151588078],"creationPoints":[],"name":"(curve)"}]}}},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[112.85257138121662,191.97453151588078],"opacity":1,"blur":0,"isLocked":false,"gid":6,"smootheningRate":0,"initialPoint":[112.85257138121662,191.97453151588078],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[292.2196979967656,487.32457590003901],"reflectionModeOverride":0,"anchorPoint":[270.70254252087443,481.42866614307741],"cornerRadius":0,"prevPoint":[0,1.3634276556741725],"inPoint":[246.45876716860445,474.78563603599895],"nextPoint":[0,1.3634276556741725]},{"outPoint":[308.32019835237998,560.47255779544446],"reflectionModeOverride":0,"anchorPoint":[307.80961189523731,532.13830093176216],"cornerRadius":0,"prevPoint":[9.9345758586960642,16.47175369678871],"inPoint":[307.29902543809465,503.80404406807986],"nextPoint":[9.9345758586960642,16.47175369678871]}],"closed":false,"reversed":false}},"fillColor":{"b":0.9882352941176471,"s":1,"h":0.13822251558303833,"a":1},"strokeStyle":{"color":{"b":0.9882352941176471,"s":1,"h":0.5806878306878307,"a":1},"dashPattern":[],"join":1,"width":0.10000000149011612,"endArrow":"","startArrow":"","cap":0},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[9.9345758586960642,15.108326041114537],"opacity":1,"blur":0,"isLocked":false,"gid":44,"smootheningRate":0,"initialPoint":[9.9345758586960642,15.108326041114537],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[345.33038784778722,480.48121812716067],"reflectionModeOverride":0,"anchorPoint":[345.33038784778722,480.48121812716067],"cornerRadius":0,"prevPoint":[86.563617484933189,-170.37985441312253],"inPoint":[308.36370636737951,480.48121812716067],"nextPoint":[86.563617484933189,-170.37985441312253]},{"outPoint":[271.39702488697174,480.48121812716067],"reflectionModeOverride":0,"anchorPoint":[271.39702488697174,480.48121812716067],"cornerRadius":0,"prevPoint":[86.563617484933189,-170.37985441312253],"inPoint":[271.39702488697174,480.48121812716067],"nextPoint":[86.563617484933189,-170.37985441312253]},{"outPoint":[345.33038784778722,480.48121812716067],"reflectionModeOverride":0,"anchorPoint":[345.33038784778722,480.48121812716067],"cornerRadius":0,"prevPoint":[86.563617484933189,-170.37985441312253],"inPoint":[345.33038784778722,480.48121812716067],"nextPoint":[86.563617484933189,-170.37985441312253]},{"outPoint":[308.36370636737951,480.48121812716067],"reflectionModeOverride":0,"anchorPoint":[271.39702488697174,480.48121812716067],"cornerRadius":0,"prevPoint":[86.563617484933189,-170.37985441312253],"inPoint":[271.39702488697174,480.48121812716067],"nextPoint":[86.563617484933189,-170.37985441312253]},{"outPoint":[308.36370636737951,547.81167390718997],"reflectionModeOverride":0,"anchorPoint":[308.36370636737951,547.81167390718997],"cornerRadius":0,"prevPoint":[86.563617484933189,-170.37985441312253],"inPoint":[308.36370636737951,547.81167390718997],"nextPoint":[86.563617484933189,-170.37985441312253]}],"closed":true,"reversed":true}},"fillColor":{"b":0,"s":0,"h":0,"a":1},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":2,"width":0.10000000149011612,"endArrow":"","startArrow":"","cap":1},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[579.21777967228218,-165.50118646031109],"opacity":1,"blur":0,"isLocked":false,"gid":37,"smootheningRate":0,"initialPoint":[579.21777967228218,-165.50118646031109],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[307.98765662154068,497.22766759942954],"reflectionModeOverride":0,"anchorPoint":[307.98765662154068,526.40806463936553],"cornerRadius":0,"prevPoint":[0,0],"inPoint":[307.98765662154068,555.58846167930153],"nextPoint":[0,0]},{"outPoint":[347.07124677007465,468.5633046399771],"reflectionModeOverride":0,"anchorPoint":[331.56894097295356,478.9361833057668],"cornerRadius":0,"prevPoint":[0,0],"inPoint":[316.06663517583246,489.3090619715565],"nextPoint":[0,0]}],"closed":false,"reversed":false}},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":2,"width":20,"endArrow":"","startArrow":"","cap":1},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[0,0],"opacity":1,"blur":0,"isLocked":false,"gid":33,"smootheningRate":0,"initialPoint":[0,0],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"compoundPathData":{"subpaths":[{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[367.7690644381571,667.02363476289884],"reflectionModeOverride":0,"anchorPoint":[367.7690644381571,667.02363476289884],"cornerRadius":0,"prevPoint":[72.193980608055426,108.16792868331186],"inPoint":[368.26333755475412,638.68961321030247],"nextPoint":[72.193980608055426,108.16792868331186]},{"outPoint":[367.82059343747073,616.38299074283532],"reflectionModeOverride":0,"anchorPoint":[367.82059343747073,616.38299074283532],"cornerRadius":0,"prevPoint":[55.02340366515682,81.837967291336099],"inPoint":[367.82059343747073,616.38299074283532],"nextPoint":[55.02340366515682,81.837967291336099]},{"outPoint":[383.13716259159514,626.44746079947163],"reflectionModeOverride":0,"anchorPoint":[403.6767241609266,616.33647011725679],"cornerRadius":0,"prevPoint":[70.109671854888575,134.1591558035534],"inPoint":[403.6767241609266,616.33647011725679],"nextPoint":[70.109671854888575,134.1591558035534]}],"closed":true,"reversed":false}},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[72.357622652088821,121.79167358010636],"opacity":1,"blur":0,"isLocked":false,"gid":48,"smootheningRate":0,"initialPoint":[72.357622652088821,121.79167358010636],"creationPoints":[],"name":"(curve)"}]}},"fillColor":{"b":0.9882352941176471,"s":1,"h":0.13822251558303833,"a":1},"strokeStyle":{"color":{"b":0.9882352941176471,"s":1,"h":0.5806878306878307,"a":1},"dashPattern":[],"join":1,"width":0.10000000149011612,"endArrow":"","startArrow":"","cap":0},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[-2.4740749822735211,26.734403557988003],"opacity":1,"blur":0,"isLocked":false,"gid":46,"smootheningRate":0,"initialPoint":[-2.4740749822735211,26.734403557988003],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"fillColor":{"b":1,"s":0,"h":0,"a":1},"maskedElements":[],"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[189.49257363188801,253.97453151588081],"reflectionModeOverride":0,"anchorPoint":[189.49257363188801,253.97453151588081],"cornerRadius":0,"prevPoint":[112.85257138121662,152.97453151588078],"inPoint":[189.49257363188801,253.97453151588081],"nextPoint":[112.85257138121662,152.97453151588078]},{"outPoint":[198.97257317412434,244.48453174476265],"reflectionModeOverride":0,"anchorPoint":[198.97257317412434,244.48453174476265],"cornerRadius":0,"prevPoint":[112.85257138121662,152.97453151588078],"inPoint":[198.97257317412434,244.48453174476265],"nextPoint":[112.85257138121662,152.97453151588078]},{"outPoint":[189.49257363188801,235.01453147773384],"reflectionModeOverride":0,"anchorPoint":[189.49257363188801,235.01453147773384],"cornerRadius":0,"prevPoint":[112.85257138121662,152.97453151588078],"inPoint":[189.49257363188801,235.01453147773384],"nextPoint":[112.85257138121662,152.97453151588078]}],"closed":true,"reversed":false}}},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[112.85257138121662,152.97453151588078],"opacity":1,"blur":0,"isLocked":false,"gid":16,"smootheningRate":0,"initialPoint":[112.85257138121662,152.97453151588078],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[323.38754763944246,487.32457590003901],"reflectionModeOverride":0,"anchorPoint":[344.90470311533363,481.42866614307741],"cornerRadius":0,"prevPoint":[615.60724563620806,1.3634276556741725],"inPoint":[369.14847846760358,474.78563603599895],"nextPoint":[615.60724563620806,1.3634276556741725]},{"outPoint":[307.28704728382809,560.47255779544446],"reflectionModeOverride":0,"anchorPoint":[307.79763374097075,532.13830093176216],"cornerRadius":0,"prevPoint":[605.67266977751206,16.47175369678871],"inPoint":[308.30822019811342,503.80404406807986],"nextPoint":[605.67266977751206,16.47175369678871]}],"closed":false,"reversed":false}},"fillColor":{"b":0.9882352941176471,"s":1,"h":0.13822251558303833,"a":1},"strokeStyle":{"color":{"b":0.9882352941176471,"s":1,"h":0.5806878306878307,"a":1},"dashPattern":[],"join":1,"width":0.10000000149011612,"endArrow":"","startArrow":"","cap":0},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[605.67266977751206,16.47175369678871],"opacity":1,"blur":0,"isLocked":false,"gid":45,"smootheningRate":0,"initialPoint":[605.67266977751206,16.47175369678871],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(line)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[13.974435927889729,160.80268978822852],"reflectionModeOverride":0,"anchorPoint":[13.974435927889729,160.80268978822852],"cornerRadius":0,"prevPoint":[0,0],"inPoint":[13.974435927889729,160.80268978822852],"nextPoint":[0,0]},{"outPoint":[144.25556161242727,291.78142890790133],"reflectionModeOverride":0,"anchorPoint":[144.25556161242727,291.78142890790133],"cornerRadius":0,"prevPoint":[0,0],"inPoint":[144.25556161242727,291.78142890790133],"nextPoint":[0,0]}],"closed":false,"reversed":false}},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":1,"width":20,"endArrow":"","startArrow":"","cap":1},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[0,0],"opacity":1,"blur":0,"isLocked":false,"gid":28,"smootheningRate":0,"initialPoint":[0,0],"creationPoints":[],"name":"(line)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[320,664.0506297595],"reflectionModeOverride":0,"anchorPoint":[320,640],"cornerRadius":0,"prevPoint":[0,0],"inPoint":[320,580],"nextPoint":[0,0]},{"outPoint":[344.050612449646,595.89893977911322],"reflectionModeOverride":0,"anchorPoint":[337.34381007033926,612.48211711168926],"cornerRadius":0,"prevPoint":[0,0],"inPoint":[327.23039949003834,637.48844227310212],"nextPoint":[0,0]},{"outPoint":[380,580],"reflectionModeOverride":0,"anchorPoint":[360,580],"cornerRadius":0,"prevPoint":[0,0],"inPoint":[352.025306224823,580],"nextPoint":[0,0]},{"outPoint":[260,580],"reflectionModeOverride":0,"anchorPoint":[280,580],"cornerRadius":0,"prevPoint":[0,0],"inPoint":[300,580],"nextPoint":[0,0]}],"closed":true,"reversed":false}},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":2,"width":0.10000000149011612,"endArrow":"","startArrow":"","cap":1},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[0,0],"opacity":1,"blur":0,"isLocked":false,"gid":34,"smootheningRate":0,"initialPoint":[0,0],"creationPoints":[],"name":"(curve)"},{"elementDescription":"(curve)","category":0,"blendMode":0,"creationViewScale":0,"isFreeHandCurve":false,"styleable":{"abstractPath":{"fillRule":0,"pathData":{"nodes":[{"outPoint":[300,640],"reflectionModeOverride":0,"anchorPoint":[300,640],"cornerRadius":0,"prevPoint":[0,0],"inPoint":[300,640],"nextPoint":[0,0]},{"outPoint":[380,580],"reflectionModeOverride":0,"anchorPoint":[340,580],"cornerRadius":0,"prevPoint":[0,0],"inPoint":[300,580],"nextPoint":[0,0]}],"closed":false,"reversed":false}},"strokeStyle":{"color":{"b":0,"s":0,"h":0,"a":1},"dashPattern":[],"join":2,"width":0.10000000149011612,"endArrow":"","startArrow":"","cap":1},"maskedElements":[]},"angle":0,"smootheningRateRaw":0,"isHidden":false,"endPointFIX":[0,0],"opacity":1,"blur":0,"isLocked":false,"gid":36,"smootheningRate":0,"initialPoint":[0,0],"creationPoints":[],"name":"(curve)"}],"cacheLayers":[],"cacheArtboardPaths":[],"undoStack":[[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":6}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -20, -20]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11,6]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -29.209948435277369, -232.41660739687057]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[12]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[12,13,14,15]}","argumentGID":0}],"methodSignature":"setSubpaths:","targetGID":11},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11}],"methodSignature":"setSuperpath:","targetGID":12},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setFill:","targetGID":12},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":12},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setShadow:","targetGID":12},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11}],"methodSignature":"setSuperpath:","targetGID":13},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setFill:","targetGID":13},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":13},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setShadow:","targetGID":13},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11}],"methodSignature":"setSuperpath:","targetGID":14},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setFill:","targetGID":14},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":14},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setShadow:","targetGID":14}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":6},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":16}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -20, -20]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[16]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":16},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":16}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setFill:","targetGID":14}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setFill:","targetGID":16}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setFill:","targetGID":16}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.01450315572447696,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.93007444840156717,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.014503091068591101,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.93451308072143913,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.014503091068591101,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.93910701763028559,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.014503091068591101,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.94055809677531532,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.014503091068591101,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.94999337125602745,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.013467045153601698,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.95297621548706413,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.013467045153601698,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.95790068402842177,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.011044777045815676,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.96266052064980523,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.0088583736096398309,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.96911575815444173,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.0077646546444650423,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.97217928832645584,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.0032726223185911016,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.98016728703982747,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.0010851843882415254,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.98662352066719217,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.99307006473711057,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":16}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[0.20437110010339629, -0, -0, 0.20437110010339629, 126.38769661378409, 170.79330548171168]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[13]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[12,13,14]}","argumentGID":0}],"methodSignature":"setSubpaths:","targetGID":11},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11}],"methodSignature":"setSuperpath:","targetGID":13},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setFill:","targetGID":13},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":13},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setShadow:","targetGID":13},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11}],"methodSignature":"setSuperpath:","targetGID":14},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setFill:","targetGID":14},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":14},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setShadow:","targetGID":14}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":21}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":185.15633048630471,\"AnchorPoint_Y\":354.17149931944061,\"inPoint_Y\":354.17149931944061,\"OutPoint_X\":185.15633048630471,\"AnchorPoint_X\":185.15633048630471,\"OutPoint_Y\":354.17149931944061},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":185.15633048630471,\"AnchorPoint_Y\":354.17149931944061,\"inPoint_Y\":354.17149931944061,\"OutPoint_X\":185.15633048630471,\"AnchorPoint_X\":185.15633048630471,\"OutPoint_Y\":354.17149931944061},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":386.50447364412418,\"AnchorPoint_Y\":554.43203524141848,\"inPoint_Y\":554.43203524141848,\"OutPoint_X\":386.50447364412418,\"AnchorPoint_X\":386.50447364412418,\"OutPoint_Y\":554.43203524141848},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":185.15633048630471,\"AnchorPoint_Y\":354.17149931944061,\"inPoint_Y\":354.17149931944061,\"OutPoint_X\":185.15633048630471,\"AnchorPoint_X\":185.15633048630471,\"OutPoint_Y\":354.17149931944061},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":386.50447364412418,\"AnchorPoint_Y\":554.43203524141848,\"inPoint_Y\":554.43203524141848,\"OutPoint_X\":386.50447364412418,\"AnchorPoint_X\":386.50447364412418,\"OutPoint_Y\":554.43203524141848},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":284.63851065196616,\"AnchorPoint_Y\":654.20422348213651,\"inPoint_Y\":654.20422348213651,\"OutPoint_X\":284.63851065196616,\"AnchorPoint_X\":284.63851065196616,\"OutPoint_Y\":654.20422348213651},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":185.15633048630471,\"AnchorPoint_Y\":354.17149931944061,\"inPoint_Y\":354.17149931944061,\"OutPoint_X\":185.15633048630471,\"AnchorPoint_X\":185.15633048630471,\"OutPoint_Y\":354.17149931944061},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":386.50447364412418,\"AnchorPoint_Y\":554.43203524141848,\"inPoint_Y\":554.43203524141848,\"OutPoint_X\":386.50447364412418,\"AnchorPoint_X\":386.50447364412418,\"OutPoint_Y\":554.43203524141848},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":284.63851065196616,\"AnchorPoint_Y\":654.20422348213651,\"inPoint_Y\":654.20422348213651,\"OutPoint_X\":284.63851065196616,\"AnchorPoint_X\":284.63851065196616,\"OutPoint_Y\":654.20422348213651},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":286.57710140084737,\"AnchorPoint_Y\":264.05198470231699,\"inPoint_Y\":264.05198470231699,\"OutPoint_X\":286.57710140084737,\"AnchorPoint_X\":286.57710140084737,\"OutPoint_Y\":264.05198470231699},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":185.15633048630471,\"AnchorPoint_Y\":354.17149931944061,\"inPoint_Y\":354.17149931944061,\"OutPoint_X\":185.15633048630471,\"AnchorPoint_X\":185.15633048630471,\"OutPoint_Y\":354.17149931944061},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":386.50447364412418,\"AnchorPoint_Y\":554.43203524141848,\"inPoint_Y\":554.43203524141848,\"OutPoint_X\":386.50447364412418,\"AnchorPoint_X\":386.50447364412418,\"OutPoint_Y\":554.43203524141848},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":284.63851065196616,\"AnchorPoint_Y\":654.20422348213651,\"inPoint_Y\":654.20422348213651,\"OutPoint_X\":284.63851065196616,\"AnchorPoint_X\":284.63851065196616,\"OutPoint_Y\":654.20422348213651},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":286.57710140084737,\"AnchorPoint_Y\":264.05198470231699,\"inPoint_Y\":264.05198470231699,\"OutPoint_X\":286.57710140084737,\"AnchorPoint_X\":286.57710140084737,\"OutPoint_Y\":264.05198470231699},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":383.69928863669242,\"AnchorPoint_Y\":361.21410026752545,\"inPoint_Y\":361.21410026752545,\"OutPoint_X\":383.69928863669242,\"AnchorPoint_X\":383.69928863669242,\"OutPoint_Y\":361.21410026752545},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":1}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":1,\"WDHueKey\":0.5806878306878307,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":1}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":1,\"WDHueKey\":0.5806878306878307,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":37.148059844970703}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":1,\"WDHueKey\":0.5806878306878307,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":2,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":37.148059844970703}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":185.15633048630471,\"AnchorPoint_Y\":354.17149931944061,\"inPoint_Y\":354.17149931944061,\"OutPoint_X\":185.15633048630471,\"AnchorPoint_X\":185.15633048630471,\"OutPoint_Y\":354.17149931944061},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":386.50447364412418,\"AnchorPoint_Y\":554.43203524141848,\"inPoint_Y\":554.43203524141848,\"OutPoint_X\":386.50447364412418,\"AnchorPoint_X\":386.50447364412418,\"OutPoint_Y\":554.43203524141848},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":284.63851065196616,\"AnchorPoint_Y\":654.20422348213651,\"inPoint_Y\":654.20422348213651,\"OutPoint_X\":284.63851065196616,\"AnchorPoint_X\":284.63851065196616,\"OutPoint_Y\":654.20422348213651},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":286.57710140084737,\"AnchorPoint_Y\":264.05198470231699,\"inPoint_Y\":264.05198470231699,\"OutPoint_X\":286.57710140084737,\"AnchorPoint_X\":286.57710140084737,\"OutPoint_Y\":264.05198470231699},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":383.69928863669242,\"AnchorPoint_Y\":361.21410026752545,\"inPoint_Y\":361.21410026752545,\"OutPoint_X\":383.69928863669242,\"AnchorPoint_X\":383.69928863669242,\"OutPoint_Y\":361.21410026752545},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":186.05023255601679,\"AnchorPoint_Y\":558.85414169234264,\"inPoint_Y\":558.85414169234264,\"OutPoint_X\":186.05023255601679,\"AnchorPoint_X\":186.05023255601679,\"OutPoint_Y\":558.85414169234264},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":185.15633048630471,\"AnchorPoint_Y\":354.17149931944061,\"inPoint_Y\":354.17149931944061,\"OutPoint_X\":185.15633048630471,\"AnchorPoint_X\":185.15633048630471,\"OutPoint_Y\":354.17149931944061},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":386.50447364412418,\"AnchorPoint_Y\":554.43203524141848,\"inPoint_Y\":554.43203524141848,\"OutPoint_X\":386.50447364412418,\"AnchorPoint_X\":386.50447364412418,\"OutPoint_Y\":554.43203524141848},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":284.63851065196616,\"AnchorPoint_Y\":654.20422348213651,\"inPoint_Y\":654.20422348213651,\"OutPoint_X\":284.63851065196616,\"AnchorPoint_X\":284.63851065196616,\"OutPoint_Y\":654.20422348213651},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":286.57710140084737,\"AnchorPoint_Y\":264.05198470231699,\"inPoint_Y\":264.05198470231699,\"OutPoint_X\":286.57710140084737,\"AnchorPoint_X\":286.57710140084737,\"OutPoint_Y\":264.05198470231699},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":383.69928863669242,\"AnchorPoint_Y\":361.21410026752545,\"inPoint_Y\":361.21410026752545,\"OutPoint_X\":383.69928863669242,\"AnchorPoint_X\":383.69928863669242,\"OutPoint_Y\":361.21410026752545},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":1,\"NodePoints\":{\"inPoint_X\":235.46249740746129,\"AnchorPoint_Y\":558.85414169234264,\"inPoint_Y\":509.44413050490067,\"OutPoint_X\":136.6379677045723,\"AnchorPoint_X\":186.05023255601679,\"OutPoint_Y\":608.26415287978466},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782582120682,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.98823529481887817,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[11]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":16},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":1,\"WDHueKey\":0.5806878306878307,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":37.148059844970703}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":1,\"WDHueKey\":0.5806878306878307,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":37.148059844970703}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0.03408561318607653,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.016189711030229925,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":37.148059844970703}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0.029926881951800856,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.016189711030229925,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":37.148059844970703}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0.021585238181938561,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.012961911164688478,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":37.148059844970703}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0.011895648503707629,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.007872629590133573,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":37.148059844970703}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0.005957393322960804,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":37.148059844970703}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":37.148059844970703}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":37.148059844970703}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":21.344829559326172}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":21.344829559326172}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":20}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[-4.3711390001862419e-08, -0.99999999999999922, 0.99999999999999922, -4.3711390001862419e-08, -173.29768953296772, 744.95852622656867]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 8.2190355245806472, 176.90598115888827]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":11},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":22}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 0.55538688884063114, -0, 182.49084631957811]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[22]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":24}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 150.32620239929324, 36.081797695525552]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[24]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[24]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0.12249755187863798, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[24]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[0.64978701032960984, -0, -0, 0.64978701032960984, 52.531948450558538, 142.05406077476505]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[24]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -55.171276915352394, 196.69205141995428]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[24]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[0.65616231221472443, -0, -0, 0.65616231221472443, 51.425334356867019, 141.12771095949628]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[22]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -55.53221494113933, 129.60740108742715]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[22]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 205.17127691535239, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[24]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 205.09503537570964, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[22]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 208.92985571850454]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[24]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 130.84123782858848]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[22]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 75]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[22]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":25}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -20, -20]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[25]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 4.5418914390142788, -306.56258907512347]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[25]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[0.96223302635797447, -0, -0, 0.96223302635797447, -0, 2.8325230231519103]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[22]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1.0392493219135692, -0, -0, 1.0392493219135692, 0, -2.9436991435176969]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[22]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 0.96223302635797447, -0, 2.8325230231519103]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[22]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 15.458108560985721, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[25]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 26.562589075123469]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[25]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 25]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[25]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 50]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[25]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -25]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[25]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":22}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":26}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -20, -20]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":20}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":0.10000000149011612}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":1,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":0.10000000149011612}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 9.881426012744555, 0.91199734232554874]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -77.745954011856824, 28.270796276850916]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 67.864527999112269, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 10, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1.1538461432654479, -0, -0, 1, -1.5384614326544779, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[26]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -136.98574299882625, 7.8612196478959504]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":27}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":25},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":3}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":24},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":26},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":3}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":22},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setElements:","targetGID":27},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -53.141264363887032, -43.604121250556744]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -70.052055171480333, -2.5049969673447094]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 219.77475934149726, 163.57319520938375]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":27},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":27}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[0.6846814845770105, -0, -0, 0.6846814845770105, -0.080018108436871196, 3.1890182924268196]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -85.587957051898314, -21.453286888159028]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":20}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setShadow:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDShadowOffsetKey\":10,\"WDShadowAngleKey\":1.5707999467849731,\"WDShadowRadiusKey\":10,\"WDShadowColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":0.33300000000000002,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"$class\":\"WDShadow\"}}","argumentGID":0}],"methodSignature":"setShadow:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setShadow:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDShadowOffsetKey\":10,\"WDShadowAngleKey\":1.5707999467849731,\"WDShadowRadiusKey\":10,\"WDShadowColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":0.33300000000000002,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"$class\":\"WDShadow\"}}","argumentGID":0}],"methodSignature":"setShadow:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":20}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":21}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":28}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":28},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":29}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":29}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":19.067760461856238,\"AnchorPoint_Y\":162.4737431408027,\"inPoint_Y\":162.4737431408027,\"OutPoint_X\":19.067760461856238,\"AnchorPoint_X\":19.067760461856238,\"OutPoint_Y\":162.4737431408027},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":29}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":19.067760461856238,\"AnchorPoint_Y\":162.4737431408027,\"inPoint_Y\":162.4737431408027,\"OutPoint_X\":19.067760461856238,\"AnchorPoint_X\":19.067760461856238,\"OutPoint_Y\":162.4737431408027},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":142.86303913891427,\"AnchorPoint_Y\":297.21030751597522,\"inPoint_Y\":297.21030751597522,\"OutPoint_X\":142.86303913891427,\"AnchorPoint_X\":142.86303913891427,\"OutPoint_Y\":297.21030751597522},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":29}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":3,"argumentEncodedJsonString":"{\"Argument\":false}","argumentGID":0}],"methodSignature":"setClosed:","targetGID":29}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setFill:","targetGID":29}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782582120682,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.98823529481887817,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":29}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":30}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -20, -20]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -258.8309537310077, 14.790477788784642]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":21},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":21}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":21},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":3}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":21}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0}],"methodSignature":"exchangeObjectAtIndex:withObjectAtIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0}],"methodSignature":"exchangeObjectAtIndex:withObjectAtIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0}],"methodSignature":"exchangeObjectAtIndex:withObjectAtIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0}],"methodSignature":"exchangeObjectAtIndex:withObjectAtIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0}],"methodSignature":"exchangeObjectAtIndex:withObjectAtIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0}],"methodSignature":"exchangeObjectAtIndex:withObjectAtIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":3}","argumentGID":0}],"methodSignature":"exchangeObjectAtIndex:withObjectAtIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":1,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":20}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":30}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":1,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":20}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":29}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0}],"methodSignature":"exchangeObjectAtIndex:withObjectAtIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":3}","argumentGID":0}],"methodSignature":"exchangeObjectAtIndex:withObjectAtIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":3}","argumentGID":0},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0}],"methodSignature":"exchangeObjectAtIndex:withObjectAtIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":1}","argumentGID":0}],"methodSignature":"exchangeObjectAtIndex:withObjectAtIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[0.98660023945785613, -0, -0, 1.0127745463822073, 7.5897658853896965, -3.7483052243093384]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[30]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":3}","argumentGID":0},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0}],"methodSignature":"exchangeObjectAtIndex:withObjectAtIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":31}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":1,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":0.10000000149011612}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":31}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":1,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":27.568212509155273}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":31}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":27.568212509155273}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":31}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":1,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":29}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782582120682,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.98823529481887817,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782582120682,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.98823529481887817,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782582120682,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.98823529481887817,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782582120682,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.98823529481887817,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11623311042785645,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11623311042785645,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11623311042785645,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11623311042785645,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11518210172653198,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11518210172653198,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11518210172653198,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11518210172653198,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11062517762184143,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11062517762184143,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11062517762184143,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11062517762184143,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10827497392892838,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10827497392892838,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10827497392892838,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10827497392892838,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10599262267351151,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10599262267351151,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10599262267351151,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10599262267351151,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10487814247608185,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10487814247608185,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10487814247608185,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10487814247608185,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10140901058912277,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10140901058912277,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10140901058912277,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10140901058912277,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10024447739124298,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10024447739124298,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10024447739124298,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10024447739124298,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.0991511270403862,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.0991511270403862,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.0991511270403862,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.0991511270403862,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.095819912850856781,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.095819912850856781,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.095819912850856781,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.095819912850856781,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.093592062592506436,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.093592062592506436,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.093592062592506436,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.093592062592506436,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.091305255889892578,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.091305255889892578,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.091305255889892578,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.091305255889892578,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.086611531674861908,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.086611531674861908,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.086611531674861908,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.086611531674861908,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.084330290555953952,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.084330290555953952,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.084330290555953952,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.084330290555953952,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.082062393426895142,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.082062393426895142,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.082062393426895142,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.082062393426895142,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.080980166792869596,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.080980166792869596,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.080980166792869596,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.080980166792869596,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.078774556517601013,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.078774556517601013,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.078774556517601013,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.078774556517601013,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.079864569008350372,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.079864569008350372,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.079864569008350372,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.079864569008350372,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.084498241543769864,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.084498241543769864,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.084498241543769864,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.084498241543769864,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.090882599353790255,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.090882599353790255,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.090882599353790255,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.090882599353790255,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.09557187557220459,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.09557187557220459,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.09557187557220459,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.09557187557220459,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.0990910604596138,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.0990910604596138,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.0990910604596138,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.0990910604596138,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10261469334363937,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10261469334363937,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10261469334363937,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10261469334363937,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10601820796728134,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10601820796728134,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10601820796728134,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10601820796728134,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10719386488199234,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10719386488199234,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10719386488199234,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.10719386488199234,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11685270816087723,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11685270816087723,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11685270816087723,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.11685270816087723,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.12441384047269821,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.12441384047269821,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.12441384047269821,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.12441384047269821,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.12794080376625061,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.12794080376625061,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.12794080376625061,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.12794080376625061,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13263343274593353,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13263343274593353,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13263343274593353,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13263343274593353,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13615038990974426,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13615038990974426,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13615038990974426,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13615038990974426,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13955500721931458,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13955500721931458,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13955500721931458,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13955500721931458,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14536766707897186,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14536766707897186,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14536766707897186,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14536766707897186,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15242382884025574,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15242382884025574,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15242382884025574,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15242382884025574,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15580509603023529,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15580509603023529,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15580509603023529,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15580509603023529,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15815529227256775,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15815529227256775,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15815529227256775,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15815529227256775,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.16035088896751404,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.16035088896751404,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.16035088896751404,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.16035088896751404,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15694738924503326,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15694738924503326,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15694738924503326,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15694738924503326,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15200117230415344,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15200117230415344,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15200117230415344,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.15200117230415344,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14730300009250641,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14730300009250641,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14730300009250641,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14730300009250641,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14378604292869568,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14378604292869568,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14378604292869568,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14378604292869568,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14143472909927368,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14143472909927368,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14143472909927368,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14143472909927368,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14034359157085419,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14034359157085419,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14034359157085419,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.14034359157085419,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":26}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":1,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":30}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":32}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -20, -20]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[32]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[27,21,30,32,29,31]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[21]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":33}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":33}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":307.98765662154068,\"AnchorPoint_Y\":526.40806463936553,\"inPoint_Y\":555.58846167930153,\"OutPoint_X\":307.98765662154068,\"AnchorPoint_X\":307.98765662154068,\"OutPoint_Y\":497.22766759942954},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":33}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":1,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":20}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":33}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":33},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":9223372036854775807}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":34}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":34}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":320,\"AnchorPoint_Y\":640,\"inPoint_Y\":680,\"OutPoint_X\":320,\"AnchorPoint_X\":320,\"OutPoint_Y\":600},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":34}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":320,\"AnchorPoint_Y\":640,\"inPoint_Y\":680,\"OutPoint_X\":320,\"AnchorPoint_X\":320,\"OutPoint_Y\":600},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":340,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":380,\"AnchorPoint_X\":360,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":34}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":320,\"AnchorPoint_Y\":640,\"inPoint_Y\":680,\"OutPoint_X\":320,\"AnchorPoint_X\":320,\"OutPoint_Y\":600},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":340,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":380,\"AnchorPoint_X\":360,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":260,\"AnchorPoint_X\":280,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":34},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":3,"argumentEncodedJsonString":"{\"Argument\":false}","argumentGID":0}],"methodSignature":"setClosed:","targetGID":34}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":320,\"AnchorPoint_Y\":640,\"inPoint_Y\":580,\"OutPoint_X\":320,\"AnchorPoint_X\":320,\"OutPoint_Y\":680.00002878904479},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":340,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":380,\"AnchorPoint_X\":360,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":260,\"AnchorPoint_X\":280,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":34}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":34},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":6}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":35}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":35}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":340,\"AnchorPoint_Y\":660,\"inPoint_Y\":620,\"OutPoint_X\":340,\"AnchorPoint_X\":340,\"OutPoint_Y\":700},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":35}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":35},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":6}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":36}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":36}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":640,\"inPoint_Y\":640,\"OutPoint_X\":300,\"AnchorPoint_X\":300,\"OutPoint_Y\":640},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":36}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":37}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -20, -20]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 20, 20]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[-1, -0, 0, 1, 640, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"KeepNodesAfterTransformTransformOptionKey\":true}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 39, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":640,\"inPoint_Y\":640,\"OutPoint_X\":300,\"AnchorPoint_X\":300,\"OutPoint_Y\":640},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{600, 0}\",\"VNPrevPointForRadiusKey\":\"{600, 0}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":220,\"AnchorPoint_X\":260,\"OutPoint_Y\":580},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{600, 0}\",\"VNPrevPointForRadiusKey\":\"{600, 0}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":37}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":640,\"inPoint_Y\":640,\"OutPoint_X\":300,\"AnchorPoint_X\":300,\"OutPoint_Y\":640},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{600, 0}\",\"VNPrevPointForRadiusKey\":\"{600, 0}\",\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":260,\"AnchorPoint_X\":260,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":37}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":640,\"inPoint_Y\":640,\"OutPoint_X\":300,\"AnchorPoint_X\":300,\"OutPoint_Y\":640},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{600, 0}\",\"VNPrevPointForRadiusKey\":\"{600, 0}\",\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":260,\"AnchorPoint_X\":260,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":340,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":340,\"AnchorPoint_X\":340,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":37}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":640,\"inPoint_Y\":640,\"OutPoint_X\":300,\"AnchorPoint_X\":300,\"OutPoint_Y\":640},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{600, 0}\",\"VNPrevPointForRadiusKey\":\"{600, 0}\",\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":260,\"AnchorPoint_X\":260,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":340,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":340,\"AnchorPoint_X\":340,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":260,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":260,\"AnchorPoint_X\":260,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":37}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":640,\"inPoint_Y\":640,\"OutPoint_X\":300,\"AnchorPoint_X\":300,\"OutPoint_Y\":640},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{600, 0}\",\"VNPrevPointForRadiusKey\":\"{600, 0}\",\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":260,\"AnchorPoint_X\":260,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":340,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":340,\"AnchorPoint_X\":340,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":260,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":260,\"AnchorPoint_X\":260,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":340,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":340,\"AnchorPoint_X\":340,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":37}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 60, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":240,\"AnchorPoint_Y\":640,\"inPoint_Y\":640,\"OutPoint_X\":240,\"AnchorPoint_X\":240,\"OutPoint_Y\":640},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{540, 0}\",\"VNPrevPointForRadiusKey\":\"{540, 0}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":240,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":200,\"AnchorPoint_X\":200,\"OutPoint_Y\":580},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-60, 0}\",\"VNPrevPointForRadiusKey\":\"{-60, 0}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":280,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":280,\"AnchorPoint_X\":280,\"OutPoint_Y\":580},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-60, 0}\",\"VNPrevPointForRadiusKey\":\"{-60, 0}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":200,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":200,\"AnchorPoint_X\":200,\"OutPoint_Y\":580},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-60, 0}\",\"VNPrevPointForRadiusKey\":\"{-60, 0}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":280,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":300,\"AnchorPoint_X\":280,\"OutPoint_Y\":600},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-60, 0}\",\"VNPrevPointForRadiusKey\":\"{-60, 0}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":37},{"actionTypeRawValue":"proxy","methodArguments":[],"methodSignature":"reversePathDirection","targetGID":37}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":300,\"AnchorPoint_Y\":580,\"inPoint_Y\":600,\"OutPoint_X\":280,\"AnchorPoint_X\":280,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":200,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":200,\"AnchorPoint_X\":200,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":280,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":280,\"AnchorPoint_X\":280,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":200,\"AnchorPoint_Y\":580,\"inPoint_Y\":580,\"OutPoint_X\":240,\"AnchorPoint_X\":200,\"OutPoint_Y\":580},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":240,\"AnchorPoint_Y\":640,\"inPoint_Y\":640,\"OutPoint_X\":240,\"AnchorPoint_X\":240,\"OutPoint_Y\":640},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":37},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":3,"argumentEncodedJsonString":"{\"Argument\":false}","argumentGID":0}],"methodSignature":"setClosed:","targetGID":37}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":36},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":6}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -60, 100]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -8.3360061810856791, -0.18596575427056905]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setFill:","targetGID":37}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0.12624915594960839, -0.84513498021431133]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1.0820554726071352, -0, -0, 1, -28.572516179113212, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 3.7693360211719664, 0.58007166688469169]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 0.8911271920692454, -0, 58.840421083655528]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0.018101184397323777, -6.1834757589472247]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0.5616683932951787, -14.721591768371582]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1.4335340527209723, 13.544422687729025]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[37]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":37},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":6}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":43}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.10440918421369,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":598.11903819000008},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":314.21352490073997,\"AnchorPoint_Y\":480.08137659705397,\"inPoint_Y\":479.94813303079826,\"OutPoint_X\":366.0442444460744,\"AnchorPoint_X\":340.12888467340719,\"OutPoint_Y\":480.21462016330969},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":314.21352490073997,\"AnchorPoint_Y\":480.08137659705397,\"inPoint_Y\":479.94813303079826,\"OutPoint_X\":340.12888467340719,\"AnchorPoint_X\":340.12888467340719,\"OutPoint_Y\":480.08137659705397},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":314.21352490073997,\"AnchorPoint_Y\":480.08137659705397,\"inPoint_Y\":479.94813303079826,\"OutPoint_X\":340.12888467340719,\"AnchorPoint_X\":340.12888467340719,\"OutPoint_Y\":480.08137659705397},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":337.32713106884489,\"AnchorPoint_Y\":505.14299981511687,\"inPoint_Y\":505.14299981511687,\"OutPoint_X\":337.32713106884489,\"AnchorPoint_X\":337.32713106884489,\"OutPoint_Y\":505.14299981511687},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":314.21352490073997,\"AnchorPoint_Y\":480.08137659705397,\"inPoint_Y\":479.94813303079826,\"OutPoint_X\":340.12888467340719,\"AnchorPoint_X\":340.12888467340719,\"OutPoint_Y\":480.08137659705397},\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":268.41762507168443,\"AnchorPoint_Y\":478.86160216124927,\"inPoint_Y\":478.86160216124927,\"OutPoint_X\":268.41762507168443,\"AnchorPoint_X\":268.41762507168443,\"OutPoint_Y\":478.86160216124927},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-68.909505997160466, -26.2813976538676}\",\"VNPrevPointForRadiusKey\":\"{-68.909505997160466, -26.2813976538676}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":268.41762507168443,\"AnchorPoint_Y\":478.86160216124927,\"inPoint_Y\":478.86160216124927,\"OutPoint_X\":268.41762507168443,\"AnchorPoint_X\":268.41762507168443,\"OutPoint_Y\":478.86160216124927},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-68.909505997160466, -26.2813976538676}\",\"VNPrevPointForRadiusKey\":\"{-68.909505997160466, -26.2813976538676}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":282.38947067174871,\"AnchorPoint_Y\":502.68576551434728,\"inPoint_Y\":502.68576551434728,\"OutPoint_X\":282.38947067174871,\"AnchorPoint_X\":282.38947067174871,\"OutPoint_Y\":502.68576551434728},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.41762507168443,\"AnchorPoint_Y\":478.86160216124927,\"inPoint_Y\":478.86160216124927,\"OutPoint_X\":268.41762507168443,\"AnchorPoint_X\":268.41762507168443,\"OutPoint_Y\":478.86160216124927},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":333.80634908853523,\"AnchorPoint_Y\":479.14166624396699,\"inPoint_Y\":479.14166624396699,\"OutPoint_X\":333.80634908853523,\"AnchorPoint_X\":333.80634908853523,\"OutPoint_Y\":479.14166624396699},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{51.416878416786517, -23.544099270380286}\",\"VNPrevPointForRadiusKey\":\"{51.416878416786517, -23.544099270380286}\",\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.41762507168443,\"AnchorPoint_Y\":478.86160216124927,\"inPoint_Y\":478.86160216124927,\"OutPoint_X\":268.41762507168443,\"AnchorPoint_X\":268.41762507168443,\"OutPoint_Y\":478.86160216124927},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":342.99265545324346,\"AnchorPoint_Y\":479.14166624396699,\"inPoint_Y\":494.80574311033359,\"OutPoint_X\":324.620042723827,\"AnchorPoint_X\":333.80634908853523,\"OutPoint_Y\":463.4775893776004},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.41762507168443,\"AnchorPoint_Y\":478.86160216124927,\"inPoint_Y\":478.86160216124927,\"OutPoint_X\":268.41762507168443,\"AnchorPoint_X\":268.41762507168443,\"OutPoint_Y\":478.86160216124927},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":333.80634908853523,\"AnchorPoint_Y\":479.14166624396699,\"inPoint_Y\":479.14166624396699,\"OutPoint_X\":333.80634908853523,\"AnchorPoint_X\":333.80634908853523,\"OutPoint_Y\":479.14166624396699},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.41762507168443,\"AnchorPoint_Y\":478.86160216124927,\"inPoint_Y\":478.86160216124927,\"OutPoint_X\":268.41762507168443,\"AnchorPoint_X\":268.41762507168443,\"OutPoint_Y\":478.86160216124927},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":3,\"NodePoints\":{\"inPoint_X\":342.99265545324346,\"AnchorPoint_Y\":479.14166624396699,\"inPoint_Y\":494.80574311033359,\"OutPoint_X\":324.620042723827,\"AnchorPoint_X\":333.80634908853523,\"OutPoint_Y\":463.4775893776004},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.41762507168443,\"AnchorPoint_Y\":478.86160216124927,\"inPoint_Y\":478.86160216124927,\"OutPoint_X\":268.41762507168443,\"AnchorPoint_X\":268.41762507168443,\"OutPoint_Y\":478.86160216124927},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":3,\"NodePoints\":{\"inPoint_X\":342.99265545324346,\"AnchorPoint_Y\":479.14166624396699,\"inPoint_Y\":494.80574311033359,\"OutPoint_X\":333.79302393751607,\"AnchorPoint_X\":333.80634908853523,\"OutPoint_Y\":478.98295741265042},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.41762507168443,\"AnchorPoint_Y\":478.86160216124927,\"inPoint_Y\":478.86160216124927,\"OutPoint_X\":268.41762507168443,\"AnchorPoint_X\":268.41762507168443,\"OutPoint_Y\":478.86160216124927},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.38209900930354,\"AnchorPoint_Y\":478.82499281784192,\"inPoint_Y\":478.82499281784192,\"OutPoint_X\":268.38209900930354,\"AnchorPoint_X\":268.38209900930354,\"OutPoint_Y\":478.82499281784192},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.22129242932607,\"AnchorPoint_Y\":541.51791009776923,\"inPoint_Y\":484.91678200553838,\"OutPoint_X\":305.16285080676988,\"AnchorPoint_X\":305.16285080676988,\"OutPoint_Y\":541.51791009776923},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":3,\"NodePoints\":{\"inPoint_X\":303.99512941310888,\"AnchorPoint_Y\":479.14166624396699,\"inPoint_Y\":487.18557523329599,\"OutPoint_X\":333.79302393751607,\"AnchorPoint_X\":333.80634908853523,\"OutPoint_Y\":478.98295741265042},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":268.41762507168443,\"AnchorPoint_Y\":478.86160216124927,\"inPoint_Y\":478.86160216124927,\"OutPoint_X\":268.41762507168443,\"AnchorPoint_X\":268.41762507168443,\"OutPoint_Y\":478.86160216124927},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":43}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":44}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":44}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":249.48159496463126,\"AnchorPoint_Y\":480.06523848740324,\"inPoint_Y\":466.59075022213392,\"OutPoint_X\":291.92349007711761,\"AnchorPoint_X\":270.70254252087443,\"OutPoint_Y\":493.53972675267255},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":44}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":249.48159496463126,\"AnchorPoint_Y\":480.06523848740324,\"inPoint_Y\":466.59075022213392,\"OutPoint_X\":291.92349007711761,\"AnchorPoint_X\":270.70254252087443,\"OutPoint_Y\":493.53972675267255},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":297.36444957939858,\"AnchorPoint_Y\":515.66654723497345,\"inPoint_Y\":487.33229037129115,\"OutPoint_X\":298.38562249368391,\"AnchorPoint_X\":297.87503603654125,\"OutPoint_Y\":544.00080409865575},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":44}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":246.45876716860445,\"AnchorPoint_Y\":480.06523848740324,\"inPoint_Y\":473.42220838032478,\"OutPoint_X\":292.2196979967656,\"AnchorPoint_X\":270.70254252087443,\"OutPoint_Y\":485.96114824436484},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":297.36444957939858,\"AnchorPoint_Y\":515.66654723497345,\"inPoint_Y\":487.33229037129115,\"OutPoint_X\":298.38562249368391,\"AnchorPoint_X\":297.87503603654125,\"OutPoint_Y\":544.00080409865575},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":44}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":45}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":246.45876716860445,\"AnchorPoint_Y\":480.06523848740324,\"inPoint_Y\":473.42220838032478,\"OutPoint_X\":292.2196979967656,\"AnchorPoint_X\":270.70254252087443,\"OutPoint_Y\":485.96114824436484},\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":307.29902543809465,\"AnchorPoint_Y\":530.77487327608799,\"inPoint_Y\":502.44061641240569,\"OutPoint_X\":308.32019835237998,\"AnchorPoint_X\":307.80961189523731,\"OutPoint_Y\":559.10913013977029},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{9.9345758586960642, 15.108326041114537}\",\"VNPrevPointForRadiusKey\":\"{9.9345758586960642, 15.108326041114537}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":45}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[-1, -0, 0, 1, 618.5121544161118, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[45]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"KeepNodesAfterTransformTransformOptionKey\":true}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -17.095091220096265, 18.636572344325828]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[45]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":246.45876716860445,\"AnchorPoint_Y\":480.06523848740324,\"inPoint_Y\":473.42220838032478,\"OutPoint_X\":292.2196979967656,\"AnchorPoint_X\":270.70254252087443,\"OutPoint_Y\":485.96114824436484},\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":307.29902543809465,\"AnchorPoint_Y\":530.77487327608799,\"inPoint_Y\":502.44061641240569,\"OutPoint_X\":308.32019835237998,\"AnchorPoint_X\":307.80961189523731,\"OutPoint_Y\":559.10913013977029},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{9.9345758586960642, 15.108326041114537}\",\"VNPrevPointForRadiusKey\":\"{9.9345758586960642, 15.108326041114537}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":44}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":46}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":45},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":8}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":44},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":6}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 2.4740749822735211, -26.734403557988003]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[46]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":50}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":50}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":305.84902480507895,\"AnchorPoint_Y\":558.859403557988,\"inPoint_Y\":530.52519454298988,\"OutPoint_X\":305.33842501772648,\"AnchorPoint_X\":305.33842501772648,\"OutPoint_Y\":558.859403557988},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-2.4740749822735211, 26.734403557988003}\",\"VNPrevPointForRadiusKey\":\"{-2.4740749822735211, 26.734403557988003}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":342.43217501772648,\"AnchorPoint_Y\":508.171903557988,\"inPoint_Y\":508.171903557988,\"OutPoint_X\":320.91501841129599,\"AnchorPoint_X\":342.43217501772648,\"OutPoint_Y\":514.06781336097845},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-2.4740749822735211, 26.734403557988003}\",\"VNPrevPointForRadiusKey\":\"{-2.4740749822735211, 26.734403557988003}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":48}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":305.84902480507895,\"AnchorPoint_Y\":558.859403557988,\"inPoint_Y\":530.52519454298988,\"OutPoint_X\":305.33842501772648,\"AnchorPoint_X\":305.33842501772648,\"OutPoint_Y\":558.859403557988},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":323.12940602919167,\"AnchorPoint_Y\":534.54856008655031,\"inPoint_Y\":534.54856008655031,\"OutPoint_X\":323.12940602919167,\"AnchorPoint_X\":323.12940602919167,\"OutPoint_Y\":534.54856008655031},\"$class\":\"WDBezierNode\"},{\"NodeTypeOverride\":0,\"NodePoints\":{\"inPoint_X\":342.43217501772648,\"AnchorPoint_Y\":508.171903557988,\"inPoint_Y\":508.171903557988,\"OutPoint_X\":320.91501841129599,\"AnchorPoint_X\":342.43217501772648,\"OutPoint_Y\":514.06781336097845},\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":48}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[47,48]}","argumentGID":0}],"methodSignature":"setSubpaths:","targetGID":46},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":46}],"methodSignature":"setSuperpath:","targetGID":48},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setFill:","targetGID":48},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":48},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setShadow:","targetGID":48},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":46}],"methodSignature":"setSuperpath:","targetGID":48},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":48},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setFill:","targetGID":48},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setShadow:","targetGID":48},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":48}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":46},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":7}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.13822251558303833,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":48}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -2.1531569701203352, 25.991399082341331]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[48]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":308.00218177519929,\"AnchorPoint_Y\":532.86800447564667,\"inPoint_Y\":504.53379546064855,\"OutPoint_X\":307.49158198784681,\"AnchorPoint_X\":307.49158198784681,\"OutPoint_Y\":532.86800447564667},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{2.1531569701203352, -25.991399082341331}\",\"VNPrevPointForRadiusKey\":\"{2.1531569701203352, -25.991399082341331}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":307.54481307650724,\"AnchorPoint_Y\":482.22702540901258,\"inPoint_Y\":482.22702540901258,\"OutPoint_X\":307.54481307650724,\"AnchorPoint_X\":307.54481307650724,\"OutPoint_Y\":482.22702540901258},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-15.584592952684432, -52.321534677537727}\",\"VNPrevPointForRadiusKey\":\"{-15.584592952684432, -52.321534677537727}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":344.58533198784681,\"AnchorPoint_Y\":482.18050447564667,\"inPoint_Y\":482.18050447564667,\"OutPoint_X\":323.06817538141632,\"AnchorPoint_X\":344.58533198784681,\"OutPoint_Y\":488.07641427863712},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{2.1531569701203352, -25.991399082341331}\",\"VNPrevPointForRadiusKey\":\"{2.1531569701203352, -25.991399082341331}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":48}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[48]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[48]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[48]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 0, -1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[48]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 0.34003453224391933]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[48]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 0.1954377384541317]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[48]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":54}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -20, -20]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[54]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[-1, -0, 0, 1, 692.07691397569363, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[54]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"KeepNodesAfterTransformTransformOptionKey\":true}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 57.024957634971202, 19.792602829855639]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[54]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":307.04977456552314,\"AnchorPoint_Y\":532.53992937509292,\"inPoint_Y\":504.20572036009486,\"OutPoint_X\":307.56037435287561,\"AnchorPoint_X\":307.56037435287561,\"OutPoint_Y\":532.53992937509292},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{612.89879937060209, -26.319474182895021}\",\"VNPrevPointForRadiusKey\":\"{612.89879937060209, -26.319474182895021}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":307.50714326421519,\"AnchorPoint_Y\":481.89895030845889,\"inPoint_Y\":481.89895030845889,\"OutPoint_X\":307.50714326421519,\"AnchorPoint_X\":307.50714326421519,\"OutPoint_Y\":481.89895030845889},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{630.6365492934068, -52.649609778091417}\",\"VNPrevPointForRadiusKey\":\"{630.6365492934068, -52.649609778091417}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":270.46662435287561,\"AnchorPoint_Y\":481.85242937509298,\"inPoint_Y\":481.85242937509298,\"OutPoint_X\":291.68464211968808,\"AnchorPoint_X\":270.46662435287561,\"OutPoint_Y\":491.96348695323337},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{615.05195634072243, -0.32807510055368994}\",\"VNPrevPointForRadiusKey\":\"{615.05195634072243, -0.32807510055368994}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":54}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":55}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":54},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":8}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":48},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":6}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setElements:","targetGID":55},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":48},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":54}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1.0330248439984473, -0, -0, 0.99999999999999989, -11.379876833051835, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[55]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":56}],"methodSignature":"removeObject:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":55},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":7}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":21},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":3}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":30},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":2}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":32},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":3}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":27},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":29},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":31},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setElements:","targetGID":56},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":27},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":29},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":30},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":21},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":31},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":32},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":0}],"methodSignature":"setGroup:","targetGID":55}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":57}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -290.115478515625, 62.302734375]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.042222879700741525,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.89467432944640213,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.042222879700741525,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.90097236067321962,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.031593452065677957,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.91739226661025597,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.019517801575741518,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.93616537665754818,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.0091232041181144082,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.94328004740819738,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0.0018620895127118644,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.95006183205443251,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.95531556443573817,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9587083584477003,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.96669617604784863,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.96977202191904677,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.97283138648692502,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.97731792325435829,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9818318081185089,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9863455118694362,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.99094089768406901,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.99553628349870182,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":1,\"WDHueKey\":0.5806878306878307,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":0.10000000149011612}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"$class\":\"StrokeStyle\",\"WDColorKey\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":0,\"$class\":\"Vectornator.Color\"},\"WDEndArrowKey\":\"\",\"WDCapKey\":0,\"WDStartArrowKey\":\"\",\"WDJoinKey\":1,\"WDWeightKey\":0.10000000149011612}}","argumentGID":0}],"methodSignature":"setStrokeStyle:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -138.240478515625, -358.288818359375]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":56},{"argumentTypeRawValue":1,"argumentEncodedJsonString":"{\"Argument\":0}","argumentGID":0}],"methodSignature":"insertObject:atIndex:","targetGID":4},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentGID":56}],"methodSignature":"removeObject:","targetGID":4}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 10.2197265625, 7.887451171875]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1.73681640625, -1.3956298828125]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":0,\"WDHueKey\":0,\"WDAlphaKey\":1,\"WDBrightnessKey\":1,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.5806878306878307,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.5806878306878307,\"WDAlphaKey\":1,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.96954748896640086,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.96362693977790437,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.95841712343394081,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.954131593465262,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.93934857275056949,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.83357840083997725,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.80253639308086555,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.76741239856207288,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.7565612097807517,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.73508462058656032,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.69529915290432798,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.68285743522209563,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.66214385499715267,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.64970324957289294,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.63305608449601369,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.62061547907175396,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.60169597095671978,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.59555519468963558,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.5870419721668565,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.57588046341116172,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.56733832218109337,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.5457271497722096,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.51220146996013671,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.45939702270785876,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.41278562784738043,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.38011749893223234,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.35006206399487472,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.33336373505125283,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.31040673049544421,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.29577720138097952,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.27499243664578588,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.25639993237471526,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.24782776017938496,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.23669294561503418,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.22722206897779043,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.22344372864464693,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.21991675861332574,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.21874110193621868,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.2197966347522779,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.23113499252562641,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.24180488325740318,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.2529452591116173,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.28146132901480636,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.29042946504840544,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.29303437322038722,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.30319262528473806,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.31050016016514809,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.31284924900341687,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.31402379342255127,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.31192273811218679,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.31087054207004555,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.30975717183940776,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"WDSaturationKey\":1,\"WDHueKey\":0.58068782091140747,\"WDAlphaKey\":0.3074892778331435,\"WDBrightnessKey\":0.9882352941176471,\"$class\":\"Vectornator.Color\"}}","argumentGID":0}],"methodSignature":"setFill:","targetGID":57}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1.0000066161593433, -0, -0, 1.0000066161593433, -0.00084115369224984499, -0.0015278888873493538]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -0, 1]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 106.25150911801597, 215.10157288799655]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":1,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {1024, 1024}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {1018.1834573966, 1022.316502396953}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {1008.5644489681886, 1015.9218488910001}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {1003.3383988868811, 1012.188740268123}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {959.56182404754463, 968.37466824766148}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {930.99873639690077, 938.04865943448704}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {883.88375480634159, 898.86742705675647}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {851.39277451811745, 876.13749149913815}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {807.42735481491377, 847.80421878677203}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {780.8131139470363, 833.66058405713125}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {758.18676120653936, 823.6793880913026}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {745.42543866806363, 820.26800024929958}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {738.45307691385142, 820.26800024929958}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {738.07015268029545, 820.26800024929958}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {738.07015268029545, 820.65313908147255}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {735.7456294412641, 820.1359296408807}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {734.20024226104533, 819.105537302637}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {730.82720724054207, 815.73250228213374}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {722.51078545309133, 807.41391622785272}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {715.22999050970566, 800.13291995732015}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {710.02528110597814, 794.3195482564854}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {708.99086222479468, 792.76802059828378}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {705.03881032957679, 786.83843280185465}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {703.71729893680003, 785.04591654871797}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {702.86608775936838, 784.19455437592615}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {701.16326275021129, 782.49188036212945}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {700.77188277648224, 782.10024872946656}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {699.97704320020512, 781.30550981676288}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {699.12865060283116, 780.87985389626033}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {698.70304501411556, 780.45414764397106}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {695.54100084364723, 776.8204946317021}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {693.70127337454369, 774.98056583545167}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {691.86235121402819, 772.67134345959084}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {689.97672115541332, 769.84279770809485}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {689.03491276184081, 768.90119064166925}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {686.67817717929256, 766.07264489017348}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {683.90469440249581, 763.76603976722345}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {682.53607245732564, 762.86897633206718}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {681.17026909221318, 762.39756881741346}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {678.95083862390538, 761.54620664462163}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {676.30580256688177, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {675.07408308165805, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {673.28025820206608, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {671.48603066818009, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {670.54341696601955, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {669.17600298373122, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {667.39103649860635, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {666.44842279644581, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {666.02281720772999, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {665.226367014277, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {663.57830298909857, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.7291050831368, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.92701772956843, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.54691207607016, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.15190821369538, 761.07479912996791}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.15190821369538, 760.69429082217562}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.15190821369538, 760.30406847954168}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.15190821369538, 759.91817467056762}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.15190821369538, 759.52795232793369}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.15190821369538, 759.12605301077474}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.15190821369538, 758.73814593033103}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.15190821369538, 758.35446671997374}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.55134127330371, 758.35446671997374}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.55134127330371, 757.96107347477482}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.55134127330371, 757.57593464260208}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.97694686201953, 757.57593464260208}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.3896675133285, 757.18274272455005}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.3896675133285, 756.35493582795493}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 755.94518475206382}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 755.5517915068649}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 754.78614436689986}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 754.3960730196261}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 754.00237778370661}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 753.60918586565458}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 753.21065877820774}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 752.81701387407497}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 752.41430924832821}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 749.69714774089903}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 748.93285955917622}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 747.99004452986878}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 747.13868235707696}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.79916693028599, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.41906127678772, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.65522608114543, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.27149653900142, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {660.88132452815421, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {660.48793128295529, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {659.69429966956, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {659.30453031300658, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {659.68503862079888, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {660.0695734715307, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {660.47263041978476, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {660.86843959074758, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.25498771294906, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {661.63670398362319, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.02566803158879, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {662.83158060094979, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {664.08383545516563, 745.8865784982213}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {665.7862578100287, 746.7378903392264}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {667.06307457617595, 747.16359659151567}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {669.70851328749336, 748.01490843252077}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {670.98533005364084, 748.44061468481004}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {672.66399580516031, 748.84437627807847}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {673.94081257130756, 749.26907589463281}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {675.19387273411121, 749.69478214692208}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {675.58525270784025, 749.69478214692208}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {675.20474440004818, 749.69478214692208}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {673.93235683113426, 749.26907589463281}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3},{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {672.1381292972485, 747.52296554887494}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {670.87500277709569, 747.09725929658589}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {670.47194582884163, 746.2471050866759}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {669.64368594616599, 745.41864387685314}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {669.24787677520317, 745.02308636482417}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {669.24787677520317, 744.6337699943515}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":287.2857717617394,\"AnchorPoint_Y\":289.25600703483042,\"inPoint_Y\":289.25600703483042,\"OutPoint_X\":287.2857717617394,\"AnchorPoint_X\":287.2857717617394,\"OutPoint_Y\":289.25600703483042},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{59.351577569932488, -881.2368652940595}\",\"VNPrevPointForRadiusKey\":\"{59.351577569932488, -881.2368652940595}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":437.28477645924727,\"AnchorPoint_Y\":289.25600703483042,\"inPoint_Y\":289.25600703483042,\"OutPoint_X\":437.28477645924727,\"AnchorPoint_X\":437.28477645924727,\"OutPoint_Y\":289.25600703483042},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{59.351577569932488, -881.2368652940595}\",\"VNPrevPointForRadiusKey\":\"{59.351577569932488, -881.2368652940595}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":437.28477645924727,\"AnchorPoint_Y\":539.25435579077384,\"inPoint_Y\":539.25435579077384,\"OutPoint_X\":437.28477645924727,\"AnchorPoint_X\":437.28477645924727,\"OutPoint_Y\":539.25435579077384},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{59.351577569932488, -881.2368652940595}\",\"VNPrevPointForRadiusKey\":\"{59.351577569932488, -881.2368652940595}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":287.2857717617394,\"AnchorPoint_Y\":539.25435579077384,\"inPoint_Y\":539.25435579077384,\"OutPoint_X\":287.2857717617394,\"AnchorPoint_X\":287.2857717617394,\"OutPoint_Y\":539.25435579077384},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{59.351577569932488, -881.2368652940595}\",\"VNPrevPointForRadiusKey\":\"{59.351577569932488, -881.2368652940595}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":22},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":287.2857717617394,\"AnchorPoint_Y\":289.25602785985438,\"inPoint_Y\":330.67709661876142,\"OutPoint_X\":287.2857717617394,\"AnchorPoint_X\":287.2857717617394,\"OutPoint_Y\":247.83495910094825},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-173.55249370630804, -465.50590420624349}\",\"VNPrevPointForRadiusKey\":\"{-173.55249370630804, -465.50590420624349}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":320.86422761918971,\"AnchorPoint_Y\":214.25650324349817,\"inPoint_Y\":214.25650324349817,\"OutPoint_X\":403.70636513700288,\"AnchorPoint_X\":362.28529637809629,\"OutPoint_Y\":214.25650324349817},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-173.55249370630804, -465.50590420624349}\",\"VNPrevPointForRadiusKey\":\"{-173.55249370630804, -465.50590420624349}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":437.28477402925387,\"AnchorPoint_Y\":289.25602785985438,\"inPoint_Y\":247.83495910094825,\"OutPoint_X\":437.28477402925387,\"AnchorPoint_X\":437.28477402925387,\"OutPoint_Y\":330.67709661876142},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-173.55249370630804, -465.50590420624349}\",\"VNPrevPointForRadiusKey\":\"{-173.55249370630804, -465.50590420624349}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":403.70636513700288,\"AnchorPoint_Y\":364.25550551101242,\"inPoint_Y\":364.25550551101242,\"OutPoint_X\":320.86422761918971,\"AnchorPoint_X\":362.28529637809629,\"OutPoint_Y\":364.25550551101242},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-173.55249370630804, -465.50590420624349}\",\"VNPrevPointForRadiusKey\":\"{-173.55249370630804, -465.50590420624349}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":24},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":287.2857717617394,\"AnchorPoint_Y\":539.25437383096278,\"inPoint_Y\":580.67544258986891,\"OutPoint_X\":287.2857717617394,\"AnchorPoint_X\":287.2857717617394,\"OutPoint_Y\":497.83330507205574},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-173.55249370630804, -215.50755823513555}\",\"VNPrevPointForRadiusKey\":\"{-173.55249370630804, -215.50755823513555}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":320.86422761918971,\"AnchorPoint_Y\":464.25484921460566,\"inPoint_Y\":464.25484921460566,\"OutPoint_X\":403.70636513700288,\"AnchorPoint_X\":362.28529637809629,\"OutPoint_Y\":464.25484921460566},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-173.55249370630804, -215.50755823513555}\",\"VNPrevPointForRadiusKey\":\"{-173.55249370630804, -215.50755823513555}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":437.28477402925387,\"AnchorPoint_Y\":539.25437383096278,\"inPoint_Y\":497.83330507205574,\"OutPoint_X\":437.28477402925387,\"AnchorPoint_X\":437.28477402925387,\"OutPoint_Y\":580.67544258986891},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-173.55249370630804, -215.50755823513555}\",\"VNPrevPointForRadiusKey\":\"{-173.55249370630804, -215.50755823513555}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":403.70636513700288,\"AnchorPoint_Y\":614.2538514821199,\"inPoint_Y\":614.2538514821199,\"OutPoint_X\":320.86422761918971,\"AnchorPoint_X\":362.28529637809629,\"OutPoint_Y\":614.2538514821199},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{-173.55249370630804, -215.50755823513555}\",\"VNPrevPointForRadiusKey\":\"{-173.55249370630804, -215.50755823513555}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":25},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":297.2857056005837,\"AnchorPoint_Y\":289.07321462503751,\"inPoint_Y\":289.07321462503751,\"OutPoint_X\":297.2857056005837,\"AnchorPoint_X\":297.2857056005837,\"OutPoint_Y\":289.07321462503751},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{99.742735489559436, -881.41965770385173}\",\"VNPrevPointForRadiusKey\":\"{99.742735489559436, -881.41965770385173}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":427.28484419717574,\"AnchorPoint_Y\":289.07321462503751,\"inPoint_Y\":289.07321462503751,\"OutPoint_X\":427.28484419717574,\"AnchorPoint_X\":427.28484419717574,\"OutPoint_Y\":289.07321462503751},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{99.742735489559436, -881.41965770385173}\",\"VNPrevPointForRadiusKey\":\"{99.742735489559436, -881.41965770385173}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":427.28484419717574,\"AnchorPoint_Y\":539.07156338098093,\"inPoint_Y\":539.07156338098093,\"OutPoint_X\":427.28484419717574,\"AnchorPoint_X\":427.28484419717574,\"OutPoint_Y\":539.07156338098093},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{99.742735489559436, -881.41965770385173}\",\"VNPrevPointForRadiusKey\":\"{99.742735489559436, -881.41965770385173}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":297.2857056005837,\"AnchorPoint_Y\":539.07156338098093,\"inPoint_Y\":539.07156338098093,\"OutPoint_X\":297.2857056005837,\"AnchorPoint_X\":297.2857056005837,\"OutPoint_Y\":539.07156338098093},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{99.742735489559436, -881.41965770385173}\",\"VNPrevPointForRadiusKey\":\"{99.742735489559436, -881.41965770385173}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":26},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":97.57351080287799,\"AnchorPoint_Y\":309.16721333385931,\"inPoint_Y\":309.16721333385931,\"OutPoint_X\":97.57351080287799,\"AnchorPoint_X\":97.57351080287799,\"OutPoint_Y\":309.16721333385931},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{78.505876495528582, 146.69454513811797}\",\"VNPrevPointForRadiusKey\":\"{78.505876495528582, 146.69454513811797}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":221.36797043606543,\"AnchorPoint_Y\":443.90288627635027,\"inPoint_Y\":443.90288627635027,\"OutPoint_X\":221.36797043606543,\"AnchorPoint_X\":221.36797043606543,\"OutPoint_Y\":443.90288627635027},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{78.505876495528582, 146.69454513811797}\",\"VNPrevPointForRadiusKey\":\"{78.505876495528582, 146.69454513811797}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":361.08361414401247,\"AnchorPoint_Y\":309.6035637643763,\"inPoint_Y\":309.6035637643763,\"OutPoint_X\":361.08361414401247,\"AnchorPoint_X\":361.08361414401247,\"OutPoint_Y\":309.6035637643763},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{78.505876495528582, 146.69454513811797}\",\"VNPrevPointForRadiusKey\":\"{78.505876495528582, 146.69454513811797}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":29},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":377.82365759764593,\"AnchorPoint_Y\":307.07623767819223,\"inPoint_Y\":307.07623767819223,\"OutPoint_X\":377.82365759764593,\"AnchorPoint_X\":377.82365759764593,\"OutPoint_Y\":307.07623767819223},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{358.49705139509047, 146.65290478922907}\",\"VNPrevPointForRadiusKey\":\"{358.49705139509047, 146.65290478922907}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":503.2994629767461,\"AnchorPoint_Y\":440.11243356580462,\"inPoint_Y\":440.11243356580462,\"OutPoint_X\":503.2994629767461,\"AnchorPoint_X\":503.2994629767461,\"OutPoint_Y\":440.11243356580462},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{358.49705139509047, 146.65290478922907}\",\"VNPrevPointForRadiusKey\":\"{358.49705139509047, 146.65290478922907}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":644.91269001662772,\"AnchorPoint_Y\":307.50708423933065,\"inPoint_Y\":307.50708423933065,\"OutPoint_X\":644.91269001662772,\"AnchorPoint_X\":644.91269001662772,\"OutPoint_Y\":307.50708423933065},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{358.49705139509047, 146.65290478922907}\",\"VNPrevPointForRadiusKey\":\"{358.49705139509047, 146.65290478922907}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":30},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":516.45695350382334,\"AnchorPoint_Y\":154.80813254227905,\"inPoint_Y\":154.80813254227905,\"OutPoint_X\":516.45695350382334,\"AnchorPoint_X\":516.45695350382334,\"OutPoint_Y\":154.80813254227905},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{1033.732755685123, -115.61701281386331}\",\"VNPrevPointForRadiusKey\":\"{1033.732755685123, -115.61701281386331}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":223.97172601151692,\"AnchorPoint_Y\":448.88181029919406,\"inPoint_Y\":448.88181029919406,\"OutPoint_X\":223.97172601151692,\"AnchorPoint_X\":223.97172601151692,\"OutPoint_Y\":448.88181029919406},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{1033.732755685123, -115.61701281386331}\",\"VNPrevPointForRadiusKey\":\"{1033.732755685123, -115.61701281386331}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":78.252109034647219,\"AnchorPoint_Y\":300.1041732651538,\"inPoint_Y\":300.1041732651538,\"OutPoint_X\":78.252109034647219,\"AnchorPoint_X\":78.252109034647219,\"OutPoint_Y\":300.1041732651538},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{1033.732755685123, -115.61701281386331}\",\"VNPrevPointForRadiusKey\":\"{1033.732755685123, -115.61701281386331}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":648.07861404640448,\"AnchorPoint_Y\":302.9355554780409,\"inPoint_Y\":302.9355554780409,\"OutPoint_X\":648.07861404640448,\"AnchorPoint_X\":648.07861404640448,\"OutPoint_Y\":302.9355554780409},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{1033.732755685123, -115.61701281386331}\",\"VNPrevPointForRadiusKey\":\"{1033.732755685123, -115.61701281386331}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":506.17105679039673,\"AnchorPoint_Y\":444.7847840681311,\"inPoint_Y\":444.7847840681311,\"OutPoint_X\":506.17105679039673,\"AnchorPoint_X\":506.17105679039673,\"OutPoint_Y\":444.7847840681311},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{1033.732755685123, -115.61701281386331}\",\"VNPrevPointForRadiusKey\":\"{1033.732755685123, -115.61701281386331}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":217.51314851045686,\"AnchorPoint_Y\":156.11368443580113,\"inPoint_Y\":156.11368443580113,\"OutPoint_X\":217.51314851045686,\"AnchorPoint_X\":217.51314851045686,\"OutPoint_Y\":156.11368443580113},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{1033.732755685123, -115.61701281386331}\",\"VNPrevPointForRadiusKey\":\"{1033.732755685123, -115.61701281386331}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":21},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":290.26965144695237,\"AnchorPoint_Y\":418.73751961026619,\"inPoint_Y\":418.73751961026619,\"OutPoint_X\":290.26965144695237,\"AnchorPoint_X\":290.26965144695237,\"OutPoint_Y\":418.73751961026619},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{78.505876495528582, 146.69454513811797}\",\"VNPrevPointForRadiusKey\":\"{78.505876495528582, 146.69454513811797}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":433.31216208615911,\"AnchorPoint_Y\":418.73751961026619,\"inPoint_Y\":418.73751961026619,\"OutPoint_X\":433.31216208615911,\"AnchorPoint_X\":433.31216208615911,\"OutPoint_Y\":418.73751961026619},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{78.505876495528582, 146.69454513811797}\",\"VNPrevPointForRadiusKey\":\"{78.505876495528582, 146.69454513811797}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":31},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":290.26965144695237,\"AnchorPoint_Y\":521.73683815036247,\"inPoint_Y\":521.73683815036247,\"OutPoint_X\":290.26965144695237,\"AnchorPoint_X\":290.26965144695237,\"OutPoint_Y\":521.73683815036247},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{78.505876495528582, 249.69386367821471}\",\"VNPrevPointForRadiusKey\":\"{78.505876495528582, 249.69386367821471}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":433.31216208615911,\"AnchorPoint_Y\":521.73683815036247,\"inPoint_Y\":521.73683815036247,\"OutPoint_X\":433.31216208615911,\"AnchorPoint_X\":433.31216208615911,\"OutPoint_Y\":521.73683815036247},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{78.505876495528582, 249.69386367821471}\",\"VNPrevPointForRadiusKey\":\"{78.505876495528582, 249.69386367821471}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":32},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":362.67570746371234,\"AnchorPoint_Y\":667.02363476289884,\"inPoint_Y\":638.68961321030247,\"OutPoint_X\":362.18143434711533,\"AnchorPoint_X\":362.18143434711533,\"OutPoint_Y\":667.02363476289884},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{66.606350517013652, 108.16792868331186}\",\"VNPrevPointForRadiusKey\":\"{66.606350517013652, 108.16792868331186}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":362.23296334642896,\"AnchorPoint_Y\":616.38299074283532,\"inPoint_Y\":616.38299074283532,\"OutPoint_X\":362.23296334642896,\"AnchorPoint_X\":362.23296334642896,\"OutPoint_Y\":616.38299074283532},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{49.435773574115046, 81.837967291336099}\",\"VNPrevPointForRadiusKey\":\"{49.435773574115046, 81.837967291336099}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":398.08909406988482,\"AnchorPoint_Y\":616.33647011725679,\"inPoint_Y\":616.33647011725679,\"OutPoint_X\":377.54953250055337,\"AnchorPoint_X\":398.08909406988482,\"OutPoint_Y\":626.44746079947163},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{64.522041763846801, 134.1591558035534}\",\"VNPrevPointForRadiusKey\":\"{64.522041763846801, 134.1591558035534}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":48},{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":[{\"NodePoints\":{\"inPoint_X\":361.7537539269963,\"AnchorPoint_Y\":667.02363476289884,\"inPoint_Y\":638.68961321030247,\"OutPoint_X\":362.24802704359331,\"AnchorPoint_X\":362.24802704359331,\"OutPoint_Y\":667.02363476289884},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{657.82311087369476, 108.16792868331186}\",\"VNPrevPointForRadiusKey\":\"{657.82311087369476, 108.16792868331186}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":362.19649804427968,\"AnchorPoint_Y\":616.38299074283532,\"inPoint_Y\":616.38299074283532,\"OutPoint_X\":362.19649804427968,\"AnchorPoint_X\":362.19649804427968,\"OutPoint_Y\":616.38299074283532},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{674.99368781659336, 81.837967291336099}\",\"VNPrevPointForRadiusKey\":\"{674.99368781659336, 81.837967291336099}\",\"$class\":\"WDBezierNode\"},{\"NodePoints\":{\"inPoint_X\":326.34036732082382,\"AnchorPoint_Y\":616.33647011725679,\"inPoint_Y\":616.33647011725679,\"OutPoint_X\":346.87992889015482,\"AnchorPoint_X\":326.34036732082382,\"OutPoint_Y\":626.44746079947163},\"NodeTypeOverride\":0,\"VNNextPointForRadiusKey\":\"{659.90741962686184, 134.1591558035534}\",\"VNPrevPointForRadiusKey\":\"{659.90741962686184, 134.1591558035534}\",\"$class\":\"WDBezierNode\"}]}","argumentGID":0}],"methodSignature":"setNodes:","targetGID":54}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, -1, 0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"proxy","methodArguments":[{"argumentTypeRawValue":6,"argumentEncodedJsonString":"{\"Argument\":\"[1, -0, -0, 1, 1, -0]\"}","argumentGID":0},{"argumentTypeRawValue":5,"argumentEncodedJsonString":"{\"Argument\":[57,56]}","argumentGID":0},{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"UpdateAngleAfterTransformTransformOptionKey\":0,\"TransformingNodesTransformOptionKey\":false}}","argumentGID":0}],"methodSignature":"applyTransform:forElements:options:","targetGID":0}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":\"Mac App icon\"}","argumentGID":0}],"methodSignature":"title","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {740, 744.6337699943515}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}],[{"actionTypeRawValue":"dynamicProxy","methodArguments":[{"argumentTypeRawValue":4,"argumentEncodedJsonString":"{\"Argument\":{\"NS.special\":3,\"NS.rectval\":\"{{0, 0}, {745, 744.6337699943515}}\",\"$class\":\"NSValue\"}}","argumentGID":0}],"methodSignature":"frame","targetGID":3}]],"isGroupingUndo":false,"currentUndoGroup":[],"currentRedoGroup":[],"isGroupingRedo":false,"redoStack":[],"nextGID":57}
diff --git a/docs/mkdocs/mkdocs.yml b/docs/mkdocs/mkdocs.yml
index 3bade7b..0ddc982 100644
--- a/docs/mkdocs/mkdocs.yml
+++ b/docs/mkdocs/mkdocs.yml
@@ -7,6 +7,8 @@ nav:
- Getting Started: getting_started.md
- Development:
- Python Environments: development/python_environments.md
+ - Contributing: development/contributing.md
+ - Code Style: development/code_style.md
- Use Cases:
- Overview: use_cases/index.md
- Use Case 1: use_cases/use_case_1.md
@@ -41,10 +43,15 @@ nav:
- Apps & Tools:
- Overview: apps_and_tools/index.md
- Console: apps_and_tools/console.md
- - Link Relay: apps_and_tools/link_relay.md
+ - Bench: apps_and_tools/bench.md
- HCI Bridge: apps_and_tools/hci_bridge.md
- Golden Gate Bridge: apps_and_tools/gg_bridge.md
- Show: apps_and_tools/show.md
+ - GATT Dump: apps_and_tools/gatt_dump.md
+ - Pair: apps_and_tools/pair.md
+ - Unbond: apps_and_tools/unbond.md
+ - USB Probe: apps_and_tools/usb_probe.md
+ - Link Relay: apps_and_tools/link_relay.md
- Hardware:
- Overview: hardware/index.md
- Platforms:
@@ -56,7 +63,7 @@ nav:
- Examples:
- Overview: examples/index.md
-copyright: Copyright 2021-2022 Google LLC
+copyright: Copyright 2021-2023 Google LLC
theme:
name: 'material'
diff --git a/docs/mkdocs/requirements.txt b/docs/mkdocs/requirements.txt
index a9b8452..a241683 100644
--- a/docs/mkdocs/requirements.txt
+++ b/docs/mkdocs/requirements.txt
@@ -1,6 +1,6 @@
# This requirements file is for python3
-mkdocs == 1.2.3
-mkdocs-material == 7.1.7
-mkdocs-material-extensions == 1.0.1
-pymdown-extensions == 8.2
-mkdocstrings == 0.15.1 \ No newline at end of file
+mkdocs == 1.4.0
+mkdocs-material == 8.5.6
+mkdocs-material-extensions == 1.0.3
+pymdown-extensions == 10.0
+mkdocstrings-python == 0.7.1
diff --git a/docs/mkdocs/src/api/examples.md b/docs/mkdocs/src/api/examples.md
index bcf30a3..3f73b7b 100644
--- a/docs/mkdocs/src/api/examples.md
+++ b/docs/mkdocs/src/api/examples.md
@@ -1,2 +1,2 @@
API EXAMPLES
-============ \ No newline at end of file
+============
diff --git a/docs/mkdocs/src/api/guide.md b/docs/mkdocs/src/api/guide.md
index b799faf..2a4aa06 100644
--- a/docs/mkdocs/src/api/guide.md
+++ b/docs/mkdocs/src/api/guide.md
@@ -1,2 +1,2 @@
API DEVELOPER GUIDE
-=================== \ No newline at end of file
+===================
diff --git a/docs/mkdocs/src/api/reference.md b/docs/mkdocs/src/api/reference.md
index cedc2c1..a5ff1bc 100644
--- a/docs/mkdocs/src/api/reference.md
+++ b/docs/mkdocs/src/api/reference.md
@@ -16,4 +16,3 @@ Bumble Python API
### HCI_Disconnect_Command
::: bumble.hci.HCI_Disconnect_Command
-
diff --git a/docs/mkdocs/src/apps_and_tools/bench.md b/docs/mkdocs/src/apps_and_tools/bench.md
new file mode 100644
index 0000000..db785d6
--- /dev/null
+++ b/docs/mkdocs/src/apps_and_tools/bench.md
@@ -0,0 +1,158 @@
+BENCH TOOL
+==========
+
+The "bench" tool implements a number of different ways of measuring the
+throughput and/or latency between two devices.
+
+# General Usage
+
+```
+Usage: bench.py [OPTIONS] COMMAND [ARGS]...
+
+Options:
+ --device-config FILENAME Device configuration file
+ --role [sender|receiver|ping|pong]
+ --mode [gatt-client|gatt-server|l2cap-client|l2cap-server|rfcomm-client|rfcomm-server]
+ --att-mtu MTU GATT MTU (gatt-client mode) [23<=x<=517]
+ -s, --packet-size SIZE Packet size (server role) [8<=x<=4096]
+ -c, --packet-count COUNT Packet count (server role)
+ -sd, --start-delay SECONDS Start delay (server role)
+ --help Show this message and exit.
+
+Commands:
+ central Run as a central (initiates the connection)
+ peripheral Run as a peripheral (waits for a connection)
+```
+
+## Options for the ``central`` Command
+```
+Usage: bumble-bench central [OPTIONS] TRANSPORT
+
+ Run as a central (initiates the connection)
+
+Options:
+ --peripheral ADDRESS_OR_NAME Address or name to connect to
+ --connection-interval, --ci CONNECTION_INTERVAL
+ Connection interval (in ms)
+ --phy [1m|2m|coded] PHY to use
+ --help Show this message and exit.
+```
+
+
+To test once device against another, one of the two devices must be running
+the ``peripheral`` command and the other the ``central`` command. The device
+running the ``peripheral`` command will accept connections from the device
+running the ``central`` command.
+When using Bluetooth LE (all modes except for ``rfcomm-server`` and ``rfcomm-client``utils),
+the default addresses configured in the tool should be sufficient. But when using
+Bluetooth Classic, the address of the Peripheral must be specified on the Central
+using the ``--peripheral`` option. The address will be printed by the Peripheral when
+it starts.
+
+Independently of whether the device is the Central or Peripheral, each device selects a
+``mode`` and and ``role`` to run as. The ``mode`` and ``role`` of the Central and Peripheral
+must be compatible.
+
+Device 1 mode | Device 2 mode
+------------------|------------------
+``gatt-client`` | ``gatt-server``
+``l2cap-client`` | ``l2cap-server``
+``rfcomm-client`` | ``rfcomm-server``
+
+Device 1 role | Device 2 role
+--------------|--------------
+``sender`` | ``receiver``
+``ping`` | ``pong``
+
+
+# Examples
+
+In the following examples, we have two USB Bluetooth controllers, one on `usb:0` and
+the other on `usb:1`, and two consoles/terminals. We will run a command in each.
+
+!!! example "GATT Throughput"
+ Using the default mode and role for the Central and Peripheral.
+
+ In the first console/terminal:
+ ```
+ $ bumble-bench peripheral usb:0
+ ```
+
+ In the second console/terminal:
+ ```
+ $ bumble-bench central usb:1
+ ```
+
+ In this default configuration, the Central runs a Sender, as a GATT client,
+ connecting to the Peripheral running a Receiver, as a GATT server.
+
+!!! example "L2CAP Throughput"
+ In the first console/terminal:
+ ```
+ $ bumble-bench --mode l2cap-server peripheral usb:0
+ ```
+
+ In the second console/terminal:
+ ```
+ $ bumble-bench --mode l2cap-client central usb:1
+ ```
+
+!!! example "RFComm Throughput"
+ In the first console/terminal:
+ ```
+ $ bumble-bench --mode rfcomm-server peripheral usb:0
+ ```
+
+ NOTE: the BT address of the Peripheral will be printed out, use it with the
+ ``--peripheral`` option for the Central.
+
+ In this example, we use a larger packet size and packet count than the default.
+
+ In the second console/terminal:
+ ```
+ $ bumble-bench --mode rfcomm-client --packet-size 2000 --packet-count 100 central --peripheral 00:16:A4:5A:40:F2 usb:1
+ ```
+
+!!! example "Ping/Pong Latency"
+ In the first console/terminal:
+ ```
+ $ bumble-bench --role pong peripheral usb:0
+ ```
+
+ In the second console/terminal:
+ ```
+ $ bumble-bench --role ping central usb:1
+ ```
+
+!!! example "Reversed modes with GATT and custom connection interval"
+ In the first console/terminal:
+ ```
+ $ bumble-bench --mode gatt-client peripheral usb:0
+ ```
+
+ In the second console/terminal:
+ ```
+ $ bumble-bench --mode gatt-server central --ci 10 usb:1
+ ```
+
+!!! example "Reversed modes with L2CAP and custom PHY"
+ In the first console/terminal:
+ ```
+ $ bumble-bench --mode l2cap-client peripheral usb:0
+ ```
+
+ In the second console/terminal:
+ ```
+ $ bumble-bench --mode l2cap-server central --phy 2m usb:1
+ ```
+
+!!! example "Reversed roles with L2CAP"
+ In the first console/terminal:
+ ```
+ $ bumble-bench --mode l2cap-client --role sender peripheral usb:0
+ ```
+
+ In the second console/terminal:
+ ```
+ $ bumble-bench --mode l2cap-server --role receiver central usb:1
+ ```
diff --git a/docs/mkdocs/src/apps_and_tools/console.md b/docs/mkdocs/src/apps_and_tools/console.md
index 9abdf2b..c8e1769 100644
--- a/docs/mkdocs/src/apps_and_tools/console.md
+++ b/docs/mkdocs/src/apps_and_tools/console.md
@@ -7,10 +7,12 @@ The Console app is an interactive text user interface that offers a number of fu
* scanning
* advertising
- * connecting to devices
+ * connecting to and disconnecting from devices
* changing connection parameters
+ * enabling encryption
* discovering GATT services and characteristics
- * read & write GATT characteristics
+ * reading and writing GATT characteristics
+ * subscribing to and unsubscribing from GATT characteristics
The console user interface has 3 main panes:
diff --git a/docs/mkdocs/src/apps_and_tools/gg_bridge.md b/docs/mkdocs/src/apps_and_tools/gg_bridge.md
index 950f47c..316f7a3 100644
--- a/docs/mkdocs/src/apps_and_tools/gg_bridge.md
+++ b/docs/mkdocs/src/apps_and_tools/gg_bridge.md
@@ -1,2 +1,2 @@
GOLDEN GATE BRIDGE
-================== \ No newline at end of file
+==================
diff --git a/docs/mkdocs/src/apps_and_tools/hci_bridge.md b/docs/mkdocs/src/apps_and_tools/hci_bridge.md
index c8def63..d0ea1fc 100644
--- a/docs/mkdocs/src/apps_and_tools/hci_bridge.md
+++ b/docs/mkdocs/src/apps_and_tools/hci_bridge.md
@@ -28,5 +28,3 @@ a host that send custom HCI commands that the controller may not understand.
(through which the communication with other virtual controllers will be mediated).
NOTE: this assumes you're running a Link Relay on port `10723`.
-
-
diff --git a/docs/mkdocs/src/apps_and_tools/index.md b/docs/mkdocs/src/apps_and_tools/index.md
index cd8b346..fe7af56 100644
--- a/docs/mkdocs/src/apps_and_tools/index.md
+++ b/docs/mkdocs/src/apps_and_tools/index.md
@@ -5,10 +5,10 @@ Included in the project are a few apps and tools, built on top of the core libra
These include:
* [Console](console.md) - an interactive text-based console
+ * [Bench](bench.md) - Speed and Latency benchmarking between two devices (LE and Classic)
* [Pair](pair.md) - Pair/bond two devices (LE and Classic)
* [Unbond](unbond.md) - Remove a previously established bond
* [HCI Bridge](hci_bridge.md) - a HCI transport bridge to connect two HCI transports and filter/snoop the HCI packets
* [Golden Gate Bridge](gg_bridge.md) - a bridge between GATT and UDP to use with the Golden Gate "stack tool"
* [Show](show.md) - Parse a file with HCI packets and print the details of each packet in a human readable form
* [Link Relay](link_relay.md) - WebSocket relay for virtual RemoteLink instances to communicate with each other.
-
diff --git a/docs/mkdocs/src/apps_and_tools/link_relay.md b/docs/mkdocs/src/apps_and_tools/link_relay.md
index 533c525..ff3fb8b 100644
--- a/docs/mkdocs/src/apps_and_tools/link_relay.md
+++ b/docs/mkdocs/src/apps_and_tools/link_relay.md
@@ -31,4 +31,3 @@ The WebSocket path used by a connecting client indicates which virtual "chat roo
It is possible to connect to a "chat room" in a relay as an observer, rather than a virtual controller. In this case, a text-based console can be used to observe what is going on in the "chat room". Tools like [`wscat`](https://github.com/websockets/wscat#readme) or [`websocat`](https://github.com/vi/websocat) can be used for that.
Example: `wscat --connect ws://localhost:10723/test`
-
diff --git a/docs/mkdocs/src/apps_and_tools/usb_probe.md b/docs/mkdocs/src/apps_and_tools/usb_probe.md
new file mode 100644
index 0000000..dd2585d
--- /dev/null
+++ b/docs/mkdocs/src/apps_and_tools/usb_probe.md
@@ -0,0 +1,50 @@
+USB PROBE TOOL
+==============
+
+This tool lists all the USB devices, with details about each device.
+For each device, the different possible Bumble transport strings that can
+refer to it are listed.
+If the device is known to be a Bluetooth HCI device, its identifier is printed
+in reverse colors, and the transport names in cyan color.
+For other devices, regardless of their type, the transport names are printed
+in red. Whether that device is actually a Bluetooth device or not depends on
+whether it is a Bluetooth device that uses a non-standard Class, or some other
+type of device (there's no way to tell).
+
+## Usage
+
+This command line tool may be invoked with no arguments, or with `--verbose`
+for extra details.
+When installed from PyPI, run as
+```
+$ bumble-usb-probe
+```
+
+or, for extra details, with the `--verbose` argument
+```
+$ bumble-usb-probe --v
+```
+
+When running from the source distribution:
+```
+$ python3 apps/usb-probe.py
+```
+
+or
+
+```
+$ python3 apps/usb-probe.py --verbose
+```
+
+!!! example
+ ```
+ $ python3 apps/usb_probe.py
+
+ ID 0A12:0001
+ Bumble Transport Names: usb:0 or usb:0A12:0001
+ Bus/Device: 020/034
+ Class: Wireless Controller
+ Subclass/Protocol: 1/1 [Bluetooth]
+ Manufacturer: None
+ Product: USB2.0-BT
+ ```
diff --git a/docs/mkdocs/src/components/controller.md b/docs/mkdocs/src/components/controller.md
index 1537712..3588e0f 100644
--- a/docs/mkdocs/src/components/controller.md
+++ b/docs/mkdocs/src/components/controller.md
@@ -1,2 +1,2 @@
CONTROLLER
-========== \ No newline at end of file
+==========
diff --git a/docs/mkdocs/src/components/gatt.md b/docs/mkdocs/src/components/gatt.md
index 614f03c..cdc06d4 100644
--- a/docs/mkdocs/src/components/gatt.md
+++ b/docs/mkdocs/src/components/gatt.md
@@ -1,2 +1,2 @@
GATT
-==== \ No newline at end of file
+====
diff --git a/docs/mkdocs/src/components/host.md b/docs/mkdocs/src/components/host.md
index 5a34473..dc2dbe6 100644
--- a/docs/mkdocs/src/components/host.md
+++ b/docs/mkdocs/src/components/host.md
@@ -1,2 +1,2 @@
HOST
-==== \ No newline at end of file
+====
diff --git a/docs/mkdocs/src/components/security_manager.md b/docs/mkdocs/src/components/security_manager.md
index 4ce3d74..4fa54bf 100644
--- a/docs/mkdocs/src/components/security_manager.md
+++ b/docs/mkdocs/src/components/security_manager.md
@@ -1,2 +1,2 @@
SECURITY MANAGER
-================ \ No newline at end of file
+================
diff --git a/docs/mkdocs/src/development/code_style.md b/docs/mkdocs/src/development/code_style.md
new file mode 100644
index 0000000..1c2bbb9
--- /dev/null
+++ b/docs/mkdocs/src/development/code_style.md
@@ -0,0 +1,43 @@
+CODE STYLE
+==========
+
+The Python code style used in this project follows the [Black code style](https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html).
+
+# Formatting
+
+For now, we are configuring the `black` formatter with the option to leave quotes unchanged.
+The preferred quote style is single quotes, which isn't a configurable option for `Black`, so we are not enforcing it. This may change in the future.
+
+## Ignoring Commit for Git Blame
+
+The adoption of `Black` as a formatter came in late in the project, with already a large code base. As a result, a large number of files were changed in a single commit, which gets in the way of tracing authorship with `git blame`. The file `git-blame-ignore-revs` contains the commit hash of when that mass-formatting event occurred, which you can use to skip it in a `git blame` analysis:
+
+!!! example "Ignoring a commit with `git blame`"
+ ```
+ $ git blame --ignore-revs-file .git-blame-ignore-revs
+ ```
+
+# Linting
+
+The project includes a `pylint` configuration (see the `pyproject.toml` file for details).
+The `pre-commit` checks only enforce that there are no errors. But we strongly recommend that you run the linter with warnings enabled at least, and possibly the "Refactor" ('R') and "Convention" ('C') categories as well.
+To run the linter, use the `project.lint` invoke command.
+
+!!! example "Running the linter with default options"
+ With the default settings, Errors and Warnings are enabled, but Refactor and Convention categories are not.
+ ```
+ $ invoke project.lint
+ ```
+
+!!! example "Running the linter with all categories"
+ ```
+ $ invoke project.lint --disable=""
+ ```
+
+# Editor/IDE Integration
+
+## Visual Studio Code
+
+The project includes a `.vscode/settings.json` file that specifies the `black` formatter and enables an editor ruler at 88 columns.
+You may want to configure your own environment to "format on save" with `black` if you find that useful. We are not making that choice at the workspace level.
+
diff --git a/docs/mkdocs/src/development/contributing.md b/docs/mkdocs/src/development/contributing.md
new file mode 100644
index 0000000..a588938
--- /dev/null
+++ b/docs/mkdocs/src/development/contributing.md
@@ -0,0 +1,11 @@
+CONTRIBUTING TO THE PROJECT
+===========================
+
+To contribute some code to the project, you will need to submit a GitHub Pull Request (a.k.a PR). Please familiarize yourself with how that works (see [GitHub Pull Requests](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests))
+
+You should follow the project's [code style](code_style.md), and pre-check your code before submitting a PR. The GitHub project is set up with some [Actions](https://github.com/features/actions) that will check that a PR passes at least the basic tests and complies with the coding style, but it is still recommended to check that for yourself before submitting a PR.
+To run the basic checks (essentially: running the tests, the linter, and the formatter), use the `project.pre-commit` `invoke` command, and address any issues found:
+
+```
+$ invoke project.pre-commit
+```
diff --git a/docs/mkdocs/src/development/python_environments.md b/docs/mkdocs/src/development/python_environments.md
index 0be529e..1aaf05a 100644
--- a/docs/mkdocs/src/development/python_environments.md
+++ b/docs/mkdocs/src/development/python_environments.md
@@ -1,11 +1,11 @@
PYTHON ENVIRONMENTS
===================
-When you don't want to install Bumble in your main/default python environment,
+When you don't want to install Bumble in your main/default python environment,
using a virtual environment, where the package and its dependencies can be
installed, isolated from the rest, may be useful.
-There are many flavors of python environments and dependency managers.
+There are many flavors of python environments and dependency managers.
This page describes a few of the most common ones.
@@ -16,7 +16,7 @@ Visit the [`venv` documentation](https://docs.python.org/3/library/venv.html) pa
## Pyenv
-`pyenv` lets you easily switch between multiple versions of Python. It's simple, unobtrusive, and follows the UNIX tradition of single-purpose tools that do one thing well.
+`pyenv` lets you easily switch between multiple versions of Python. It's simple, unobtrusive, and follows the UNIX tradition of single-purpose tools that do one thing well.
Visit the [`pyenv` site](https://github.com/pyenv/pyenv) for instructions on how to install
and use `pyenv`
@@ -25,10 +25,10 @@ and use `pyenv`
Conda is a convenient package manager and virtual environment.
The file `environment.yml` is a Conda environment file that you can use to create
a new Conda environment. Once created, you can simply activate this environment when
-working with Bumble.
+working with Bumble.
Visit the [Conda site](https://docs.conda.io/en/latest/) for instructions on how to install
and use Conda.
-A few useful commands:
+A few useful commands:
### Create a new `bumble` Conda environment
```
diff --git a/docs/mkdocs/src/examples/index.md b/docs/mkdocs/src/examples/index.md
index 9e6285f..ae729ae 100644
--- a/docs/mkdocs/src/examples/index.md
+++ b/docs/mkdocs/src/examples/index.md
@@ -69,4 +69,4 @@ An app that connects to an RFComm server and bridges the RFComm channel to a loc
An app that implements an RFComm server and, when a connection is received, bridges the channel to a local TCP socket
## `run_scanner.py`
-An app that scan for BLE devices and print the advertisements received. \ No newline at end of file
+An app that scan for BLE devices and print the advertisements received.
diff --git a/docs/mkdocs/src/getting_started.md b/docs/mkdocs/src/getting_started.md
index 832691a..b2063d1 100644
--- a/docs/mkdocs/src/getting_started.md
+++ b/docs/mkdocs/src/getting_started.md
@@ -5,18 +5,18 @@ GETTING STARTED WITH BUMBLE
You need Python 3.8 or above. Python >= 3.9 is recommended, but 3.8 should be sufficient if
necessary (there may be some optional functionality that will not work on some platforms with
-python 3.8).
+python 3.8).
Visit the [Python site](https://www.python.org/) for instructions on how to install Python
-for your platform.
+for your platform.
Throughout the documentation, when shell commands are shown, it is assumed that you can
invoke Python as
```
$ python
```
-If invoking python is different on your platform (it may be `python3` for example, or just `py` or `py.exe`),
+If invoking python is different on your platform (it may be `python3` for example, or just `py` or `py.exe`),
adjust accordingly.
-You may be simply using Bumble as a module for your own application or as a dependency to your own
+You may be simply using Bumble as a module for your own application or as a dependency to your own
module, or you may be working on modifying or contributing to the Bumble module or example code
itself.
@@ -65,15 +65,17 @@ $ python -m pip install git+https://github.com/google/bumble.git@27c0551
# Working On The Bumble Code
When you work on the Bumble code itself, and run some of the tests or example apps, or import the
-module in your own code, you typically either install the package from source in "development mode" as described above, or you may choose to skip the install phase.
+module in your own code, you typically either install the package from source in "development mode" as described above, or you may choose to skip the install phase.
+
+If you plan on contributing to the project, please read the [contributing](development/contributing.md) section.
## Without Installing
-If you prefer not to install the package (even in development mode), you can load the module directly from its location in the project.
+If you prefer not to install the package (even in development mode), you can load the module directly from its location in the project.
A simple way to do that is to set your `PYTHONPATH` to
point to the root project directory, where the `bumble` subdirectory is located. You may set
`PYTHONPATH` globally, or locally with each command line execution (on Unix-like systems).
-Example with a global `PYTHONPATH`, from a unix shell, when the working directory is the root
+Example with a global `PYTHONPATH`, from a unix shell, when the working directory is the root
directory of the project.
```bash
@@ -96,11 +98,11 @@ $ PYTHONPATH=. python examples/run_advertiser.py examples/device1.json serial:/d
```
# Where To Go Next
-Once you've installed or downloaded Bumble, you can either start using some of the
+Once you've installed or downloaded Bumble, you can either start using some of the
[Bundled apps and tools](apps_and_tools/index.md), or look at the [examples](examples/index.md)
to get a feel for how to use the APIs, and start writing your own applications.
Depending on the use case you're interested in exploring, you may need to use a physical Bluetooth
controller, like a USB dongle or a board with a Bluetooth radio. Visit the [Hardware page](hardware/index.md)
-for more information on using a physical radio, and/or the [Transports page](transports/index.md) for more
+for more information on using a physical radio, and/or the [Transports page](transports/index.md) for more
details on interfacing with either hardware modules or virtual controllers over various transports.
diff --git a/docs/mkdocs/src/hardware/index.md b/docs/mkdocs/src/hardware/index.md
index e088fe1..986532b 100644
--- a/docs/mkdocs/src/hardware/index.md
+++ b/docs/mkdocs/src/hardware/index.md
@@ -1,18 +1,18 @@
HARDWARE
========
-The Bumble Host connects to a controller over an [HCI Transport](../transports/index.md).
-To use a hardware controller attached to the host on which the host application is running, the transport is typically either [HCI over UART](../transports/serial.md) or [HCI over USB](../transports/usb.md).
-On Linux, the [VHCI Transport](../transports/vhci.md) can be used to communicate with any controller hardware managed by the operating system. Alternatively, a remote controller (a phyiscal controller attached to a remote host) can be used by connecting one of the networked transports (such as the [TCP Client transport](../transports/tcp_client.md), the [TCP Server transport](../transports/tcp_server.md) or the [UDP Transport](../transports/udp.md)) to an [HCI Bridge](../apps_and_tools/hci_bridge) bridging the network transport to a physical controller on a remote host.
+The Bumble Host connects to a controller over an [HCI Transport](../transports/index.md).
+To use a hardware controller attached to the host on which the host application is running, the transport is typically either [HCI over UART](../transports/serial.md) or [HCI over USB](../transports/usb.md).
+On Linux, the [VHCI Transport](../transports/vhci.md) can be used to communicate with any controller hardware managed by the operating system. Alternatively, a remote controller (a phyiscal controller attached to a remote host) can be used by connecting one of the networked transports (such as the [TCP Client transport](../transports/tcp_client.md), the [TCP Server transport](../transports/tcp_server.md) or the [UDP Transport](../transports/udp.md)) to an [HCI Bridge](../apps_and_tools/hci_bridge) bridging the network transport to a physical controller on a remote host.
-In theory, any controller that is compliant with the HCI over UART or HCI over USB protocols can be used.
+In theory, any controller that is compliant with the HCI over UART or HCI over USB protocols can be used.
-HCI over USB is very common, implemented by a number of commercial Bluetooth dongles.
+HCI over USB is very common, implemented by a number of commercial Bluetooth dongles.
It is also possible to use an embedded development board, running a specialized application, such as the [`HCI UART`](https://docs.zephyrproject.org/latest/samples/bluetooth/hci_uart/README.html) and [`HCI USB`](https://docs.zephyrproject.org/latest/samples/bluetooth/hci_usb/README.html) demo applications from the [Zephyr project](https://www.zephyrproject.org/), or the [`blehci`](https://mynewt.apache.org/latest/tutorials/ble/blehci_project.html) application from [mynewt/nimble](https://mynewt.apache.org/)
Some specific USB dongles and embedded boards that are known to work include:
-
+
* [Nordic nRF52840 DK board](https://www.nordicsemi.com/Products/Development-hardware/nrf52840-dk) with the Zephyr `HCI UART` application
* [Nordic nRF52840 DK board](https://www.nordicsemi.com/Products/Development-hardware/nrf52840-dk) with the mynewt `blehci` application
* [Nordic nrf52840 dongle](https://www.nordicsemi.com/Products/Development-hardware/nRF52840-Dongle) with the Zephyr `HCI USB` application
diff --git a/docs/mkdocs/src/images/bumble_layers.svg b/docs/mkdocs/src/images/bumble_layers.svg
index 3da9f58..c0dbca1 100644
--- a/docs/mkdocs/src/images/bumble_layers.svg
+++ b/docs/mkdocs/src/images/bumble_layers.svg
@@ -1 +1 @@
-<svg version="1.1" viewBox="0.0 0.0 539.0209973753281 600.7742782152231" fill="none" stroke="none" stroke-linecap="square" stroke-miterlimit="10" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg"><clipPath id="p.0"><path d="m0 0l539.021 0l0 600.7743l-539.021 0l0 -600.7743z" clip-rule="nonzero"/></clipPath><g clip-path="url(#p.0)"><path fill="#000000" fill-opacity="0.0" d="m0 0l539.021 0l0 600.7743l-539.021 0z" fill-rule="evenodd"/><path fill="#000000" fill-opacity="0.0" d="m362.34805 205.27522l0 -159.87402" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m362.34805 205.27522l0 -159.87402" fill-rule="evenodd"/><path fill="#000000" fill-opacity="0.0" d="m94.91498 205.27522l0 -159.87402" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m94.91498 205.27522l0 -159.87402" fill-rule="evenodd"/><path fill="#000000" fill-opacity="0.0" d="m131.88086 534.9836l0 -116.81891" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m131.88086 534.9836l0 -116.81891" fill-rule="evenodd"/><path fill="#000000" fill-opacity="0.0" d="m404.9701 534.9836l0 -124.62991" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m404.9701 534.9836l0 -124.62991" fill-rule="evenodd"/><g filter="url(#shadowFilter-p.1)"><use xlink:href="#p.1" transform="matrix(1.0 0.0 0.0 1.0 0.0 2.0)"/></g><defs><filter id="shadowFilter-p.1" filterUnits="userSpaceOnUse"><feGaussianBlur in="SourceAlpha" stdDeviation="2.0" result="blur"/><feComponentTransfer in="blur" color-interpolation-filters="sRGB"><feFuncR type="linear" slope="0" intercept="0.0"/><feFuncG type="linear" slope="0" intercept="0.0"/><feFuncB type="linear" slope="0" intercept="0.0"/><feFuncA type="linear" slope="0.5" intercept="0"/></feComponentTransfer></filter></defs><g id="p.1"><path fill="#a4c2f4" d="m4.8992295 210.33295l0 0c0 -8.175705 6.627728 -14.803436 14.803446 -14.803436l497.4482 0c3.9261475 0 7.6914673 1.5596466 10.467651 4.3358307c2.776184 2.776184 4.3358154 6.5414886 4.3358154 10.467606l0 59.212006c0 8.17572 -6.6277466 14.803467 -14.803467 14.803467l-497.4482 0c-8.175717 0 -14.803446 -6.6277466 -14.803446 -14.803467z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m4.8992295 210.33295l0 0c0 -8.175705 6.627728 -14.803436 14.803446 -14.803436l497.4482 0c3.9261475 0 7.6914673 1.5596466 10.467651 4.3358307c2.776184 2.776184 4.3358154 6.5414886 4.3358154 10.467606l0 59.212006c0 8.17572 -6.6277466 14.803467 -14.803467 14.803467l-497.4482 0c-8.175717 0 -14.803446 -6.6277466 -14.803446 -14.803467z" fill-rule="evenodd"/></g><g filter="url(#shadowFilter-p.2)"><use xlink:href="#p.2" transform="matrix(1.0 0.0 0.0 1.0 0.0 2.0)"/></g><defs><filter id="shadowFilter-p.2" filterUnits="userSpaceOnUse"><feGaussianBlur in="SourceAlpha" stdDeviation="2.0" result="blur"/><feComponentTransfer in="blur" color-interpolation-filters="sRGB"><feFuncR type="linear" slope="0" intercept="0.0"/><feFuncG type="linear" slope="0" intercept="0.0"/><feFuncB type="linear" slope="0" intercept="0.0"/><feFuncA type="linear" slope="0.5" intercept="0"/></feComponentTransfer></filter></defs><g id="p.2"><path fill="#b6d7a8" d="m4.8992295 13.393214l0 0c0 -5.2562323 4.2610183 -9.517251 9.51725 -9.517251l508.0206 0c2.52417 0 4.9448853 1.0027075 6.7297363 2.787538c1.7848511 1.7848306 2.7875366 4.205581 2.7875366 6.729713l0 38.06786c0 5.256233 -4.2609863 9.51725 -9.517273 9.51725l-508.0206 0c-5.2562323 0 -9.51725 -4.261017 -9.51725 -9.51725z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m4.8992295 13.393214l0 0c0 -5.2562323 4.2610183 -9.517251 9.51725 -9.517251l508.0206 0c2.52417 0 4.9448853 1.0027075 6.7297363 2.787538c1.7848511 1.7848306 2.7875366 4.205581 2.7875366 6.729713l0 38.06786c0 5.256233 -4.2609863 9.51725 -9.517273 9.51725l-508.0206 0c-5.2562323 0 -9.51725 -4.261017 -9.51725 -9.51725z" fill-rule="evenodd"/><path fill="#000000" d="m221.21878 39.34714l5.078125 -13.359375l1.78125 0l5.078125 13.359375l-1.734375 0l-3.671875 -9.984375l-0.53125 -1.4375l-0.0625 0l-0.53125 1.4375l-3.671875 9.984375l-1.734375 0zm5.78125 -3.671875l0 -1.5l3.078125 0l0.546875 1.5l-3.625 0zm-3.625 0l0.546875 -1.5l3.078125 0l0 1.5l-3.625 0zm11.327408 7.703125l0 -13.546875l1.515625 0l0 1.421875l0.078125 0q0.25 -0.453125 0.71875 -0.84375q0.484375 -0.390625 1.125 -0.625q0.640625 -0.25 1.390625 -0.25q1.3125 0 2.328125 0.65625q1.03125 0.65625 1.625 1.796875q0.609375 1.125 0.609375 2.609375q0 1.46875 -0.609375 2.609375q-0.59375 1.140625 -1.625 1.796875q-1.015625 0.640625 -2.328125 0.640625q-1.125 0 -1.984375 -0.515625q-0.859375 -0.53125 -1.25 -1.1875l-0.078125 0l0.078125 1.3125l0 4.125l-1.59375 0zm4.671875 -5.171875q0.8125 0 1.53125 -0.4375q0.71875 -0.4375 1.15625 -1.25q0.4375 -0.828125 0.4375 -1.921875q0 -1.125 -0.4375 -1.9375q-0.4375 -0.8125 -1.15625 -1.25q-0.71875 -0.4375 -1.53125 -0.4375q-0.828125 0 -1.546875 0.4375q-0.71875 0.4375 -1.171875 1.25q-0.4375 0.8125 -0.4375 1.9375q0 1.109375 0.4375 1.921875q0.453125 0.8125 1.171875 1.25q0.71875 0.4375 1.546875 0.4375zm6.372528 5.171875l0 -13.546875l1.515625 0l0 1.421875l0.078125 0q0.25 -0.453125 0.71875 -0.84375q0.484375 -0.390625 1.125 -0.625q0.640625 -0.25 1.390625 -0.25q1.3125 0 2.328125 0.65625q1.03125 0.65625 1.625 1.796875q0.609375 1.125 0.609375 2.609375q0 1.46875 -0.609375 2.609375q-0.59375 1.140625 -1.625 1.796875q-1.015625 0.640625 -2.328125 0.640625q-1.125 0 -1.984375 -0.515625q-0.859375 -0.53125 -1.25 -1.1875l-0.078125 0l0.078125 1.3125l0 4.125l-1.59375 0zm4.671875 -5.171875q0.8125 0 1.53125 -0.4375q0.71875 -0.4375 1.15625 -1.25q0.4375 -0.828125 0.4375 -1.921875q0 -1.125 -0.4375 -1.9375q-0.4375 -0.8125 -1.15625 -1.25q-0.71875 -0.4375 -1.53125 -0.4375q-0.828125 0 -1.546875 0.4375q-0.71875 0.4375 -1.171875 1.25q-0.4375 0.8125 -0.4375 1.9375q0 1.109375 0.4375 1.921875q0.453125 0.8125 1.171875 1.25q0.71875 0.4375 1.546875 0.4375zm6.372513 1.140625l0 -13.359375l1.59375 0l0 13.359375l-1.59375 0zm4.0927124 0l0 -9.515625l1.578125 0l0 9.515625l-1.578125 0zm0.78125 -11.265625q-0.46875 0 -0.8125 -0.328125q-0.328125 -0.34375 -0.328125 -0.8125q0 -0.484375 0.328125 -0.8125q0.34375 -0.328125 0.8125 -0.328125q0.484375 0 0.8125 0.328125q0.328125 0.328125 0.328125 0.8125q0 0.46875 -0.328125 0.8125q-0.328125 0.328125 -0.8125 0.328125zm7.497986 11.5625q-1.40625 0 -2.5 -0.65625q-1.078125 -0.671875 -1.703125 -1.8125q-0.609375 -1.15625 -0.609375 -2.578125q0 -1.46875 0.609375 -2.59375q0.625 -1.140625 1.703125 -1.796875q1.09375 -0.671875 2.5 -0.671875q1.609375 0 2.640625 0.734375q1.03125 0.734375 1.46875 1.890625l-1.4375 0.609375q-0.359375 -0.890625 -1.0625 -1.34375q-0.6875 -0.453125 -1.6875 -0.453125q-0.828125 0 -1.546875 0.453125q-0.71875 0.4375 -1.171875 1.25q-0.453125 0.8125 -0.453125 1.921875q0 1.078125 0.453125 1.90625q0.453125 0.8125 1.171875 1.265625q0.71875 0.4375 1.546875 0.4375q1.015625 0 1.734375 -0.46875q0.734375 -0.46875 1.09375 -1.3125l1.40625 0.59375q-0.46875 1.09375 -1.515625 1.859375q-1.03125 0.765625 -2.640625 0.765625zm8.827332 0q-1.0625 0 -1.875 -0.40625q-0.796875 -0.40625 -1.25 -1.125q-0.453125 -0.71875 -0.453125 -1.640625q0 -1.046875 0.53125 -1.765625q0.546875 -0.71875 1.453125 -1.078125q0.921875 -0.359375 2.015625 -0.359375q0.640625 0 1.171875 0.109375q0.546875 0.09375 0.9375 0.234375q0.40625 0.140625 0.625 0.265625l0 -0.578125q0 -1.078125 -0.765625 -1.703125q-0.765625 -0.640625 -1.875 -0.640625q-0.78125 0 -1.46875 0.34375q-0.671875 0.34375 -1.0625 0.953125l-1.203125 -0.890625q0.375 -0.5625 0.9375 -0.96875q0.5625 -0.40625 1.28125 -0.625q0.71875 -0.234375 1.515625 -0.234375q1.9375 0 3.03125 1.03125q1.109375 1.015625 1.109375 2.75l0 6.03125l-1.5 0l0 -1.359375l-0.078125 0q-0.25 0.40625 -0.703125 0.796875q-0.4375 0.375 -1.046875 0.609375q-0.609375 0.25 -1.328125 0.25zm0.140625 -1.390625q0.828125 0 1.5 -0.40625q0.6875 -0.421875 1.09375 -1.109375q0.421875 -0.6875 0.421875 -1.515625q-0.4375 -0.296875 -1.078125 -0.484375q-0.640625 -0.1875 -1.40625 -0.1875q-1.359375 0 -2.0 0.5625q-0.640625 0.5625 -0.640625 1.375q0 0.78125 0.59375 1.28125q0.609375 0.484375 1.515625 0.484375zm5.876068 -8.421875l5.578125 0l0 1.4375l-5.578125 0l0 -1.4375zm1.671875 7.015625l0 -9.703125l1.578125 0l0 9.3125q0 0.75 0.3125 1.15625q0.3125 0.40625 1.015625 0.40625q0.3125 0 0.578125 -0.09375q0.265625 -0.09375 0.46875 -0.21875l0 1.546875q-0.25 0.109375 -0.546875 0.171875q-0.28125 0.078125 -0.765625 0.078125q-1.1875 0 -1.921875 -0.703125q-0.71875 -0.703125 -0.71875 -1.953125zm6.0434875 2.5l0 -9.515625l1.578125 0l0 9.515625l-1.578125 0zm0.78125 -11.265625q-0.46875 0 -0.8125 -0.328125q-0.328125 -0.34375 -0.328125 -0.8125q0 -0.484375 0.328125 -0.8125q0.34375 -0.328125 0.8125 -0.328125q0.484375 0 0.8125 0.328125q0.328125 0.328125 0.328125 0.8125q0 0.46875 -0.328125 0.8125q-0.328125 0.328125 -0.8125 0.328125zm7.576111 11.5625q-1.4375 0 -2.546875 -0.671875q-1.09375 -0.671875 -1.71875 -1.8125q-0.625 -1.15625 -0.625 -2.5625q0 -1.421875 0.625 -2.5625q0.625 -1.15625 1.71875 -1.828125q1.109375 -0.671875 2.546875 -0.671875q1.4375 0 2.53125 0.6875q1.109375 0.671875 1.734375 1.828125q0.625 1.140625 0.625 2.546875q0 1.40625 -0.625 2.5625q-0.625 1.140625 -1.734375 1.8125q-1.09375 0.671875 -2.53125 0.671875zm0 -1.4375q0.859375 0 1.609375 -0.421875q0.75 -0.4375 1.21875 -1.25q0.46875 -0.8125 0.46875 -1.9375q0 -1.140625 -0.46875 -1.953125q-0.46875 -0.8125 -1.21875 -1.234375q-0.75 -0.4375 -1.609375 -0.4375q-0.859375 0 -1.625 0.4375q-0.765625 0.421875 -1.234375 1.234375q-0.46875 0.8125 -0.46875 1.953125q0 1.125 0.46875 1.9375q0.46875 0.8125 1.234375 1.25q0.765625 0.421875 1.625 0.421875zm6.5418396 1.140625l0 -9.515625l1.515625 0l0 1.40625l0.078125 0q0.375 -0.703125 1.21875 -1.203125q0.84375 -0.5 1.859375 -0.5q1.75 0 2.625 1.015625q0.890625 1.015625 0.890625 2.703125l0 6.09375l-1.578125 0l0 -5.859375q0 -1.375 -0.671875 -1.9375q-0.65625 -0.578125 -1.703125 -0.578125q-0.78125 0 -1.375 0.4375q-0.59375 0.4375 -0.9375 1.125q-0.328125 0.6875 -0.328125 1.453125l0 5.359375l-1.59375 0z" fill-rule="nonzero"/></g><g filter="url(#shadowFilter-p.3)"><use xlink:href="#p.3" transform="matrix(1.0 0.0 0.0 1.0 0.0 2.0)"/></g><defs><filter id="shadowFilter-p.3" filterUnits="userSpaceOnUse"><feGaussianBlur in="SourceAlpha" stdDeviation="2.0" result="blur"/><feComponentTransfer in="blur" color-interpolation-filters="sRGB"><feFuncR type="linear" slope="0" intercept="0.0"/><feFuncG type="linear" slope="0" intercept="0.0"/><feFuncB type="linear" slope="0" intercept="0.0"/><feFuncA type="linear" slope="0.5" intercept="0"/></feComponentTransfer></filter></defs><g id="p.3"><path fill="#c9daf8" d="m4.8992295 97.076035l0 0c0 -8.175713 6.627728 -14.803444 14.803446 -14.803444l147.81042 0c3.926117 0 7.691437 1.5596466 10.467621 4.3358307c2.776184 2.776184 4.3358307 6.5414963 4.3358307 10.467613l0 59.212006c0 8.17572 -6.6277313 14.803452 -14.803452 14.803452l-147.81042 0c-8.175717 0 -14.803446 -6.6277313 -14.803446 -14.803452z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m4.8992295 97.076035l0 0c0 -8.175713 6.627728 -14.803444 14.803446 -14.803444l147.81042 0c3.926117 0 7.691437 1.5596466 10.467621 4.3358307c2.776184 2.776184 4.3358307 6.5414963 4.3358307 10.467613l0 59.212006c0 8.17572 -6.6277313 14.803452 -14.803452 14.803452l-147.81042 0c-8.175717 0 -14.803446 -6.6277313 -14.803446 -14.803452z" fill-rule="evenodd"/><path fill="#000000" d="m66.37746 133.60204l0 -13.359367l4.015625 0q2.09375 0 3.609375 0.859375q1.515625 0.84375 2.328125 2.359375q0.828125 1.5 0.828125 3.46875q0 1.9531174 -0.828125 3.4531174q-0.8125 1.5 -2.328125 2.359375q-1.515625 0.859375 -3.609375 0.859375l-4.015625 0zm1.578125 -1.515625l2.4375 0q1.578125 0 2.734375 -0.59375q1.15625 -0.609375 1.78125 -1.765625q0.640625 -1.15625 0.640625 -2.7968674q0 -1.65625 -0.640625 -2.8125q-0.625 -1.15625 -1.78125 -1.75q-1.15625 -0.609375 -2.734375 -0.609375l-2.4375 0l0 10.328117zm15.163467 1.8125q-1.375 0 -2.453125 -0.640625q-1.0625 -0.65625 -1.671875 -1.796875q-0.609375 -1.140625 -0.609375 -2.59375q0 -1.3593674 0.5625 -2.5156174q0.578125 -1.15625 1.609375 -1.859375q1.03125 -0.703125 2.4375 -0.703125q1.421875 0 2.4375 0.625q1.015625 0.625 1.5625 1.734375q0.546875 1.09375 0.546875 2.5156174q0 0.125 -0.015625 0.265625q0 0.125 -0.015625 0.21875l-8.1875 0l0 -1.3124924l6.546875 0q-0.015625 -0.390625 -0.1875 -0.84375q-0.15625 -0.46875 -0.5 -0.859375q-0.34375 -0.40625 -0.875 -0.65625q-0.53125 -0.25 -1.3125 -0.25q-0.9375 0 -1.625 0.484375q-0.671875 0.46875 -1.046875 1.296875q-0.359375 0.8125 -0.359375 1.8593674q0 1.203125 0.46875 2.015625q0.46875 0.796875 1.203125 1.1875q0.75 0.390625 1.546875 0.390625q1.046875 0 1.71875 -0.484375q0.6875 -0.5 1.09375 -1.234375l1.34375 0.65625q-0.5625 1.078125 -1.609375 1.796875q-1.03125 0.703125 -2.609375 0.703125zm8.879303 -0.296875l-3.84375 -9.515617l1.703125 0l2.953125 7.6562424l0.03125 0l2.984375 -7.6562424l1.65625 0l-3.875 9.515617l-1.609375 0zm6.9486847 0l0 -9.515617l1.578125 0l0 9.515617l-1.578125 0zm0.78125 -11.265617q-0.46875 0 -0.8125 -0.328125q-0.328125 -0.34375 -0.328125 -0.8125q0 -0.484375 0.328125 -0.8125q0.34375 -0.328125 0.8125 -0.328125q0.484375 0 0.8125 0.328125q0.328125 0.328125 0.328125 0.8125q0 0.46875 -0.328125 0.8125q-0.328125 0.328125 -0.8125 0.328125zm7.4979706 11.562492q-1.40625 0 -2.5 -0.65625q-1.078125 -0.671875 -1.703125 -1.8125q-0.609375 -1.15625 -0.609375 -2.578125q0 -1.4687424 0.609375 -2.5937424q0.625 -1.140625 1.703125 -1.796875q1.09375 -0.671875 2.5 -0.671875q1.609375 0 2.640625 0.734375q1.03125 0.734375 1.46875 1.890625l-1.4375 0.609375q-0.359375 -0.890625 -1.0625 -1.34375q-0.6875 -0.453125 -1.6875 -0.453125q-0.828125 0 -1.546875 0.453125q-0.71875 0.4375 -1.171875 1.25q-0.453125 0.8125 -0.453125 1.9218674q0 1.078125 0.453125 1.90625q0.453125 0.8125 1.171875 1.265625q0.71875 0.4375 1.546875 0.4375q1.015625 0 1.734375 -0.46875q0.734375 -0.46875 1.09375 -1.3125l1.40625 0.59375q-0.46875 1.09375 -1.515625 1.859375q-1.03125 0.765625 -2.640625 0.765625zm10.014847 0q-1.375 0 -2.453125 -0.640625q-1.0625 -0.65625 -1.671875 -1.796875q-0.609375 -1.140625 -0.609375 -2.59375q0 -1.3593674 0.5625 -2.5156174q0.578125 -1.15625 1.609375 -1.859375q1.03125 -0.703125 2.4375 -0.703125q1.421875 0 2.4375 0.625q1.015625 0.625 1.5625 1.734375q0.546875 1.09375 0.546875 2.5156174q0 0.125 -0.015625 0.265625q0 0.125 -0.015625 0.21875l-8.1875 0l0 -1.3124924l6.546875 0q-0.015625 -0.390625 -0.1875 -0.84375q-0.15625 -0.46875 -0.5 -0.859375q-0.34375 -0.40625 -0.875 -0.65625q-0.53125 -0.25 -1.3125 -0.25q-0.9375 0 -1.625 0.484375q-0.671875 0.46875 -1.046875 1.296875q-0.359375 0.8125 -0.359375 1.8593674q0 1.203125 0.46875 2.015625q0.46875 0.796875 1.203125 1.1875q0.75 0.390625 1.546875 0.390625q1.046875 0 1.71875 -0.484375q0.6875 -0.5 1.09375 -1.234375l1.34375 0.65625q-0.5625 1.078125 -1.609375 1.796875q-1.03125 0.703125 -2.609375 0.703125z" fill-rule="nonzero"/></g><g filter="url(#shadowFilter-p.4)"><use xlink:href="#p.4" transform="matrix(1.0 0.0 0.0 1.0 0.0 2.0)"/></g><defs><filter id="shadowFilter-p.4" filterUnits="userSpaceOnUse"><feGaussianBlur in="SourceAlpha" stdDeviation="2.0" result="blur"/><feComponentTransfer in="blur" color-interpolation-filters="sRGB"><feFuncR type="linear" slope="0" intercept="0.0"/><feFuncG type="linear" slope="0" intercept="0.0"/><feFuncB type="linear" slope="0" intercept="0.0"/><feFuncA type="linear" slope="0.5" intercept="0"/></feComponentTransfer></filter></defs><g id="p.4"><path fill="#c9daf8" d="m192.74174 100.78206l0 0c0 -7.7669296 6.296341 -14.063271 14.063278 -14.063271l311.08603 0c3.7298584 0 7.306885 1.4816589 9.944275 4.119034c2.637329 2.6373749 4.1190186 6.214424 4.1190186 9.944237l0 56.251404c0 7.7669373 -6.2963257 14.063278 -14.063293 14.063278l-311.08603 0c-7.7669373 0 -14.063278 -6.296341 -14.063278 -14.063278z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m192.74174 100.78206l0 0c0 -7.7669296 6.296341 -14.063271 14.063278 -14.063271l311.08603 0c3.7298584 0 7.306885 1.4816589 9.944275 4.119034c2.637329 2.6373749 4.1190186 6.214424 4.1190186 9.944237l0 56.251404c0 7.7669373 -6.2963257 14.063278 -14.063293 14.063278l-311.08603 0c-7.7669373 0 -14.063278 -6.296341 -14.063278 -14.063278z" fill-rule="evenodd"/></g><path fill="#a2c4c9" d="m203.9767 122.657425l0 0c0 -4.68219 3.7956696 -8.4778595 8.4778595 -8.4778595l57.060028 0c2.2484741 0 4.404846 0.89320374 5.994751 2.4831085c1.5899048 1.5899048 2.4831238 3.7462845 2.4831238 5.994751l0 33.910416c0 4.682205 -3.7956848 8.4778595 -8.477875 8.4778595l-57.060028 0c-4.68219 0 -8.4778595 -3.7956543 -8.4778595 -8.4778595z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m203.9767 122.657425l0 0c0 -4.68219 3.7956696 -8.4778595 8.4778595 -8.4778595l57.060028 0c2.2484741 0 4.404846 0.89320374 5.994751 2.4831085c1.5899048 1.5899048 2.4831238 3.7462845 2.4831238 5.994751l0 33.910416c0 4.682205 -3.7956848 8.4778595 -8.477875 8.4778595l-57.060028 0c-4.68219 0 -8.4778595 -3.7956543 -8.4778595 -8.4778595z" fill-rule="evenodd"/><path fill="#000000" d="m221.41891 145.47264l4.359375 -11.453125l1.53125 0l4.359375 11.453125l-1.5 0l-3.140625 -8.5625l-0.453125 -1.234375l-0.0625 0l-0.453125 1.234375l-3.140625 8.5625l-1.5 0zm4.96875 -3.15625l0 -1.28125l2.640625 0l0.453125 1.28125l-3.09375 0zm-3.109375 0l0.46875 -1.28125l2.640625 0l0 1.28125l-3.109375 0zm9.3450165 3.15625l0 -1.359375q0.046875 -0.046875 0.375 -0.375q0.34375 -0.34375 0.84375 -0.84375q0.5 -0.515625 1.03125 -1.0625q0.546875 -0.546875 1.015625 -1.03125q0.484375 -0.5 0.75 -0.796875q0.5 -0.546875 0.796875 -0.9375q0.3125 -0.390625 0.453125 -0.765625q0.140625 -0.375 0.140625 -0.875q0 -0.46875 -0.25 -0.890625q-0.234375 -0.421875 -0.6875 -0.6875q-0.453125 -0.28125 -1.140625 -0.28125q-0.640625 0 -1.078125 0.28125q-0.4375 0.265625 -0.6875 0.640625q-0.234375 0.375 -0.3125 0.6875l-1.234375 -0.5q0.09375 -0.34375 0.34375 -0.75q0.25 -0.40625 0.65625 -0.78125q0.40625 -0.375 0.984375 -0.625q0.59375 -0.25 1.359375 -0.25q1.046875 0 1.8125 0.453125q0.76564026 0.4375 1.1875153 1.15625q0.421875 0.703125 0.421875 1.53125q0 0.71875 -0.28125 1.375q-0.265625 0.640625 -0.67189026 1.171875q-0.390625 0.53125 -0.796875 0.921875q-0.21875 0.203125 -0.59375 0.578125q-0.359375 0.375 -0.78125 0.796875q-0.40625 0.421875 -0.8125 0.828125q-0.390625 0.390625 -0.6875 0.703125q-0.296875 0.296875 -0.40625 0.390625l0 0l5.1562653 0l0 1.296875l-6.9062653 0zm8.978531 0l0 -11.453125l3.453125 0q1.796875 0 3.09375 0.734375q1.296875 0.71875 2.0 2.015625q0.703125 1.296875 0.703125 2.96875q0 1.6875 -0.703125 2.984375q-0.703125 1.28125 -2.0 2.015625q-1.296875 0.734375 -3.09375 0.734375l-3.453125 0zm1.359375 -1.296875l2.09375 0q1.34375 0 2.328125 -0.515625q1.0 -0.53125 1.546875 -1.515625q0.546875 -0.984375 0.546875 -2.40625q0 -1.40625 -0.546875 -2.390625q-0.546875 -1.0 -1.546875 -1.515625q-0.984375 -0.515625 -2.328125 -0.515625l-2.09375 0l0 8.859375zm9.888641 1.296875l0 -11.453125l3.859375 0q0.953125 0 1.765625 0.4375q0.828125 0.421875 1.3125 1.1875q0.484375 0.75 0.484375 1.765625q0 0.984375 -0.484375 1.765625q-0.484375 0.765625 -1.3125 1.203125q-0.8125 0.421875 -1.765625 0.421875l-3.140625 0l0 -1.296875l3.171875 0q0.671875 0 1.140625 -0.3125q0.484375 -0.3125 0.75 -0.78125q0.265625 -0.484375 0.265625 -1.0q0 -0.515625 -0.265625 -0.984375q-0.265625 -0.484375 -0.75 -0.796875q-0.46875 -0.3125 -1.140625 -0.3125l-2.53125 0l0 10.15625l-1.359375 0z" fill-rule="nonzero"/><path fill="#a2c4c9" d="m284.8796 122.657425l0 0c0 -4.68219 3.7956543 -8.4778595 8.477844 -8.4778595l57.060028 0c2.2484741 0 4.404846 0.89320374 5.994751 2.4831085c1.5899048 1.5899048 2.4831238 3.7462845 2.4831238 5.994751l0 33.910416c0 4.682205 -3.7956848 8.4778595 -8.477875 8.4778595l-57.060028 0c-4.68219 0 -8.477844 -3.7956543 -8.477844 -8.4778595z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m284.8796 122.657425l0 0c0 -4.68219 3.7956543 -8.4778595 8.477844 -8.4778595l57.060028 0c2.2484741 0 4.404846 0.89320374 5.994751 2.4831085c1.5899048 1.5899048 2.4831238 3.7462845 2.4831238 5.994751l0 33.910416c0 4.682205 -3.7956848 8.4778595 -8.477875 8.4778595l-57.060028 0c-4.68219 0 -8.477844 -3.7956543 -8.477844 -8.4778595z" fill-rule="evenodd"/><path fill="#000000" d="m308.7287 145.47264l0 -11.453125l1.359375 0l0 11.453125l-1.359375 0zm0.71875 -5.21875l0 -1.296875l6.84375 0l0 1.296875l-6.84375 0zm6.53125 5.21875l0 -11.453125l1.359375 0l0 11.453125l-1.359375 0zm3.9180298 0l0 -11.453125l6.625 0l0 1.296875l-5.265625 0l0 10.15625l-1.359375 0zm0.71875 -4.953125l0 -1.28125l5.390625 0l0 1.28125l-5.390625 0zm7.777252 4.953125l0 -11.453125l3.859375 0q0.953125 0 1.765625 0.4375q0.828125 0.421875 1.3125 1.1875q0.484375 0.75 0.484375 1.765625q0 0.984375 -0.484375 1.765625q-0.484375 0.765625 -1.3125 1.203125q-0.8125 0.421875 -1.765625 0.421875l-3.140625 0l0 -1.296875l3.171875 0q0.671875 0 1.140625 -0.3125q0.484375 -0.3125 0.75 -0.78125q0.265625 -0.484375 0.265625 -1.0q0 -0.515625 -0.265625 -0.984375q-0.265625 -0.484375 -0.75 -0.796875q-0.46875 -0.3125 -1.140625 -0.3125l-2.53125 0l0 10.15625l-1.359375 0z" fill-rule="nonzero"/><path fill="#a2c4c9" d="m365.78247 122.657425l0 0c0 -4.68219 3.7956848 -8.4778595 8.477875 -8.4778595l57.060028 0c2.2484741 0 4.404846 0.89320374 5.994751 2.4831085c1.5899048 1.5899048 2.4830933 3.7462845 2.4830933 5.994751l0 33.910416c0 4.682205 -3.7956543 8.4778595 -8.477844 8.4778595l-57.060028 0c-4.68219 0 -8.477875 -3.7956543 -8.477875 -8.4778595z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m365.78247 122.657425l0 0c0 -4.68219 3.7956848 -8.4778595 8.477875 -8.4778595l57.060028 0c2.2484741 0 4.404846 0.89320374 5.994751 2.4831085c1.5899048 1.5899048 2.4830933 3.7462845 2.4830933 5.994751l0 33.910416c0 4.682205 -3.7956543 8.4778595 -8.477844 8.4778595l-57.060028 0c-4.68219 0 -8.477875 -3.7956543 -8.477875 -8.4778595z" fill-rule="evenodd"/><path fill="#000000" d="m390.90356 145.47264l0 -11.453125l1.359375 0l0 11.453125l-1.359375 0zm0.71875 -5.21875l0 -1.296875l6.84375 0l0 1.296875l-6.84375 0zm6.53125 5.21875l0 -11.453125l1.359375 0l0 11.453125l-1.359375 0zm3.9180298 0l0 -11.453125l1.359375 0l0 11.453125l-1.359375 0zm3.9200134 0l0 -11.453125l3.453125 0q1.796875 0 3.09375 0.734375q1.296875 0.71875 2.0 2.015625q0.703125 1.296875 0.703125 2.96875q0 1.6875 -0.703125 2.984375q-0.703125 1.28125 -2.0 2.015625q-1.296875 0.734375 -3.09375 0.734375l-3.453125 0zm1.359375 -1.296875l2.09375 0q1.34375 0 2.328125 -0.515625q1.0 -0.53125 1.546875 -1.515625q0.546875 -0.984375 0.546875 -2.40625q0 -1.40625 -0.546875 -2.390625q-0.546875 -1.0 -1.546875 -1.515625q-0.984375 -0.515625 -2.328125 -0.515625l-2.09375 0l0 8.859375z" fill-rule="nonzero"/><g filter="url(#shadowFilter-p.5)"><use xlink:href="#p.5" transform="matrix(1.0 0.0 0.0 1.0 0.0 2.0)"/></g><defs><filter id="shadowFilter-p.5" filterUnits="userSpaceOnUse"><feGaussianBlur in="SourceAlpha" stdDeviation="2.0" result="blur"/><feComponentTransfer in="blur" color-interpolation-filters="sRGB"><feFuncR type="linear" slope="0" intercept="0.0"/><feFuncG type="linear" slope="0" intercept="0.0"/><feFuncB type="linear" slope="0" intercept="0.0"/><feFuncA type="linear" slope="0.5" intercept="0"/></feComponentTransfer></filter></defs><g id="p.5"><path fill="#6d9eeb" d="m4.8992295 317.66617l0 0c0 -5.2562256 4.2610183 -9.517242 9.51725 -9.517242l508.0206 0c2.52417 0 4.9448853 1.0027161 6.7297363 2.7875366c1.7848511 1.7848206 2.7875366 4.205597 2.7875366 6.729706l0 38.06787c0 5.2562256 -4.2609863 9.517242 -9.517273 9.517242l-508.0206 0c-5.2562323 0 -9.51725 -4.261017 -9.51725 -9.517242z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m4.8992295 317.66617l0 0c0 -5.2562256 4.2610183 -9.517242 9.51725 -9.517242l508.0206 0c2.52417 0 4.9448853 1.0027161 6.7297363 2.7875366c1.7848511 1.7848206 2.7875366 4.205597 2.7875366 6.729706l0 38.06787c0 5.2562256 -4.2609863 9.517242 -9.517273 9.517242l-508.0206 0c-5.2562323 0 -9.51725 -4.261017 -9.51725 -9.517242z" fill-rule="evenodd"/><path fill="#000000" d="m252.81201 342.56012l0 -11.453125l1.359375 0l0 11.453125l-1.359375 0zm0.71875 -5.21875l0 -1.296875l6.84375 0l0 1.296875l-6.84375 0zm6.53125 5.21875l0 -11.453125l1.359375 0l0 11.453125l-1.359375 0zm7.242401 0.25q-1.234375 0 -2.1875 -0.5625q-0.9375 -0.578125 -1.46875 -1.5625q-0.53125 -0.984375 -0.53125 -2.203125q0 -1.21875 0.53125 -2.203125q0.53125 -0.984375 1.46875 -1.5625q0.953125 -0.578125 2.1875 -0.578125q1.234375 0 2.171875 0.59375q0.953125 0.578125 1.484375 1.5625q0.53125 0.984375 0.53125 2.1875q0 1.21875 -0.53125 2.203125q-0.53125 0.984375 -1.484375 1.5625q-0.9375 0.5625 -2.171875 0.5625zm0 -1.21875q0.734375 0 1.375 -0.375q0.65625 -0.375 1.046875 -1.0625q0.40625 -0.703125 0.40625 -1.671875q0 -0.984375 -0.40625 -1.671875q-0.390625 -0.703125 -1.046875 -1.0625q-0.640625 -0.375 -1.375 -0.375q-0.734375 0 -1.390625 0.375q-0.65625 0.359375 -1.0625 1.0625q-0.390625 0.6875 -0.390625 1.671875q0 0.96875 0.390625 1.671875q0.40625 0.6875 1.0625 1.0625q0.65625 0.375 1.390625 0.375zm8.549774 1.21875q-0.921875 0 -1.625 -0.296875q-0.6875 -0.296875 -1.140625 -0.796875q-0.453125 -0.5 -0.671875 -1.09375l1.203125 -0.546875q0.328125 0.734375 0.9375 1.140625q0.609375 0.40625 1.390625 0.40625q0.75 0 1.25 -0.296875q0.515625 -0.3125 0.515625 -0.90625q0 -0.375 -0.21875 -0.625q-0.203125 -0.25 -0.609375 -0.421875q-0.390625 -0.171875 -0.96875 -0.3125l-1.0 -0.265625q-0.5625 -0.15625 -1.078125 -0.4375q-0.515625 -0.296875 -0.828125 -0.75q-0.3125 -0.453125 -0.3125 -1.109375q0 -0.734375 0.421875 -1.265625q0.4375 -0.53125 1.140625 -0.8125q0.703125 -0.28125 1.515625 -0.28125q0.703125 0 1.3125 0.203125q0.625 0.203125 1.078125 0.59375q0.46875 0.390625 0.703125 0.96875l-1.171875 0.546875q-0.3125 -0.609375 -0.828125 -0.84375q-0.5 -0.25 -1.125 -0.25q-0.671875 0 -1.171875 0.296875q-0.5 0.296875 -0.5 0.8125q0 0.515625 0.40625 0.765625q0.40625 0.25 1.0 0.421875l1.1875 0.296875q1.203125 0.3125 1.8125 0.90625q0.609375 0.59375 0.609375 1.46875q0 0.765625 -0.4375 1.328125q-0.4375 0.546875 -1.171875 0.859375q-0.734375 0.296875 -1.625 0.296875zm4.0817566 -8.40625l4.78125 0l0 1.234375l-4.78125 0l0 -1.234375zm1.421875 6.015625l0 -8.328125l1.359375 0l0 7.984375q0 0.640625 0.265625 1.0q0.265625 0.34375 0.875 0.34375q0.265625 0 0.484375 -0.078125q0.234375 -0.078125 0.40625 -0.1875l0 1.328125q-0.203125 0.09375 -0.453125 0.140625q-0.25 0.0625 -0.671875 0.0625q-1.015625 0 -1.640625 -0.59375q-0.625 -0.609375 -0.625 -1.671875z" fill-rule="nonzero"/></g><path fill="#a2c4c9" d="m141.82906 235.04298l0 0c0 -4.8590393 3.9390259 -8.798065 8.798065 -8.798065l43.852676 0c2.3333893 0 4.571213 0.92692566 6.221176 2.576889c1.6499634 1.6499634 2.576889 3.8877869 2.576889 6.221176l0 35.19124c0 4.85907 -3.9390259 8.798096 -8.798065 8.798096l-43.852676 0c-4.8590393 0 -8.798065 -3.9390259 -8.798065 -8.798096z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m141.82906 235.04298l0 0c0 -4.8590393 3.9390259 -8.798065 8.798065 -8.798065l43.852676 0c2.3333893 0 4.571213 0.92692566 6.221176 2.576889c1.6499634 1.6499634 2.576889 3.8877869 2.576889 6.221176l0 35.19124c0 4.85907 -3.9390259 8.798096 -8.798065 8.798096l-43.852676 0c-4.8590393 0 -8.798065 -3.9390259 -8.798065 -8.798096z" fill-rule="evenodd"/><path fill="#000000" d="m162.77774 250.34612q-0.90625 0 -1.71875 -0.328125q-0.8125 -0.34375 -1.421875 -0.953125q-0.609375 -0.609375 -0.953125 -1.421875q-0.34375 -0.828125 -0.34375 -1.78125q0 -0.953125 0.34375 -1.765625q0.34375 -0.828125 0.953125 -1.4375q0.609375 -0.609375 1.421875 -0.9375q0.8125 -0.34375 1.71875 -0.34375q0.953125 0 1.78125 0.34375q0.84375 0.328125 1.375 0.9375l-0.71875 0.71875q-0.265625 -0.328125 -0.65625 -0.5625q-0.375 -0.234375 -0.828125 -0.34375q-0.4375 -0.125 -0.9375 -0.125q-0.6875 0 -1.3125 0.25q-0.609375 0.25 -1.09375 0.71875q-0.46875 0.453125 -0.75 1.109375q-0.265625 0.640625 -0.265625 1.4375q0 0.8125 0.28125 1.453125q0.28125 0.640625 0.75 1.109375q0.484375 0.46875 1.09375 0.71875q0.625 0.234375 1.296875 0.234375q0.578125 0 1.125 -0.15625q0.546875 -0.171875 0.984375 -0.5q0.4375 -0.34375 0.71875 -0.890625q0.296875 -0.546875 0.359375 -1.296875l-3.171875 0l0 -0.953125l4.125 0q0.03125 0.15625 0.046875 0.3125q0.015625 0.140625 0.015625 0.3125l0 0l0 0l0 0q0 0.921875 -0.3125 1.6875q-0.3125 0.765625 -0.875 1.3125q-0.5625 0.546875 -1.328125 0.84375q-0.765625 0.296875 -1.703125 0.296875zm4.551193 -0.1875l3.25 -8.59375l1.15625 0l3.265625 8.59375l-1.109375 0l-2.375 -6.421875l-0.328125 -0.921875l-0.046875 0l-0.34375 0.921875l-2.359375 6.421875l-1.109375 0zm3.71875 -2.359375l0 -0.96875l1.96875 0l0.359375 0.96875l-2.328125 0zm-2.328125 0l0.34375 -0.96875l1.984375 0l0 0.96875l-2.328125 0zm8.400681 2.359375l0 -7.984375l1.03125 0l0 7.984375l-1.03125 0zm-2.40625 -7.625l0 -0.96875l5.828125 0l0 0.96875l-5.828125 0zm8.862289 7.625l0 -7.984375l1.03125 0l0 7.984375l-1.03125 0zm-2.40625 -7.625l0 -0.96875l5.828125 0l0 0.96875l-5.828125 0z" fill-rule="nonzero"/><path fill="#000000" d="m161.77573 264.3461q-0.9375 0 -1.75 -0.328125q-0.8125 -0.34375 -1.421875 -0.953125q-0.59375 -0.609375 -0.9375 -1.421875q-0.328125 -0.828125 -0.328125 -1.78125q0 -0.953125 0.328125 -1.765625q0.34375 -0.828125 0.9375 -1.421875q0.609375 -0.609375 1.421875 -0.95310974q0.8125 -0.34375 1.75 -0.34375q0.671875 0 1.234375 0.171875q0.578125 0.15625 1.046875 0.46873474q0.484375 0.3125 0.875 0.765625l-0.734375 0.703125q-0.328125 -0.390625 -0.703125 -0.640625q-0.359375 -0.265625 -0.78125 -0.375q-0.421875 -0.125 -0.9375 -0.125q-0.921875 0 -1.703125 0.4375q-0.765625 0.421875 -1.234375 1.21875q-0.46875 0.78125 -0.46875 1.859375q0 1.0625 0.46875 1.859375q0.46875 0.796875 1.234375 1.234375q0.78125 0.421875 1.703125 0.421875q0.578125 0 1.046875 -0.15625q0.46875 -0.15625 0.875 -0.4375q0.40625 -0.296875 0.734375 -0.6875l0.75 0.71875q-0.375 0.4375 -0.90625 0.796875q-0.515625 0.34375 -1.140625 0.546875q-0.625 0.1875 -1.359375 0.1875zm4.537689 -0.1875l0 -8.593735l1.03125 0l0 8.593735l-1.03125 0zm2.641388 0l0 -6.125l1.015625 0l0 6.125l-1.015625 0zm0.5 -7.25q-0.296875 0 -0.515625 -0.21875q-0.21875 -0.21875 -0.21875 -0.515625q0 -0.31248474 0.21875 -0.51560974q0.21875 -0.21875 0.515625 -0.21875q0.3125 0 0.515625 0.21875q0.21875 0.203125 0.21875 0.51560974q0 0.296875 -0.21875 0.515625q-0.203125 0.21875 -0.515625 0.21875zm4.7770233 7.4375q-0.890625 0 -1.578125 -0.40625q-0.6875 -0.421875 -1.078125 -1.15625q-0.390625 -0.734375 -0.390625 -1.671875q0 -0.875 0.359375 -1.609375q0.359375 -0.75 1.03125 -1.203125q0.671875 -0.453125 1.5625 -0.453125q0.921875 0 1.5625 0.40625q0.65625 0.390625 1.015625 1.109375q0.359375 0.703125 0.359375 1.609375q0 0.09375 -0.015625 0.1875q0 0.078125 -0.015625 0.125l-5.265625 0l0 -0.828125l4.21875 0q-0.015625 -0.25 -0.125 -0.546875q-0.09375 -0.296875 -0.328125 -0.546875q-0.21875 -0.265625 -0.5625 -0.421875q-0.328125 -0.171875 -0.84375 -0.171875q-0.59375 0 -1.03125 0.3125q-0.4375 0.296875 -0.671875 0.828125q-0.234375 0.53125 -0.234375 1.203125q0 0.78125 0.296875 1.296875q0.296875 0.515625 0.765625 0.765625q0.484375 0.25 1.0 0.25q0.671875 0 1.109375 -0.3125q0.4375 -0.328125 0.703125 -0.796875l0.859375 0.421875q-0.359375 0.703125 -1.03125 1.15625q-0.671875 0.453125 -1.671875 0.453125zm4.0216675 -0.1875l0 -6.125l0.984375 0l0 0.90625l0.046875 0q0.234375 -0.4375 0.78125 -0.765625q0.546875 -0.328125 1.1875 -0.328125q1.140625 0 1.703125 0.65625q0.578125 0.65625 0.578125 1.734375l0 3.921875l-1.03125 0l0 -3.765625q0 -0.890625 -0.421875 -1.25q-0.421875 -0.375 -1.09375 -0.375q-0.515625 0 -0.90625 0.28125q-0.375 0.28125 -0.59375 0.734375q-0.203125 0.4375 -0.203125 0.9375l0 3.4375l-1.03125 0zm6.0257874 -6.125l3.578125 0l0 0.921875l-3.578125 0l0 -0.921875zm1.0625 4.515625l0 -6.234375l1.015625 0l0 5.984375q0 0.484375 0.1875 0.75q0.203125 0.25 0.671875 0.25q0.203125 0 0.359375 -0.046875q0.171875 -0.0625 0.3125 -0.15625l0 1.0q-0.15625 0.078125 -0.34375 0.109375q-0.1875 0.046875 -0.5 0.046875q-0.765625 0 -1.234375 -0.4375q-0.46875 -0.453125 -0.46875 -1.265625z" fill-rule="nonzero"/><path fill="#a2c4c9" d="m77.69106 235.04298l0 0c0 -4.8590393 3.9390335 -8.798065 8.798073 -8.798065l43.852676 0c2.3333893 0 4.571213 0.92692566 6.221176 2.576889c1.6499481 1.6499634 2.576889 3.8877869 2.576889 6.221176l0 35.19124c0 4.85907 -3.9390259 8.798096 -8.798065 8.798096l-43.852676 0c-4.8590393 0 -8.798073 -3.9390259 -8.798073 -8.798096z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m77.69106 235.04298l0 0c0 -4.8590393 3.9390335 -8.798065 8.798073 -8.798065l43.852676 0c2.3333893 0 4.571213 0.92692566 6.221176 2.576889c1.6499481 1.6499634 2.576889 3.8877869 2.576889 6.221176l0 35.19124c0 4.85907 -3.9390259 8.798096 -8.798065 8.798096l-43.852676 0c-4.8590393 0 -8.798073 -3.9390259 -8.798073 -8.798096z" fill-rule="evenodd"/><path fill="#000000" d="m101.24976 257.3461q-0.90625 0 -1.71875 -0.328125q-0.8125 -0.34375 -1.421875 -0.953125q-0.609375 -0.60935974 -0.953125 -1.4218597q-0.34375 -0.828125 -0.34375 -1.78125q0 -0.953125 0.34375 -1.765625q0.34375 -0.828125 0.953125 -1.4375q0.609375 -0.609375 1.421875 -0.9375q0.8125 -0.34375 1.71875 -0.34375q0.953125 0 1.78125 0.34375q0.84375 0.328125 1.375 0.9375l-0.71875 0.71875q-0.265625 -0.328125 -0.65625 -0.5625q-0.375 -0.234375 -0.828125 -0.34375q-0.4375 -0.125 -0.9375 -0.125q-0.6875 0 -1.3125 0.25q-0.609375 0.25 -1.09375 0.71875q-0.46875 0.453125 -0.75 1.109375q-0.265625 0.640625 -0.265625 1.4375q0 0.8125 0.28125 1.453125q0.28125 0.640625 0.75 1.109375q0.484375 0.46875 1.09375 0.71873474q0.625 0.234375 1.296875 0.234375q0.578125 0 1.125 -0.15625q0.546875 -0.171875 0.984375 -0.49998474q0.4375 -0.34375 0.71875 -0.890625q0.296875 -0.546875 0.359375 -1.296875l-3.171875 0l0 -0.953125l4.125 0q0.03125 0.15625 0.046875 0.3125q0.015625 0.140625 0.015625 0.3125l0 0l0 0l0 0q0 0.921875 -0.3125 1.6875q-0.3125 0.765625 -0.875 1.3124847q-0.5625 0.546875 -1.328125 0.84375q-0.765625 0.296875 -1.703125 0.296875zm4.551193 -0.1875l3.25 -8.593735l1.15625 0l3.265625 8.593735l-1.109375 0l-2.375 -6.4218597l-0.328125 -0.921875l-0.046875 0l-0.34375 0.921875l-2.359375 6.4218597l-1.109375 0zm3.71875 -2.3593597l0 -0.96875l1.96875 0l0.359375 0.96875l-2.328125 0zm-2.328125 0l0.34375 -0.96875l1.984375 0l0 0.96875l-2.328125 0zm7.4150543 2.3593597l0 -8.593735l2.90625 0q0.71875 0 1.328125 0.328125q0.609375 0.328125 0.96875 0.90625q0.375 0.5625 0.375 1.3125q0 0.75 -0.375 1.328125q-0.359375 0.5625 -0.96875 0.890625q-0.609375 0.328125 -1.328125 0.328125l-2.359375 0l0 -0.96875l2.375 0q0.5 0 0.859375 -0.234375q0.359375 -0.234375 0.5625 -0.59375q0.203125 -0.359375 0.203125 -0.75q0 -0.390625 -0.203125 -0.75q-0.203125 -0.359375 -0.5625 -0.59375q-0.359375 -0.234375 -0.859375 -0.234375l-1.890625 0l0 7.6249847l-1.03125 0z" fill-rule="nonzero"/><path fill="#a2c4c9" d="m205.96704 235.04298l0 0c0 -4.8590393 3.9390259 -8.798065 8.798065 -8.798065l43.85266 0c2.3334045 0 4.571228 0.92692566 6.2211914 2.576889c1.6499634 1.6499634 2.5769043 3.8877869 2.5769043 6.221176l0 35.19124c0 4.85907 -3.9390259 8.798096 -8.798096 8.798096l-43.85266 0c-4.8590393 0 -8.798065 -3.9390259 -8.798065 -8.798096z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m205.96704 235.04298l0 0c0 -4.8590393 3.9390259 -8.798065 8.798065 -8.798065l43.85266 0c2.3334045 0 4.571228 0.92692566 6.2211914 2.576889c1.6499634 1.6499634 2.5769043 3.8877869 2.5769043 6.221176l0 35.19124c0 4.85907 -3.9390259 8.798096 -8.798096 8.798096l-43.85266 0c-4.8590393 0 -8.798065 -3.9390259 -8.798065 -8.798096z" fill-rule="evenodd"/><path fill="#000000" d="m226.91573 250.34612q-0.90625 0 -1.71875 -0.328125q-0.8125 -0.34375 -1.421875 -0.953125q-0.609375 -0.609375 -0.953125 -1.421875q-0.34375 -0.828125 -0.34375 -1.78125q0 -0.953125 0.34375 -1.765625q0.34375 -0.828125 0.953125 -1.4375q0.609375 -0.609375 1.421875 -0.9375q0.8125 -0.34375 1.71875 -0.34375q0.953125 0 1.78125 0.34375q0.84375 0.328125 1.375 0.9375l-0.71875 0.71875q-0.265625 -0.328125 -0.65625 -0.5625q-0.375 -0.234375 -0.828125 -0.34375q-0.4375 -0.125 -0.9375 -0.125q-0.6875 0 -1.3125 0.25q-0.609375 0.25 -1.09375 0.71875q-0.46875 0.453125 -0.75 1.109375q-0.265625 0.640625 -0.265625 1.4375q0 0.8125 0.28125 1.453125q0.28125 0.640625 0.75 1.109375q0.484375 0.46875 1.09375 0.71875q0.625 0.234375 1.296875 0.234375q0.578125 0 1.125 -0.15625q0.546875 -0.171875 0.984375 -0.5q0.4375 -0.34375 0.71875 -0.890625q0.296875 -0.546875 0.359375 -1.296875l-3.171875 0l0 -0.953125l4.125 0q0.03125 0.15625 0.046875 0.3125q0.015625 0.140625 0.015625 0.3125l0 0l0 0l0 0q0 0.921875 -0.3125 1.6875q-0.3125 0.765625 -0.875 1.3125q-0.5625 0.546875 -1.328125 0.84375q-0.765625 0.296875 -1.703125 0.296875zm4.551193 -0.1875l3.25 -8.59375l1.15625 0l3.265625 8.59375l-1.109375 0l-2.375 -6.421875l-0.328125 -0.921875l-0.046875 0l-0.34375 0.921875l-2.359375 6.421875l-1.109375 0zm3.71875 -2.359375l0 -0.96875l1.96875 0l0.359375 0.96875l-2.328125 0zm-2.328125 0l0.34375 -0.96875l1.984375 0l0 0.96875l-2.328125 0zm8.400681 2.359375l0 -7.984375l1.03125 0l0 7.984375l-1.03125 0zm-2.40625 -7.625l0 -0.96875l5.828125 0l0 0.96875l-5.828125 0zm8.862289 7.625l0 -7.984375l1.03125 0l0 7.984375l-1.03125 0zm-2.40625 -7.625l0 -0.96875l5.828125 0l0 0.96875l-5.828125 0z" fill-rule="nonzero"/><path fill="#000000" d="m222.3267 264.3461q-0.625 0 -1.234375 -0.265625q-0.609375 -0.265625 -1.078125 -0.78125q-0.46875 -0.515625 -0.6875 -1.28125l0.96875 -0.390625q0.203125 0.75 0.734375 1.25q0.546875 0.5 1.328125 0.5q0.46875 0 0.875 -0.171875q0.40625 -0.171875 0.640625 -0.5q0.25 -0.34375 0.25 -0.828125q0 -0.4375 -0.21875 -0.734375q-0.203125 -0.296875 -0.625 -0.53125q-0.40625 -0.234375 -1.03125 -0.453125l-0.53125 -0.1875q-0.359375 -0.125 -0.734375 -0.3125q-0.359375 -0.1875 -0.671875 -0.453125q-0.296875 -0.28125 -0.484375 -0.65625q-0.171875 -0.375 -0.171875 -0.890625q0 -0.625 0.328125 -1.140625q0.34375 -0.515625 0.921875 -0.82810974q0.59375 -0.3125 1.359375 -0.3125q0.8125 0 1.359375 0.296875q0.546875 0.28125 0.859375 0.68748474q0.3125 0.40625 0.421875 0.734375l-0.953125 0.421875q-0.0625 -0.265625 -0.265625 -0.53125q-0.203125 -0.265625 -0.546875 -0.453125q-0.34375 -0.1875 -0.859375 -0.1875q-0.421875 0 -0.796875 0.171875q-0.359375 0.171875 -0.578125 0.46875q-0.21875 0.28125 -0.21875 0.671875q0 0.53125 0.421875 0.84375q0.4375 0.3125 1.171875 0.5625l0.5625 0.203125q0.390625 0.125 0.78125 0.328125q0.40625 0.1875 0.75 0.484375q0.359375 0.296875 0.5625 0.734375q0.21875 0.4375 0.21875 1.046875q0 0.671875 -0.265625 1.140625q-0.25 0.46875 -0.671875 0.78125q-0.40625 0.296875 -0.90625 0.421875q-0.5 0.140625 -0.984375 0.140625zm6.869049 0q-0.890625 0 -1.578125 -0.40625q-0.6875 -0.421875 -1.078125 -1.15625q-0.390625 -0.734375 -0.390625 -1.671875q0 -0.875 0.359375 -1.609375q0.359375 -0.75 1.03125 -1.203125q0.671875 -0.453125 1.5625 -0.453125q0.921875 0 1.5625 0.40625q0.65625 0.390625 1.015625 1.109375q0.359375 0.703125 0.359375 1.609375q0 0.09375 -0.015625 0.1875q0 0.078125 -0.015625 0.125l-5.265625 0l0 -0.828125l4.21875 0q-0.015625 -0.25 -0.125 -0.546875q-0.09375 -0.296875 -0.328125 -0.546875q-0.21875 -0.265625 -0.5625 -0.421875q-0.328125 -0.171875 -0.84375 -0.171875q-0.59375 0 -1.03125 0.3125q-0.4375 0.296875 -0.671875 0.828125q-0.234375 0.53125 -0.234375 1.203125q0 0.78125 0.296875 1.296875q0.296875 0.515625 0.765625 0.765625q0.484375 0.25 1.0 0.25q0.671875 0 1.109375 -0.3125q0.4375 -0.328125 0.703125 -0.796875l0.859375 0.421875q-0.359375 0.703125 -1.03125 1.15625q-0.671875 0.453125 -1.671875 0.453125zm4.0216675 -0.1875l0 -6.125l0.984375 0l0 0.984375l0.046875 0q0.109375 -0.34375 0.390625 -0.59375q0.28125 -0.265625 0.640625 -0.40625q0.375 -0.15625 0.734375 -0.15625q0.28125 0 0.4375 0.03125q0.15625 0.03125 0.28125 0.078125l0 1.109375q-0.1875 -0.09375 -0.40625 -0.140625q-0.21875 -0.046875 -0.453125 -0.046875q-0.4375 0 -0.8125 0.25q-0.375 0.25 -0.59375 0.671875q-0.21875 0.421875 -0.21875 0.921875l0 3.421875l-1.03125 0zm6.5165253 0l-2.484375 -6.125l1.09375 0l1.90625 4.921875l0.015625 0l1.921875 -4.921875l1.0625 0l-2.484375 6.125l-1.03125 0zm6.9099274 0.1875q-0.890625 0 -1.578125 -0.40625q-0.6875 -0.421875 -1.078125 -1.15625q-0.390625 -0.734375 -0.390625 -1.671875q0 -0.875 0.359375 -1.609375q0.359375 -0.75 1.03125 -1.203125q0.671875 -0.453125 1.5625 -0.453125q0.921875 0 1.5625 0.40625q0.65625 0.390625 1.015625 1.109375q0.359375 0.703125 0.359375 1.609375q0 0.09375 -0.015625 0.1875q0 0.078125 -0.015625 0.125l-5.265625 0l0 -0.828125l4.21875 0q-0.015625 -0.25 -0.125 -0.546875q-0.09375 -0.296875 -0.328125 -0.546875q-0.21875 -0.265625 -0.5625 -0.421875q-0.328125 -0.171875 -0.84375 -0.171875q-0.59375 0 -1.03125 0.3125q-0.4375 0.296875 -0.671875 0.828125q-0.234375 0.53125 -0.234375 1.203125q0 0.78125 0.296875 1.296875q0.296875 0.515625 0.765625 0.765625q0.484375 0.25 1.0 0.25q0.671875 0 1.109375 -0.3125q0.4375 -0.328125 0.703125 -0.796875l0.859375 0.421875q-0.359375 0.703125 -1.03125 1.15625q-0.671875 0.453125 -1.671875 0.453125zm4.0216675 -0.1875l0 -6.125l0.984375 0l0 0.984375l0.046875 0q0.109375 -0.34375 0.390625 -0.59375q0.28125 -0.265625 0.640625 -0.40625q0.375 -0.15625 0.734375 -0.15625q0.28125 0 0.4375 0.03125q0.15625 0.03125 0.28125 0.078125l0 1.109375q-0.1875 -0.09375 -0.40625 -0.140625q-0.21875 -0.046875 -0.453125 -0.046875q-0.4375 0 -0.8125 0.25q-0.375 0.25 -0.59375 0.671875q-0.21875 0.421875 -0.21875 0.921875l0 3.421875l-1.03125 0z" fill-rule="nonzero"/><path fill="#a2c4c9" d="m270.105 235.04298l0 0c0 -4.8590393 3.9390564 -8.798065 8.798096 -8.798065l43.85266 0c2.3334045 0 4.571228 0.92692566 6.2211914 2.576889c1.6499329 1.6499634 2.5768738 3.8877869 2.5768738 6.221176l0 35.19124c0 4.85907 -3.9390259 8.798096 -8.798065 8.798096l-43.85266 0c-4.8590393 0 -8.798096 -3.9390259 -8.798096 -8.798096z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m270.105 235.04298l0 0c0 -4.8590393 3.9390564 -8.798065 8.798096 -8.798065l43.85266 0c2.3334045 0 4.571228 0.92692566 6.2211914 2.576889c1.6499329 1.6499634 2.5768738 3.8877869 2.5768738 6.221176l0 35.19124c0 4.85907 -3.9390259 8.798096 -8.798065 8.798096l-43.85266 0c-4.8590393 0 -8.798096 -3.9390259 -8.798096 -8.798096z" fill-rule="evenodd"/><path fill="#000000" d="m281.83264 250.34612q-0.625 0 -1.234375 -0.265625q-0.609375 -0.265625 -1.078125 -0.78125q-0.46875 -0.515625 -0.6875 -1.28125l0.96875 -0.390625q0.203125 0.75 0.734375 1.25q0.546875 0.5 1.328125 0.5q0.46875 0 0.875 -0.171875q0.40625 -0.171875 0.640625 -0.5q0.25 -0.34375 0.25 -0.828125q0 -0.4375 -0.21875 -0.734375q-0.203125 -0.296875 -0.625 -0.53125q-0.40625 -0.234375 -1.03125 -0.453125l-0.53125 -0.1875q-0.359375 -0.125 -0.734375 -0.3125q-0.359375 -0.1875 -0.671875 -0.453125q-0.296875 -0.28125 -0.484375 -0.65625q-0.171875 -0.375 -0.171875 -0.890625q0 -0.625 0.328125 -1.140625q0.34375 -0.515625 0.921875 -0.828125q0.59375 -0.3125 1.359375 -0.3125q0.8125 0 1.359375 0.296875q0.546875 0.28125 0.859375 0.6875q0.3125 0.40625 0.421875 0.734375l-0.953125 0.421875q-0.0625 -0.265625 -0.265625 -0.53125q-0.203125 -0.265625 -0.546875 -0.453125q-0.34375 -0.1875 -0.859375 -0.1875q-0.421875 0 -0.796875 0.171875q-0.359375 0.171875 -0.578125 0.46875q-0.21875 0.28125 -0.21875 0.671875q0 0.53125 0.421875 0.84375q0.4375 0.3125 1.171875 0.5625l0.5625 0.203125q0.390625 0.125 0.78125 0.328125q0.40625 0.1875 0.75 0.484375q0.359375 0.296875 0.5625 0.734375q0.21875 0.4375 0.21875 1.046875q0 0.671875 -0.265625 1.140625q-0.25 0.46875 -0.671875 0.78125q-0.40625 0.296875 -0.90625 0.421875q-0.5 0.140625 -0.984375 0.140625zm6.869049 0q-0.890625 0 -1.578125 -0.40625q-0.6875 -0.421875 -1.078125 -1.15625q-0.390625 -0.734375 -0.390625 -1.671875q0 -0.875 0.359375 -1.609375q0.359375 -0.75 1.03125 -1.203125q0.671875 -0.453125 1.5625 -0.453125q0.921875 0 1.5625 0.40625q0.65625 0.390625 1.015625 1.109375q0.359375 0.703125 0.359375 1.609375q0 0.09375 -0.015625 0.1875q0 0.078125 -0.015625 0.125l-5.265625 0l0 -0.828125l4.21875 0q-0.015625 -0.25 -0.125 -0.546875q-0.09375 -0.296875 -0.328125 -0.546875q-0.21875 -0.265625 -0.5625 -0.421875q-0.328125 -0.171875 -0.84375 -0.171875q-0.59375 0 -1.03125 0.3125q-0.4375 0.296875 -0.671875 0.828125q-0.234375 0.53125 -0.234375 1.203125q0 0.78125 0.296875 1.296875q0.296875 0.515625 0.765625 0.765625q0.484375 0.25 1.0 0.25q0.671875 0 1.109375 -0.3125q0.4375 -0.328125 0.703125 -0.796875l0.859375 0.421875q-0.359375 0.703125 -1.03125 1.15625q-0.671875 0.453125 -1.671875 0.453125zm6.862915 0q-0.90625 0 -1.609375 -0.421875q-0.703125 -0.421875 -1.09375 -1.15625q-0.390625 -0.75 -0.390625 -1.671875q0 -0.9375 0.390625 -1.65625q0.390625 -0.734375 1.09375 -1.15625q0.703125 -0.4375 1.609375 -0.4375q1.03125 0 1.6875 0.484375q0.671875 0.46875 0.953125 1.203125l-0.921875 0.390625q-0.234375 -0.5625 -0.6875 -0.859375q-0.453125 -0.296875 -1.078125 -0.296875q-0.546875 0 -1.015625 0.296875q-0.453125 0.28125 -0.75 0.8125q-0.28125 0.515625 -0.28125 1.21875q0 0.703125 0.28125 1.234375q0.296875 0.515625 0.75 0.8125q0.46875 0.28125 1.015625 0.28125q0.640625 0 1.109375 -0.296875q0.46875 -0.296875 0.703125 -0.859375l0.90625 0.390625q-0.296875 0.703125 -0.96875 1.203125q-0.671875 0.484375 -1.703125 0.484375zm5.989563 0q-1.125 0 -1.703125 -0.65625q-0.5625 -0.65625 -0.5625 -1.796875l0 -3.859375l1.03125 0l0 3.703125q0 0.90625 0.40625 1.296875q0.421875 0.390625 1.046875 0.390625q0.546875 0 0.9375 -0.28125q0.40625 -0.28125 0.609375 -0.71875q0.21875 -0.453125 0.21875 -0.921875l0 -3.46875l1.015625 0l0 6.125l-0.96875 0l0 -0.890625l-0.046875 0q-0.15625 0.296875 -0.46875 0.546875q-0.296875 0.234375 -0.6875 0.375q-0.390625 0.15625 -0.828125 0.15625zm4.513275 -0.1875l0 -6.125l0.984375 0l0 0.984375l0.046875 0q0.109375 -0.34375 0.390625 -0.59375q0.28125 -0.265625 0.640625 -0.40625q0.375 -0.15625 0.734375 -0.15625q0.28125 0 0.4375 0.03125q0.15625 0.03125 0.28125 0.078125l0 1.109375q-0.1875 -0.09375 -0.40625 -0.140625q-0.21875 -0.046875 -0.453125 -0.046875q-0.4375 0 -0.8125 0.25q-0.375 0.25 -0.59375 0.671875q-0.21875 0.421875 -0.21875 0.921875l0 3.421875l-1.03125 0zm4.6094055 0l0 -6.125l1.015625 0l0 6.125l-1.015625 0zm0.5 -7.25q-0.296875 0 -0.515625 -0.21875q-0.21875 -0.21875 -0.21875 -0.515625q0 -0.3125 0.21875 -0.515625q0.21875 -0.21875 0.515625 -0.21875q0.3125 0 0.515625 0.21875q0.21875 0.203125 0.21875 0.515625q0 0.296875 -0.21875 0.515625q-0.203125 0.21875 -0.515625 0.21875zm1.6364136 1.125l3.578125 0l0 0.921875l-3.578125 0l0 -0.921875zm1.0625 4.515625l0 -6.234375l1.015625 0l0 5.984375q0 0.484375 0.1875 0.75q0.203125 0.25 0.671875 0.25q0.203125 0 0.359375 -0.046875q0.171875 -0.0625 0.3125 -0.15625l0 1.0q-0.15625 0.078125 -0.34375 0.109375q-0.1875 0.046875 -0.5 0.046875q-0.765625 0 -1.234375 -0.4375q-0.46875 -0.453125 -0.46875 -1.265625zm5.549408 3.890625q-0.046875 0.078125 -0.09375 0.171875q-0.046875 0.109375 -0.0625 0.140625l-1.046875 0q0.0625 -0.15625 0.140625 -0.34375q0.09375 -0.1875 0.21875 -0.453125q0.0625 -0.15625 0.125 -0.296875q0.0625 -0.125 0.140625 -0.28125q0.078125 -0.15625 0.1875 -0.40625l0.84375 -1.828125l0.21875 -0.5625l1.859375 -4.546875l1.09375 0l-3.171875 7.3125q-0.046875 0.109375 -0.15625 0.34375q-0.09375 0.234375 -0.1875 0.453125q-0.078125 0.21875 -0.109375 0.296875zm0.21875 -2.53125l-2.59375 -5.875l1.109375 0l1.921875 4.546875l0.09375 0l-0.53125 1.328125z" fill-rule="nonzero"/><path fill="#000000" d="m277.8184 264.1586l0 -8.593735l1.484375 0l2.734375 7.0468597l0.046875 0l2.734375 -7.0468597l1.484375 0l0 8.593735l-1.015625 0l0 -5.453125l0.046875 -1.640625l-0.046875 0l-2.8125 7.09375l-0.828125 0l-2.8125 -7.09375l-0.046875 0l0.046875 1.640625l0 5.453125l-1.015625 0zm11.977722 0.1875q-0.6875 0 -1.203125 -0.265625q-0.515625 -0.265625 -0.8125 -0.71875q-0.296875 -0.46875 -0.296875 -1.046875q0 -0.671875 0.34375 -1.125q0.359375 -0.46875 0.9375 -0.703125q0.59375 -0.234375 1.296875 -0.234375q0.40625 0 0.75 0.0625q0.359375 0.0625 0.609375 0.15625q0.265625 0.09375 0.390625 0.171875l0 -0.375q0 -0.6875 -0.5 -1.09375q-0.484375 -0.421875 -1.1875 -0.421875q-0.5 0 -0.9375 0.234375q-0.4375 0.21875 -0.6875 0.609375l-0.78125 -0.578125q0.25 -0.359375 0.609375 -0.625q0.359375 -0.265625 0.8125 -0.40625q0.46875 -0.140625 0.984375 -0.140625q1.25 0 1.953125 0.671875q0.71875 0.65625 0.71875 1.765625l0 3.875l-0.984375 0l0 -0.875l-0.046875 0q-0.15625 0.265625 -0.453125 0.515625q-0.28125 0.234375 -0.671875 0.390625q-0.375 0.15625 -0.84375 0.15625zm0.09375 -0.890625q0.53125 0 0.96875 -0.265625q0.4375 -0.265625 0.6875 -0.703125q0.265625 -0.453125 0.265625 -0.984375q-0.265625 -0.1875 -0.6875 -0.296875q-0.40625 -0.125 -0.90625 -0.125q-0.875 0 -1.28125 0.359375q-0.40625 0.359375 -0.40625 0.875q0 0.515625 0.375 0.828125q0.390625 0.3125 0.984375 0.3125zm4.30954 0.703125l0 -6.125l0.984375 0l0 0.90625l0.046875 0q0.234375 -0.4375 0.78125 -0.765625q0.546875 -0.328125 1.1875 -0.328125q1.140625 0 1.703125 0.65625q0.578125 0.65625 0.578125 1.734375l0 3.921875l-1.03125 0l0 -3.765625q0 -0.890625 -0.421875 -1.25q-0.421875 -0.375 -1.09375 -0.375q-0.515625 0 -0.90625 0.28125q-0.375 0.28125 -0.59375 0.734375q-0.203125 0.4375 -0.203125 0.9375l0 3.4375l-1.03125 0zm8.640778 0.1875q-0.6875 0 -1.203125 -0.265625q-0.515625 -0.265625 -0.8125 -0.71875q-0.296875 -0.46875 -0.296875 -1.046875q0 -0.671875 0.34375 -1.125q0.359375 -0.46875 0.9375 -0.703125q0.59375 -0.234375 1.296875 -0.234375q0.40625 0 0.75 0.0625q0.359375 0.0625 0.609375 0.15625q0.265625 0.09375 0.390625 0.171875l0 -0.375q0 -0.6875 -0.5 -1.09375q-0.484375 -0.421875 -1.1875 -0.421875q-0.5 0 -0.9375 0.234375q-0.4375 0.21875 -0.6875 0.609375l-0.78125 -0.578125q0.25 -0.359375 0.609375 -0.625q0.359375 -0.265625 0.8125 -0.40625q0.46875 -0.140625 0.984375 -0.140625q1.25 0 1.953125 0.671875q0.71875 0.65625 0.71875 1.765625l0 3.875l-0.984375 0l0 -0.875l-0.046875 0q-0.15625 0.265625 -0.453125 0.515625q-0.28125 0.234375 -0.671875 0.390625q-0.375 0.15625 -0.84375 0.15625zm0.09375 -0.890625q0.53125 0 0.96875 -0.265625q0.4375 -0.265625 0.6875 -0.703125q0.265625 -0.453125 0.265625 -0.984375q-0.265625 -0.1875 -0.6875 -0.296875q-0.40625 -0.125 -0.90625 -0.125q-0.875 0 -1.28125 0.359375q-0.40625 0.359375 -0.40625 0.875q0 0.515625 0.375 0.828125q0.390625 0.3125 0.984375 0.3125zm6.937042 3.484375q-0.78125 0 -1.34375 -0.265625q-0.546875 -0.25 -0.890625 -0.65625q-0.34375 -0.390625 -0.484375 -0.796875l0.9375 -0.390625q0.1875 0.5 0.640625 0.84375q0.46875 0.34375 1.140625 0.34375q0.96875 0 1.484375 -0.5625q0.515625 -0.546875 0.515625 -1.546875l0 -0.6875l-0.046875 0q-0.296875 0.453125 -0.84375 0.765625q-0.53125 0.296875 -1.25 0.296875q-0.78125 0 -1.4375 -0.40625q-0.65625 -0.421875 -1.046875 -1.140625q-0.375 -0.71875 -0.375 -1.671875q0 -0.953125 0.375 -1.671875q0.390625 -0.734375 1.046875 -1.140625q0.65625 -0.40625 1.4375 -0.40625q0.71875 0 1.25 0.3125q0.546875 0.296875 0.84375 0.75l0.046875 0l0 -0.875l0.96875 0l0 5.890625q0 1.015625 -0.390625 1.6875q-0.390625 0.671875 -1.0625 1.0q-0.65625 0.328125 -1.515625 0.328125zm0 -3.578125q0.546875 0 1.0 -0.265625q0.453125 -0.28125 0.71875 -0.796875q0.28125 -0.515625 0.28125 -1.234375q0 -0.75 -0.28125 -1.25q-0.265625 -0.515625 -0.71875 -0.78125q-0.453125 -0.265625 -1.0 -0.265625q-0.53125 0 -1.0 0.28125q-0.453125 0.265625 -0.734375 0.78125q-0.265625 0.5 -0.265625 1.234375q0 0.734375 0.265625 1.25q0.28125 0.5 0.734375 0.78125q0.46875 0.265625 1.0 0.265625zm7.15094 0.984375q-0.890625 0 -1.578125 -0.40625q-0.6875 -0.421875 -1.078125 -1.15625q-0.390625 -0.734375 -0.390625 -1.671875q0 -0.875 0.359375 -1.609375q0.359375 -0.75 1.03125 -1.203125q0.671875 -0.453125 1.5625 -0.453125q0.921875 0 1.5625 0.40625q0.65625 0.390625 1.015625 1.109375q0.359375 0.703125 0.359375 1.609375q0 0.09375 -0.015625 0.1875q0 0.078125 -0.015625 0.125l-5.265625 0l0 -0.828125l4.21875 0q-0.015625 -0.25 -0.125 -0.546875q-0.09375 -0.296875 -0.328125 -0.546875q-0.21875 -0.265625 -0.5625 -0.421875q-0.328125 -0.171875 -0.84375 -0.171875q-0.59375 0 -1.03125 0.3125q-0.4375 0.296875 -0.671875 0.828125q-0.234375 0.53125 -0.234375 1.203125q0 0.78125 0.296875 1.296875q0.296875 0.515625 0.765625 0.765625q0.484375 0.25 1.0 0.25q0.671875 0 1.109375 -0.3125q0.4375 -0.328125 0.703125 -0.796875l0.859375 0.421875q-0.359375 0.703125 -1.03125 1.15625q-0.671875 0.453125 -1.671875 0.453125zm4.0216675 -0.1875l0 -6.125l0.984375 0l0 0.984375l0.046875 0q0.109375 -0.34375 0.390625 -0.59375q0.28125 -0.265625 0.640625 -0.40625q0.375 -0.15625 0.734375 -0.15625q0.28125 0 0.4375 0.03125q0.15625 0.03125 0.28125 0.078125l0 1.109375q-0.1875 -0.09375 -0.40625 -0.140625q-0.21875 -0.046875 -0.453125 -0.046875q-0.4375 0 -0.8125 0.25q-0.375 0.25 -0.59375 0.671875q-0.21875 0.421875 -0.21875 0.921875l0 3.421875l-1.03125 0z" fill-rule="nonzero"/><path fill="#a2c4c9" d="m13.553075 235.04298l0 0c0 -4.8590393 3.9390326 -8.798065 8.798076 -8.798065l43.85267 0c2.3333893 0 4.5712204 0.92692566 6.221176 2.576889c1.6499634 1.6499634 2.5768967 3.8877869 2.5768967 6.221176l0 35.19124c0 4.85907 -3.9390335 8.798096 -8.798073 8.798096l-43.85267 0c-4.859043 0 -8.798076 -3.9390259 -8.798076 -8.798096z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m13.553075 235.04298l0 0c0 -4.8590393 3.9390326 -8.798065 8.798076 -8.798065l43.85267 0c2.3333893 0 4.5712204 0.92692566 6.221176 2.576889c1.6499634 1.6499634 2.5768967 3.8877869 2.5768967 6.221176l0 35.19124c0 4.85907 -3.9390335 8.798096 -8.798073 8.798096l-43.85267 0c-4.859043 0 -8.798076 -3.9390259 -8.798076 -8.798096z" fill-rule="evenodd"/><path fill="#000000" d="m27.098484 257.1586l0 -8.593735l1.03125 0l0 7.6249847l3.75 0l0 0.96875l-4.78125 0zm5.7017975 0l0 -1.015625q0.03125 -0.046875 0.28125 -0.29685974q0.25 -0.25 0.625 -0.625q0.375 -0.375 0.78125 -0.78125q0.40625 -0.421875 0.75 -0.78125q0.359375 -0.375 0.5625 -0.609375q0.375 -0.40625 0.59375 -0.6875q0.234375 -0.296875 0.34375 -0.578125q0.109375 -0.28125 0.109375 -0.65625q0 -0.359375 -0.1875 -0.671875q-0.171875 -0.3125 -0.515625 -0.515625q-0.34375 -0.203125 -0.859375 -0.203125q-0.46875 0 -0.8125 0.203125q-0.328125 0.203125 -0.515625 0.484375q-0.171875 0.28125 -0.234375 0.5l-0.921875 -0.359375q0.078125 -0.265625 0.265625 -0.5625q0.1875 -0.3125 0.484375 -0.59375q0.3125 -0.28125 0.75 -0.46875q0.4375 -0.1875 1.015625 -0.1875q0.78125 0 1.34375 0.34375q0.578125 0.328125 0.890625 0.859375q0.328125 0.53125 0.328125 1.15625q0 0.53125 -0.203125 1.03125q-0.203125 0.484375 -0.5 0.875q-0.296875 0.390625 -0.609375 0.703125q-0.15625 0.15625 -0.4375 0.4375q-0.28125 0.265625 -0.59375 0.59375q-0.3125 0.3125 -0.609375 0.609375q-0.296875 0.296875 -0.515625 0.53125q-0.21875 0.21873474 -0.3125 0.29685974l0 0l3.875 0l0 0.96875l-5.171875 0zm10.749542 0.1875q-0.9375 0 -1.75 -0.328125q-0.8125 -0.34375 -1.421875 -0.953125q-0.59375 -0.60935974 -0.9375 -1.4218597q-0.328125 -0.828125 -0.328125 -1.78125q0 -0.953125 0.328125 -1.765625q0.34375 -0.828125 0.9375 -1.421875q0.609375 -0.609375 1.421875 -0.953125q0.8125 -0.34375 1.75 -0.34375q0.671875 0 1.234375 0.171875q0.578125 0.15625 1.046875 0.46875q0.484375 0.3125 0.875 0.765625l-0.734375 0.703125q-0.328125 -0.390625 -0.703125 -0.640625q-0.359375 -0.265625 -0.78125 -0.375q-0.421875 -0.125 -0.9375 -0.125q-0.921875 0 -1.703125 0.4375q-0.765625 0.421875 -1.234375 1.21875q-0.46875 0.78125 -0.46875 1.859375q0 1.0625 0.46875 1.859375q0.46875 0.796875 1.234375 1.234375q0.78125 0.42185974 1.703125 0.42185974q0.578125 0 1.046875 -0.15625q0.46875 -0.15625 0.875 -0.43748474q0.40625 -0.296875 0.734375 -0.6875l0.75 0.71875q-0.375 0.43748474 -0.90625 0.79685974q-0.515625 0.34375 -1.140625 0.546875q-0.625 0.1875 -1.359375 0.1875zm4.0951843 -0.1875l3.25 -8.593735l1.15625 0l3.265625 8.593735l-1.109375 0l-2.375 -6.4218597l-0.328125 -0.921875l-0.046875 0l-0.34375 0.921875l-2.359375 6.4218597l-1.109375 0zm3.71875 -2.3593597l0 -0.96875l1.96875 0l0.359375 0.96875l-2.328125 0zm-2.328125 0l0.34375 -0.96875l1.984375 0l0 0.96875l-2.328125 0zm7.4150543 2.3593597l0 -8.593735l2.90625 0q0.71875 0 1.328125 0.328125q0.609375 0.328125 0.96875 0.90625q0.375 0.5625 0.375 1.3125q0 0.75 -0.375 1.328125q-0.359375 0.5625 -0.96875 0.890625q-0.609375 0.328125 -1.328125 0.328125l-2.359375 0l0 -0.96875l2.375 0q0.5 0 0.859375 -0.234375q0.359375 -0.234375 0.5625 -0.59375q0.203125 -0.359375 0.203125 -0.75q0 -0.390625 -0.203125 -0.75q-0.203125 -0.359375 -0.5625 -0.59375q-0.359375 -0.234375 -0.859375 -0.234375l-1.890625 0l0 7.6249847l-1.03125 0z" fill-rule="nonzero"/><path fill="#a2c4c9" d="m334.243 235.04298l0 0c0 -4.8590393 3.9390259 -8.798065 8.798065 -8.798065l43.85269 0c2.333374 0 4.5711975 0.92692566 6.221161 2.576889c1.6499634 1.6499634 2.5769043 3.8877869 2.5769043 6.221176l0 35.19124c0 4.85907 -3.9390259 8.798096 -8.798065 8.798096l-43.85269 0c-4.8590393 0 -8.798065 -3.9390259 -8.798065 -8.798096z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m334.243 235.04298l0 0c0 -4.8590393 3.9390259 -8.798065 8.798065 -8.798065l43.85269 0c2.333374 0 4.5711975 0.92692566 6.221161 2.576889c1.6499634 1.6499634 2.5769043 3.8877869 2.5769043 6.221176l0 35.19124c0 4.85907 -3.9390259 8.798096 -8.798065 8.798096l-43.85269 0c-4.8590393 0 -8.798065 -3.9390259 -8.798065 -8.798096z" fill-rule="evenodd"/><path fill="#000000" d="m357.28073 257.3461q-0.625 0 -1.234375 -0.265625q-0.609375 -0.265625 -1.078125 -0.78125q-0.46875 -0.51560974 -0.6875 -1.2812347l0.96875 -0.390625q0.203125 0.75 0.734375 1.25q0.546875 0.49998474 1.328125 0.49998474q0.46875 0 0.875 -0.171875q0.40625 -0.171875 0.640625 -0.49998474q0.25 -0.34375 0.25 -0.828125q0 -0.4375 -0.21875 -0.734375q-0.203125 -0.296875 -0.625 -0.53125q-0.40625 -0.234375 -1.03125 -0.453125l-0.53125 -0.1875q-0.359375 -0.125 -0.734375 -0.3125q-0.359375 -0.1875 -0.671875 -0.453125q-0.296875 -0.28125 -0.484375 -0.65625q-0.171875 -0.375 -0.171875 -0.890625q0 -0.625 0.328125 -1.140625q0.34375 -0.515625 0.921875 -0.828125q0.59375 -0.3125 1.359375 -0.3125q0.8125 0 1.359375 0.296875q0.546875 0.28125 0.859375 0.6875q0.3125 0.40625 0.421875 0.734375l-0.953125 0.421875q-0.0625 -0.265625 -0.265625 -0.53125q-0.203125 -0.265625 -0.546875 -0.453125q-0.34375 -0.1875 -0.859375 -0.1875q-0.421875 0 -0.796875 0.171875q-0.359375 0.171875 -0.578125 0.46875q-0.21875 0.28125 -0.21875 0.671875q0 0.53125 0.421875 0.84375q0.4375 0.3125 1.171875 0.5625l0.5625 0.203125q0.390625 0.125 0.78125 0.328125q0.40625 0.1875 0.75 0.484375q0.359375 0.296875 0.5625 0.734375q0.21875 0.4375 0.21875 1.046875q0 0.671875 -0.265625 1.1406097q-0.25 0.46875 -0.671875 0.78125q-0.40625 0.296875 -0.90625 0.421875q-0.5 0.140625 -0.984375 0.140625zm4.337799 -0.1875l0 -8.593735l2.59375 0q1.34375 0 2.3125 0.546875q0.984375 0.546875 1.5 1.515625q0.53125 0.96875 0.53125 2.234375q0 1.265625 -0.53125 2.234375q-0.515625 0.95310974 -1.5 1.5156097q-0.96875 0.546875 -2.3125 0.546875l-2.59375 0zm1.03125 -0.96875l1.5625 0q1.015625 0 1.75 -0.39060974q0.75 -0.390625 1.15625 -1.125q0.40625 -0.75 0.40625 -1.8125q0 -1.0625 -0.40625 -1.796875q-0.40625 -0.75 -1.15625 -1.140625q-0.734375 -0.390625 -1.75 -0.390625l-1.5625 0l0 6.6562347zm7.4048157 0.96875l0 -8.593735l2.90625 0q0.71875 0 1.328125 0.328125q0.609375 0.328125 0.96875 0.90625q0.375 0.5625 0.375 1.3125q0 0.75 -0.375 1.328125q-0.359375 0.5625 -0.96875 0.890625q-0.609375 0.328125 -1.328125 0.328125l-2.359375 0l0 -0.96875l2.375 0q0.5 0 0.859375 -0.234375q0.359375 -0.234375 0.5625 -0.59375q0.203125 -0.359375 0.203125 -0.75q0 -0.390625 -0.203125 -0.75q-0.203125 -0.359375 -0.5625 -0.59375q-0.359375 -0.234375 -0.859375 -0.234375l-1.890625 0l0 7.6249847l-1.03125 0z" fill-rule="nonzero"/><path fill="#a2c4c9" d="m398.381 235.04298l0 0c0 -4.8590393 3.9390259 -8.798065 8.798065 -8.798065l43.947144 0c2.3334045 0 4.571228 0.92692566 6.2211914 2.576889c1.6499634 1.6499634 2.5769043 3.8877869 2.5769043 6.221176l0 35.19124c0 4.85907 -3.9390564 8.798096 -8.798096 8.798096l-43.947144 0c-4.8590393 0 -8.798065 -3.9390259 -8.798065 -8.798096z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m398.381 235.04298l0 0c0 -4.8590393 3.9390259 -8.798065 8.798065 -8.798065l43.947144 0c2.3334045 0 4.571228 0.92692566 6.2211914 2.576889c1.6499634 1.6499634 2.5769043 3.8877869 2.5769043 6.221176l0 35.19124c0 4.85907 -3.9390564 8.798096 -8.798096 8.798096l-43.947144 0c-4.8590393 0 -8.798065 -3.9390259 -8.798065 -8.798096z" fill-rule="evenodd"/><path fill="#000000" d="m405.1216 257.1586l0 -8.593735l2.90625 0q0.71875 0 1.328125 0.328125q0.609375 0.328125 0.96875 0.90625q0.375 0.5625 0.375 1.3125q0 0.453125 -0.171875 0.90625q-0.171875 0.453125 -0.53125 0.828125q-0.34375 0.359375 -0.890625 0.59375q-0.546875 0.21875 -1.296875 0.21875l-2.140625 0l0 -0.953125l2.296875 0q0.453125 0 0.828125 -0.203125q0.390625 -0.203125 0.625 -0.5625q0.25 -0.359375 0.25 -0.828125q0 -0.390625 -0.203125 -0.75q-0.203125 -0.359375 -0.5625 -0.59375q-0.359375 -0.234375 -0.859375 -0.234375l-1.890625 0l0 7.6249847l-1.03125 0zm2.078125 -3.9374847l1.125 -0.0625l2.703125 3.9531097l0 0.046875l-1.203125 0l-2.625 -3.9374847zm4.9539185 3.9374847l0 -8.593735l4.96875 0l0 0.96875l-3.9375 0l0 7.6249847l-1.03125 0zm0.546875 -3.7187347l0 -0.96875l4.046875 0l0 0.96875l-4.046875 0zm9.73642 3.9062347q-0.9375 0 -1.75 -0.328125q-0.8125 -0.34375 -1.421875 -0.953125q-0.59375 -0.60935974 -0.9375 -1.4218597q-0.328125 -0.828125 -0.328125 -1.78125q0 -0.953125 0.328125 -1.765625q0.34375 -0.828125 0.9375 -1.421875q0.609375 -0.609375 1.421875 -0.953125q0.8125 -0.34375 1.75 -0.34375q0.671875 0 1.234375 0.171875q0.578125 0.15625 1.046875 0.46875q0.484375 0.3125 0.875 0.765625l-0.734375 0.703125q-0.328125 -0.390625 -0.703125 -0.640625q-0.359375 -0.265625 -0.78125 -0.375q-0.421875 -0.125 -0.9375 -0.125q-0.921875 0 -1.703125 0.4375q-0.765625 0.421875 -1.234375 1.21875q-0.46875 0.78125 -0.46875 1.859375q0 1.0625 0.46875 1.859375q0.46875 0.796875 1.234375 1.234375q0.78125 0.42185974 1.703125 0.42185974q0.578125 0 1.046875 -0.15625q0.46875 -0.15625 0.875 -0.43748474q0.40625 -0.296875 0.734375 -0.6875l0.75 0.71875q-0.375 0.43748474 -0.90625 0.79685974q-0.515625 0.34375 -1.140625 0.546875q-0.625 0.1875 -1.359375 0.1875zm7.2457886 0q-0.921875 0 -1.640625 -0.421875q-0.703125 -0.4375 -1.109375 -1.1718597q-0.390625 -0.734375 -0.390625 -1.65625q0 -0.90625 0.390625 -1.640625q0.40625 -0.75 1.109375 -1.171875q0.71875 -0.4375 1.640625 -0.4375q0.921875 0 1.625 0.4375q0.71875 0.4375 1.109375 1.1875q0.40625 0.734375 0.40625 1.625q0 0.921875 -0.40625 1.65625q-0.390625 0.73435974 -1.109375 1.1718597q-0.703125 0.421875 -1.625 0.421875zm0 -0.921875q0.546875 0 1.03125 -0.265625q0.484375 -0.28123474 0.78125 -0.79685974q0.3125 -0.53125 0.3125 -1.265625q0 -0.734375 -0.3125 -1.25q-0.296875 -0.53125 -0.78125 -0.796875q-0.484375 -0.28125 -1.03125 -0.28125q-0.546875 0 -1.046875 0.28125q-0.484375 0.265625 -0.796875 0.796875q-0.296875 0.515625 -0.296875 1.25q0 0.734375 0.296875 1.265625q0.3125 0.515625 0.796875 0.79685974q0.5 0.265625 1.046875 0.265625zm4.203949 0.734375l0 -6.1249847l0.984375 0l0 0.90625l0.046875 0q0.15625 -0.296875 0.453125 -0.546875q0.296875 -0.25 0.671875 -0.390625q0.375 -0.15625 0.78125 -0.15625q0.6875 0 1.171875 0.328125q0.5 0.328125 0.703125 0.859375q0.3125 -0.515625 0.84375 -0.84375q0.53125 -0.34375 1.265625 -0.34375q1.09375 0 1.609375 0.671875q0.515625 0.65625 0.515625 1.71875l0 3.9218597l-1.015625 0l0 -3.7656097q0 -0.890625 -0.359375 -1.25q-0.359375 -0.375 -1.015625 -0.375q-0.46875 0 -0.84375 0.28125q-0.359375 0.265625 -0.578125 0.703125q-0.203125 0.4375 -0.203125 0.953125l0 3.4531097l-1.015625 0l0 -3.7499847q0 -0.890625 -0.359375 -1.265625q-0.359375 -0.375 -1.015625 -0.375q-0.46875 0 -0.828125 0.28125q-0.359375 0.265625 -0.578125 0.71875q-0.203125 0.4375 -0.203125 0.953125l0 3.4374847l-1.03125 0zm10.500061 0l0 -6.1249847l0.984375 0l0 0.90625l0.046875 0q0.15625 -0.296875 0.453125 -0.546875q0.296875 -0.25 0.671875 -0.390625q0.375 -0.15625 0.78125 -0.15625q0.6875 0 1.171875 0.328125q0.5 0.328125 0.703125 0.859375q0.3125 -0.515625 0.84375 -0.84375q0.53125 -0.34375 1.265625 -0.34375q1.09375 0 1.609375 0.671875q0.515625 0.65625 0.515625 1.71875l0 3.9218597l-1.015625 0l0 -3.7656097q0 -0.890625 -0.359375 -1.25q-0.359375 -0.375 -1.015625 -0.375q-0.46875 0 -0.84375 0.28125q-0.359375 0.265625 -0.578125 0.703125q-0.203125 0.4375 -0.203125 0.953125l0 3.4531097l-1.015625 0l0 -3.7499847q0 -0.890625 -0.359375 -1.265625q-0.359375 -0.375 -1.015625 -0.375q-0.46875 0 -0.828125 0.28125q-0.359375 0.265625 -0.578125 0.71875q-0.203125 0.4375 -0.203125 0.953125l0 3.4374847l-1.03125 0z" fill-rule="nonzero"/><g filter="url(#shadowFilter-p.6)"><use xlink:href="#p.6" transform="matrix(1.0 0.0 0.0 1.0 0.0 2.0)"/></g><defs><filter id="shadowFilter-p.6" filterUnits="userSpaceOnUse"><feGaussianBlur in="SourceAlpha" stdDeviation="2.0" result="blur"/><feComponentTransfer in="blur" color-interpolation-filters="sRGB"><feFuncR type="linear" slope="0" intercept="0.0"/><feFuncG type="linear" slope="0" intercept="0.0"/><feFuncB type="linear" slope="0" intercept="0.0"/><feFuncA type="linear" slope="0.5" intercept="0"/></feComponentTransfer></filter></defs><g id="p.6"><path fill="#f6b26b" d="m1.2233764 468.88928l0 0c0 -5.2562256 4.2610183 -9.517242 9.517251 -9.517242l235.35919 0c2.5241394 0 4.9448853 1.0026855 6.729721 2.7875366c1.7848206 1.7848206 2.7875366 4.2055664 2.7875366 6.729706l0 38.06784c0 5.256256 -4.261017 9.517242 -9.517258 9.517242l-235.35919 0c-5.2562327 0 -9.517251 -4.2609863 -9.517251 -9.517242z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m1.2233764 468.88928l0 0c0 -5.2562256 4.2610183 -9.517242 9.517251 -9.517242l235.35919 0c2.5241394 0 4.9448853 1.0026855 6.729721 2.7875366c1.7848206 1.7848206 2.7875366 4.2055664 2.7875366 6.729706l0 38.06784c0 5.256256 -4.261017 9.517242 -9.517258 9.517242l-235.35919 0c-5.2562327 0 -9.517251 -4.2609863 -9.517251 -9.517242z" fill-rule="evenodd"/><path fill="#000000" d="m99.084404 494.0332q-1.265625 0 -2.34375 -0.453125q-1.078125 -0.453125 -1.890625 -1.25q-0.8125 -0.8125 -1.265625 -1.90625q-0.4375 -1.109375 -0.4375 -2.375q0 -1.28125 0.4375 -2.359375q0.453125 -1.09375 1.265625 -1.890625q0.8125 -0.8125 1.890625 -1.265625q1.078125 -0.46875 2.34375 -0.46875q0.875 0 1.640625 0.234375q0.765625 0.21875 1.40625 0.640625q0.640625 0.40625 1.140625 1.0l-0.96875 0.953125q-0.4375 -0.53125 -0.921875 -0.859375q-0.484375 -0.34375 -1.0625 -0.5q-0.5625 -0.171875 -1.234375 -0.171875q-1.234375 0 -2.28125 0.578125q-1.03125 0.578125 -1.65625 1.625q-0.625 1.046875 -0.625 2.484375q0 1.4375 0.625 2.5q0.625 1.046875 1.65625 1.625q1.046875 0.5625 2.28125 0.5625q0.75 0 1.375 -0.203125q0.640625 -0.203125 1.171875 -0.578125q0.546875 -0.390625 0.984375 -0.921875l1.0 0.953125q-0.5 0.59375 -1.203125 1.0625q-0.6875 0.46875 -1.53125 0.734375q-0.84375 0.25 -1.796875 0.25zm9.645386 0q-1.234375 0 -2.1875 -0.5625q-0.9375 -0.578125 -1.46875 -1.5625q-0.53125 -0.984375 -0.53125 -2.203125q0 -1.21875 0.53125 -2.203125q0.53125 -0.984375 1.46875 -1.5625q0.953125 -0.578125 2.1875 -0.578125q1.234375 0 2.171875 0.59375q0.953125 0.578125 1.484375 1.5625q0.53125 0.984375 0.53125 2.1875q0 1.21875 -0.53125 2.203125q-0.53125 0.984375 -1.484375 1.5625q-0.9375 0.5625 -2.171875 0.5625zm0 -1.21875q0.734375 0 1.375 -0.375q0.65625 -0.375 1.046875 -1.0625q0.40625 -0.703125 0.40625 -1.671875q0 -0.984375 -0.40625 -1.671875q-0.390625 -0.703125 -1.046875 -1.0625q-0.640625 -0.375 -1.375 -0.375q-0.734375 0 -1.390625 0.375q-0.65625 0.359375 -1.0625 1.0625q-0.390625 0.6875 -0.390625 1.671875q0 0.96875 0.390625 1.671875q0.40625 0.6875 1.0625 1.0625q0.65625 0.375 1.390625 0.375zm5.6260223 0.96875l0 -8.15625l1.28125 0l0 1.203125l0.078125 0q0.3125 -0.59375 1.03125 -1.03125q0.734375 -0.4375 1.609375 -0.4375q1.5 0 2.25 0.875q0.765625 0.875 0.765625 2.3125l0 5.234375l-1.359375 0l0 -5.03125q0 -1.171875 -0.578125 -1.65625q-0.5625 -0.5 -1.453125 -0.5q-0.671875 0 -1.1875 0.375q-0.515625 0.375 -0.796875 0.96875q-0.28125 0.59375 -0.28125 1.25l0 4.59375l-1.359375 0zm8.013519 -8.15625l4.78125 0l0 1.234375l-4.78125 0l0 -1.234375zm1.421875 6.015625l0 -8.328125l1.359375 0l0 7.984375q0 0.640625 0.265625 1.0q0.265625 0.34375 0.875 0.34375q0.265625 0 0.484375 -0.078125q0.234375 -0.078125 0.40625 -0.1875l0 1.328125q-0.203125 0.09375 -0.453125 0.140625q-0.25 0.0625 -0.671875 0.0625q-1.015625 0 -1.640625 -0.59375q-0.625 -0.609375 -0.625 -1.671875zm4.980629 2.140625l0 -8.15625l1.28125 0l0 1.3125l0.078125 0q0.15625 -0.46875 0.53125 -0.8125q0.375 -0.34375 0.859375 -0.546875q0.484375 -0.203125 0.96875 -0.203125q0.375 0 0.578125 0.046875q0.203125 0.046875 0.390625 0.125l0 1.46875q-0.265625 -0.125 -0.5625 -0.1875q-0.296875 -0.078125 -0.59375 -0.078125q-0.59375 0 -1.09375 0.34375q-0.5 0.328125 -0.796875 0.890625q-0.28125 0.5625 -0.28125 1.234375l0 4.5625l-1.359375 0zm9.27002 0.25q-1.234375 0 -2.1875 -0.5625q-0.9375 -0.578125 -1.46875 -1.5625q-0.53125 -0.984375 -0.53125 -2.203125q0 -1.21875 0.53125 -2.203125q0.53125 -0.984375 1.46875 -1.5625q0.953125 -0.578125 2.1875 -0.578125q1.234375 0 2.171875 0.59375q0.953125 0.578125 1.484375 1.5625q0.53125 0.984375 0.53125 2.1875q0 1.21875 -0.53125 2.203125q-0.53125 0.984375 -1.484375 1.5625q-0.9375 0.5625 -2.171875 0.5625zm0 -1.21875q0.734375 0 1.375 -0.375q0.65625 -0.375 1.046875 -1.0625q0.40625 -0.703125 0.40625 -1.671875q0 -0.984375 -0.40625 -1.671875q-0.390625 -0.703125 -1.046875 -1.0625q-0.640625 -0.375 -1.375 -0.375q-0.734375 0 -1.390625 0.375q-0.65625 0.359375 -1.0625 1.0625q-0.390625 0.6875 -0.390625 1.671875q0 0.96875 0.390625 1.671875q0.40625 0.6875 1.0625 1.0625q0.65625 0.375 1.390625 0.375zm5.706024 0.96875l0 -11.453125l1.359375 0l0 11.453125l-1.359375 0zm3.376007 0l0 -11.453125l1.359375 0l0 11.453125l-1.359375 0zm6.9210052 0.25q-1.1875 0 -2.109375 -0.546875q-0.921875 -0.5625 -1.4375 -1.53125q-0.515625 -0.984375 -0.515625 -2.234375q0 -1.171875 0.484375 -2.15625q0.484375 -1.0 1.375 -1.59375q0.890625 -0.609375 2.09375 -0.609375q1.21875 0 2.078125 0.546875q0.875 0.53125 1.34375 1.484375q0.484375 0.9375 0.484375 2.15625q0 0.109375 -0.015625 0.21875q0 0.109375 -0.015625 0.1875l-7.03125 0l0 -1.109375l5.609375 0q-0.015625 -0.34375 -0.15625 -0.734375q-0.125 -0.390625 -0.421875 -0.734375q-0.296875 -0.34375 -0.75 -0.5625q-0.453125 -0.21875 -1.125 -0.21875q-0.796875 0 -1.390625 0.40625q-0.578125 0.40625 -0.890625 1.125q-0.3125 0.703125 -0.3125 1.59375q0 1.03125 0.390625 1.734375q0.40625 0.6875 1.03125 1.03125q0.640625 0.328125 1.328125 0.328125q0.890625 0 1.46875 -0.421875q0.59375 -0.4375 0.953125 -1.0625l1.140625 0.5625q-0.46875 0.9375 -1.375 1.546875q-0.890625 0.59375 -2.234375 0.59375zm5.383011 -0.25l0 -8.15625l1.28125 0l0 1.3125l0.078125 0q0.15625 -0.46875 0.53125 -0.8125q0.375 -0.34375 0.859375 -0.546875q0.484375 -0.203125 0.96875 -0.203125q0.375 0 0.578125 0.046875q0.203125 0.046875 0.390625 0.125l0 1.46875q-0.265625 -0.125 -0.5625 -0.1875q-0.296875 -0.078125 -0.59375 -0.078125q-0.59375 0 -1.09375 0.34375q-0.5 0.328125 -0.796875 0.890625q-0.28125 0.5625 -0.28125 1.234375l0 4.5625l-1.359375 0z" fill-rule="nonzero"/></g><g filter="url(#shadowFilter-p.7)"><use xlink:href="#p.7" transform="matrix(1.0 0.0 0.0 1.0 0.0 2.0)"/></g><defs><filter id="shadowFilter-p.7" filterUnits="userSpaceOnUse"><feGaussianBlur in="SourceAlpha" stdDeviation="2.0" result="blur"/><feComponentTransfer in="blur" color-interpolation-filters="sRGB"><feFuncR type="linear" slope="0" intercept="0.0"/><feFuncG type="linear" slope="0" intercept="0.0"/><feFuncB type="linear" slope="0" intercept="0.0"/><feFuncA type="linear" slope="0.5" intercept="0"/></feComponentTransfer></filter></defs><g id="p.7"><path fill="#f6b26b" d="m4.684006 544.50085l0 0c0 -5.2562866 4.2610183 -9.517273 9.51725 -9.517273l235.35919 0c2.5241394 0 4.9448853 1.0026855 6.729706 2.7875366c1.7848511 1.7848511 2.7875366 4.2055664 2.7875366 6.7297363l0 38.06781c0 5.2562256 -4.2610016 9.517273 -9.517242 9.517273l-235.35919 0c-5.2562323 0 -9.51725 -4.2610474 -9.51725 -9.517273z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m4.684006 544.50085l0 0c0 -5.2562866 4.2610183 -9.517273 9.51725 -9.517273l235.35919 0c2.5241394 0 4.9448853 1.0026855 6.729706 2.7875366c1.7848511 1.7848511 2.7875366 4.2055664 2.7875366 6.7297363l0 38.06781c0 5.2562256 -4.2610016 9.517273 -9.517242 9.517273l-235.35919 0c-5.2562323 0 -9.51725 -4.2610474 -9.51725 -9.517273z" fill-rule="evenodd"/><path fill="#000000" d="m112.98605 569.3948l0 -11.453125l3.875 0q0.953125 0 1.765625 0.4375q0.8125 0.421875 1.296875 1.1875q0.484375 0.75 0.484375 1.765625q0 0.609375 -0.234375 1.21875q-0.21875 0.59375 -0.6875 1.09375q-0.46875 0.484375 -1.203125 0.78125q-0.71875 0.296875 -1.734375 0.296875l-2.84375 0l0 -1.265625l3.078125 0q0.578125 0 1.09375 -0.265625q0.515625 -0.28125 0.828125 -0.75q0.328125 -0.484375 0.328125 -1.109375q0 -0.515625 -0.265625 -0.984375q-0.265625 -0.484375 -0.75 -0.796875q-0.46875 -0.3125 -1.140625 -0.3125l-2.53125 0l0 10.15625l-1.359375 0zm2.765625 -5.25l1.484375 -0.078125l3.625 5.265625l0 0.0625l-1.609375 0l-3.5 -5.25zm8.794525 5.5q-0.90625 0 -1.59375 -0.34375q-0.6875 -0.359375 -1.078125 -0.96875q-0.390625 -0.625 -0.390625 -1.40625q0 -0.890625 0.453125 -1.5q0.46875 -0.625 1.25 -0.9375q0.796875 -0.3125 1.734375 -0.3125q0.546875 0 1.0 0.09375q0.46875 0.078125 0.8125 0.203125q0.34375 0.125 0.515625 0.234375l0 -0.5q0 -0.921875 -0.65625 -1.46875q-0.640625 -0.546875 -1.59375 -0.546875q-0.671875 0 -1.265625 0.296875q-0.578125 0.296875 -0.90625 0.828125l-1.03125 -0.765625q0.328125 -0.484375 0.796875 -0.828125q0.484375 -0.359375 1.09375 -0.546875q0.625 -0.203125 1.3125 -0.203125q1.671875 0 2.609375 0.890625q0.9375 0.875 0.9375 2.359375l0 5.171875l-1.296875 0l0 -1.171875l-0.0625 0q-0.203125 0.359375 -0.59375 0.6875q-0.375 0.328125 -0.90625 0.53125q-0.515625 0.203125 -1.140625 0.203125zm0.140625 -1.1875q0.703125 0 1.28125 -0.34375q0.578125 -0.359375 0.921875 -0.953125q0.359375 -0.59375 0.359375 -1.296875q-0.359375 -0.265625 -0.921875 -0.421875q-0.546875 -0.15625 -1.203125 -0.15625q-1.15625 0 -1.703125 0.484375q-0.546875 0.46875 -0.546875 1.171875q0 0.671875 0.5 1.09375q0.515625 0.421875 1.3125 0.421875zm9.150391 1.1875q-1.109375 0 -2.0 -0.546875q-0.890625 -0.5625 -1.40625 -1.53125q-0.5 -0.984375 -0.5 -2.25q0 -1.265625 0.5 -2.234375q0.515625 -0.984375 1.40625 -1.546875q0.890625 -0.5625 2.0 -0.5625q0.65625 0 1.1875 0.21875q0.546875 0.203125 0.953125 0.546875q0.421875 0.328125 0.640625 0.71875l0.0625 0l-0.0625 -1.140625l0 -3.375l1.359375 0l0 11.453125l-1.296875 0l0 -1.203125l-0.0625 0q-0.21875 0.375 -0.640625 0.71875q-0.40625 0.328125 -0.953125 0.53125q-0.53125 0.203125 -1.1875 0.203125zm0.140625 -1.21875q0.703125 0 1.3125 -0.375q0.625 -0.390625 1.0 -1.078125q0.390625 -0.703125 0.390625 -1.65625q0 -0.96875 -0.390625 -1.65625q-0.375 -0.703125 -1.0 -1.078125q-0.609375 -0.375 -1.3125 -0.375q-0.703125 0 -1.328125 0.375q-0.609375 0.375 -1.0 1.078125q-0.375 0.6875 -0.375 1.65625q0 0.9375 0.375 1.640625q0.390625 0.703125 1.0 1.09375q0.625 0.375 1.328125 0.375zm6.147644 0.96875l0 -8.15625l1.359375 0l0 8.15625l-1.359375 0zm0.671875 -9.65625q-0.40625 0 -0.703125 -0.28125q-0.28125 -0.296875 -0.28125 -0.703125q0 -0.421875 0.28125 -0.6875q0.296875 -0.28125 0.703125 -0.28125q0.40625 0 0.6875 0.28125q0.28125 0.265625 0.28125 0.6875q0 0.40625 -0.28125 0.703125q-0.28125 0.28125 -0.6875 0.28125zm6.4891357 9.90625q-1.234375 0 -2.1875 -0.5625q-0.9375 -0.578125 -1.46875 -1.5625q-0.53125 -0.984375 -0.53125 -2.203125q0 -1.21875 0.53125 -2.203125q0.53125 -0.984375 1.46875 -1.5625q0.953125 -0.578125 2.1875 -0.578125q1.234375 0 2.171875 0.59375q0.953125 0.578125 1.484375 1.5625q0.53125 0.984375 0.53125 2.1875q0 1.21875 -0.53125 2.203125q-0.53125 0.984375 -1.484375 1.5625q-0.9375 0.5625 -2.171875 0.5625zm0 -1.21875q0.734375 0 1.375 -0.375q0.65625 -0.375 1.046875 -1.0625q0.40625 -0.703125 0.40625 -1.671875q0 -0.984375 -0.40625 -1.671875q-0.390625 -0.703125 -1.046875 -1.0625q-0.640625 -0.375 -1.375 -0.375q-0.734375 0 -1.390625 0.375q-0.65625 0.359375 -1.0625 1.0625q-0.390625 0.6875 -0.390625 1.671875q0 0.96875 0.390625 1.671875q0.40625 0.6875 1.0625 1.0625q0.65625 0.375 1.390625 0.375z" fill-rule="nonzero"/></g><g filter="url(#shadowFilter-p.8)"><use xlink:href="#p.8" transform="matrix(1.0 0.0 0.0 1.0 0.0 2.0)"/></g><defs><filter id="shadowFilter-p.8" filterUnits="userSpaceOnUse"><feGaussianBlur in="SourceAlpha" stdDeviation="2.0" result="blur"/><feComponentTransfer in="blur" color-interpolation-filters="sRGB"><feFuncR type="linear" slope="0" intercept="0.0"/><feFuncG type="linear" slope="0" intercept="0.0"/><feFuncB type="linear" slope="0" intercept="0.0"/><feFuncA type="linear" slope="0.5" intercept="0"/></feComponentTransfer></filter></defs><g id="p.8"><path fill="#1155cc" d="m274.31787 468.88928l0 0c0 -5.2562256 4.261017 -9.517242 9.517242 -9.517242l234.94974 0c2.52417 0 4.9448853 1.0026855 6.7297363 2.7875366c1.7848511 1.7848206 2.7875366 4.2055664 2.7875366 6.729706l0 38.06784c0 5.256256 -4.2610474 9.517242 -9.517273 9.517242l-234.94974 0c-5.2562256 0 -9.517242 -4.2609863 -9.517242 -9.517242z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m274.31787 468.88928l0 0c0 -5.2562256 4.261017 -9.517242 9.517242 -9.517242l234.94974 0c2.52417 0 4.9448853 1.0026855 6.7297363 2.7875366c1.7848511 1.7848206 2.7875366 4.2055664 2.7875366 6.729706l0 38.06784c0 5.256256 -4.2610474 9.517242 -9.517273 9.517242l-234.94974 0c-5.2562256 0 -9.517242 -4.2609863 -9.517242 -9.517242z" fill-rule="evenodd"/><path fill="#000000" d="m344.86313 493.7832l-4.0625 -11.453125l1.515625 0l2.828125 8.296875l0.375 1.140625l0.078125 0l0.390625 -1.140625l2.96875 -8.296875l1.5 0l-4.1875 11.453125l-1.40625 0zm6.635376 0l0 -8.15625l1.359375 0l0 8.15625l-1.359375 0zm0.671875 -9.65625q-0.40625 0 -0.703125 -0.28125q-0.28125 -0.296875 -0.28125 -0.703125q0 -0.421875 0.28125 -0.6875q0.296875 -0.28125 0.703125 -0.28125q0.40625 0 0.6875 0.28125q0.28125 0.265625 0.28125 0.6875q0 0.40625 -0.28125 0.703125q-0.28125 0.28125 -0.6875 0.28125zm2.8191528 9.65625l0 -8.15625l1.28125 0l0 1.296875l0.078125 0q0.203125 -0.5 0.578125 -0.828125q0.375 -0.34375 0.875 -0.515625q0.515625 -0.1875 1.03125 -0.1875q0.234375 0 0.34375 0.015625q0.125 0 0.234375 0.03125l0 1.40625q-0.15625 -0.03125 -0.34375 -0.046875q-0.171875 -0.03125 -0.390625 -0.03125q-0.6875 0 -1.21875 0.3125q-0.53125 0.3125 -0.828125 0.875q-0.28125 0.5625 -0.28125 1.296875l0 4.53125l-1.359375 0zm5.5 -8.15625l4.78125 0l0 1.234375l-4.78125 0l0 -1.234375zm1.421875 6.015625l0 -8.328125l1.359375 0l0 7.984375q0 0.640625 0.265625 1.0q0.265625 0.34375 0.875 0.34375q0.265625 0 0.484375 -0.078125q0.234375 -0.078125 0.40625 -0.1875l0 1.328125q-0.203125 0.09375 -0.453125 0.140625q-0.25 0.0625 -0.671875 0.0625q-1.015625 0 -1.640625 -0.59375q-0.625 -0.609375 -0.625 -1.671875zm7.9512634 2.390625q-1.5 0 -2.265625 -0.875q-0.765625 -0.875 -0.765625 -2.40625l0 -5.125l1.359375 0l0 4.921875q0 1.21875 0.5625 1.75q0.5625 0.515625 1.390625 0.515625q0.71875 0 1.25 -0.375q0.53125 -0.390625 0.8125 -0.96875q0.296875 -0.59375 0.296875 -1.234375l0 -4.609375l1.359375 0l0 8.15625l-1.296875 0l0 -1.1875l-0.0625 0q-0.203125 0.390625 -0.625 0.71875q-0.40625 0.328125 -0.921875 0.515625q-0.515625 0.203125 -1.09375 0.203125zm8.536652 0q-0.90625 0 -1.59375 -0.34375q-0.6875 -0.359375 -1.078125 -0.96875q-0.390625 -0.625 -0.390625 -1.40625q0 -0.890625 0.453125 -1.5q0.46875 -0.625 1.25 -0.9375q0.796875 -0.3125 1.734375 -0.3125q0.546875 0 1.0 0.09375q0.46875 0.078125 0.8125 0.203125q0.34375 0.125 0.515625 0.234375l0 -0.5q0 -0.921875 -0.65625 -1.46875q-0.640625 -0.546875 -1.59375 -0.546875q-0.671875 0 -1.265625 0.296875q-0.578125 0.296875 -0.90625 0.828125l-1.03125 -0.765625q0.328125 -0.484375 0.796875 -0.828125q0.484375 -0.359375 1.09375 -0.546875q0.625 -0.203125 1.3125 -0.203125q1.671875 0 2.609375 0.890625q0.9375 0.875 0.9375 2.359375l0 5.171875l-1.296875 0l0 -1.171875l-0.0625 0q-0.203125 0.359375 -0.59375 0.6875q-0.375 0.328125 -0.90625 0.53125q-0.515625 0.203125 -1.140625 0.203125zm0.140625 -1.1875q0.703125 0 1.28125 -0.34375q0.578125 -0.359375 0.921875 -0.953125q0.359375 -0.59375 0.359375 -1.296875q-0.359375 -0.265625 -0.921875 -0.421875q-0.546875 -0.15625 -1.203125 -0.15625q-1.15625 0 -1.703125 0.484375q-0.546875 0.46875 -0.546875 1.171875q0 0.671875 0.5 1.09375q0.515625 0.421875 1.3125 0.421875zm5.761627 0.9375l0 -11.453125l1.359375 0l0 11.453125l-1.359375 0zm12.40863 0.25q-1.265625 0 -2.34375 -0.453125q-1.078125 -0.453125 -1.890625 -1.25q-0.8125 -0.8125 -1.265625 -1.90625q-0.4375 -1.109375 -0.4375 -2.375q0 -1.28125 0.4375 -2.359375q0.453125 -1.09375 1.265625 -1.890625q0.8125 -0.8125 1.890625 -1.265625q1.078125 -0.46875 2.34375 -0.46875q0.875 0 1.640625 0.234375q0.765625 0.21875 1.40625 0.640625q0.640625 0.40625 1.140625 1.0l-0.96875 0.953125q-0.4375 -0.53125 -0.921875 -0.859375q-0.484375 -0.34375 -1.0625 -0.5q-0.5625 -0.171875 -1.234375 -0.171875q-1.234375 0 -2.28125 0.578125q-1.03125 0.578125 -1.65625 1.625q-0.625 1.046875 -0.625 2.484375q0 1.4375 0.625 2.5q0.625 1.046875 1.65625 1.625q1.046875 0.5625 2.28125 0.5625q0.75 0 1.375 -0.203125q0.640625 -0.203125 1.171875 -0.578125q0.546875 -0.390625 0.984375 -0.921875l1.0 0.953125q-0.5 0.59375 -1.203125 1.0625q-0.6875 0.46875 -1.53125 0.734375q-0.84375 0.25 -1.796875 0.25zm9.645386 0q-1.234375 0 -2.1875 -0.5625q-0.9375 -0.578125 -1.46875 -1.5625q-0.53125 -0.984375 -0.53125 -2.203125q0 -1.21875 0.53125 -2.203125q0.53125 -0.984375 1.46875 -1.5625q0.953125 -0.578125 2.1875 -0.578125q1.234375 0 2.171875 0.59375q0.953125 0.578125 1.484375 1.5625q0.53125 0.984375 0.53125 2.1875q0 1.21875 -0.53125 2.203125q-0.53125 0.984375 -1.484375 1.5625q-0.9375 0.5625 -2.171875 0.5625zm0 -1.21875q0.734375 0 1.375 -0.375q0.65625 -0.375 1.046875 -1.0625q0.40625 -0.703125 0.40625 -1.671875q0 -0.984375 -0.40625 -1.671875q-0.390625 -0.703125 -1.046875 -1.0625q-0.640625 -0.375 -1.375 -0.375q-0.734375 0 -1.390625 0.375q-0.65625 0.359375 -1.0625 1.0625q-0.390625 0.6875 -0.390625 1.671875q0 0.96875 0.390625 1.671875q0.40625 0.6875 1.0625 1.0625q0.65625 0.375 1.390625 0.375zm5.6260376 0.96875l0 -8.15625l1.28125 0l0 1.203125l0.078125 0q0.3125 -0.59375 1.03125 -1.03125q0.734375 -0.4375 1.609375 -0.4375q1.5 0 2.25 0.875q0.765625 0.875 0.765625 2.3125l0 5.234375l-1.359375 0l0 -5.03125q0 -1.171875 -0.578125 -1.65625q-0.5625 -0.5 -1.453125 -0.5q-0.671875 0 -1.1875 0.375q-0.515625 0.375 -0.796875 0.96875q-0.28125 0.59375 -0.28125 1.25l0 4.59375l-1.359375 0zm8.013519 -8.15625l4.78125 0l0 1.234375l-4.78125 0l0 -1.234375zm1.421875 6.015625l0 -8.328125l1.359375 0l0 7.984375q0 0.640625 0.265625 1.0q0.265625 0.34375 0.875 0.34375q0.265625 0 0.484375 -0.078125q0.234375 -0.078125 0.40625 -0.1875l0 1.328125q-0.203125 0.09375 -0.453125 0.140625q-0.25 0.0625 -0.671875 0.0625q-1.015625 0 -1.640625 -0.59375q-0.625 -0.609375 -0.625 -1.671875zm4.9806213 2.140625l0 -8.15625l1.28125 0l0 1.3125l0.078125 0q0.15625 -0.46875 0.53125 -0.8125q0.375 -0.34375 0.859375 -0.546875q0.484375 -0.203125 0.96875 -0.203125q0.375 0 0.578125 0.046875q0.203125 0.046875 0.390625 0.125l0 1.46875q-0.265625 -0.125 -0.5625 -0.1875q-0.296875 -0.078125 -0.59375 -0.078125q-0.59375 0 -1.09375 0.34375q-0.5 0.328125 -0.796875 0.890625q-0.28125 0.5625 -0.28125 1.234375l0 4.5625l-1.359375 0zm9.27002 0.25q-1.234375 0 -2.1875 -0.5625q-0.9375 -0.578125 -1.46875 -1.5625q-0.53125 -0.984375 -0.53125 -2.203125q0 -1.21875 0.53125 -2.203125q0.53125 -0.984375 1.46875 -1.5625q0.953125 -0.578125 2.1875 -0.578125q1.234375 0 2.171875 0.59375q0.953125 0.578125 1.484375 1.5625q0.53125 0.984375 0.53125 2.1875q0 1.21875 -0.53125 2.203125q-0.53125 0.984375 -1.484375 1.5625q-0.9375 0.5625 -2.171875 0.5625zm0 -1.21875q0.734375 0 1.375 -0.375q0.65625 -0.375 1.046875 -1.0625q0.40625 -0.703125 0.40625 -1.671875q0 -0.984375 -0.40625 -1.671875q-0.390625 -0.703125 -1.046875 -1.0625q-0.640625 -0.375 -1.375 -0.375q-0.734375 0 -1.390625 0.375q-0.65625 0.359375 -1.0625 1.0625q-0.390625 0.6875 -0.390625 1.671875q0 0.96875 0.390625 1.671875q0.40625 0.6875 1.0625 1.0625q0.65625 0.375 1.390625 0.375zm5.706024 0.96875l0 -11.453125l1.359375 0l0 11.453125l-1.359375 0zm3.376007 0l0 -11.453125l1.359375 0l0 11.453125l-1.359375 0zm6.9210205 0.25q-1.1875 0 -2.109375 -0.546875q-0.921875 -0.5625 -1.4375 -1.53125q-0.515625 -0.984375 -0.515625 -2.234375q0 -1.171875 0.484375 -2.15625q0.484375 -1.0 1.375 -1.59375q0.890625 -0.609375 2.09375 -0.609375q1.21875 0 2.078125 0.546875q0.875 0.53125 1.34375 1.484375q0.484375 0.9375 0.484375 2.15625q0 0.109375 -0.015625 0.21875q0 0.109375 -0.015625 0.1875l-7.03125 0l0 -1.109375l5.609375 0q-0.015625 -0.34375 -0.15625 -0.734375q-0.125 -0.390625 -0.421875 -0.734375q-0.296875 -0.34375 -0.75 -0.5625q-0.453125 -0.21875 -1.125 -0.21875q-0.796875 0 -1.390625 0.40625q-0.578125 0.40625 -0.890625 1.125q-0.3125 0.703125 -0.3125 1.59375q0 1.03125 0.390625 1.734375q0.40625 0.6875 1.03125 1.03125q0.640625 0.328125 1.328125 0.328125q0.890625 0 1.46875 -0.421875q0.59375 -0.4375 0.953125 -1.0625l1.140625 0.5625q-0.46875 0.9375 -1.375 1.546875q-0.890625 0.59375 -2.234375 0.59375zm5.3829956 -0.25l0 -8.15625l1.28125 0l0 1.3125l0.078125 0q0.15625 -0.46875 0.53125 -0.8125q0.375 -0.34375 0.859375 -0.546875q0.484375 -0.203125 0.96875 -0.203125q0.375 0 0.578125 0.046875q0.203125 0.046875 0.390625 0.125l0 1.46875q-0.265625 -0.125 -0.5625 -0.1875q-0.296875 -0.078125 -0.59375 -0.078125q-0.59375 0 -1.09375 0.34375q-0.5 0.328125 -0.796875 0.890625q-0.28125 0.5625 -0.28125 1.234375l0 4.5625l-1.359375 0z" fill-rule="nonzero"/></g><g filter="url(#shadowFilter-p.9)"><use xlink:href="#p.9" transform="matrix(1.0 0.0 0.0 1.0 0.0 2.0)"/></g><defs><filter id="shadowFilter-p.9" filterUnits="userSpaceOnUse"><feGaussianBlur in="SourceAlpha" stdDeviation="2.0" result="blur"/><feComponentTransfer in="blur" color-interpolation-filters="sRGB"><feFuncR type="linear" slope="0" intercept="0.0"/><feFuncG type="linear" slope="0" intercept="0.0"/><feFuncB type="linear" slope="0" intercept="0.0"/><feFuncA type="linear" slope="0.5" intercept="0"/></feComponentTransfer></filter></defs><g id="p.9"><path fill="#1155cc" d="m277.77325 544.50085l0 0c0 -5.2562866 4.261017 -9.517273 9.517242 -9.517273l235.35922 0c2.524109 0 4.9448853 1.0026855 6.7296753 2.7875366c1.7848511 1.7848511 2.7875366 4.2055664 2.7875366 6.7297363l0 38.06781c0 5.2562256 -4.2609863 9.517273 -9.517212 9.517273l-235.35922 0c-5.2562256 0 -9.517242 -4.2610474 -9.517242 -9.517273z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m277.77325 544.50085l0 0c0 -5.2562866 4.261017 -9.517273 9.517242 -9.517273l235.35922 0c2.524109 0 4.9448853 1.0026855 6.7296753 2.7875366c1.7848511 1.7848511 2.7875366 4.2055664 2.7875366 6.7297363l0 38.06781c0 5.2562256 -4.2609863 9.517273 -9.517212 9.517273l-235.35922 0c-5.2562256 0 -9.517242 -4.2610474 -9.517242 -9.517273z" fill-rule="evenodd"/><path fill="#000000" d="m348.32324 569.3948l-4.0625 -11.453125l1.515625 0l2.828125 8.296875l0.375 1.140625l0.078125 0l0.390625 -1.140625l2.96875 -8.296875l1.5 0l-4.1875 11.453125l-1.40625 0zm6.635376 0l0 -8.15625l1.359375 0l0 8.15625l-1.359375 0zm0.671875 -9.65625q-0.40625 0 -0.703125 -0.28125q-0.28125 -0.296875 -0.28125 -0.703125q0 -0.421875 0.28125 -0.6875q0.296875 -0.28125 0.703125 -0.28125q0.40625 0 0.6875 0.28125q0.28125 0.265625 0.28125 0.6875q0 0.40625 -0.28125 0.703125q-0.28125 0.28125 -0.6875 0.28125zm2.8191528 9.65625l0 -8.15625l1.28125 0l0 1.296875l0.078125 0q0.203125 -0.5 0.578125 -0.828125q0.375 -0.34375 0.875 -0.515625q0.515625 -0.1875 1.03125 -0.1875q0.234375 0 0.34375 0.015625q0.125 0 0.234375 0.03125l0 1.40625q-0.15625 -0.03125 -0.34375 -0.046875q-0.171875 -0.03125 -0.390625 -0.03125q-0.6875 0 -1.21875 0.3125q-0.53125 0.3125 -0.828125 0.875q-0.28125 0.5625 -0.28125 1.296875l0 4.53125l-1.359375 0zm5.5 -8.15625l4.78125 0l0 1.234375l-4.78125 0l0 -1.234375zm1.421875 6.015625l0 -8.328125l1.359375 0l0 7.984375q0 0.640625 0.265625 1.0q0.265625 0.34375 0.875 0.34375q0.265625 0 0.484375 -0.078125q0.234375 -0.078125 0.40625 -0.1875l0 1.328125q-0.203125 0.09375 -0.453125 0.140625q-0.25 0.0625 -0.671875 0.0625q-1.015625 0 -1.640625 -0.59375q-0.625 -0.609375 -0.625 -1.671875zm7.9512634 2.390625q-1.5 0 -2.265625 -0.875q-0.765625 -0.875 -0.765625 -2.40625l0 -5.125l1.359375 0l0 4.921875q0 1.21875 0.5625 1.75q0.5625 0.515625 1.390625 0.515625q0.71875 0 1.25 -0.375q0.53125 -0.390625 0.8125 -0.96875q0.296875 -0.59375 0.296875 -1.234375l0 -4.609375l1.359375 0l0 8.15625l-1.296875 0l0 -1.1875l-0.0625 0q-0.203125 0.390625 -0.625 0.71875q-0.40625 0.328125 -0.921875 0.515625q-0.515625 0.203125 -1.09375 0.203125zm8.536652 0q-0.90625 0 -1.59375 -0.34375q-0.6875 -0.359375 -1.078125 -0.96875q-0.390625 -0.625 -0.390625 -1.40625q0 -0.890625 0.453125 -1.5q0.46875 -0.625 1.25 -0.9375q0.796875 -0.3125 1.734375 -0.3125q0.546875 0 1.0 0.09375q0.46875 0.078125 0.8125 0.203125q0.34375 0.125 0.515625 0.234375l0 -0.5q0 -0.921875 -0.65625 -1.46875q-0.640625 -0.546875 -1.59375 -0.546875q-0.671875 0 -1.265625 0.296875q-0.578125 0.296875 -0.90625 0.828125l-1.03125 -0.765625q0.328125 -0.484375 0.796875 -0.828125q0.484375 -0.359375 1.09375 -0.546875q0.625 -0.203125 1.3125 -0.203125q1.671875 0 2.609375 0.890625q0.9375 0.875 0.9375 2.359375l0 5.171875l-1.296875 0l0 -1.171875l-0.0625 0q-0.203125 0.359375 -0.59375 0.6875q-0.375 0.328125 -0.90625 0.53125q-0.515625 0.203125 -1.140625 0.203125zm0.140625 -1.1875q0.703125 0 1.28125 -0.34375q0.578125 -0.359375 0.921875 -0.953125q0.359375 -0.59375 0.359375 -1.296875q-0.359375 -0.265625 -0.921875 -0.421875q-0.546875 -0.15625 -1.203125 -0.15625q-1.15625 0 -1.703125 0.484375q-0.546875 0.46875 -0.546875 1.171875q0 0.671875 0.5 1.09375q0.515625 0.421875 1.3125 0.421875zm5.761627 0.9375l0 -11.453125l1.359375 0l0 11.453125l-1.359375 0zm7.3536377 0l0 -11.453125l1.359375 0l0 10.15625l5.0 0l0 1.296875l-6.359375 0zm8.003387 0l0 -8.15625l1.359375 0l0 8.15625l-1.359375 0zm0.671875 -9.65625q-0.40625 0 -0.703125 -0.28125q-0.28125 -0.296875 -0.28125 -0.703125q0 -0.421875 0.28125 -0.6875q0.296875 -0.28125 0.703125 -0.28125q0.40625 0 0.6875 0.28125q0.28125 0.265625 0.28125 0.6875q0 0.40625 -0.28125 0.703125q-0.28125 0.28125 -0.6875 0.28125zm2.8191528 9.65625l0 -8.15625l1.28125 0l0 1.203125l0.078125 0q0.3125 -0.59375 1.03125 -1.03125q0.734375 -0.4375 1.609375 -0.4375q1.5 0 2.25 0.875q0.765625 0.875 0.765625 2.3125l0 5.234375l-1.359375 0l0 -5.03125q0 -1.171875 -0.578125 -1.65625q-0.5625 -0.5 -1.453125 -0.5q-0.671875 0 -1.1875 0.375q-0.515625 0.375 -0.796875 0.96875q-0.28125 0.59375 -0.28125 1.25l0 4.59375l-1.359375 0zm8.976013 0l0 -11.453125l1.359375 0l0 11.453125l-1.359375 0zm0.5 -1.65625l0 -1.75l4.6875 -4.75l1.734375 0l0 0.0625l-6.421875 6.4375zm4.890625 1.65625l-2.953125 -4.390625l0.96875 -0.9375l3.609375 5.265625l0 0.0625l-1.625 0zm6.6670227 0l0 -11.453125l1.359375 0l0 10.15625l5.0 0l0 1.296875l-6.359375 0zm10.472137 0.25q-0.90625 0 -1.59375 -0.34375q-0.6875 -0.359375 -1.078125 -0.96875q-0.390625 -0.625 -0.390625 -1.40625q0 -0.890625 0.453125 -1.5q0.46875 -0.625 1.25 -0.9375q0.796875 -0.3125 1.734375 -0.3125q0.546875 0 1.0 0.09375q0.46875 0.078125 0.8125 0.203125q0.34375 0.125 0.515625 0.234375l0 -0.5q0 -0.921875 -0.65625 -1.46875q-0.640625 -0.546875 -1.59375 -0.546875q-0.671875 0 -1.265625 0.296875q-0.578125 0.296875 -0.90625 0.828125l-1.03125 -0.765625q0.328125 -0.484375 0.796875 -0.828125q0.484375 -0.359375 1.09375 -0.546875q0.625 -0.203125 1.3125 -0.203125q1.671875 0 2.609375 0.890625q0.9375 0.875 0.9375 2.359375l0 5.171875l-1.296875 0l0 -1.171875l-0.0625 0q-0.203125 0.359375 -0.59375 0.6875q-0.375 0.328125 -0.90625 0.53125q-0.515625 0.203125 -1.140625 0.203125zm0.140625 -1.1875q0.703125 0 1.28125 -0.34375q0.578125 -0.359375 0.921875 -0.953125q0.359375 -0.59375 0.359375 -1.296875q-0.359375 -0.265625 -0.921875 -0.421875q-0.546875 -0.15625 -1.203125 -0.15625q-1.15625 0 -1.703125 0.484375q-0.546875 0.46875 -0.546875 1.171875q0 0.671875 0.5 1.09375q0.515625 0.421875 1.3125 0.421875zm7.9297485 3.984375q-0.046875 0.109375 -0.109375 0.234375q-0.0625 0.140625 -0.078125 0.171875l-1.40625 0q0.09375 -0.203125 0.203125 -0.453125q0.109375 -0.25 0.265625 -0.59375q0.09375 -0.21875 0.171875 -0.390625q0.09375 -0.171875 0.1875 -0.390625q0.109375 -0.21875 0.25 -0.53125l1.125 -2.4375l0.296875 -0.75l2.46875 -6.0625l1.46875 0l-4.21875 9.734375q-0.0625 0.15625 -0.203125 0.46875q-0.140625 0.3125 -0.265625 0.59375q-0.109375 0.296875 -0.15625 0.40625zm0.296875 -3.390625l-3.453125 -7.8125l1.46875 0l2.5625 6.0625l0.140625 0l-0.71875 1.75zm9.048004 0.59375q-1.1875 0 -2.109375 -0.546875q-0.921875 -0.5625 -1.4375 -1.53125q-0.515625 -0.984375 -0.515625 -2.234375q0 -1.171875 0.484375 -2.15625q0.484375 -1.0 1.375 -1.59375q0.890625 -0.609375 2.09375 -0.609375q1.21875 0 2.078125 0.546875q0.875 0.53125 1.34375 1.484375q0.484375 0.9375 0.484375 2.15625q0 0.109375 -0.015625 0.21875q0 0.109375 -0.015625 0.1875l-7.03125 0l0 -1.109375l5.609375 0q-0.015625 -0.34375 -0.15625 -0.734375q-0.125 -0.390625 -0.421875 -0.734375q-0.296875 -0.34375 -0.75 -0.5625q-0.453125 -0.21875 -1.125 -0.21875q-0.796875 0 -1.390625 0.40625q-0.578125 0.40625 -0.890625 1.125q-0.3125 0.703125 -0.3125 1.59375q0 1.03125 0.390625 1.734375q0.40625 0.6875 1.03125 1.03125q0.640625 0.328125 1.328125 0.328125q0.890625 0 1.46875 -0.421875q0.59375 -0.4375 0.953125 -1.0625l1.140625 0.5625q-0.46875 0.9375 -1.375 1.546875q-0.890625 0.59375 -2.234375 0.59375zm5.383026 -0.25l0 -8.15625l1.28125 0l0 1.3125l0.078125 0q0.15625 -0.46875 0.53125 -0.8125q0.375 -0.34375 0.859375 -0.546875q0.484375 -0.203125 0.96875 -0.203125q0.375 0 0.578125 0.046875q0.203125 0.046875 0.390625 0.125l0 1.46875q-0.265625 -0.125 -0.5625 -0.1875q-0.296875 -0.078125 -0.59375 -0.078125q-0.59375 0 -1.09375 0.34375q-0.5 0.328125 -0.796875 0.890625q-0.28125 0.5625 -0.28125 1.234375l0 4.5625l-1.359375 0z" fill-rule="nonzero"/></g><path fill="#a2c4c9" d="m462.61346 235.04298l0 0c0 -4.8590393 3.9390564 -8.798065 8.798096 -8.798065l43.947144 0c2.333374 0 4.571228 0.92692566 6.2211914 2.576889c1.6499634 1.6499634 2.5769043 3.8877869 2.5769043 6.221176l0 35.19124c0 4.85907 -3.9390259 8.798096 -8.798096 8.798096l-43.947144 0c-4.8590393 0 -8.798096 -3.9390259 -8.798096 -8.798096z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m462.61346 235.04298l0 0c0 -4.8590393 3.9390564 -8.798065 8.798096 -8.798065l43.947144 0c2.333374 0 4.571228 0.92692566 6.2211914 2.576889c1.6499634 1.6499634 2.5769043 3.8877869 2.5769043 6.221176l0 35.19124c0 4.85907 -3.9390259 8.798096 -8.798096 8.798096l-43.947144 0c-4.8590393 0 -8.798096 -3.9390259 -8.798096 -8.798096z" fill-rule="evenodd"/><path fill="#000000" d="m490.619 257.23672q-0.3125 0 -0.546875 -0.21875q-0.21875 -0.234375 -0.21875 -0.5625q0 -0.3125 0.21875 -0.53123474q0.234375 -0.21875 0.546875 -0.21875q0.328125 0 0.546875 0.21875q0.234375 0.21873474 0.234375 0.53123474q0 0.328125 -0.234375 0.5625q-0.21875 0.21875 -0.546875 0.21875zm2.765625 0q-0.3125 0 -0.546875 -0.21875q-0.21875 -0.234375 -0.21875 -0.5625q0 -0.3125 0.21875 -0.53123474q0.234375 -0.21875 0.546875 -0.21875q0.328125 0 0.546875 0.21875q0.234375 0.21873474 0.234375 0.53123474q0 0.328125 -0.234375 0.5625q-0.21875 0.21875 -0.546875 0.21875zm2.75 0q-0.3125 0 -0.546875 -0.21875q-0.21875 -0.234375 -0.21875 -0.5625q0 -0.3125 0.21875 -0.53123474q0.234375 -0.21875 0.546875 -0.21875q0.328125 0 0.546875 0.21875q0.234375 0.21873474 0.234375 0.53123474q0 0.328125 -0.234375 0.5625q-0.21875 0.21875 -0.546875 0.21875z" fill-rule="nonzero"/><path fill="#a2c4c9" d="m446.68536 122.657425l0 0c0 -4.68219 3.7956848 -8.4778595 8.477875 -8.4778595l57.060028 0c2.2484741 0 4.404846 0.89320374 5.994751 2.4831085c1.5899048 1.5899048 2.4830933 3.7462845 2.4830933 5.994751l0 33.910416c0 4.682205 -3.7956543 8.4778595 -8.477844 8.4778595l-57.060028 0c-4.68219 0 -8.477875 -3.7956543 -8.477875 -8.4778595z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m446.68536 122.657425l0 0c0 -4.68219 3.7956848 -8.4778595 8.477875 -8.4778595l57.060028 0c2.2484741 0 4.404846 0.89320374 5.994751 2.4831085c1.5899048 1.5899048 2.4830933 3.7462845 2.4830933 5.994751l0 33.910416c0 4.682205 -3.7956543 8.4778595 -8.477844 8.4778595l-57.060028 0c-4.68219 0 -8.477875 -3.7956543 -8.477875 -8.4778595z" fill-rule="evenodd"/><path fill="#000000" d="m480.01547 145.56639q-0.4375 0 -0.734375 -0.296875q-0.296875 -0.296875 -0.296875 -0.71875q0 -0.421875 0.296875 -0.71875q0.296875 -0.296875 0.734375 -0.296875q0.4375 0 0.71875 0.296875q0.296875 0.296875 0.296875 0.71875q0 0.421875 -0.296875 0.71875q-0.28125 0.296875 -0.71875 0.296875zm3.6875 0q-0.4375 0 -0.734375 -0.296875q-0.296875 -0.296875 -0.296875 -0.71875q0 -0.421875 0.296875 -0.71875q0.296875 -0.296875 0.734375 -0.296875q0.4375 0 0.71875 0.296875q0.296875 0.296875 0.296875 0.71875q0 0.421875 -0.296875 0.71875q-0.28125 0.296875 -0.71875 0.296875zm3.671875 0q-0.4375 0 -0.734375 -0.296875q-0.296875 -0.296875 -0.296875 -0.71875q0 -0.421875 0.296875 -0.71875q0.296875 -0.296875 0.734375 -0.296875q0.4375 0 0.71875 0.296875q0.296875 0.296875 0.296875 0.71875q0 0.421875 -0.296875 0.71875q-0.28125 0.296875 -0.71875 0.296875z" fill-rule="nonzero"/><path fill="#000000" fill-opacity="0.0" d="m268.4268 284.34842l0 23.811005" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m268.4268 284.34842l0 23.811005" fill-rule="evenodd"/><g filter="url(#shadowFilter-p.10)"><use xlink:href="#p.10" transform="matrix(1.0 0.0 0.0 1.0 0.0 2.0)"/></g><defs><filter id="shadowFilter-p.10" filterUnits="userSpaceOnUse"><feGaussianBlur in="SourceAlpha" stdDeviation="2.0" result="blur"/><feComponentTransfer in="blur" color-interpolation-filters="sRGB"><feFuncR type="linear" slope="0" intercept="0.0"/><feFuncG type="linear" slope="0" intercept="0.0"/><feFuncB type="linear" slope="0" intercept="0.0"/><feFuncA type="linear" slope="0.5" intercept="0"/></feComponentTransfer></filter></defs><g id="p.10"><path fill="#3c78d8" d="m4.8992295 393.27774l0 0c0 -5.256256 4.2610183 -9.517273 9.51725 -9.517273l508.0206 0c2.52417 0 4.9448853 1.0027161 6.7297363 2.7875366c1.7848511 1.7848511 2.7875366 4.205597 2.7875366 6.7297363l0 38.06784c0 5.2562256 -4.2609863 9.517273 -9.517273 9.517273l-508.0206 0c-5.2562323 0 -9.51725 -4.2610474 -9.51725 -9.517273z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m4.8992295 393.27774l0 0c0 -5.256256 4.2610183 -9.517273 9.51725 -9.517273l508.0206 0c2.52417 0 4.9448853 1.0027161 6.7297363 2.7875366c1.7848511 1.7848511 2.7875366 4.205597 2.7875366 6.7297363l0 38.06784c0 5.2562256 -4.2609863 9.517273 -9.517273 9.517273l-508.0206 0c-5.2562323 0 -9.51725 -4.2610474 -9.51725 -9.517273z" fill-rule="evenodd"/><path fill="#000000" d="m220.21194 418.17166l0 -11.453125l1.359375 0l0 11.453125l-1.359375 0zm0.71875 -5.21875l0 -1.296875l6.84375 0l0 1.296875l-6.84375 0zm6.53125 5.21875l0 -11.453125l1.359375 0l0 11.453125l-1.359375 0zm9.133026 0.25q-1.265625 0 -2.34375 -0.453125q-1.078125 -0.453125 -1.890625 -1.25q-0.8125 -0.8125 -1.265625 -1.90625q-0.4375 -1.109375 -0.4375 -2.375q0 -1.28125 0.4375 -2.359375q0.453125 -1.09375 1.265625 -1.890625q0.8125 -0.8125 1.890625 -1.265625q1.078125 -0.46875 2.34375 -0.46875q0.875 0 1.640625 0.234375q0.765625 0.21875 1.40625 0.640625q0.640625 0.40625 1.140625 1.0l-0.96875 0.953125q-0.4375 -0.53125 -0.921875 -0.859375q-0.484375 -0.34375 -1.0625 -0.5q-0.5625 -0.171875 -1.234375 -0.171875q-1.234375 0 -2.28125 0.578125q-1.03125 0.578125 -1.65625 1.625q-0.625 1.046875 -0.625 2.484375q0 1.4375 0.625 2.5q0.625 1.046875 1.65625 1.625q1.046875 0.5625 2.28125 0.5625q0.75 0 1.375 -0.203125q0.640625 -0.203125 1.171875 -0.578125q0.546875 -0.390625 0.984375 -0.921875l1.0 0.953125q-0.5 0.59375 -1.203125 1.0625q-0.6875 0.46875 -1.53125 0.734375q-0.84375 0.25 -1.796875 0.25zm6.481018 -0.25l0 -11.453125l1.359375 0l0 11.453125l-1.359375 0zm9.33577 0l0 -10.640625l1.359375 0l0 10.640625l-1.359375 0zm-3.203125 -10.15625l0 -1.296875l7.7656097 0l0 1.296875l-7.7656097 0zm8.241745 10.15625l0 -8.15625l1.28125 0l0 1.3125l0.078125 0q0.15625 -0.46875 0.53125 -0.8125q0.375 -0.34375 0.859375 -0.546875q0.484375 -0.203125 0.96875 -0.203125q0.375 0 0.578125 0.046875q0.203125 0.046875 0.390625 0.125l0 1.46875q-0.265625 -0.125 -0.5625 -0.1875q-0.296875 -0.078125 -0.59375 -0.078125q-0.59375 0 -1.09375 0.34375q-0.5 0.328125 -0.796875 0.890625q-0.28125 0.5625 -0.28125 1.234375l0 4.5625l-1.359375 0zm8.273773 0.25q-0.90625 0 -1.59375 -0.34375q-0.6875 -0.359375 -1.078125 -0.96875q-0.390625 -0.625 -0.390625 -1.40625q0 -0.890625 0.453125 -1.5q0.46875 -0.625 1.25 -0.9375q0.796875 -0.3125 1.734375 -0.3125q0.546875 0 1.0 0.09375q0.46875 0.078125 0.8125 0.203125q0.34375 0.125 0.515625 0.234375l0 -0.5q0 -0.921875 -0.65625 -1.46875q-0.640625 -0.546875 -1.59375 -0.546875q-0.671875 0 -1.265625 0.296875q-0.578125 0.296875 -0.90625 0.828125l-1.03125 -0.765625q0.328125 -0.484375 0.796875 -0.828125q0.484375 -0.359375 1.09375 -0.546875q0.625 -0.203125 1.3125 -0.203125q1.671875 0 2.609375 0.890625q0.9375 0.875 0.9375 2.359375l0 5.171875l-1.296875 0l0 -1.171875l-0.0625 0q-0.203125 0.359375 -0.59375 0.6875q-0.375 0.328125 -0.90625 0.53125q-0.515625 0.203125 -1.140625 0.203125zm0.140625 -1.1875q0.703125 0 1.28125 -0.34375q0.578125 -0.359375 0.921875 -0.953125q0.359375 -0.59375 0.359375 -1.296875q-0.359375 -0.265625 -0.921875 -0.421875q-0.546875 -0.15625 -1.203125 -0.15625q-1.15625 0 -1.703125 0.484375q-0.546875 0.46875 -0.546875 1.171875q0 0.671875 0.5 1.09375q0.515625 0.421875 1.3125 0.421875zm5.7616577 0.9375l0 -8.15625l1.28125 0l0 1.203125l0.078125 0q0.3125 -0.59375 1.03125 -1.03125q0.734375 -0.4375 1.609375 -0.4375q1.5 0 2.25 0.875q0.765625 0.875 0.765625 2.3125l0 5.234375l-1.359375 0l0 -5.03125q0 -1.171875 -0.578125 -1.65625q-0.5625 -0.5 -1.453125 -0.5q-0.671875 0 -1.1875 0.375q-0.515625 0.375 -0.796875 0.96875q-0.28125 0.59375 -0.28125 1.25l0 4.59375l-1.359375 0zm11.739746 0.25q-0.921875 0 -1.625 -0.296875q-0.6875 -0.296875 -1.140625 -0.796875q-0.453125 -0.5 -0.671875 -1.09375l1.203125 -0.546875q0.328125 0.734375 0.9375 1.140625q0.609375 0.40625 1.390625 0.40625q0.75 0 1.25 -0.296875q0.515625 -0.3125 0.515625 -0.90625q0 -0.375 -0.21875 -0.625q-0.203125 -0.25 -0.609375 -0.421875q-0.390625 -0.171875 -0.96875 -0.3125l-1.0 -0.265625q-0.5625 -0.15625 -1.078125 -0.4375q-0.515625 -0.296875 -0.828125 -0.75q-0.3125 -0.453125 -0.3125 -1.109375q0 -0.734375 0.421875 -1.265625q0.4375 -0.53125 1.140625 -0.8125q0.703125 -0.28125 1.515625 -0.28125q0.703125 0 1.3125 0.203125q0.625 0.203125 1.078125 0.59375q0.46875 0.390625 0.703125 0.96875l-1.171875 0.546875q-0.3125 -0.609375 -0.828125 -0.84375q-0.5 -0.25 -1.125 -0.25q-0.671875 0 -1.171875 0.296875q-0.5 0.296875 -0.5 0.8125q0 0.515625 0.40625 0.765625q0.40625 0.25 1.0 0.421875l1.1875 0.296875q1.203125 0.3125 1.8125 0.90625q0.609375 0.59375 0.609375 1.46875q0 0.765625 -0.4375 1.328125q-0.4375 0.546875 -1.171875 0.859375q-0.734375 0.296875 -1.625 0.296875zm4.6442566 3.203125l0 -11.609375l1.28125 0l0 1.21875l0.078125 0q0.21875 -0.390625 0.625 -0.71875q0.40625 -0.34375 0.953125 -0.546875q0.546875 -0.21875 1.203125 -0.21875q1.109375 0 1.984375 0.5625q0.890625 0.5625 1.40625 1.546875q0.515625 0.96875 0.515625 2.234375q0 1.265625 -0.515625 2.25q-0.515625 0.96875 -1.40625 1.53125q-0.875 0.546875 -1.984375 0.546875q-0.984375 0 -1.71875 -0.4375q-0.734375 -0.453125 -1.0625 -1.015625l-0.078125 0l0.078125 1.125l0 3.53125l-1.359375 0zm4.0 -4.421875q0.703125 0 1.3125 -0.375q0.609375 -0.390625 0.984375 -1.09375q0.390625 -0.703125 0.390625 -1.640625q0 -0.96875 -0.390625 -1.65625q-0.375 -0.703125 -0.984375 -1.078125q-0.609375 -0.375 -1.3125 -0.375q-0.71875 0 -1.328125 0.375q-0.609375 0.375 -1.0 1.078125q-0.390625 0.6875 -0.390625 1.65625q0 0.953125 0.390625 1.65625q0.390625 0.6875 1.0 1.078125q0.609375 0.375 1.328125 0.375zm9.382019 1.21875q-1.234375 0 -2.1875 -0.5625q-0.9375 -0.578125 -1.46875 -1.5625q-0.53125 -0.984375 -0.53125 -2.203125q0 -1.21875 0.53125 -2.203125q0.53125 -0.984375 1.46875 -1.5625q0.953125 -0.578125 2.1875 -0.578125q1.234375 0 2.171875 0.59375q0.953125 0.578125 1.484375 1.5625q0.53125 0.984375 0.53125 2.1875q0 1.21875 -0.53125 2.203125q-0.53125 0.984375 -1.484375 1.5625q-0.9375 0.5625 -2.171875 0.5625zm0 -1.21875q0.734375 0 1.375 -0.375q0.65625 -0.375 1.046875 -1.0625q0.40625 -0.703125 0.40625 -1.671875q0 -0.984375 -0.40625 -1.671875q-0.390625 -0.703125 -1.046875 -1.0625q-0.640625 -0.375 -1.375 -0.375q-0.734375 0 -1.390625 0.375q-0.65625 0.359375 -1.0625 1.0625q-0.390625 0.6875 -0.390625 1.671875q0 0.96875 0.390625 1.671875q0.40625 0.6875 1.0625 1.0625q0.65625 0.375 1.390625 0.375zm5.626007 0.96875l0 -8.15625l1.28125 0l0 1.296875l0.078125 0q0.203125 -0.5 0.578125 -0.828125q0.375 -0.34375 0.875 -0.515625q0.515625 -0.1875 1.03125 -0.1875q0.234375 0 0.34375 0.015625q0.125 0 0.234375 0.03125l0 1.40625q-0.15625 -0.03125 -0.34375 -0.046875q-0.171875 -0.03125 -0.390625 -0.03125q-0.6875 0 -1.21875 0.3125q-0.53125 0.3125 -0.828125 0.875q-0.28125 0.5625 -0.28125 1.296875l0 4.53125l-1.359375 0zm5.5 -8.15625l4.78125 0l0 1.234375l-4.78125 0l0 -1.234375zm1.421875 6.015625l0 -8.328125l1.359375 0l0 7.984375q0 0.640625 0.265625 1.0q0.265625 0.34375 0.875 0.34375q0.265625 0 0.484375 -0.078125q0.234375 -0.078125 0.40625 -0.1875l0 1.328125q-0.203125 0.09375 -0.453125 0.140625q-0.25 0.0625 -0.671875 0.0625q-1.015625 0 -1.640625 -0.59375q-0.625 -0.609375 -0.625 -1.671875z" fill-rule="nonzero"/></g><path fill="#000000" fill-opacity="0.0" d="m268.4268 365.25128l0 18.519684" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m268.4268 365.25128l0 18.519684" fill-rule="evenodd"/><path fill="#a4c2f4" d="m205.13545 82.27259l314.42523 0c3.2869873 0 6.439392 1.3057632 8.763672 3.6300278c2.3242188 2.3242722 3.630005 5.4766617 3.630005 8.763672l0 12.3937c0 0.0015640259 -0.0012817383 0.0028305054 -0.0028076172 0.0028305054l-339.20978 -0.0028305054l0 0c-0.0015563965 0 -0.002822876 -0.0012664795 -0.002822876 -0.002822876l0.002822876 -12.390877l0 0c0 -6.8448486 5.5488586 -12.3937 12.393707 -12.3937z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m205.13545 82.27259l314.42523 0c3.2869873 0 6.439392 1.3057632 8.763672 3.6300278c2.3242188 2.3242722 3.630005 5.4766617 3.630005 8.763672l0 12.3937c0 0.0015640259 -0.0012817383 0.0028305054 -0.0028076172 0.0028305054l-339.20978 -0.0028305054l0 0c-0.0015563965 0 -0.002822876 -0.0012664795 -0.002822876 -0.002822876l0.002822876 -12.390877l0 0c0 -6.8448486 5.5488586 -12.3937 12.393707 -12.3937z" fill-rule="evenodd"/><path fill="#000000" d="m339.0376 99.98258l0 -10.484375l3.96875 0q1.046875 0 1.59375 0.09375q0.765625 0.125 1.28125 0.484375q0.53125 0.359375 0.84375 1.015625q0.328125 0.65625 0.328125 1.4375q0 1.328125 -0.859375 2.265625q-0.84375 0.921875 -3.078125 0.921875l-2.6875 0l0 4.265625l-1.390625 0zm1.390625 -5.5l2.71875 0q1.34375 0 1.90625 -0.5q0.5625 -0.5 0.5625 -1.40625q0 -0.671875 -0.328125 -1.140625q-0.328125 -0.46875 -0.875 -0.609375q-0.359375 -0.09375 -1.296875 -0.09375l-2.6875 0l0 3.75zm8.213104 5.5l0 -7.59375l1.15625 0l0 1.140625q0.453125 -0.796875 0.828125 -1.046875q0.375 -0.265625 0.8125 -0.265625q0.65625 0 1.328125 0.40625l-0.4375 1.203125q-0.46875 -0.28125 -0.953125 -0.28125q-0.421875 0 -0.765625 0.25q-0.328125 0.25 -0.46875 0.703125q-0.21875 0.6875 -0.21875 1.5l0 3.984375l-1.28125 0zm4.4118958 -3.796875q0 -2.109375 1.171875 -3.125q0.984375 -0.84375 2.390625 -0.84375q1.578125 0 2.5625 1.03125q1.0 1.015625 1.0 2.828125q0 1.46875 -0.4375 2.3125q-0.4375 0.828125 -1.28125 1.296875q-0.84375 0.46875 -1.84375 0.46875q-1.59375 0 -2.578125 -1.015625q-0.984375 -1.03125 -0.984375 -2.953125zm1.328125 0q0 1.453125 0.625 2.1875q0.640625 0.71875 1.609375 0.71875q0.96875 0 1.59375 -0.71875q0.640625 -0.734375 0.640625 -2.234375q0 -1.40625 -0.640625 -2.125q-0.640625 -0.734375 -1.59375 -0.734375q-0.96875 0 -1.609375 0.71875q-0.625 0.71875 -0.625 2.1875zm7.619873 3.796875l0 -6.59375l-1.140625 0l0 -1.0l1.140625 0l0 -0.8125q0 -0.765625 0.125 -1.140625q0.1875 -0.5 0.65625 -0.8125q0.46875 -0.3125 1.3125 -0.3125q0.546875 0 1.203125 0.125l-0.1875 1.125q-0.40625 -0.0625 -0.765625 -0.0625q-0.578125 0 -0.828125 0.25q-0.234375 0.25 -0.234375 0.9375l0 0.703125l1.46875 0l0 1.0l-1.46875 0l0 6.59375l-1.28125 0zm3.7594604 -9.015625l0 -1.46875l1.296875 0l0 1.46875l-1.296875 0zm0 9.015625l0 -7.59375l1.296875 0l0 7.59375l-1.296875 0zm3.2249146 0l0 -10.484375l1.28125 0l0 10.484375l-1.28125 0zm8.490509 -2.453125l1.328125 0.171875q-0.3125 1.171875 -1.171875 1.8125q-0.84375 0.640625 -2.171875 0.640625q-1.671875 0 -2.65625 -1.015625q-0.96875 -1.03125 -0.96875 -2.890625q0 -1.921875 0.984375 -2.96875q1.0 -1.0625 2.578125 -1.0625q1.515625 0 2.484375 1.03125q0.96875 1.03125 0.96875 2.921875q0 0.109375 -0.015625 0.34375l-5.65625 0q0.0625 1.25 0.703125 1.921875q0.640625 0.65625 1.59375 0.65625q0.703125 0 1.203125 -0.359375q0.5 -0.375 0.796875 -1.203125zm-4.234375 -2.078125l4.25 0q-0.09375 -0.953125 -0.484375 -1.4375q-0.625 -0.75 -1.609375 -0.75q-0.875 0 -1.484375 0.59375q-0.609375 0.59375 -0.671875 1.59375zm6.666748 2.265625l1.265625 -0.203125q0.109375 0.765625 0.59375 1.171875q0.5 0.40625 1.375 0.40625q0.890625 0 1.3125 -0.359375q0.4375 -0.359375 0.4375 -0.84375q0 -0.4375 -0.375 -0.6875q-0.265625 -0.171875 -1.3125 -0.4375q-1.421875 -0.359375 -1.96875 -0.609375q-0.546875 -0.265625 -0.828125 -0.734375q-0.28125 -0.46875 -0.28125 -1.015625q0 -0.515625 0.21875 -0.9375q0.234375 -0.4375 0.640625 -0.734375q0.296875 -0.21875 0.8125 -0.359375q0.53125 -0.15625 1.125 -0.15625q0.890625 0 1.5625 0.265625q0.671875 0.25 1.0 0.6875q0.328125 0.4375 0.4375 1.171875l-1.25 0.171875q-0.09375 -0.578125 -0.5 -0.90625q-0.40625 -0.34375 -1.15625 -0.34375q-0.890625 0 -1.28125 0.296875q-0.375 0.296875 -0.375 0.6875q0 0.25 0.15625 0.453125q0.15625 0.203125 0.5 0.34375q0.1875 0.078125 1.140625 0.328125q1.359375 0.359375 1.890625 0.59375q0.546875 0.234375 0.859375 0.6875q0.3125 0.4375 0.3125 1.09375q0 0.640625 -0.375 1.21875q-0.375 0.5625 -1.09375 0.875q-0.703125 0.3125 -1.59375 0.3125q-1.484375 0 -2.265625 -0.609375q-0.765625 -0.625 -0.984375 -1.828125z" fill-rule="nonzero"/><path fill="#6d9eeb" d="m17.29293 195.78148l502.26773 0c3.2869873 0 6.439392 1.3057556 8.763672 3.6300201c2.3242188 2.3242798 3.630005 5.4766693 3.630005 8.763672l0 12.393707c0 0.0024261475 -0.001953125 0.0043945312 -0.0043945312 0.0043945312l-527.0507 -0.0043945312l0 0c-0.0024256706 0 -0.004392147 -0.0019683838 -0.004392147 -0.0043945312l0.004392147 -12.389313l0 0c0 -6.8448486 5.5488486 -12.393692 12.393702 -12.393692z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m17.29293 195.78148l502.26773 0c3.2869873 0 6.439392 1.3057556 8.763672 3.6300201c2.3242188 2.3242798 3.630005 5.4766693 3.630005 8.763672l0 12.393707c0 0.0024261475 -0.001953125 0.0043945312 -0.0043945312 0.0043945312l-527.0507 -0.0043945312l0 0c-0.0024256706 0 -0.004392147 -0.0019683838 -0.004392147 -0.0043945312l0.004392147 -12.389313l0 0c0 -6.8448486 5.5488486 -12.393692 12.393702 -12.393692z" fill-rule="evenodd"/><path fill="#000000" d="m239.0048 213.49147l0 -10.484375l3.96875 0q1.046875 0 1.59375 0.09375q0.765625 0.125 1.28125 0.484375q0.53125 0.359375 0.84375 1.015625q0.328125 0.65625 0.328125 1.4375q0 1.328125 -0.859375 2.265625q-0.84375 0.921875 -3.078125 0.921875l-2.6875 0l0 4.265625l-1.390625 0zm1.390625 -5.5l2.71875 0q1.34375 0 1.90625 -0.5q0.5625 -0.5 0.5625 -1.40625q0 -0.671875 -0.328125 -1.140625q-0.328125 -0.46875 -0.875 -0.609375q-0.359375 -0.09375 -1.296875 -0.09375l-2.6875 0l0 3.75zm8.213104 5.5l0 -7.59375l1.15625 0l0 1.140625q0.453125 -0.796875 0.828125 -1.046875q0.375 -0.265625 0.8125 -0.265625q0.65625 0 1.328125 0.40625l-0.4375 1.203125q-0.46875 -0.28125 -0.953125 -0.28125q-0.421875 0 -0.765625 0.25q-0.328125 0.25 -0.46875 0.703125q-0.21875 0.6875 -0.21875 1.5l0 3.984375l-1.28125 0zm4.4118958 -3.796875q0 -2.109375 1.171875 -3.125q0.984375 -0.84375 2.3906097 -0.84375q1.578125 0 2.5625 1.03125q1.0 1.015625 1.0 2.828125q0 1.46875 -0.4375 2.3125q-0.4375 0.828125 -1.28125 1.296875q-0.84375 0.46875 -1.84375 0.46875q-1.5937347 0 -2.5781097 -1.015625q-0.984375 -1.03125 -0.984375 -2.953125zm1.328125 0q0 1.453125 0.625 2.1875q0.640625 0.71875 1.6093597 0.71875q0.96875 0 1.59375 -0.71875q0.640625 -0.734375 0.640625 -2.234375q0 -1.40625 -0.640625 -2.125q-0.640625 -0.734375 -1.59375 -0.734375q-0.96873474 0 -1.6093597 0.71875q-0.625 0.71875 -0.625 2.1875zm10.119858 2.640625l0.1875 1.140625q-0.546875 0.109375 -0.984375 0.109375q-0.6875 0 -1.078125 -0.21875q-0.390625 -0.21875 -0.546875 -0.578125q-0.15625 -0.359375 -0.15625 -1.515625l0 -4.375l-0.953125 0l0 -1.0l0.953125 0l0 -1.890625l1.28125 -0.765625l0 2.65625l1.296875 0l0 1.0l-1.296875 0l0 4.4375q0 0.546875 0.0625 0.71875q0.078125 0.15625 0.21875 0.25q0.15625 0.078125 0.453125 0.078125q0.203125 0 0.5625 -0.046875zm0.77508545 -2.640625q0 -2.109375 1.171875 -3.125q0.984375 -0.84375 2.390625 -0.84375q1.578125 0 2.5625 1.03125q1.0 1.015625 1.0 2.828125q0 1.46875 -0.4375 2.3125q-0.4375 0.828125 -1.28125 1.296875q-0.84375 0.46875 -1.84375 0.46875q-1.59375 0 -2.578125 -1.015625q-0.984375 -1.03125 -0.984375 -2.953125zm1.328125 0q0 1.453125 0.625 2.1875q0.640625 0.71875 1.609375 0.71875q0.96875 0 1.59375 -0.71875q0.640625 -0.734375 0.640625 -2.234375q0 -1.40625 -0.640625 -2.125q-0.640625 -0.734375 -1.59375 -0.734375q-0.96875 0 -1.609375 0.71875q-0.625 0.71875 -0.625 2.1875zm12.260498 1.015625l1.265625 0.15625q-0.203125 1.3125 -1.0625 2.0625q-0.84375 0.734375 -2.09375 0.734375q-1.5625 0 -2.515625 -1.015625q-0.9375 -1.03125 -0.9375 -2.921875q0 -1.234375 0.40625 -2.15625q0.40625 -0.921875 1.234375 -1.375q0.84375 -0.46875 1.8125 -0.46875q1.25 0 2.03125 0.625q0.78125 0.625 1.015625 1.765625l-1.265625 0.203125q-0.171875 -0.765625 -0.625 -1.15625q-0.453125 -0.390625 -1.09375 -0.390625q-0.984375 0 -1.59375 0.703125q-0.609375 0.703125 -0.609375 2.203125q0 1.53125 0.578125 2.234375q0.59375 0.6875 1.546875 0.6875q0.75 0 1.265625 -0.453125q0.515625 -0.46875 0.640625 -1.4375zm1.890625 -1.015625q0 -2.109375 1.171875 -3.125q0.984375 -0.84375 2.390625 -0.84375q1.578125 0 2.5625 1.03125q1.0 1.015625 1.0 2.828125q0 1.46875 -0.4375 2.3125q-0.4375 0.828125 -1.28125 1.296875q-0.84375 0.46875 -1.84375 0.46875q-1.59375 0 -2.578125 -1.015625q-0.984375 -1.03125 -0.984375 -2.953125zm1.328125 0q0 1.453125 0.625 2.1875q0.640625 0.71875 1.609375 0.71875q0.96875 0 1.59375 -0.71875q0.640625 -0.734375 0.640625 -2.234375q0 -1.40625 -0.640625 -2.125q-0.640625 -0.734375 -1.59375 -0.734375q-0.96875 0 -1.609375 0.71875q-0.625 0.71875 -0.625 2.1875zm7.2760925 3.796875l0 -10.484375l1.28125 0l0 10.484375l-1.28125 0zm2.771759 -2.265625l1.265625 -0.203125q0.109375 0.765625 0.59375 1.171875q0.5 0.40625 1.375 0.40625q0.890625 0 1.3125 -0.359375q0.4375 -0.359375 0.4375 -0.84375q0 -0.4375 -0.375 -0.6875q-0.265625 -0.171875 -1.3125 -0.4375q-1.421875 -0.359375 -1.96875 -0.609375q-0.546875 -0.265625 -0.828125 -0.734375q-0.28125 -0.46875 -0.28125 -1.015625q0 -0.515625 0.21875 -0.9375q0.234375 -0.4375 0.640625 -0.734375q0.296875 -0.21875 0.8125 -0.359375q0.53125 -0.15625 1.125 -0.15625q0.890625 0 1.5625 0.265625q0.671875 0.25 1.0 0.6875q0.328125 0.4375 0.4375 1.171875l-1.25 0.171875q-0.09375 -0.578125 -0.5 -0.90625q-0.40625 -0.34375 -1.15625 -0.34375q-0.890625 0 -1.28125 0.296875q-0.375 0.296875 -0.375 0.6875q0 0.25 0.15625 0.453125q0.15625 0.203125 0.5 0.34375q0.1875 0.078125 1.140625 0.328125q1.359375 0.359375 1.890625 0.59375q0.546875 0.234375 0.859375 0.6875q0.3125 0.4375 0.3125 1.09375q0 0.640625 -0.375 1.21875q-0.375 0.5625 -1.09375 0.875q-0.703125 0.3125 -1.59375 0.3125q-1.484375 0 -2.265625 -0.609375q-0.765625 -0.625 -0.984375 -1.828125z" fill-rule="nonzero"/></g></svg> \ No newline at end of file
+<svg version="1.1" viewBox="0.0 0.0 539.0209973753281 600.7742782152231" fill="none" stroke="none" stroke-linecap="square" stroke-miterlimit="10" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg"><clipPath id="p.0"><path d="m0 0l539.021 0l0 600.7743l-539.021 0l0 -600.7743z" clip-rule="nonzero"/></clipPath><g clip-path="url(#p.0)"><path fill="#000000" fill-opacity="0.0" d="m0 0l539.021 0l0 600.7743l-539.021 0z" fill-rule="evenodd"/><path fill="#000000" fill-opacity="0.0" d="m362.34805 205.27522l0 -159.87402" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m362.34805 205.27522l0 -159.87402" fill-rule="evenodd"/><path fill="#000000" fill-opacity="0.0" d="m94.91498 205.27522l0 -159.87402" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m94.91498 205.27522l0 -159.87402" fill-rule="evenodd"/><path fill="#000000" fill-opacity="0.0" d="m131.88086 534.9836l0 -116.81891" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m131.88086 534.9836l0 -116.81891" fill-rule="evenodd"/><path fill="#000000" fill-opacity="0.0" d="m404.9701 534.9836l0 -124.62991" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m404.9701 534.9836l0 -124.62991" fill-rule="evenodd"/><g filter="url(#shadowFilter-p.1)"><use xlink:href="#p.1" transform="matrix(1.0 0.0 0.0 1.0 0.0 2.0)"/></g><defs><filter id="shadowFilter-p.1" filterUnits="userSpaceOnUse"><feGaussianBlur in="SourceAlpha" stdDeviation="2.0" result="blur"/><feComponentTransfer in="blur" color-interpolation-filters="sRGB"><feFuncR type="linear" slope="0" intercept="0.0"/><feFuncG type="linear" slope="0" intercept="0.0"/><feFuncB type="linear" slope="0" intercept="0.0"/><feFuncA type="linear" slope="0.5" intercept="0"/></feComponentTransfer></filter></defs><g id="p.1"><path fill="#a4c2f4" d="m4.8992295 210.33295l0 0c0 -8.175705 6.627728 -14.803436 14.803446 -14.803436l497.4482 0c3.9261475 0 7.6914673 1.5596466 10.467651 4.3358307c2.776184 2.776184 4.3358154 6.5414886 4.3358154 10.467606l0 59.212006c0 8.17572 -6.6277466 14.803467 -14.803467 14.803467l-497.4482 0c-8.175717 0 -14.803446 -6.6277466 -14.803446 -14.803467z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m4.8992295 210.33295l0 0c0 -8.175705 6.627728 -14.803436 14.803446 -14.803436l497.4482 0c3.9261475 0 7.6914673 1.5596466 10.467651 4.3358307c2.776184 2.776184 4.3358154 6.5414886 4.3358154 10.467606l0 59.212006c0 8.17572 -6.6277466 14.803467 -14.803467 14.803467l-497.4482 0c-8.175717 0 -14.803446 -6.6277466 -14.803446 -14.803467z" fill-rule="evenodd"/></g><g filter="url(#shadowFilter-p.2)"><use xlink:href="#p.2" transform="matrix(1.0 0.0 0.0 1.0 0.0 2.0)"/></g><defs><filter id="shadowFilter-p.2" filterUnits="userSpaceOnUse"><feGaussianBlur in="SourceAlpha" stdDeviation="2.0" result="blur"/><feComponentTransfer in="blur" color-interpolation-filters="sRGB"><feFuncR type="linear" slope="0" intercept="0.0"/><feFuncG type="linear" slope="0" intercept="0.0"/><feFuncB type="linear" slope="0" intercept="0.0"/><feFuncA type="linear" slope="0.5" intercept="0"/></feComponentTransfer></filter></defs><g id="p.2"><path fill="#b6d7a8" d="m4.8992295 13.393214l0 0c0 -5.2562323 4.2610183 -9.517251 9.51725 -9.517251l508.0206 0c2.52417 0 4.9448853 1.0027075 6.7297363 2.787538c1.7848511 1.7848306 2.7875366 4.205581 2.7875366 6.729713l0 38.06786c0 5.256233 -4.2609863 9.51725 -9.517273 9.51725l-508.0206 0c-5.2562323 0 -9.51725 -4.261017 -9.51725 -9.51725z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m4.8992295 13.393214l0 0c0 -5.2562323 4.2610183 -9.517251 9.51725 -9.517251l508.0206 0c2.52417 0 4.9448853 1.0027075 6.7297363 2.787538c1.7848511 1.7848306 2.7875366 4.205581 2.7875366 6.729713l0 38.06786c0 5.256233 -4.2609863 9.51725 -9.517273 9.51725l-508.0206 0c-5.2562323 0 -9.51725 -4.261017 -9.51725 -9.51725z" fill-rule="evenodd"/><path fill="#000000" d="m221.21878 39.34714l5.078125 -13.359375l1.78125 0l5.078125 13.359375l-1.734375 0l-3.671875 -9.984375l-0.53125 -1.4375l-0.0625 0l-0.53125 1.4375l-3.671875 9.984375l-1.734375 0zm5.78125 -3.671875l0 -1.5l3.078125 0l0.546875 1.5l-3.625 0zm-3.625 0l0.546875 -1.5l3.078125 0l0 1.5l-3.625 0zm11.327408 7.703125l0 -13.546875l1.515625 0l0 1.421875l0.078125 0q0.25 -0.453125 0.71875 -0.84375q0.484375 -0.390625 1.125 -0.625q0.640625 -0.25 1.390625 -0.25q1.3125 0 2.328125 0.65625q1.03125 0.65625 1.625 1.796875q0.609375 1.125 0.609375 2.609375q0 1.46875 -0.609375 2.609375q-0.59375 1.140625 -1.625 1.796875q-1.015625 0.640625 -2.328125 0.640625q-1.125 0 -1.984375 -0.515625q-0.859375 -0.53125 -1.25 -1.1875l-0.078125 0l0.078125 1.3125l0 4.125l-1.59375 0zm4.671875 -5.171875q0.8125 0 1.53125 -0.4375q0.71875 -0.4375 1.15625 -1.25q0.4375 -0.828125 0.4375 -1.921875q0 -1.125 -0.4375 -1.9375q-0.4375 -0.8125 -1.15625 -1.25q-0.71875 -0.4375 -1.53125 -0.4375q-0.828125 0 -1.546875 0.4375q-0.71875 0.4375 -1.171875 1.25q-0.4375 0.8125 -0.4375 1.9375q0 1.109375 0.4375 1.921875q0.453125 0.8125 1.171875 1.25q0.71875 0.4375 1.546875 0.4375zm6.372528 5.171875l0 -13.546875l1.515625 0l0 1.421875l0.078125 0q0.25 -0.453125 0.71875 -0.84375q0.484375 -0.390625 1.125 -0.625q0.640625 -0.25 1.390625 -0.25q1.3125 0 2.328125 0.65625q1.03125 0.65625 1.625 1.796875q0.609375 1.125 0.609375 2.609375q0 1.46875 -0.609375 2.609375q-0.59375 1.140625 -1.625 1.796875q-1.015625 0.640625 -2.328125 0.640625q-1.125 0 -1.984375 -0.515625q-0.859375 -0.53125 -1.25 -1.1875l-0.078125 0l0.078125 1.3125l0 4.125l-1.59375 0zm4.671875 -5.171875q0.8125 0 1.53125 -0.4375q0.71875 -0.4375 1.15625 -1.25q0.4375 -0.828125 0.4375 -1.921875q0 -1.125 -0.4375 -1.9375q-0.4375 -0.8125 -1.15625 -1.25q-0.71875 -0.4375 -1.53125 -0.4375q-0.828125 0 -1.546875 0.4375q-0.71875 0.4375 -1.171875 1.25q-0.4375 0.8125 -0.4375 1.9375q0 1.109375 0.4375 1.921875q0.453125 0.8125 1.171875 1.25q0.71875 0.4375 1.546875 0.4375zm6.372513 1.140625l0 -13.359375l1.59375 0l0 13.359375l-1.59375 0zm4.0927124 0l0 -9.515625l1.578125 0l0 9.515625l-1.578125 0zm0.78125 -11.265625q-0.46875 0 -0.8125 -0.328125q-0.328125 -0.34375 -0.328125 -0.8125q0 -0.484375 0.328125 -0.8125q0.34375 -0.328125 0.8125 -0.328125q0.484375 0 0.8125 0.328125q0.328125 0.328125 0.328125 0.8125q0 0.46875 -0.328125 0.8125q-0.328125 0.328125 -0.8125 0.328125zm7.497986 11.5625q-1.40625 0 -2.5 -0.65625q-1.078125 -0.671875 -1.703125 -1.8125q-0.609375 -1.15625 -0.609375 -2.578125q0 -1.46875 0.609375 -2.59375q0.625 -1.140625 1.703125 -1.796875q1.09375 -0.671875 2.5 -0.671875q1.609375 0 2.640625 0.734375q1.03125 0.734375 1.46875 1.890625l-1.4375 0.609375q-0.359375 -0.890625 -1.0625 -1.34375q-0.6875 -0.453125 -1.6875 -0.453125q-0.828125 0 -1.546875 0.453125q-0.71875 0.4375 -1.171875 1.25q-0.453125 0.8125 -0.453125 1.921875q0 1.078125 0.453125 1.90625q0.453125 0.8125 1.171875 1.265625q0.71875 0.4375 1.546875 0.4375q1.015625 0 1.734375 -0.46875q0.734375 -0.46875 1.09375 -1.3125l1.40625 0.59375q-0.46875 1.09375 -1.515625 1.859375q-1.03125 0.765625 -2.640625 0.765625zm8.827332 0q-1.0625 0 -1.875 -0.40625q-0.796875 -0.40625 -1.25 -1.125q-0.453125 -0.71875 -0.453125 -1.640625q0 -1.046875 0.53125 -1.765625q0.546875 -0.71875 1.453125 -1.078125q0.921875 -0.359375 2.015625 -0.359375q0.640625 0 1.171875 0.109375q0.546875 0.09375 0.9375 0.234375q0.40625 0.140625 0.625 0.265625l0 -0.578125q0 -1.078125 -0.765625 -1.703125q-0.765625 -0.640625 -1.875 -0.640625q-0.78125 0 -1.46875 0.34375q-0.671875 0.34375 -1.0625 0.953125l-1.203125 -0.890625q0.375 -0.5625 0.9375 -0.96875q0.5625 -0.40625 1.28125 -0.625q0.71875 -0.234375 1.515625 -0.234375q1.9375 0 3.03125 1.03125q1.109375 1.015625 1.109375 2.75l0 6.03125l-1.5 0l0 -1.359375l-0.078125 0q-0.25 0.40625 -0.703125 0.796875q-0.4375 0.375 -1.046875 0.609375q-0.609375 0.25 -1.328125 0.25zm0.140625 -1.390625q0.828125 0 1.5 -0.40625q0.6875 -0.421875 1.09375 -1.109375q0.421875 -0.6875 0.421875 -1.515625q-0.4375 -0.296875 -1.078125 -0.484375q-0.640625 -0.1875 -1.40625 -0.1875q-1.359375 0 -2.0 0.5625q-0.640625 0.5625 -0.640625 1.375q0 0.78125 0.59375 1.28125q0.609375 0.484375 1.515625 0.484375zm5.876068 -8.421875l5.578125 0l0 1.4375l-5.578125 0l0 -1.4375zm1.671875 7.015625l0 -9.703125l1.578125 0l0 9.3125q0 0.75 0.3125 1.15625q0.3125 0.40625 1.015625 0.40625q0.3125 0 0.578125 -0.09375q0.265625 -0.09375 0.46875 -0.21875l0 1.546875q-0.25 0.109375 -0.546875 0.171875q-0.28125 0.078125 -0.765625 0.078125q-1.1875 0 -1.921875 -0.703125q-0.71875 -0.703125 -0.71875 -1.953125zm6.0434875 2.5l0 -9.515625l1.578125 0l0 9.515625l-1.578125 0zm0.78125 -11.265625q-0.46875 0 -0.8125 -0.328125q-0.328125 -0.34375 -0.328125 -0.8125q0 -0.484375 0.328125 -0.8125q0.34375 -0.328125 0.8125 -0.328125q0.484375 0 0.8125 0.328125q0.328125 0.328125 0.328125 0.8125q0 0.46875 -0.328125 0.8125q-0.328125 0.328125 -0.8125 0.328125zm7.576111 11.5625q-1.4375 0 -2.546875 -0.671875q-1.09375 -0.671875 -1.71875 -1.8125q-0.625 -1.15625 -0.625 -2.5625q0 -1.421875 0.625 -2.5625q0.625 -1.15625 1.71875 -1.828125q1.109375 -0.671875 2.546875 -0.671875q1.4375 0 2.53125 0.6875q1.109375 0.671875 1.734375 1.828125q0.625 1.140625 0.625 2.546875q0 1.40625 -0.625 2.5625q-0.625 1.140625 -1.734375 1.8125q-1.09375 0.671875 -2.53125 0.671875zm0 -1.4375q0.859375 0 1.609375 -0.421875q0.75 -0.4375 1.21875 -1.25q0.46875 -0.8125 0.46875 -1.9375q0 -1.140625 -0.46875 -1.953125q-0.46875 -0.8125 -1.21875 -1.234375q-0.75 -0.4375 -1.609375 -0.4375q-0.859375 0 -1.625 0.4375q-0.765625 0.421875 -1.234375 1.234375q-0.46875 0.8125 -0.46875 1.953125q0 1.125 0.46875 1.9375q0.46875 0.8125 1.234375 1.25q0.765625 0.421875 1.625 0.421875zm6.5418396 1.140625l0 -9.515625l1.515625 0l0 1.40625l0.078125 0q0.375 -0.703125 1.21875 -1.203125q0.84375 -0.5 1.859375 -0.5q1.75 0 2.625 1.015625q0.890625 1.015625 0.890625 2.703125l0 6.09375l-1.578125 0l0 -5.859375q0 -1.375 -0.671875 -1.9375q-0.65625 -0.578125 -1.703125 -0.578125q-0.78125 0 -1.375 0.4375q-0.59375 0.4375 -0.9375 1.125q-0.328125 0.6875 -0.328125 1.453125l0 5.359375l-1.59375 0z" fill-rule="nonzero"/></g><g filter="url(#shadowFilter-p.3)"><use xlink:href="#p.3" transform="matrix(1.0 0.0 0.0 1.0 0.0 2.0)"/></g><defs><filter id="shadowFilter-p.3" filterUnits="userSpaceOnUse"><feGaussianBlur in="SourceAlpha" stdDeviation="2.0" result="blur"/><feComponentTransfer in="blur" color-interpolation-filters="sRGB"><feFuncR type="linear" slope="0" intercept="0.0"/><feFuncG type="linear" slope="0" intercept="0.0"/><feFuncB type="linear" slope="0" intercept="0.0"/><feFuncA type="linear" slope="0.5" intercept="0"/></feComponentTransfer></filter></defs><g id="p.3"><path fill="#c9daf8" d="m4.8992295 97.076035l0 0c0 -8.175713 6.627728 -14.803444 14.803446 -14.803444l147.81042 0c3.926117 0 7.691437 1.5596466 10.467621 4.3358307c2.776184 2.776184 4.3358307 6.5414963 4.3358307 10.467613l0 59.212006c0 8.17572 -6.6277313 14.803452 -14.803452 14.803452l-147.81042 0c-8.175717 0 -14.803446 -6.6277313 -14.803446 -14.803452z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m4.8992295 97.076035l0 0c0 -8.175713 6.627728 -14.803444 14.803446 -14.803444l147.81042 0c3.926117 0 7.691437 1.5596466 10.467621 4.3358307c2.776184 2.776184 4.3358307 6.5414963 4.3358307 10.467613l0 59.212006c0 8.17572 -6.6277313 14.803452 -14.803452 14.803452l-147.81042 0c-8.175717 0 -14.803446 -6.6277313 -14.803446 -14.803452z" fill-rule="evenodd"/><path fill="#000000" d="m66.37746 133.60204l0 -13.359367l4.015625 0q2.09375 0 3.609375 0.859375q1.515625 0.84375 2.328125 2.359375q0.828125 1.5 0.828125 3.46875q0 1.9531174 -0.828125 3.4531174q-0.8125 1.5 -2.328125 2.359375q-1.515625 0.859375 -3.609375 0.859375l-4.015625 0zm1.578125 -1.515625l2.4375 0q1.578125 0 2.734375 -0.59375q1.15625 -0.609375 1.78125 -1.765625q0.640625 -1.15625 0.640625 -2.7968674q0 -1.65625 -0.640625 -2.8125q-0.625 -1.15625 -1.78125 -1.75q-1.15625 -0.609375 -2.734375 -0.609375l-2.4375 0l0 10.328117zm15.163467 1.8125q-1.375 0 -2.453125 -0.640625q-1.0625 -0.65625 -1.671875 -1.796875q-0.609375 -1.140625 -0.609375 -2.59375q0 -1.3593674 0.5625 -2.5156174q0.578125 -1.15625 1.609375 -1.859375q1.03125 -0.703125 2.4375 -0.703125q1.421875 0 2.4375 0.625q1.015625 0.625 1.5625 1.734375q0.546875 1.09375 0.546875 2.5156174q0 0.125 -0.015625 0.265625q0 0.125 -0.015625 0.21875l-8.1875 0l0 -1.3124924l6.546875 0q-0.015625 -0.390625 -0.1875 -0.84375q-0.15625 -0.46875 -0.5 -0.859375q-0.34375 -0.40625 -0.875 -0.65625q-0.53125 -0.25 -1.3125 -0.25q-0.9375 0 -1.625 0.484375q-0.671875 0.46875 -1.046875 1.296875q-0.359375 0.8125 -0.359375 1.8593674q0 1.203125 0.46875 2.015625q0.46875 0.796875 1.203125 1.1875q0.75 0.390625 1.546875 0.390625q1.046875 0 1.71875 -0.484375q0.6875 -0.5 1.09375 -1.234375l1.34375 0.65625q-0.5625 1.078125 -1.609375 1.796875q-1.03125 0.703125 -2.609375 0.703125zm8.879303 -0.296875l-3.84375 -9.515617l1.703125 0l2.953125 7.6562424l0.03125 0l2.984375 -7.6562424l1.65625 0l-3.875 9.515617l-1.609375 0zm6.9486847 0l0 -9.515617l1.578125 0l0 9.515617l-1.578125 0zm0.78125 -11.265617q-0.46875 0 -0.8125 -0.328125q-0.328125 -0.34375 -0.328125 -0.8125q0 -0.484375 0.328125 -0.8125q0.34375 -0.328125 0.8125 -0.328125q0.484375 0 0.8125 0.328125q0.328125 0.328125 0.328125 0.8125q0 0.46875 -0.328125 0.8125q-0.328125 0.328125 -0.8125 0.328125zm7.4979706 11.562492q-1.40625 0 -2.5 -0.65625q-1.078125 -0.671875 -1.703125 -1.8125q-0.609375 -1.15625 -0.609375 -2.578125q0 -1.4687424 0.609375 -2.5937424q0.625 -1.140625 1.703125 -1.796875q1.09375 -0.671875 2.5 -0.671875q1.609375 0 2.640625 0.734375q1.03125 0.734375 1.46875 1.890625l-1.4375 0.609375q-0.359375 -0.890625 -1.0625 -1.34375q-0.6875 -0.453125 -1.6875 -0.453125q-0.828125 0 -1.546875 0.453125q-0.71875 0.4375 -1.171875 1.25q-0.453125 0.8125 -0.453125 1.9218674q0 1.078125 0.453125 1.90625q0.453125 0.8125 1.171875 1.265625q0.71875 0.4375 1.546875 0.4375q1.015625 0 1.734375 -0.46875q0.734375 -0.46875 1.09375 -1.3125l1.40625 0.59375q-0.46875 1.09375 -1.515625 1.859375q-1.03125 0.765625 -2.640625 0.765625zm10.014847 0q-1.375 0 -2.453125 -0.640625q-1.0625 -0.65625 -1.671875 -1.796875q-0.609375 -1.140625 -0.609375 -2.59375q0 -1.3593674 0.5625 -2.5156174q0.578125 -1.15625 1.609375 -1.859375q1.03125 -0.703125 2.4375 -0.703125q1.421875 0 2.4375 0.625q1.015625 0.625 1.5625 1.734375q0.546875 1.09375 0.546875 2.5156174q0 0.125 -0.015625 0.265625q0 0.125 -0.015625 0.21875l-8.1875 0l0 -1.3124924l6.546875 0q-0.015625 -0.390625 -0.1875 -0.84375q-0.15625 -0.46875 -0.5 -0.859375q-0.34375 -0.40625 -0.875 -0.65625q-0.53125 -0.25 -1.3125 -0.25q-0.9375 0 -1.625 0.484375q-0.671875 0.46875 -1.046875 1.296875q-0.359375 0.8125 -0.359375 1.8593674q0 1.203125 0.46875 2.015625q0.46875 0.796875 1.203125 1.1875q0.75 0.390625 1.546875 0.390625q1.046875 0 1.71875 -0.484375q0.6875 -0.5 1.09375 -1.234375l1.34375 0.65625q-0.5625 1.078125 -1.609375 1.796875q-1.03125 0.703125 -2.609375 0.703125z" fill-rule="nonzero"/></g><g filter="url(#shadowFilter-p.4)"><use xlink:href="#p.4" transform="matrix(1.0 0.0 0.0 1.0 0.0 2.0)"/></g><defs><filter id="shadowFilter-p.4" filterUnits="userSpaceOnUse"><feGaussianBlur in="SourceAlpha" stdDeviation="2.0" result="blur"/><feComponentTransfer in="blur" color-interpolation-filters="sRGB"><feFuncR type="linear" slope="0" intercept="0.0"/><feFuncG type="linear" slope="0" intercept="0.0"/><feFuncB type="linear" slope="0" intercept="0.0"/><feFuncA type="linear" slope="0.5" intercept="0"/></feComponentTransfer></filter></defs><g id="p.4"><path fill="#c9daf8" d="m192.74174 100.78206l0 0c0 -7.7669296 6.296341 -14.063271 14.063278 -14.063271l311.08603 0c3.7298584 0 7.306885 1.4816589 9.944275 4.119034c2.637329 2.6373749 4.1190186 6.214424 4.1190186 9.944237l0 56.251404c0 7.7669373 -6.2963257 14.063278 -14.063293 14.063278l-311.08603 0c-7.7669373 0 -14.063278 -6.296341 -14.063278 -14.063278z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m192.74174 100.78206l0 0c0 -7.7669296 6.296341 -14.063271 14.063278 -14.063271l311.08603 0c3.7298584 0 7.306885 1.4816589 9.944275 4.119034c2.637329 2.6373749 4.1190186 6.214424 4.1190186 9.944237l0 56.251404c0 7.7669373 -6.2963257 14.063278 -14.063293 14.063278l-311.08603 0c-7.7669373 0 -14.063278 -6.296341 -14.063278 -14.063278z" fill-rule="evenodd"/></g><path fill="#a2c4c9" d="m203.9767 122.657425l0 0c0 -4.68219 3.7956696 -8.4778595 8.4778595 -8.4778595l57.060028 0c2.2484741 0 4.404846 0.89320374 5.994751 2.4831085c1.5899048 1.5899048 2.4831238 3.7462845 2.4831238 5.994751l0 33.910416c0 4.682205 -3.7956848 8.4778595 -8.477875 8.4778595l-57.060028 0c-4.68219 0 -8.4778595 -3.7956543 -8.4778595 -8.4778595z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m203.9767 122.657425l0 0c0 -4.68219 3.7956696 -8.4778595 8.4778595 -8.4778595l57.060028 0c2.2484741 0 4.404846 0.89320374 5.994751 2.4831085c1.5899048 1.5899048 2.4831238 3.7462845 2.4831238 5.994751l0 33.910416c0 4.682205 -3.7956848 8.4778595 -8.477875 8.4778595l-57.060028 0c-4.68219 0 -8.4778595 -3.7956543 -8.4778595 -8.4778595z" fill-rule="evenodd"/><path fill="#000000" d="m221.41891 145.47264l4.359375 -11.453125l1.53125 0l4.359375 11.453125l-1.5 0l-3.140625 -8.5625l-0.453125 -1.234375l-0.0625 0l-0.453125 1.234375l-3.140625 8.5625l-1.5 0zm4.96875 -3.15625l0 -1.28125l2.640625 0l0.453125 1.28125l-3.09375 0zm-3.109375 0l0.46875 -1.28125l2.640625 0l0 1.28125l-3.109375 0zm9.3450165 3.15625l0 -1.359375q0.046875 -0.046875 0.375 -0.375q0.34375 -0.34375 0.84375 -0.84375q0.5 -0.515625 1.03125 -1.0625q0.546875 -0.546875 1.015625 -1.03125q0.484375 -0.5 0.75 -0.796875q0.5 -0.546875 0.796875 -0.9375q0.3125 -0.390625 0.453125 -0.765625q0.140625 -0.375 0.140625 -0.875q0 -0.46875 -0.25 -0.890625q-0.234375 -0.421875 -0.6875 -0.6875q-0.453125 -0.28125 -1.140625 -0.28125q-0.640625 0 -1.078125 0.28125q-0.4375 0.265625 -0.6875 0.640625q-0.234375 0.375 -0.3125 0.6875l-1.234375 -0.5q0.09375 -0.34375 0.34375 -0.75q0.25 -0.40625 0.65625 -0.78125q0.40625 -0.375 0.984375 -0.625q0.59375 -0.25 1.359375 -0.25q1.046875 0 1.8125 0.453125q0.76564026 0.4375 1.1875153 1.15625q0.421875 0.703125 0.421875 1.53125q0 0.71875 -0.28125 1.375q-0.265625 0.640625 -0.67189026 1.171875q-0.390625 0.53125 -0.796875 0.921875q-0.21875 0.203125 -0.59375 0.578125q-0.359375 0.375 -0.78125 0.796875q-0.40625 0.421875 -0.8125 0.828125q-0.390625 0.390625 -0.6875 0.703125q-0.296875 0.296875 -0.40625 0.390625l0 0l5.1562653 0l0 1.296875l-6.9062653 0zm8.978531 0l0 -11.453125l3.453125 0q1.796875 0 3.09375 0.734375q1.296875 0.71875 2.0 2.015625q0.703125 1.296875 0.703125 2.96875q0 1.6875 -0.703125 2.984375q-0.703125 1.28125 -2.0 2.015625q-1.296875 0.734375 -3.09375 0.734375l-3.453125 0zm1.359375 -1.296875l2.09375 0q1.34375 0 2.328125 -0.515625q1.0 -0.53125 1.546875 -1.515625q0.546875 -0.984375 0.546875 -2.40625q0 -1.40625 -0.546875 -2.390625q-0.546875 -1.0 -1.546875 -1.515625q-0.984375 -0.515625 -2.328125 -0.515625l-2.09375 0l0 8.859375zm9.888641 1.296875l0 -11.453125l3.859375 0q0.953125 0 1.765625 0.4375q0.828125 0.421875 1.3125 1.1875q0.484375 0.75 0.484375 1.765625q0 0.984375 -0.484375 1.765625q-0.484375 0.765625 -1.3125 1.203125q-0.8125 0.421875 -1.765625 0.421875l-3.140625 0l0 -1.296875l3.171875 0q0.671875 0 1.140625 -0.3125q0.484375 -0.3125 0.75 -0.78125q0.265625 -0.484375 0.265625 -1.0q0 -0.515625 -0.265625 -0.984375q-0.265625 -0.484375 -0.75 -0.796875q-0.46875 -0.3125 -1.140625 -0.3125l-2.53125 0l0 10.15625l-1.359375 0z" fill-rule="nonzero"/><path fill="#a2c4c9" d="m284.8796 122.657425l0 0c0 -4.68219 3.7956543 -8.4778595 8.477844 -8.4778595l57.060028 0c2.2484741 0 4.404846 0.89320374 5.994751 2.4831085c1.5899048 1.5899048 2.4831238 3.7462845 2.4831238 5.994751l0 33.910416c0 4.682205 -3.7956848 8.4778595 -8.477875 8.4778595l-57.060028 0c-4.68219 0 -8.477844 -3.7956543 -8.477844 -8.4778595z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m284.8796 122.657425l0 0c0 -4.68219 3.7956543 -8.4778595 8.477844 -8.4778595l57.060028 0c2.2484741 0 4.404846 0.89320374 5.994751 2.4831085c1.5899048 1.5899048 2.4831238 3.7462845 2.4831238 5.994751l0 33.910416c0 4.682205 -3.7956848 8.4778595 -8.477875 8.4778595l-57.060028 0c-4.68219 0 -8.477844 -3.7956543 -8.477844 -8.4778595z" fill-rule="evenodd"/><path fill="#000000" d="m308.7287 145.47264l0 -11.453125l1.359375 0l0 11.453125l-1.359375 0zm0.71875 -5.21875l0 -1.296875l6.84375 0l0 1.296875l-6.84375 0zm6.53125 5.21875l0 -11.453125l1.359375 0l0 11.453125l-1.359375 0zm3.9180298 0l0 -11.453125l6.625 0l0 1.296875l-5.265625 0l0 10.15625l-1.359375 0zm0.71875 -4.953125l0 -1.28125l5.390625 0l0 1.28125l-5.390625 0zm7.777252 4.953125l0 -11.453125l3.859375 0q0.953125 0 1.765625 0.4375q0.828125 0.421875 1.3125 1.1875q0.484375 0.75 0.484375 1.765625q0 0.984375 -0.484375 1.765625q-0.484375 0.765625 -1.3125 1.203125q-0.8125 0.421875 -1.765625 0.421875l-3.140625 0l0 -1.296875l3.171875 0q0.671875 0 1.140625 -0.3125q0.484375 -0.3125 0.75 -0.78125q0.265625 -0.484375 0.265625 -1.0q0 -0.515625 -0.265625 -0.984375q-0.265625 -0.484375 -0.75 -0.796875q-0.46875 -0.3125 -1.140625 -0.3125l-2.53125 0l0 10.15625l-1.359375 0z" fill-rule="nonzero"/><path fill="#a2c4c9" d="m365.78247 122.657425l0 0c0 -4.68219 3.7956848 -8.4778595 8.477875 -8.4778595l57.060028 0c2.2484741 0 4.404846 0.89320374 5.994751 2.4831085c1.5899048 1.5899048 2.4830933 3.7462845 2.4830933 5.994751l0 33.910416c0 4.682205 -3.7956543 8.4778595 -8.477844 8.4778595l-57.060028 0c-4.68219 0 -8.477875 -3.7956543 -8.477875 -8.4778595z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m365.78247 122.657425l0 0c0 -4.68219 3.7956848 -8.4778595 8.477875 -8.4778595l57.060028 0c2.2484741 0 4.404846 0.89320374 5.994751 2.4831085c1.5899048 1.5899048 2.4830933 3.7462845 2.4830933 5.994751l0 33.910416c0 4.682205 -3.7956543 8.4778595 -8.477844 8.4778595l-57.060028 0c-4.68219 0 -8.477875 -3.7956543 -8.477875 -8.4778595z" fill-rule="evenodd"/><path fill="#000000" d="m390.90356 145.47264l0 -11.453125l1.359375 0l0 11.453125l-1.359375 0zm0.71875 -5.21875l0 -1.296875l6.84375 0l0 1.296875l-6.84375 0zm6.53125 5.21875l0 -11.453125l1.359375 0l0 11.453125l-1.359375 0zm3.9180298 0l0 -11.453125l1.359375 0l0 11.453125l-1.359375 0zm3.9200134 0l0 -11.453125l3.453125 0q1.796875 0 3.09375 0.734375q1.296875 0.71875 2.0 2.015625q0.703125 1.296875 0.703125 2.96875q0 1.6875 -0.703125 2.984375q-0.703125 1.28125 -2.0 2.015625q-1.296875 0.734375 -3.09375 0.734375l-3.453125 0zm1.359375 -1.296875l2.09375 0q1.34375 0 2.328125 -0.515625q1.0 -0.53125 1.546875 -1.515625q0.546875 -0.984375 0.546875 -2.40625q0 -1.40625 -0.546875 -2.390625q-0.546875 -1.0 -1.546875 -1.515625q-0.984375 -0.515625 -2.328125 -0.515625l-2.09375 0l0 8.859375z" fill-rule="nonzero"/><g filter="url(#shadowFilter-p.5)"><use xlink:href="#p.5" transform="matrix(1.0 0.0 0.0 1.0 0.0 2.0)"/></g><defs><filter id="shadowFilter-p.5" filterUnits="userSpaceOnUse"><feGaussianBlur in="SourceAlpha" stdDeviation="2.0" result="blur"/><feComponentTransfer in="blur" color-interpolation-filters="sRGB"><feFuncR type="linear" slope="0" intercept="0.0"/><feFuncG type="linear" slope="0" intercept="0.0"/><feFuncB type="linear" slope="0" intercept="0.0"/><feFuncA type="linear" slope="0.5" intercept="0"/></feComponentTransfer></filter></defs><g id="p.5"><path fill="#6d9eeb" d="m4.8992295 317.66617l0 0c0 -5.2562256 4.2610183 -9.517242 9.51725 -9.517242l508.0206 0c2.52417 0 4.9448853 1.0027161 6.7297363 2.7875366c1.7848511 1.7848206 2.7875366 4.205597 2.7875366 6.729706l0 38.06787c0 5.2562256 -4.2609863 9.517242 -9.517273 9.517242l-508.0206 0c-5.2562323 0 -9.51725 -4.261017 -9.51725 -9.517242z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m4.8992295 317.66617l0 0c0 -5.2562256 4.2610183 -9.517242 9.51725 -9.517242l508.0206 0c2.52417 0 4.9448853 1.0027161 6.7297363 2.7875366c1.7848511 1.7848206 2.7875366 4.205597 2.7875366 6.729706l0 38.06787c0 5.2562256 -4.2609863 9.517242 -9.517273 9.517242l-508.0206 0c-5.2562323 0 -9.51725 -4.261017 -9.51725 -9.517242z" fill-rule="evenodd"/><path fill="#000000" d="m252.81201 342.56012l0 -11.453125l1.359375 0l0 11.453125l-1.359375 0zm0.71875 -5.21875l0 -1.296875l6.84375 0l0 1.296875l-6.84375 0zm6.53125 5.21875l0 -11.453125l1.359375 0l0 11.453125l-1.359375 0zm7.242401 0.25q-1.234375 0 -2.1875 -0.5625q-0.9375 -0.578125 -1.46875 -1.5625q-0.53125 -0.984375 -0.53125 -2.203125q0 -1.21875 0.53125 -2.203125q0.53125 -0.984375 1.46875 -1.5625q0.953125 -0.578125 2.1875 -0.578125q1.234375 0 2.171875 0.59375q0.953125 0.578125 1.484375 1.5625q0.53125 0.984375 0.53125 2.1875q0 1.21875 -0.53125 2.203125q-0.53125 0.984375 -1.484375 1.5625q-0.9375 0.5625 -2.171875 0.5625zm0 -1.21875q0.734375 0 1.375 -0.375q0.65625 -0.375 1.046875 -1.0625q0.40625 -0.703125 0.40625 -1.671875q0 -0.984375 -0.40625 -1.671875q-0.390625 -0.703125 -1.046875 -1.0625q-0.640625 -0.375 -1.375 -0.375q-0.734375 0 -1.390625 0.375q-0.65625 0.359375 -1.0625 1.0625q-0.390625 0.6875 -0.390625 1.671875q0 0.96875 0.390625 1.671875q0.40625 0.6875 1.0625 1.0625q0.65625 0.375 1.390625 0.375zm8.549774 1.21875q-0.921875 0 -1.625 -0.296875q-0.6875 -0.296875 -1.140625 -0.796875q-0.453125 -0.5 -0.671875 -1.09375l1.203125 -0.546875q0.328125 0.734375 0.9375 1.140625q0.609375 0.40625 1.390625 0.40625q0.75 0 1.25 -0.296875q0.515625 -0.3125 0.515625 -0.90625q0 -0.375 -0.21875 -0.625q-0.203125 -0.25 -0.609375 -0.421875q-0.390625 -0.171875 -0.96875 -0.3125l-1.0 -0.265625q-0.5625 -0.15625 -1.078125 -0.4375q-0.515625 -0.296875 -0.828125 -0.75q-0.3125 -0.453125 -0.3125 -1.109375q0 -0.734375 0.421875 -1.265625q0.4375 -0.53125 1.140625 -0.8125q0.703125 -0.28125 1.515625 -0.28125q0.703125 0 1.3125 0.203125q0.625 0.203125 1.078125 0.59375q0.46875 0.390625 0.703125 0.96875l-1.171875 0.546875q-0.3125 -0.609375 -0.828125 -0.84375q-0.5 -0.25 -1.125 -0.25q-0.671875 0 -1.171875 0.296875q-0.5 0.296875 -0.5 0.8125q0 0.515625 0.40625 0.765625q0.40625 0.25 1.0 0.421875l1.1875 0.296875q1.203125 0.3125 1.8125 0.90625q0.609375 0.59375 0.609375 1.46875q0 0.765625 -0.4375 1.328125q-0.4375 0.546875 -1.171875 0.859375q-0.734375 0.296875 -1.625 0.296875zm4.0817566 -8.40625l4.78125 0l0 1.234375l-4.78125 0l0 -1.234375zm1.421875 6.015625l0 -8.328125l1.359375 0l0 7.984375q0 0.640625 0.265625 1.0q0.265625 0.34375 0.875 0.34375q0.265625 0 0.484375 -0.078125q0.234375 -0.078125 0.40625 -0.1875l0 1.328125q-0.203125 0.09375 -0.453125 0.140625q-0.25 0.0625 -0.671875 0.0625q-1.015625 0 -1.640625 -0.59375q-0.625 -0.609375 -0.625 -1.671875z" fill-rule="nonzero"/></g><path fill="#a2c4c9" d="m141.82906 235.04298l0 0c0 -4.8590393 3.9390259 -8.798065 8.798065 -8.798065l43.852676 0c2.3333893 0 4.571213 0.92692566 6.221176 2.576889c1.6499634 1.6499634 2.576889 3.8877869 2.576889 6.221176l0 35.19124c0 4.85907 -3.9390259 8.798096 -8.798065 8.798096l-43.852676 0c-4.8590393 0 -8.798065 -3.9390259 -8.798065 -8.798096z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m141.82906 235.04298l0 0c0 -4.8590393 3.9390259 -8.798065 8.798065 -8.798065l43.852676 0c2.3333893 0 4.571213 0.92692566 6.221176 2.576889c1.6499634 1.6499634 2.576889 3.8877869 2.576889 6.221176l0 35.19124c0 4.85907 -3.9390259 8.798096 -8.798065 8.798096l-43.852676 0c-4.8590393 0 -8.798065 -3.9390259 -8.798065 -8.798096z" fill-rule="evenodd"/><path fill="#000000" d="m162.77774 250.34612q-0.90625 0 -1.71875 -0.328125q-0.8125 -0.34375 -1.421875 -0.953125q-0.609375 -0.609375 -0.953125 -1.421875q-0.34375 -0.828125 -0.34375 -1.78125q0 -0.953125 0.34375 -1.765625q0.34375 -0.828125 0.953125 -1.4375q0.609375 -0.609375 1.421875 -0.9375q0.8125 -0.34375 1.71875 -0.34375q0.953125 0 1.78125 0.34375q0.84375 0.328125 1.375 0.9375l-0.71875 0.71875q-0.265625 -0.328125 -0.65625 -0.5625q-0.375 -0.234375 -0.828125 -0.34375q-0.4375 -0.125 -0.9375 -0.125q-0.6875 0 -1.3125 0.25q-0.609375 0.25 -1.09375 0.71875q-0.46875 0.453125 -0.75 1.109375q-0.265625 0.640625 -0.265625 1.4375q0 0.8125 0.28125 1.453125q0.28125 0.640625 0.75 1.109375q0.484375 0.46875 1.09375 0.71875q0.625 0.234375 1.296875 0.234375q0.578125 0 1.125 -0.15625q0.546875 -0.171875 0.984375 -0.5q0.4375 -0.34375 0.71875 -0.890625q0.296875 -0.546875 0.359375 -1.296875l-3.171875 0l0 -0.953125l4.125 0q0.03125 0.15625 0.046875 0.3125q0.015625 0.140625 0.015625 0.3125l0 0l0 0l0 0q0 0.921875 -0.3125 1.6875q-0.3125 0.765625 -0.875 1.3125q-0.5625 0.546875 -1.328125 0.84375q-0.765625 0.296875 -1.703125 0.296875zm4.551193 -0.1875l3.25 -8.59375l1.15625 0l3.265625 8.59375l-1.109375 0l-2.375 -6.421875l-0.328125 -0.921875l-0.046875 0l-0.34375 0.921875l-2.359375 6.421875l-1.109375 0zm3.71875 -2.359375l0 -0.96875l1.96875 0l0.359375 0.96875l-2.328125 0zm-2.328125 0l0.34375 -0.96875l1.984375 0l0 0.96875l-2.328125 0zm8.400681 2.359375l0 -7.984375l1.03125 0l0 7.984375l-1.03125 0zm-2.40625 -7.625l0 -0.96875l5.828125 0l0 0.96875l-5.828125 0zm8.862289 7.625l0 -7.984375l1.03125 0l0 7.984375l-1.03125 0zm-2.40625 -7.625l0 -0.96875l5.828125 0l0 0.96875l-5.828125 0z" fill-rule="nonzero"/><path fill="#000000" d="m161.77573 264.3461q-0.9375 0 -1.75 -0.328125q-0.8125 -0.34375 -1.421875 -0.953125q-0.59375 -0.609375 -0.9375 -1.421875q-0.328125 -0.828125 -0.328125 -1.78125q0 -0.953125 0.328125 -1.765625q0.34375 -0.828125 0.9375 -1.421875q0.609375 -0.609375 1.421875 -0.95310974q0.8125 -0.34375 1.75 -0.34375q0.671875 0 1.234375 0.171875q0.578125 0.15625 1.046875 0.46873474q0.484375 0.3125 0.875 0.765625l-0.734375 0.703125q-0.328125 -0.390625 -0.703125 -0.640625q-0.359375 -0.265625 -0.78125 -0.375q-0.421875 -0.125 -0.9375 -0.125q-0.921875 0 -1.703125 0.4375q-0.765625 0.421875 -1.234375 1.21875q-0.46875 0.78125 -0.46875 1.859375q0 1.0625 0.46875 1.859375q0.46875 0.796875 1.234375 1.234375q0.78125 0.421875 1.703125 0.421875q0.578125 0 1.046875 -0.15625q0.46875 -0.15625 0.875 -0.4375q0.40625 -0.296875 0.734375 -0.6875l0.75 0.71875q-0.375 0.4375 -0.90625 0.796875q-0.515625 0.34375 -1.140625 0.546875q-0.625 0.1875 -1.359375 0.1875zm4.537689 -0.1875l0 -8.593735l1.03125 0l0 8.593735l-1.03125 0zm2.641388 0l0 -6.125l1.015625 0l0 6.125l-1.015625 0zm0.5 -7.25q-0.296875 0 -0.515625 -0.21875q-0.21875 -0.21875 -0.21875 -0.515625q0 -0.31248474 0.21875 -0.51560974q0.21875 -0.21875 0.515625 -0.21875q0.3125 0 0.515625 0.21875q0.21875 0.203125 0.21875 0.51560974q0 0.296875 -0.21875 0.515625q-0.203125 0.21875 -0.515625 0.21875zm4.7770233 7.4375q-0.890625 0 -1.578125 -0.40625q-0.6875 -0.421875 -1.078125 -1.15625q-0.390625 -0.734375 -0.390625 -1.671875q0 -0.875 0.359375 -1.609375q0.359375 -0.75 1.03125 -1.203125q0.671875 -0.453125 1.5625 -0.453125q0.921875 0 1.5625 0.40625q0.65625 0.390625 1.015625 1.109375q0.359375 0.703125 0.359375 1.609375q0 0.09375 -0.015625 0.1875q0 0.078125 -0.015625 0.125l-5.265625 0l0 -0.828125l4.21875 0q-0.015625 -0.25 -0.125 -0.546875q-0.09375 -0.296875 -0.328125 -0.546875q-0.21875 -0.265625 -0.5625 -0.421875q-0.328125 -0.171875 -0.84375 -0.171875q-0.59375 0 -1.03125 0.3125q-0.4375 0.296875 -0.671875 0.828125q-0.234375 0.53125 -0.234375 1.203125q0 0.78125 0.296875 1.296875q0.296875 0.515625 0.765625 0.765625q0.484375 0.25 1.0 0.25q0.671875 0 1.109375 -0.3125q0.4375 -0.328125 0.703125 -0.796875l0.859375 0.421875q-0.359375 0.703125 -1.03125 1.15625q-0.671875 0.453125 -1.671875 0.453125zm4.0216675 -0.1875l0 -6.125l0.984375 0l0 0.90625l0.046875 0q0.234375 -0.4375 0.78125 -0.765625q0.546875 -0.328125 1.1875 -0.328125q1.140625 0 1.703125 0.65625q0.578125 0.65625 0.578125 1.734375l0 3.921875l-1.03125 0l0 -3.765625q0 -0.890625 -0.421875 -1.25q-0.421875 -0.375 -1.09375 -0.375q-0.515625 0 -0.90625 0.28125q-0.375 0.28125 -0.59375 0.734375q-0.203125 0.4375 -0.203125 0.9375l0 3.4375l-1.03125 0zm6.0257874 -6.125l3.578125 0l0 0.921875l-3.578125 0l0 -0.921875zm1.0625 4.515625l0 -6.234375l1.015625 0l0 5.984375q0 0.484375 0.1875 0.75q0.203125 0.25 0.671875 0.25q0.203125 0 0.359375 -0.046875q0.171875 -0.0625 0.3125 -0.15625l0 1.0q-0.15625 0.078125 -0.34375 0.109375q-0.1875 0.046875 -0.5 0.046875q-0.765625 0 -1.234375 -0.4375q-0.46875 -0.453125 -0.46875 -1.265625z" fill-rule="nonzero"/><path fill="#a2c4c9" d="m77.69106 235.04298l0 0c0 -4.8590393 3.9390335 -8.798065 8.798073 -8.798065l43.852676 0c2.3333893 0 4.571213 0.92692566 6.221176 2.576889c1.6499481 1.6499634 2.576889 3.8877869 2.576889 6.221176l0 35.19124c0 4.85907 -3.9390259 8.798096 -8.798065 8.798096l-43.852676 0c-4.8590393 0 -8.798073 -3.9390259 -8.798073 -8.798096z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m77.69106 235.04298l0 0c0 -4.8590393 3.9390335 -8.798065 8.798073 -8.798065l43.852676 0c2.3333893 0 4.571213 0.92692566 6.221176 2.576889c1.6499481 1.6499634 2.576889 3.8877869 2.576889 6.221176l0 35.19124c0 4.85907 -3.9390259 8.798096 -8.798065 8.798096l-43.852676 0c-4.8590393 0 -8.798073 -3.9390259 -8.798073 -8.798096z" fill-rule="evenodd"/><path fill="#000000" d="m101.24976 257.3461q-0.90625 0 -1.71875 -0.328125q-0.8125 -0.34375 -1.421875 -0.953125q-0.609375 -0.60935974 -0.953125 -1.4218597q-0.34375 -0.828125 -0.34375 -1.78125q0 -0.953125 0.34375 -1.765625q0.34375 -0.828125 0.953125 -1.4375q0.609375 -0.609375 1.421875 -0.9375q0.8125 -0.34375 1.71875 -0.34375q0.953125 0 1.78125 0.34375q0.84375 0.328125 1.375 0.9375l-0.71875 0.71875q-0.265625 -0.328125 -0.65625 -0.5625q-0.375 -0.234375 -0.828125 -0.34375q-0.4375 -0.125 -0.9375 -0.125q-0.6875 0 -1.3125 0.25q-0.609375 0.25 -1.09375 0.71875q-0.46875 0.453125 -0.75 1.109375q-0.265625 0.640625 -0.265625 1.4375q0 0.8125 0.28125 1.453125q0.28125 0.640625 0.75 1.109375q0.484375 0.46875 1.09375 0.71873474q0.625 0.234375 1.296875 0.234375q0.578125 0 1.125 -0.15625q0.546875 -0.171875 0.984375 -0.49998474q0.4375 -0.34375 0.71875 -0.890625q0.296875 -0.546875 0.359375 -1.296875l-3.171875 0l0 -0.953125l4.125 0q0.03125 0.15625 0.046875 0.3125q0.015625 0.140625 0.015625 0.3125l0 0l0 0l0 0q0 0.921875 -0.3125 1.6875q-0.3125 0.765625 -0.875 1.3124847q-0.5625 0.546875 -1.328125 0.84375q-0.765625 0.296875 -1.703125 0.296875zm4.551193 -0.1875l3.25 -8.593735l1.15625 0l3.265625 8.593735l-1.109375 0l-2.375 -6.4218597l-0.328125 -0.921875l-0.046875 0l-0.34375 0.921875l-2.359375 6.4218597l-1.109375 0zm3.71875 -2.3593597l0 -0.96875l1.96875 0l0.359375 0.96875l-2.328125 0zm-2.328125 0l0.34375 -0.96875l1.984375 0l0 0.96875l-2.328125 0zm7.4150543 2.3593597l0 -8.593735l2.90625 0q0.71875 0 1.328125 0.328125q0.609375 0.328125 0.96875 0.90625q0.375 0.5625 0.375 1.3125q0 0.75 -0.375 1.328125q-0.359375 0.5625 -0.96875 0.890625q-0.609375 0.328125 -1.328125 0.328125l-2.359375 0l0 -0.96875l2.375 0q0.5 0 0.859375 -0.234375q0.359375 -0.234375 0.5625 -0.59375q0.203125 -0.359375 0.203125 -0.75q0 -0.390625 -0.203125 -0.75q-0.203125 -0.359375 -0.5625 -0.59375q-0.359375 -0.234375 -0.859375 -0.234375l-1.890625 0l0 7.6249847l-1.03125 0z" fill-rule="nonzero"/><path fill="#a2c4c9" d="m205.96704 235.04298l0 0c0 -4.8590393 3.9390259 -8.798065 8.798065 -8.798065l43.85266 0c2.3334045 0 4.571228 0.92692566 6.2211914 2.576889c1.6499634 1.6499634 2.5769043 3.8877869 2.5769043 6.221176l0 35.19124c0 4.85907 -3.9390259 8.798096 -8.798096 8.798096l-43.85266 0c-4.8590393 0 -8.798065 -3.9390259 -8.798065 -8.798096z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m205.96704 235.04298l0 0c0 -4.8590393 3.9390259 -8.798065 8.798065 -8.798065l43.85266 0c2.3334045 0 4.571228 0.92692566 6.2211914 2.576889c1.6499634 1.6499634 2.5769043 3.8877869 2.5769043 6.221176l0 35.19124c0 4.85907 -3.9390259 8.798096 -8.798096 8.798096l-43.85266 0c-4.8590393 0 -8.798065 -3.9390259 -8.798065 -8.798096z" fill-rule="evenodd"/><path fill="#000000" d="m226.91573 250.34612q-0.90625 0 -1.71875 -0.328125q-0.8125 -0.34375 -1.421875 -0.953125q-0.609375 -0.609375 -0.953125 -1.421875q-0.34375 -0.828125 -0.34375 -1.78125q0 -0.953125 0.34375 -1.765625q0.34375 -0.828125 0.953125 -1.4375q0.609375 -0.609375 1.421875 -0.9375q0.8125 -0.34375 1.71875 -0.34375q0.953125 0 1.78125 0.34375q0.84375 0.328125 1.375 0.9375l-0.71875 0.71875q-0.265625 -0.328125 -0.65625 -0.5625q-0.375 -0.234375 -0.828125 -0.34375q-0.4375 -0.125 -0.9375 -0.125q-0.6875 0 -1.3125 0.25q-0.609375 0.25 -1.09375 0.71875q-0.46875 0.453125 -0.75 1.109375q-0.265625 0.640625 -0.265625 1.4375q0 0.8125 0.28125 1.453125q0.28125 0.640625 0.75 1.109375q0.484375 0.46875 1.09375 0.71875q0.625 0.234375 1.296875 0.234375q0.578125 0 1.125 -0.15625q0.546875 -0.171875 0.984375 -0.5q0.4375 -0.34375 0.71875 -0.890625q0.296875 -0.546875 0.359375 -1.296875l-3.171875 0l0 -0.953125l4.125 0q0.03125 0.15625 0.046875 0.3125q0.015625 0.140625 0.015625 0.3125l0 0l0 0l0 0q0 0.921875 -0.3125 1.6875q-0.3125 0.765625 -0.875 1.3125q-0.5625 0.546875 -1.328125 0.84375q-0.765625 0.296875 -1.703125 0.296875zm4.551193 -0.1875l3.25 -8.59375l1.15625 0l3.265625 8.59375l-1.109375 0l-2.375 -6.421875l-0.328125 -0.921875l-0.046875 0l-0.34375 0.921875l-2.359375 6.421875l-1.109375 0zm3.71875 -2.359375l0 -0.96875l1.96875 0l0.359375 0.96875l-2.328125 0zm-2.328125 0l0.34375 -0.96875l1.984375 0l0 0.96875l-2.328125 0zm8.400681 2.359375l0 -7.984375l1.03125 0l0 7.984375l-1.03125 0zm-2.40625 -7.625l0 -0.96875l5.828125 0l0 0.96875l-5.828125 0zm8.862289 7.625l0 -7.984375l1.03125 0l0 7.984375l-1.03125 0zm-2.40625 -7.625l0 -0.96875l5.828125 0l0 0.96875l-5.828125 0z" fill-rule="nonzero"/><path fill="#000000" d="m222.3267 264.3461q-0.625 0 -1.234375 -0.265625q-0.609375 -0.265625 -1.078125 -0.78125q-0.46875 -0.515625 -0.6875 -1.28125l0.96875 -0.390625q0.203125 0.75 0.734375 1.25q0.546875 0.5 1.328125 0.5q0.46875 0 0.875 -0.171875q0.40625 -0.171875 0.640625 -0.5q0.25 -0.34375 0.25 -0.828125q0 -0.4375 -0.21875 -0.734375q-0.203125 -0.296875 -0.625 -0.53125q-0.40625 -0.234375 -1.03125 -0.453125l-0.53125 -0.1875q-0.359375 -0.125 -0.734375 -0.3125q-0.359375 -0.1875 -0.671875 -0.453125q-0.296875 -0.28125 -0.484375 -0.65625q-0.171875 -0.375 -0.171875 -0.890625q0 -0.625 0.328125 -1.140625q0.34375 -0.515625 0.921875 -0.82810974q0.59375 -0.3125 1.359375 -0.3125q0.8125 0 1.359375 0.296875q0.546875 0.28125 0.859375 0.68748474q0.3125 0.40625 0.421875 0.734375l-0.953125 0.421875q-0.0625 -0.265625 -0.265625 -0.53125q-0.203125 -0.265625 -0.546875 -0.453125q-0.34375 -0.1875 -0.859375 -0.1875q-0.421875 0 -0.796875 0.171875q-0.359375 0.171875 -0.578125 0.46875q-0.21875 0.28125 -0.21875 0.671875q0 0.53125 0.421875 0.84375q0.4375 0.3125 1.171875 0.5625l0.5625 0.203125q0.390625 0.125 0.78125 0.328125q0.40625 0.1875 0.75 0.484375q0.359375 0.296875 0.5625 0.734375q0.21875 0.4375 0.21875 1.046875q0 0.671875 -0.265625 1.140625q-0.25 0.46875 -0.671875 0.78125q-0.40625 0.296875 -0.90625 0.421875q-0.5 0.140625 -0.984375 0.140625zm6.869049 0q-0.890625 0 -1.578125 -0.40625q-0.6875 -0.421875 -1.078125 -1.15625q-0.390625 -0.734375 -0.390625 -1.671875q0 -0.875 0.359375 -1.609375q0.359375 -0.75 1.03125 -1.203125q0.671875 -0.453125 1.5625 -0.453125q0.921875 0 1.5625 0.40625q0.65625 0.390625 1.015625 1.109375q0.359375 0.703125 0.359375 1.609375q0 0.09375 -0.015625 0.1875q0 0.078125 -0.015625 0.125l-5.265625 0l0 -0.828125l4.21875 0q-0.015625 -0.25 -0.125 -0.546875q-0.09375 -0.296875 -0.328125 -0.546875q-0.21875 -0.265625 -0.5625 -0.421875q-0.328125 -0.171875 -0.84375 -0.171875q-0.59375 0 -1.03125 0.3125q-0.4375 0.296875 -0.671875 0.828125q-0.234375 0.53125 -0.234375 1.203125q0 0.78125 0.296875 1.296875q0.296875 0.515625 0.765625 0.765625q0.484375 0.25 1.0 0.25q0.671875 0 1.109375 -0.3125q0.4375 -0.328125 0.703125 -0.796875l0.859375 0.421875q-0.359375 0.703125 -1.03125 1.15625q-0.671875 0.453125 -1.671875 0.453125zm4.0216675 -0.1875l0 -6.125l0.984375 0l0 0.984375l0.046875 0q0.109375 -0.34375 0.390625 -0.59375q0.28125 -0.265625 0.640625 -0.40625q0.375 -0.15625 0.734375 -0.15625q0.28125 0 0.4375 0.03125q0.15625 0.03125 0.28125 0.078125l0 1.109375q-0.1875 -0.09375 -0.40625 -0.140625q-0.21875 -0.046875 -0.453125 -0.046875q-0.4375 0 -0.8125 0.25q-0.375 0.25 -0.59375 0.671875q-0.21875 0.421875 -0.21875 0.921875l0 3.421875l-1.03125 0zm6.5165253 0l-2.484375 -6.125l1.09375 0l1.90625 4.921875l0.015625 0l1.921875 -4.921875l1.0625 0l-2.484375 6.125l-1.03125 0zm6.9099274 0.1875q-0.890625 0 -1.578125 -0.40625q-0.6875 -0.421875 -1.078125 -1.15625q-0.390625 -0.734375 -0.390625 -1.671875q0 -0.875 0.359375 -1.609375q0.359375 -0.75 1.03125 -1.203125q0.671875 -0.453125 1.5625 -0.453125q0.921875 0 1.5625 0.40625q0.65625 0.390625 1.015625 1.109375q0.359375 0.703125 0.359375 1.609375q0 0.09375 -0.015625 0.1875q0 0.078125 -0.015625 0.125l-5.265625 0l0 -0.828125l4.21875 0q-0.015625 -0.25 -0.125 -0.546875q-0.09375 -0.296875 -0.328125 -0.546875q-0.21875 -0.265625 -0.5625 -0.421875q-0.328125 -0.171875 -0.84375 -0.171875q-0.59375 0 -1.03125 0.3125q-0.4375 0.296875 -0.671875 0.828125q-0.234375 0.53125 -0.234375 1.203125q0 0.78125 0.296875 1.296875q0.296875 0.515625 0.765625 0.765625q0.484375 0.25 1.0 0.25q0.671875 0 1.109375 -0.3125q0.4375 -0.328125 0.703125 -0.796875l0.859375 0.421875q-0.359375 0.703125 -1.03125 1.15625q-0.671875 0.453125 -1.671875 0.453125zm4.0216675 -0.1875l0 -6.125l0.984375 0l0 0.984375l0.046875 0q0.109375 -0.34375 0.390625 -0.59375q0.28125 -0.265625 0.640625 -0.40625q0.375 -0.15625 0.734375 -0.15625q0.28125 0 0.4375 0.03125q0.15625 0.03125 0.28125 0.078125l0 1.109375q-0.1875 -0.09375 -0.40625 -0.140625q-0.21875 -0.046875 -0.453125 -0.046875q-0.4375 0 -0.8125 0.25q-0.375 0.25 -0.59375 0.671875q-0.21875 0.421875 -0.21875 0.921875l0 3.421875l-1.03125 0z" fill-rule="nonzero"/><path fill="#a2c4c9" d="m270.105 235.04298l0 0c0 -4.8590393 3.9390564 -8.798065 8.798096 -8.798065l43.85266 0c2.3334045 0 4.571228 0.92692566 6.2211914 2.576889c1.6499329 1.6499634 2.5768738 3.8877869 2.5768738 6.221176l0 35.19124c0 4.85907 -3.9390259 8.798096 -8.798065 8.798096l-43.85266 0c-4.8590393 0 -8.798096 -3.9390259 -8.798096 -8.798096z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m270.105 235.04298l0 0c0 -4.8590393 3.9390564 -8.798065 8.798096 -8.798065l43.85266 0c2.3334045 0 4.571228 0.92692566 6.2211914 2.576889c1.6499329 1.6499634 2.5768738 3.8877869 2.5768738 6.221176l0 35.19124c0 4.85907 -3.9390259 8.798096 -8.798065 8.798096l-43.85266 0c-4.8590393 0 -8.798096 -3.9390259 -8.798096 -8.798096z" fill-rule="evenodd"/><path fill="#000000" d="m281.83264 250.34612q-0.625 0 -1.234375 -0.265625q-0.609375 -0.265625 -1.078125 -0.78125q-0.46875 -0.515625 -0.6875 -1.28125l0.96875 -0.390625q0.203125 0.75 0.734375 1.25q0.546875 0.5 1.328125 0.5q0.46875 0 0.875 -0.171875q0.40625 -0.171875 0.640625 -0.5q0.25 -0.34375 0.25 -0.828125q0 -0.4375 -0.21875 -0.734375q-0.203125 -0.296875 -0.625 -0.53125q-0.40625 -0.234375 -1.03125 -0.453125l-0.53125 -0.1875q-0.359375 -0.125 -0.734375 -0.3125q-0.359375 -0.1875 -0.671875 -0.453125q-0.296875 -0.28125 -0.484375 -0.65625q-0.171875 -0.375 -0.171875 -0.890625q0 -0.625 0.328125 -1.140625q0.34375 -0.515625 0.921875 -0.828125q0.59375 -0.3125 1.359375 -0.3125q0.8125 0 1.359375 0.296875q0.546875 0.28125 0.859375 0.6875q0.3125 0.40625 0.421875 0.734375l-0.953125 0.421875q-0.0625 -0.265625 -0.265625 -0.53125q-0.203125 -0.265625 -0.546875 -0.453125q-0.34375 -0.1875 -0.859375 -0.1875q-0.421875 0 -0.796875 0.171875q-0.359375 0.171875 -0.578125 0.46875q-0.21875 0.28125 -0.21875 0.671875q0 0.53125 0.421875 0.84375q0.4375 0.3125 1.171875 0.5625l0.5625 0.203125q0.390625 0.125 0.78125 0.328125q0.40625 0.1875 0.75 0.484375q0.359375 0.296875 0.5625 0.734375q0.21875 0.4375 0.21875 1.046875q0 0.671875 -0.265625 1.140625q-0.25 0.46875 -0.671875 0.78125q-0.40625 0.296875 -0.90625 0.421875q-0.5 0.140625 -0.984375 0.140625zm6.869049 0q-0.890625 0 -1.578125 -0.40625q-0.6875 -0.421875 -1.078125 -1.15625q-0.390625 -0.734375 -0.390625 -1.671875q0 -0.875 0.359375 -1.609375q0.359375 -0.75 1.03125 -1.203125q0.671875 -0.453125 1.5625 -0.453125q0.921875 0 1.5625 0.40625q0.65625 0.390625 1.015625 1.109375q0.359375 0.703125 0.359375 1.609375q0 0.09375 -0.015625 0.1875q0 0.078125 -0.015625 0.125l-5.265625 0l0 -0.828125l4.21875 0q-0.015625 -0.25 -0.125 -0.546875q-0.09375 -0.296875 -0.328125 -0.546875q-0.21875 -0.265625 -0.5625 -0.421875q-0.328125 -0.171875 -0.84375 -0.171875q-0.59375 0 -1.03125 0.3125q-0.4375 0.296875 -0.671875 0.828125q-0.234375 0.53125 -0.234375 1.203125q0 0.78125 0.296875 1.296875q0.296875 0.515625 0.765625 0.765625q0.484375 0.25 1.0 0.25q0.671875 0 1.109375 -0.3125q0.4375 -0.328125 0.703125 -0.796875l0.859375 0.421875q-0.359375 0.703125 -1.03125 1.15625q-0.671875 0.453125 -1.671875 0.453125zm6.862915 0q-0.90625 0 -1.609375 -0.421875q-0.703125 -0.421875 -1.09375 -1.15625q-0.390625 -0.75 -0.390625 -1.671875q0 -0.9375 0.390625 -1.65625q0.390625 -0.734375 1.09375 -1.15625q0.703125 -0.4375 1.609375 -0.4375q1.03125 0 1.6875 0.484375q0.671875 0.46875 0.953125 1.203125l-0.921875 0.390625q-0.234375 -0.5625 -0.6875 -0.859375q-0.453125 -0.296875 -1.078125 -0.296875q-0.546875 0 -1.015625 0.296875q-0.453125 0.28125 -0.75 0.8125q-0.28125 0.515625 -0.28125 1.21875q0 0.703125 0.28125 1.234375q0.296875 0.515625 0.75 0.8125q0.46875 0.28125 1.015625 0.28125q0.640625 0 1.109375 -0.296875q0.46875 -0.296875 0.703125 -0.859375l0.90625 0.390625q-0.296875 0.703125 -0.96875 1.203125q-0.671875 0.484375 -1.703125 0.484375zm5.989563 0q-1.125 0 -1.703125 -0.65625q-0.5625 -0.65625 -0.5625 -1.796875l0 -3.859375l1.03125 0l0 3.703125q0 0.90625 0.40625 1.296875q0.421875 0.390625 1.046875 0.390625q0.546875 0 0.9375 -0.28125q0.40625 -0.28125 0.609375 -0.71875q0.21875 -0.453125 0.21875 -0.921875l0 -3.46875l1.015625 0l0 6.125l-0.96875 0l0 -0.890625l-0.046875 0q-0.15625 0.296875 -0.46875 0.546875q-0.296875 0.234375 -0.6875 0.375q-0.390625 0.15625 -0.828125 0.15625zm4.513275 -0.1875l0 -6.125l0.984375 0l0 0.984375l0.046875 0q0.109375 -0.34375 0.390625 -0.59375q0.28125 -0.265625 0.640625 -0.40625q0.375 -0.15625 0.734375 -0.15625q0.28125 0 0.4375 0.03125q0.15625 0.03125 0.28125 0.078125l0 1.109375q-0.1875 -0.09375 -0.40625 -0.140625q-0.21875 -0.046875 -0.453125 -0.046875q-0.4375 0 -0.8125 0.25q-0.375 0.25 -0.59375 0.671875q-0.21875 0.421875 -0.21875 0.921875l0 3.421875l-1.03125 0zm4.6094055 0l0 -6.125l1.015625 0l0 6.125l-1.015625 0zm0.5 -7.25q-0.296875 0 -0.515625 -0.21875q-0.21875 -0.21875 -0.21875 -0.515625q0 -0.3125 0.21875 -0.515625q0.21875 -0.21875 0.515625 -0.21875q0.3125 0 0.515625 0.21875q0.21875 0.203125 0.21875 0.515625q0 0.296875 -0.21875 0.515625q-0.203125 0.21875 -0.515625 0.21875zm1.6364136 1.125l3.578125 0l0 0.921875l-3.578125 0l0 -0.921875zm1.0625 4.515625l0 -6.234375l1.015625 0l0 5.984375q0 0.484375 0.1875 0.75q0.203125 0.25 0.671875 0.25q0.203125 0 0.359375 -0.046875q0.171875 -0.0625 0.3125 -0.15625l0 1.0q-0.15625 0.078125 -0.34375 0.109375q-0.1875 0.046875 -0.5 0.046875q-0.765625 0 -1.234375 -0.4375q-0.46875 -0.453125 -0.46875 -1.265625zm5.549408 3.890625q-0.046875 0.078125 -0.09375 0.171875q-0.046875 0.109375 -0.0625 0.140625l-1.046875 0q0.0625 -0.15625 0.140625 -0.34375q0.09375 -0.1875 0.21875 -0.453125q0.0625 -0.15625 0.125 -0.296875q0.0625 -0.125 0.140625 -0.28125q0.078125 -0.15625 0.1875 -0.40625l0.84375 -1.828125l0.21875 -0.5625l1.859375 -4.546875l1.09375 0l-3.171875 7.3125q-0.046875 0.109375 -0.15625 0.34375q-0.09375 0.234375 -0.1875 0.453125q-0.078125 0.21875 -0.109375 0.296875zm0.21875 -2.53125l-2.59375 -5.875l1.109375 0l1.921875 4.546875l0.09375 0l-0.53125 1.328125z" fill-rule="nonzero"/><path fill="#000000" d="m277.8184 264.1586l0 -8.593735l1.484375 0l2.734375 7.0468597l0.046875 0l2.734375 -7.0468597l1.484375 0l0 8.593735l-1.015625 0l0 -5.453125l0.046875 -1.640625l-0.046875 0l-2.8125 7.09375l-0.828125 0l-2.8125 -7.09375l-0.046875 0l0.046875 1.640625l0 5.453125l-1.015625 0zm11.977722 0.1875q-0.6875 0 -1.203125 -0.265625q-0.515625 -0.265625 -0.8125 -0.71875q-0.296875 -0.46875 -0.296875 -1.046875q0 -0.671875 0.34375 -1.125q0.359375 -0.46875 0.9375 -0.703125q0.59375 -0.234375 1.296875 -0.234375q0.40625 0 0.75 0.0625q0.359375 0.0625 0.609375 0.15625q0.265625 0.09375 0.390625 0.171875l0 -0.375q0 -0.6875 -0.5 -1.09375q-0.484375 -0.421875 -1.1875 -0.421875q-0.5 0 -0.9375 0.234375q-0.4375 0.21875 -0.6875 0.609375l-0.78125 -0.578125q0.25 -0.359375 0.609375 -0.625q0.359375 -0.265625 0.8125 -0.40625q0.46875 -0.140625 0.984375 -0.140625q1.25 0 1.953125 0.671875q0.71875 0.65625 0.71875 1.765625l0 3.875l-0.984375 0l0 -0.875l-0.046875 0q-0.15625 0.265625 -0.453125 0.515625q-0.28125 0.234375 -0.671875 0.390625q-0.375 0.15625 -0.84375 0.15625zm0.09375 -0.890625q0.53125 0 0.96875 -0.265625q0.4375 -0.265625 0.6875 -0.703125q0.265625 -0.453125 0.265625 -0.984375q-0.265625 -0.1875 -0.6875 -0.296875q-0.40625 -0.125 -0.90625 -0.125q-0.875 0 -1.28125 0.359375q-0.40625 0.359375 -0.40625 0.875q0 0.515625 0.375 0.828125q0.390625 0.3125 0.984375 0.3125zm4.30954 0.703125l0 -6.125l0.984375 0l0 0.90625l0.046875 0q0.234375 -0.4375 0.78125 -0.765625q0.546875 -0.328125 1.1875 -0.328125q1.140625 0 1.703125 0.65625q0.578125 0.65625 0.578125 1.734375l0 3.921875l-1.03125 0l0 -3.765625q0 -0.890625 -0.421875 -1.25q-0.421875 -0.375 -1.09375 -0.375q-0.515625 0 -0.90625 0.28125q-0.375 0.28125 -0.59375 0.734375q-0.203125 0.4375 -0.203125 0.9375l0 3.4375l-1.03125 0zm8.640778 0.1875q-0.6875 0 -1.203125 -0.265625q-0.515625 -0.265625 -0.8125 -0.71875q-0.296875 -0.46875 -0.296875 -1.046875q0 -0.671875 0.34375 -1.125q0.359375 -0.46875 0.9375 -0.703125q0.59375 -0.234375 1.296875 -0.234375q0.40625 0 0.75 0.0625q0.359375 0.0625 0.609375 0.15625q0.265625 0.09375 0.390625 0.171875l0 -0.375q0 -0.6875 -0.5 -1.09375q-0.484375 -0.421875 -1.1875 -0.421875q-0.5 0 -0.9375 0.234375q-0.4375 0.21875 -0.6875 0.609375l-0.78125 -0.578125q0.25 -0.359375 0.609375 -0.625q0.359375 -0.265625 0.8125 -0.40625q0.46875 -0.140625 0.984375 -0.140625q1.25 0 1.953125 0.671875q0.71875 0.65625 0.71875 1.765625l0 3.875l-0.984375 0l0 -0.875l-0.046875 0q-0.15625 0.265625 -0.453125 0.515625q-0.28125 0.234375 -0.671875 0.390625q-0.375 0.15625 -0.84375 0.15625zm0.09375 -0.890625q0.53125 0 0.96875 -0.265625q0.4375 -0.265625 0.6875 -0.703125q0.265625 -0.453125 0.265625 -0.984375q-0.265625 -0.1875 -0.6875 -0.296875q-0.40625 -0.125 -0.90625 -0.125q-0.875 0 -1.28125 0.359375q-0.40625 0.359375 -0.40625 0.875q0 0.515625 0.375 0.828125q0.390625 0.3125 0.984375 0.3125zm6.937042 3.484375q-0.78125 0 -1.34375 -0.265625q-0.546875 -0.25 -0.890625 -0.65625q-0.34375 -0.390625 -0.484375 -0.796875l0.9375 -0.390625q0.1875 0.5 0.640625 0.84375q0.46875 0.34375 1.140625 0.34375q0.96875 0 1.484375 -0.5625q0.515625 -0.546875 0.515625 -1.546875l0 -0.6875l-0.046875 0q-0.296875 0.453125 -0.84375 0.765625q-0.53125 0.296875 -1.25 0.296875q-0.78125 0 -1.4375 -0.40625q-0.65625 -0.421875 -1.046875 -1.140625q-0.375 -0.71875 -0.375 -1.671875q0 -0.953125 0.375 -1.671875q0.390625 -0.734375 1.046875 -1.140625q0.65625 -0.40625 1.4375 -0.40625q0.71875 0 1.25 0.3125q0.546875 0.296875 0.84375 0.75l0.046875 0l0 -0.875l0.96875 0l0 5.890625q0 1.015625 -0.390625 1.6875q-0.390625 0.671875 -1.0625 1.0q-0.65625 0.328125 -1.515625 0.328125zm0 -3.578125q0.546875 0 1.0 -0.265625q0.453125 -0.28125 0.71875 -0.796875q0.28125 -0.515625 0.28125 -1.234375q0 -0.75 -0.28125 -1.25q-0.265625 -0.515625 -0.71875 -0.78125q-0.453125 -0.265625 -1.0 -0.265625q-0.53125 0 -1.0 0.28125q-0.453125 0.265625 -0.734375 0.78125q-0.265625 0.5 -0.265625 1.234375q0 0.734375 0.265625 1.25q0.28125 0.5 0.734375 0.78125q0.46875 0.265625 1.0 0.265625zm7.15094 0.984375q-0.890625 0 -1.578125 -0.40625q-0.6875 -0.421875 -1.078125 -1.15625q-0.390625 -0.734375 -0.390625 -1.671875q0 -0.875 0.359375 -1.609375q0.359375 -0.75 1.03125 -1.203125q0.671875 -0.453125 1.5625 -0.453125q0.921875 0 1.5625 0.40625q0.65625 0.390625 1.015625 1.109375q0.359375 0.703125 0.359375 1.609375q0 0.09375 -0.015625 0.1875q0 0.078125 -0.015625 0.125l-5.265625 0l0 -0.828125l4.21875 0q-0.015625 -0.25 -0.125 -0.546875q-0.09375 -0.296875 -0.328125 -0.546875q-0.21875 -0.265625 -0.5625 -0.421875q-0.328125 -0.171875 -0.84375 -0.171875q-0.59375 0 -1.03125 0.3125q-0.4375 0.296875 -0.671875 0.828125q-0.234375 0.53125 -0.234375 1.203125q0 0.78125 0.296875 1.296875q0.296875 0.515625 0.765625 0.765625q0.484375 0.25 1.0 0.25q0.671875 0 1.109375 -0.3125q0.4375 -0.328125 0.703125 -0.796875l0.859375 0.421875q-0.359375 0.703125 -1.03125 1.15625q-0.671875 0.453125 -1.671875 0.453125zm4.0216675 -0.1875l0 -6.125l0.984375 0l0 0.984375l0.046875 0q0.109375 -0.34375 0.390625 -0.59375q0.28125 -0.265625 0.640625 -0.40625q0.375 -0.15625 0.734375 -0.15625q0.28125 0 0.4375 0.03125q0.15625 0.03125 0.28125 0.078125l0 1.109375q-0.1875 -0.09375 -0.40625 -0.140625q-0.21875 -0.046875 -0.453125 -0.046875q-0.4375 0 -0.8125 0.25q-0.375 0.25 -0.59375 0.671875q-0.21875 0.421875 -0.21875 0.921875l0 3.421875l-1.03125 0z" fill-rule="nonzero"/><path fill="#a2c4c9" d="m13.553075 235.04298l0 0c0 -4.8590393 3.9390326 -8.798065 8.798076 -8.798065l43.85267 0c2.3333893 0 4.5712204 0.92692566 6.221176 2.576889c1.6499634 1.6499634 2.5768967 3.8877869 2.5768967 6.221176l0 35.19124c0 4.85907 -3.9390335 8.798096 -8.798073 8.798096l-43.85267 0c-4.859043 0 -8.798076 -3.9390259 -8.798076 -8.798096z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m13.553075 235.04298l0 0c0 -4.8590393 3.9390326 -8.798065 8.798076 -8.798065l43.85267 0c2.3333893 0 4.5712204 0.92692566 6.221176 2.576889c1.6499634 1.6499634 2.5768967 3.8877869 2.5768967 6.221176l0 35.19124c0 4.85907 -3.9390335 8.798096 -8.798073 8.798096l-43.85267 0c-4.859043 0 -8.798076 -3.9390259 -8.798076 -8.798096z" fill-rule="evenodd"/><path fill="#000000" d="m27.098484 257.1586l0 -8.593735l1.03125 0l0 7.6249847l3.75 0l0 0.96875l-4.78125 0zm5.7017975 0l0 -1.015625q0.03125 -0.046875 0.28125 -0.29685974q0.25 -0.25 0.625 -0.625q0.375 -0.375 0.78125 -0.78125q0.40625 -0.421875 0.75 -0.78125q0.359375 -0.375 0.5625 -0.609375q0.375 -0.40625 0.59375 -0.6875q0.234375 -0.296875 0.34375 -0.578125q0.109375 -0.28125 0.109375 -0.65625q0 -0.359375 -0.1875 -0.671875q-0.171875 -0.3125 -0.515625 -0.515625q-0.34375 -0.203125 -0.859375 -0.203125q-0.46875 0 -0.8125 0.203125q-0.328125 0.203125 -0.515625 0.484375q-0.171875 0.28125 -0.234375 0.5l-0.921875 -0.359375q0.078125 -0.265625 0.265625 -0.5625q0.1875 -0.3125 0.484375 -0.59375q0.3125 -0.28125 0.75 -0.46875q0.4375 -0.1875 1.015625 -0.1875q0.78125 0 1.34375 0.34375q0.578125 0.328125 0.890625 0.859375q0.328125 0.53125 0.328125 1.15625q0 0.53125 -0.203125 1.03125q-0.203125 0.484375 -0.5 0.875q-0.296875 0.390625 -0.609375 0.703125q-0.15625 0.15625 -0.4375 0.4375q-0.28125 0.265625 -0.59375 0.59375q-0.3125 0.3125 -0.609375 0.609375q-0.296875 0.296875 -0.515625 0.53125q-0.21875 0.21873474 -0.3125 0.29685974l0 0l3.875 0l0 0.96875l-5.171875 0zm10.749542 0.1875q-0.9375 0 -1.75 -0.328125q-0.8125 -0.34375 -1.421875 -0.953125q-0.59375 -0.60935974 -0.9375 -1.4218597q-0.328125 -0.828125 -0.328125 -1.78125q0 -0.953125 0.328125 -1.765625q0.34375 -0.828125 0.9375 -1.421875q0.609375 -0.609375 1.421875 -0.953125q0.8125 -0.34375 1.75 -0.34375q0.671875 0 1.234375 0.171875q0.578125 0.15625 1.046875 0.46875q0.484375 0.3125 0.875 0.765625l-0.734375 0.703125q-0.328125 -0.390625 -0.703125 -0.640625q-0.359375 -0.265625 -0.78125 -0.375q-0.421875 -0.125 -0.9375 -0.125q-0.921875 0 -1.703125 0.4375q-0.765625 0.421875 -1.234375 1.21875q-0.46875 0.78125 -0.46875 1.859375q0 1.0625 0.46875 1.859375q0.46875 0.796875 1.234375 1.234375q0.78125 0.42185974 1.703125 0.42185974q0.578125 0 1.046875 -0.15625q0.46875 -0.15625 0.875 -0.43748474q0.40625 -0.296875 0.734375 -0.6875l0.75 0.71875q-0.375 0.43748474 -0.90625 0.79685974q-0.515625 0.34375 -1.140625 0.546875q-0.625 0.1875 -1.359375 0.1875zm4.0951843 -0.1875l3.25 -8.593735l1.15625 0l3.265625 8.593735l-1.109375 0l-2.375 -6.4218597l-0.328125 -0.921875l-0.046875 0l-0.34375 0.921875l-2.359375 6.4218597l-1.109375 0zm3.71875 -2.3593597l0 -0.96875l1.96875 0l0.359375 0.96875l-2.328125 0zm-2.328125 0l0.34375 -0.96875l1.984375 0l0 0.96875l-2.328125 0zm7.4150543 2.3593597l0 -8.593735l2.90625 0q0.71875 0 1.328125 0.328125q0.609375 0.328125 0.96875 0.90625q0.375 0.5625 0.375 1.3125q0 0.75 -0.375 1.328125q-0.359375 0.5625 -0.96875 0.890625q-0.609375 0.328125 -1.328125 0.328125l-2.359375 0l0 -0.96875l2.375 0q0.5 0 0.859375 -0.234375q0.359375 -0.234375 0.5625 -0.59375q0.203125 -0.359375 0.203125 -0.75q0 -0.390625 -0.203125 -0.75q-0.203125 -0.359375 -0.5625 -0.59375q-0.359375 -0.234375 -0.859375 -0.234375l-1.890625 0l0 7.6249847l-1.03125 0z" fill-rule="nonzero"/><path fill="#a2c4c9" d="m334.243 235.04298l0 0c0 -4.8590393 3.9390259 -8.798065 8.798065 -8.798065l43.85269 0c2.333374 0 4.5711975 0.92692566 6.221161 2.576889c1.6499634 1.6499634 2.5769043 3.8877869 2.5769043 6.221176l0 35.19124c0 4.85907 -3.9390259 8.798096 -8.798065 8.798096l-43.85269 0c-4.8590393 0 -8.798065 -3.9390259 -8.798065 -8.798096z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m334.243 235.04298l0 0c0 -4.8590393 3.9390259 -8.798065 8.798065 -8.798065l43.85269 0c2.333374 0 4.5711975 0.92692566 6.221161 2.576889c1.6499634 1.6499634 2.5769043 3.8877869 2.5769043 6.221176l0 35.19124c0 4.85907 -3.9390259 8.798096 -8.798065 8.798096l-43.85269 0c-4.8590393 0 -8.798065 -3.9390259 -8.798065 -8.798096z" fill-rule="evenodd"/><path fill="#000000" d="m357.28073 257.3461q-0.625 0 -1.234375 -0.265625q-0.609375 -0.265625 -1.078125 -0.78125q-0.46875 -0.51560974 -0.6875 -1.2812347l0.96875 -0.390625q0.203125 0.75 0.734375 1.25q0.546875 0.49998474 1.328125 0.49998474q0.46875 0 0.875 -0.171875q0.40625 -0.171875 0.640625 -0.49998474q0.25 -0.34375 0.25 -0.828125q0 -0.4375 -0.21875 -0.734375q-0.203125 -0.296875 -0.625 -0.53125q-0.40625 -0.234375 -1.03125 -0.453125l-0.53125 -0.1875q-0.359375 -0.125 -0.734375 -0.3125q-0.359375 -0.1875 -0.671875 -0.453125q-0.296875 -0.28125 -0.484375 -0.65625q-0.171875 -0.375 -0.171875 -0.890625q0 -0.625 0.328125 -1.140625q0.34375 -0.515625 0.921875 -0.828125q0.59375 -0.3125 1.359375 -0.3125q0.8125 0 1.359375 0.296875q0.546875 0.28125 0.859375 0.6875q0.3125 0.40625 0.421875 0.734375l-0.953125 0.421875q-0.0625 -0.265625 -0.265625 -0.53125q-0.203125 -0.265625 -0.546875 -0.453125q-0.34375 -0.1875 -0.859375 -0.1875q-0.421875 0 -0.796875 0.171875q-0.359375 0.171875 -0.578125 0.46875q-0.21875 0.28125 -0.21875 0.671875q0 0.53125 0.421875 0.84375q0.4375 0.3125 1.171875 0.5625l0.5625 0.203125q0.390625 0.125 0.78125 0.328125q0.40625 0.1875 0.75 0.484375q0.359375 0.296875 0.5625 0.734375q0.21875 0.4375 0.21875 1.046875q0 0.671875 -0.265625 1.1406097q-0.25 0.46875 -0.671875 0.78125q-0.40625 0.296875 -0.90625 0.421875q-0.5 0.140625 -0.984375 0.140625zm4.337799 -0.1875l0 -8.593735l2.59375 0q1.34375 0 2.3125 0.546875q0.984375 0.546875 1.5 1.515625q0.53125 0.96875 0.53125 2.234375q0 1.265625 -0.53125 2.234375q-0.515625 0.95310974 -1.5 1.5156097q-0.96875 0.546875 -2.3125 0.546875l-2.59375 0zm1.03125 -0.96875l1.5625 0q1.015625 0 1.75 -0.39060974q0.75 -0.390625 1.15625 -1.125q0.40625 -0.75 0.40625 -1.8125q0 -1.0625 -0.40625 -1.796875q-0.40625 -0.75 -1.15625 -1.140625q-0.734375 -0.390625 -1.75 -0.390625l-1.5625 0l0 6.6562347zm7.4048157 0.96875l0 -8.593735l2.90625 0q0.71875 0 1.328125 0.328125q0.609375 0.328125 0.96875 0.90625q0.375 0.5625 0.375 1.3125q0 0.75 -0.375 1.328125q-0.359375 0.5625 -0.96875 0.890625q-0.609375 0.328125 -1.328125 0.328125l-2.359375 0l0 -0.96875l2.375 0q0.5 0 0.859375 -0.234375q0.359375 -0.234375 0.5625 -0.59375q0.203125 -0.359375 0.203125 -0.75q0 -0.390625 -0.203125 -0.75q-0.203125 -0.359375 -0.5625 -0.59375q-0.359375 -0.234375 -0.859375 -0.234375l-1.890625 0l0 7.6249847l-1.03125 0z" fill-rule="nonzero"/><path fill="#a2c4c9" d="m398.381 235.04298l0 0c0 -4.8590393 3.9390259 -8.798065 8.798065 -8.798065l43.947144 0c2.3334045 0 4.571228 0.92692566 6.2211914 2.576889c1.6499634 1.6499634 2.5769043 3.8877869 2.5769043 6.221176l0 35.19124c0 4.85907 -3.9390564 8.798096 -8.798096 8.798096l-43.947144 0c-4.8590393 0 -8.798065 -3.9390259 -8.798065 -8.798096z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m398.381 235.04298l0 0c0 -4.8590393 3.9390259 -8.798065 8.798065 -8.798065l43.947144 0c2.3334045 0 4.571228 0.92692566 6.2211914 2.576889c1.6499634 1.6499634 2.5769043 3.8877869 2.5769043 6.221176l0 35.19124c0 4.85907 -3.9390564 8.798096 -8.798096 8.798096l-43.947144 0c-4.8590393 0 -8.798065 -3.9390259 -8.798065 -8.798096z" fill-rule="evenodd"/><path fill="#000000" d="m405.1216 257.1586l0 -8.593735l2.90625 0q0.71875 0 1.328125 0.328125q0.609375 0.328125 0.96875 0.90625q0.375 0.5625 0.375 1.3125q0 0.453125 -0.171875 0.90625q-0.171875 0.453125 -0.53125 0.828125q-0.34375 0.359375 -0.890625 0.59375q-0.546875 0.21875 -1.296875 0.21875l-2.140625 0l0 -0.953125l2.296875 0q0.453125 0 0.828125 -0.203125q0.390625 -0.203125 0.625 -0.5625q0.25 -0.359375 0.25 -0.828125q0 -0.390625 -0.203125 -0.75q-0.203125 -0.359375 -0.5625 -0.59375q-0.359375 -0.234375 -0.859375 -0.234375l-1.890625 0l0 7.6249847l-1.03125 0zm2.078125 -3.9374847l1.125 -0.0625l2.703125 3.9531097l0 0.046875l-1.203125 0l-2.625 -3.9374847zm4.9539185 3.9374847l0 -8.593735l4.96875 0l0 0.96875l-3.9375 0l0 7.6249847l-1.03125 0zm0.546875 -3.7187347l0 -0.96875l4.046875 0l0 0.96875l-4.046875 0zm9.73642 3.9062347q-0.9375 0 -1.75 -0.328125q-0.8125 -0.34375 -1.421875 -0.953125q-0.59375 -0.60935974 -0.9375 -1.4218597q-0.328125 -0.828125 -0.328125 -1.78125q0 -0.953125 0.328125 -1.765625q0.34375 -0.828125 0.9375 -1.421875q0.609375 -0.609375 1.421875 -0.953125q0.8125 -0.34375 1.75 -0.34375q0.671875 0 1.234375 0.171875q0.578125 0.15625 1.046875 0.46875q0.484375 0.3125 0.875 0.765625l-0.734375 0.703125q-0.328125 -0.390625 -0.703125 -0.640625q-0.359375 -0.265625 -0.78125 -0.375q-0.421875 -0.125 -0.9375 -0.125q-0.921875 0 -1.703125 0.4375q-0.765625 0.421875 -1.234375 1.21875q-0.46875 0.78125 -0.46875 1.859375q0 1.0625 0.46875 1.859375q0.46875 0.796875 1.234375 1.234375q0.78125 0.42185974 1.703125 0.42185974q0.578125 0 1.046875 -0.15625q0.46875 -0.15625 0.875 -0.43748474q0.40625 -0.296875 0.734375 -0.6875l0.75 0.71875q-0.375 0.43748474 -0.90625 0.79685974q-0.515625 0.34375 -1.140625 0.546875q-0.625 0.1875 -1.359375 0.1875zm7.2457886 0q-0.921875 0 -1.640625 -0.421875q-0.703125 -0.4375 -1.109375 -1.1718597q-0.390625 -0.734375 -0.390625 -1.65625q0 -0.90625 0.390625 -1.640625q0.40625 -0.75 1.109375 -1.171875q0.71875 -0.4375 1.640625 -0.4375q0.921875 0 1.625 0.4375q0.71875 0.4375 1.109375 1.1875q0.40625 0.734375 0.40625 1.625q0 0.921875 -0.40625 1.65625q-0.390625 0.73435974 -1.109375 1.1718597q-0.703125 0.421875 -1.625 0.421875zm0 -0.921875q0.546875 0 1.03125 -0.265625q0.484375 -0.28123474 0.78125 -0.79685974q0.3125 -0.53125 0.3125 -1.265625q0 -0.734375 -0.3125 -1.25q-0.296875 -0.53125 -0.78125 -0.796875q-0.484375 -0.28125 -1.03125 -0.28125q-0.546875 0 -1.046875 0.28125q-0.484375 0.265625 -0.796875 0.796875q-0.296875 0.515625 -0.296875 1.25q0 0.734375 0.296875 1.265625q0.3125 0.515625 0.796875 0.79685974q0.5 0.265625 1.046875 0.265625zm4.203949 0.734375l0 -6.1249847l0.984375 0l0 0.90625l0.046875 0q0.15625 -0.296875 0.453125 -0.546875q0.296875 -0.25 0.671875 -0.390625q0.375 -0.15625 0.78125 -0.15625q0.6875 0 1.171875 0.328125q0.5 0.328125 0.703125 0.859375q0.3125 -0.515625 0.84375 -0.84375q0.53125 -0.34375 1.265625 -0.34375q1.09375 0 1.609375 0.671875q0.515625 0.65625 0.515625 1.71875l0 3.9218597l-1.015625 0l0 -3.7656097q0 -0.890625 -0.359375 -1.25q-0.359375 -0.375 -1.015625 -0.375q-0.46875 0 -0.84375 0.28125q-0.359375 0.265625 -0.578125 0.703125q-0.203125 0.4375 -0.203125 0.953125l0 3.4531097l-1.015625 0l0 -3.7499847q0 -0.890625 -0.359375 -1.265625q-0.359375 -0.375 -1.015625 -0.375q-0.46875 0 -0.828125 0.28125q-0.359375 0.265625 -0.578125 0.71875q-0.203125 0.4375 -0.203125 0.953125l0 3.4374847l-1.03125 0zm10.500061 0l0 -6.1249847l0.984375 0l0 0.90625l0.046875 0q0.15625 -0.296875 0.453125 -0.546875q0.296875 -0.25 0.671875 -0.390625q0.375 -0.15625 0.78125 -0.15625q0.6875 0 1.171875 0.328125q0.5 0.328125 0.703125 0.859375q0.3125 -0.515625 0.84375 -0.84375q0.53125 -0.34375 1.265625 -0.34375q1.09375 0 1.609375 0.671875q0.515625 0.65625 0.515625 1.71875l0 3.9218597l-1.015625 0l0 -3.7656097q0 -0.890625 -0.359375 -1.25q-0.359375 -0.375 -1.015625 -0.375q-0.46875 0 -0.84375 0.28125q-0.359375 0.265625 -0.578125 0.703125q-0.203125 0.4375 -0.203125 0.953125l0 3.4531097l-1.015625 0l0 -3.7499847q0 -0.890625 -0.359375 -1.265625q-0.359375 -0.375 -1.015625 -0.375q-0.46875 0 -0.828125 0.28125q-0.359375 0.265625 -0.578125 0.71875q-0.203125 0.4375 -0.203125 0.953125l0 3.4374847l-1.03125 0z" fill-rule="nonzero"/><g filter="url(#shadowFilter-p.6)"><use xlink:href="#p.6" transform="matrix(1.0 0.0 0.0 1.0 0.0 2.0)"/></g><defs><filter id="shadowFilter-p.6" filterUnits="userSpaceOnUse"><feGaussianBlur in="SourceAlpha" stdDeviation="2.0" result="blur"/><feComponentTransfer in="blur" color-interpolation-filters="sRGB"><feFuncR type="linear" slope="0" intercept="0.0"/><feFuncG type="linear" slope="0" intercept="0.0"/><feFuncB type="linear" slope="0" intercept="0.0"/><feFuncA type="linear" slope="0.5" intercept="0"/></feComponentTransfer></filter></defs><g id="p.6"><path fill="#f6b26b" d="m1.2233764 468.88928l0 0c0 -5.2562256 4.2610183 -9.517242 9.517251 -9.517242l235.35919 0c2.5241394 0 4.9448853 1.0026855 6.729721 2.7875366c1.7848206 1.7848206 2.7875366 4.2055664 2.7875366 6.729706l0 38.06784c0 5.256256 -4.261017 9.517242 -9.517258 9.517242l-235.35919 0c-5.2562327 0 -9.517251 -4.2609863 -9.517251 -9.517242z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m1.2233764 468.88928l0 0c0 -5.2562256 4.2610183 -9.517242 9.517251 -9.517242l235.35919 0c2.5241394 0 4.9448853 1.0026855 6.729721 2.7875366c1.7848206 1.7848206 2.7875366 4.2055664 2.7875366 6.729706l0 38.06784c0 5.256256 -4.261017 9.517242 -9.517258 9.517242l-235.35919 0c-5.2562327 0 -9.517251 -4.2609863 -9.517251 -9.517242z" fill-rule="evenodd"/><path fill="#000000" d="m99.084404 494.0332q-1.265625 0 -2.34375 -0.453125q-1.078125 -0.453125 -1.890625 -1.25q-0.8125 -0.8125 -1.265625 -1.90625q-0.4375 -1.109375 -0.4375 -2.375q0 -1.28125 0.4375 -2.359375q0.453125 -1.09375 1.265625 -1.890625q0.8125 -0.8125 1.890625 -1.265625q1.078125 -0.46875 2.34375 -0.46875q0.875 0 1.640625 0.234375q0.765625 0.21875 1.40625 0.640625q0.640625 0.40625 1.140625 1.0l-0.96875 0.953125q-0.4375 -0.53125 -0.921875 -0.859375q-0.484375 -0.34375 -1.0625 -0.5q-0.5625 -0.171875 -1.234375 -0.171875q-1.234375 0 -2.28125 0.578125q-1.03125 0.578125 -1.65625 1.625q-0.625 1.046875 -0.625 2.484375q0 1.4375 0.625 2.5q0.625 1.046875 1.65625 1.625q1.046875 0.5625 2.28125 0.5625q0.75 0 1.375 -0.203125q0.640625 -0.203125 1.171875 -0.578125q0.546875 -0.390625 0.984375 -0.921875l1.0 0.953125q-0.5 0.59375 -1.203125 1.0625q-0.6875 0.46875 -1.53125 0.734375q-0.84375 0.25 -1.796875 0.25zm9.645386 0q-1.234375 0 -2.1875 -0.5625q-0.9375 -0.578125 -1.46875 -1.5625q-0.53125 -0.984375 -0.53125 -2.203125q0 -1.21875 0.53125 -2.203125q0.53125 -0.984375 1.46875 -1.5625q0.953125 -0.578125 2.1875 -0.578125q1.234375 0 2.171875 0.59375q0.953125 0.578125 1.484375 1.5625q0.53125 0.984375 0.53125 2.1875q0 1.21875 -0.53125 2.203125q-0.53125 0.984375 -1.484375 1.5625q-0.9375 0.5625 -2.171875 0.5625zm0 -1.21875q0.734375 0 1.375 -0.375q0.65625 -0.375 1.046875 -1.0625q0.40625 -0.703125 0.40625 -1.671875q0 -0.984375 -0.40625 -1.671875q-0.390625 -0.703125 -1.046875 -1.0625q-0.640625 -0.375 -1.375 -0.375q-0.734375 0 -1.390625 0.375q-0.65625 0.359375 -1.0625 1.0625q-0.390625 0.6875 -0.390625 1.671875q0 0.96875 0.390625 1.671875q0.40625 0.6875 1.0625 1.0625q0.65625 0.375 1.390625 0.375zm5.6260223 0.96875l0 -8.15625l1.28125 0l0 1.203125l0.078125 0q0.3125 -0.59375 1.03125 -1.03125q0.734375 -0.4375 1.609375 -0.4375q1.5 0 2.25 0.875q0.765625 0.875 0.765625 2.3125l0 5.234375l-1.359375 0l0 -5.03125q0 -1.171875 -0.578125 -1.65625q-0.5625 -0.5 -1.453125 -0.5q-0.671875 0 -1.1875 0.375q-0.515625 0.375 -0.796875 0.96875q-0.28125 0.59375 -0.28125 1.25l0 4.59375l-1.359375 0zm8.013519 -8.15625l4.78125 0l0 1.234375l-4.78125 0l0 -1.234375zm1.421875 6.015625l0 -8.328125l1.359375 0l0 7.984375q0 0.640625 0.265625 1.0q0.265625 0.34375 0.875 0.34375q0.265625 0 0.484375 -0.078125q0.234375 -0.078125 0.40625 -0.1875l0 1.328125q-0.203125 0.09375 -0.453125 0.140625q-0.25 0.0625 -0.671875 0.0625q-1.015625 0 -1.640625 -0.59375q-0.625 -0.609375 -0.625 -1.671875zm4.980629 2.140625l0 -8.15625l1.28125 0l0 1.3125l0.078125 0q0.15625 -0.46875 0.53125 -0.8125q0.375 -0.34375 0.859375 -0.546875q0.484375 -0.203125 0.96875 -0.203125q0.375 0 0.578125 0.046875q0.203125 0.046875 0.390625 0.125l0 1.46875q-0.265625 -0.125 -0.5625 -0.1875q-0.296875 -0.078125 -0.59375 -0.078125q-0.59375 0 -1.09375 0.34375q-0.5 0.328125 -0.796875 0.890625q-0.28125 0.5625 -0.28125 1.234375l0 4.5625l-1.359375 0zm9.27002 0.25q-1.234375 0 -2.1875 -0.5625q-0.9375 -0.578125 -1.46875 -1.5625q-0.53125 -0.984375 -0.53125 -2.203125q0 -1.21875 0.53125 -2.203125q0.53125 -0.984375 1.46875 -1.5625q0.953125 -0.578125 2.1875 -0.578125q1.234375 0 2.171875 0.59375q0.953125 0.578125 1.484375 1.5625q0.53125 0.984375 0.53125 2.1875q0 1.21875 -0.53125 2.203125q-0.53125 0.984375 -1.484375 1.5625q-0.9375 0.5625 -2.171875 0.5625zm0 -1.21875q0.734375 0 1.375 -0.375q0.65625 -0.375 1.046875 -1.0625q0.40625 -0.703125 0.40625 -1.671875q0 -0.984375 -0.40625 -1.671875q-0.390625 -0.703125 -1.046875 -1.0625q-0.640625 -0.375 -1.375 -0.375q-0.734375 0 -1.390625 0.375q-0.65625 0.359375 -1.0625 1.0625q-0.390625 0.6875 -0.390625 1.671875q0 0.96875 0.390625 1.671875q0.40625 0.6875 1.0625 1.0625q0.65625 0.375 1.390625 0.375zm5.706024 0.96875l0 -11.453125l1.359375 0l0 11.453125l-1.359375 0zm3.376007 0l0 -11.453125l1.359375 0l0 11.453125l-1.359375 0zm6.9210052 0.25q-1.1875 0 -2.109375 -0.546875q-0.921875 -0.5625 -1.4375 -1.53125q-0.515625 -0.984375 -0.515625 -2.234375q0 -1.171875 0.484375 -2.15625q0.484375 -1.0 1.375 -1.59375q0.890625 -0.609375 2.09375 -0.609375q1.21875 0 2.078125 0.546875q0.875 0.53125 1.34375 1.484375q0.484375 0.9375 0.484375 2.15625q0 0.109375 -0.015625 0.21875q0 0.109375 -0.015625 0.1875l-7.03125 0l0 -1.109375l5.609375 0q-0.015625 -0.34375 -0.15625 -0.734375q-0.125 -0.390625 -0.421875 -0.734375q-0.296875 -0.34375 -0.75 -0.5625q-0.453125 -0.21875 -1.125 -0.21875q-0.796875 0 -1.390625 0.40625q-0.578125 0.40625 -0.890625 1.125q-0.3125 0.703125 -0.3125 1.59375q0 1.03125 0.390625 1.734375q0.40625 0.6875 1.03125 1.03125q0.640625 0.328125 1.328125 0.328125q0.890625 0 1.46875 -0.421875q0.59375 -0.4375 0.953125 -1.0625l1.140625 0.5625q-0.46875 0.9375 -1.375 1.546875q-0.890625 0.59375 -2.234375 0.59375zm5.383011 -0.25l0 -8.15625l1.28125 0l0 1.3125l0.078125 0q0.15625 -0.46875 0.53125 -0.8125q0.375 -0.34375 0.859375 -0.546875q0.484375 -0.203125 0.96875 -0.203125q0.375 0 0.578125 0.046875q0.203125 0.046875 0.390625 0.125l0 1.46875q-0.265625 -0.125 -0.5625 -0.1875q-0.296875 -0.078125 -0.59375 -0.078125q-0.59375 0 -1.09375 0.34375q-0.5 0.328125 -0.796875 0.890625q-0.28125 0.5625 -0.28125 1.234375l0 4.5625l-1.359375 0z" fill-rule="nonzero"/></g><g filter="url(#shadowFilter-p.7)"><use xlink:href="#p.7" transform="matrix(1.0 0.0 0.0 1.0 0.0 2.0)"/></g><defs><filter id="shadowFilter-p.7" filterUnits="userSpaceOnUse"><feGaussianBlur in="SourceAlpha" stdDeviation="2.0" result="blur"/><feComponentTransfer in="blur" color-interpolation-filters="sRGB"><feFuncR type="linear" slope="0" intercept="0.0"/><feFuncG type="linear" slope="0" intercept="0.0"/><feFuncB type="linear" slope="0" intercept="0.0"/><feFuncA type="linear" slope="0.5" intercept="0"/></feComponentTransfer></filter></defs><g id="p.7"><path fill="#f6b26b" d="m4.684006 544.50085l0 0c0 -5.2562866 4.2610183 -9.517273 9.51725 -9.517273l235.35919 0c2.5241394 0 4.9448853 1.0026855 6.729706 2.7875366c1.7848511 1.7848511 2.7875366 4.2055664 2.7875366 6.7297363l0 38.06781c0 5.2562256 -4.2610016 9.517273 -9.517242 9.517273l-235.35919 0c-5.2562323 0 -9.51725 -4.2610474 -9.51725 -9.517273z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m4.684006 544.50085l0 0c0 -5.2562866 4.2610183 -9.517273 9.51725 -9.517273l235.35919 0c2.5241394 0 4.9448853 1.0026855 6.729706 2.7875366c1.7848511 1.7848511 2.7875366 4.2055664 2.7875366 6.7297363l0 38.06781c0 5.2562256 -4.2610016 9.517273 -9.517242 9.517273l-235.35919 0c-5.2562323 0 -9.51725 -4.2610474 -9.51725 -9.517273z" fill-rule="evenodd"/><path fill="#000000" d="m112.98605 569.3948l0 -11.453125l3.875 0q0.953125 0 1.765625 0.4375q0.8125 0.421875 1.296875 1.1875q0.484375 0.75 0.484375 1.765625q0 0.609375 -0.234375 1.21875q-0.21875 0.59375 -0.6875 1.09375q-0.46875 0.484375 -1.203125 0.78125q-0.71875 0.296875 -1.734375 0.296875l-2.84375 0l0 -1.265625l3.078125 0q0.578125 0 1.09375 -0.265625q0.515625 -0.28125 0.828125 -0.75q0.328125 -0.484375 0.328125 -1.109375q0 -0.515625 -0.265625 -0.984375q-0.265625 -0.484375 -0.75 -0.796875q-0.46875 -0.3125 -1.140625 -0.3125l-2.53125 0l0 10.15625l-1.359375 0zm2.765625 -5.25l1.484375 -0.078125l3.625 5.265625l0 0.0625l-1.609375 0l-3.5 -5.25zm8.794525 5.5q-0.90625 0 -1.59375 -0.34375q-0.6875 -0.359375 -1.078125 -0.96875q-0.390625 -0.625 -0.390625 -1.40625q0 -0.890625 0.453125 -1.5q0.46875 -0.625 1.25 -0.9375q0.796875 -0.3125 1.734375 -0.3125q0.546875 0 1.0 0.09375q0.46875 0.078125 0.8125 0.203125q0.34375 0.125 0.515625 0.234375l0 -0.5q0 -0.921875 -0.65625 -1.46875q-0.640625 -0.546875 -1.59375 -0.546875q-0.671875 0 -1.265625 0.296875q-0.578125 0.296875 -0.90625 0.828125l-1.03125 -0.765625q0.328125 -0.484375 0.796875 -0.828125q0.484375 -0.359375 1.09375 -0.546875q0.625 -0.203125 1.3125 -0.203125q1.671875 0 2.609375 0.890625q0.9375 0.875 0.9375 2.359375l0 5.171875l-1.296875 0l0 -1.171875l-0.0625 0q-0.203125 0.359375 -0.59375 0.6875q-0.375 0.328125 -0.90625 0.53125q-0.515625 0.203125 -1.140625 0.203125zm0.140625 -1.1875q0.703125 0 1.28125 -0.34375q0.578125 -0.359375 0.921875 -0.953125q0.359375 -0.59375 0.359375 -1.296875q-0.359375 -0.265625 -0.921875 -0.421875q-0.546875 -0.15625 -1.203125 -0.15625q-1.15625 0 -1.703125 0.484375q-0.546875 0.46875 -0.546875 1.171875q0 0.671875 0.5 1.09375q0.515625 0.421875 1.3125 0.421875zm9.150391 1.1875q-1.109375 0 -2.0 -0.546875q-0.890625 -0.5625 -1.40625 -1.53125q-0.5 -0.984375 -0.5 -2.25q0 -1.265625 0.5 -2.234375q0.515625 -0.984375 1.40625 -1.546875q0.890625 -0.5625 2.0 -0.5625q0.65625 0 1.1875 0.21875q0.546875 0.203125 0.953125 0.546875q0.421875 0.328125 0.640625 0.71875l0.0625 0l-0.0625 -1.140625l0 -3.375l1.359375 0l0 11.453125l-1.296875 0l0 -1.203125l-0.0625 0q-0.21875 0.375 -0.640625 0.71875q-0.40625 0.328125 -0.953125 0.53125q-0.53125 0.203125 -1.1875 0.203125zm0.140625 -1.21875q0.703125 0 1.3125 -0.375q0.625 -0.390625 1.0 -1.078125q0.390625 -0.703125 0.390625 -1.65625q0 -0.96875 -0.390625 -1.65625q-0.375 -0.703125 -1.0 -1.078125q-0.609375 -0.375 -1.3125 -0.375q-0.703125 0 -1.328125 0.375q-0.609375 0.375 -1.0 1.078125q-0.375 0.6875 -0.375 1.65625q0 0.9375 0.375 1.640625q0.390625 0.703125 1.0 1.09375q0.625 0.375 1.328125 0.375zm6.147644 0.96875l0 -8.15625l1.359375 0l0 8.15625l-1.359375 0zm0.671875 -9.65625q-0.40625 0 -0.703125 -0.28125q-0.28125 -0.296875 -0.28125 -0.703125q0 -0.421875 0.28125 -0.6875q0.296875 -0.28125 0.703125 -0.28125q0.40625 0 0.6875 0.28125q0.28125 0.265625 0.28125 0.6875q0 0.40625 -0.28125 0.703125q-0.28125 0.28125 -0.6875 0.28125zm6.4891357 9.90625q-1.234375 0 -2.1875 -0.5625q-0.9375 -0.578125 -1.46875 -1.5625q-0.53125 -0.984375 -0.53125 -2.203125q0 -1.21875 0.53125 -2.203125q0.53125 -0.984375 1.46875 -1.5625q0.953125 -0.578125 2.1875 -0.578125q1.234375 0 2.171875 0.59375q0.953125 0.578125 1.484375 1.5625q0.53125 0.984375 0.53125 2.1875q0 1.21875 -0.53125 2.203125q-0.53125 0.984375 -1.484375 1.5625q-0.9375 0.5625 -2.171875 0.5625zm0 -1.21875q0.734375 0 1.375 -0.375q0.65625 -0.375 1.046875 -1.0625q0.40625 -0.703125 0.40625 -1.671875q0 -0.984375 -0.40625 -1.671875q-0.390625 -0.703125 -1.046875 -1.0625q-0.640625 -0.375 -1.375 -0.375q-0.734375 0 -1.390625 0.375q-0.65625 0.359375 -1.0625 1.0625q-0.390625 0.6875 -0.390625 1.671875q0 0.96875 0.390625 1.671875q0.40625 0.6875 1.0625 1.0625q0.65625 0.375 1.390625 0.375z" fill-rule="nonzero"/></g><g filter="url(#shadowFilter-p.8)"><use xlink:href="#p.8" transform="matrix(1.0 0.0 0.0 1.0 0.0 2.0)"/></g><defs><filter id="shadowFilter-p.8" filterUnits="userSpaceOnUse"><feGaussianBlur in="SourceAlpha" stdDeviation="2.0" result="blur"/><feComponentTransfer in="blur" color-interpolation-filters="sRGB"><feFuncR type="linear" slope="0" intercept="0.0"/><feFuncG type="linear" slope="0" intercept="0.0"/><feFuncB type="linear" slope="0" intercept="0.0"/><feFuncA type="linear" slope="0.5" intercept="0"/></feComponentTransfer></filter></defs><g id="p.8"><path fill="#1155cc" d="m274.31787 468.88928l0 0c0 -5.2562256 4.261017 -9.517242 9.517242 -9.517242l234.94974 0c2.52417 0 4.9448853 1.0026855 6.7297363 2.7875366c1.7848511 1.7848206 2.7875366 4.2055664 2.7875366 6.729706l0 38.06784c0 5.256256 -4.2610474 9.517242 -9.517273 9.517242l-234.94974 0c-5.2562256 0 -9.517242 -4.2609863 -9.517242 -9.517242z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m274.31787 468.88928l0 0c0 -5.2562256 4.261017 -9.517242 9.517242 -9.517242l234.94974 0c2.52417 0 4.9448853 1.0026855 6.7297363 2.7875366c1.7848511 1.7848206 2.7875366 4.2055664 2.7875366 6.729706l0 38.06784c0 5.256256 -4.2610474 9.517242 -9.517273 9.517242l-234.94974 0c-5.2562256 0 -9.517242 -4.2609863 -9.517242 -9.517242z" fill-rule="evenodd"/><path fill="#000000" d="m344.86313 493.7832l-4.0625 -11.453125l1.515625 0l2.828125 8.296875l0.375 1.140625l0.078125 0l0.390625 -1.140625l2.96875 -8.296875l1.5 0l-4.1875 11.453125l-1.40625 0zm6.635376 0l0 -8.15625l1.359375 0l0 8.15625l-1.359375 0zm0.671875 -9.65625q-0.40625 0 -0.703125 -0.28125q-0.28125 -0.296875 -0.28125 -0.703125q0 -0.421875 0.28125 -0.6875q0.296875 -0.28125 0.703125 -0.28125q0.40625 0 0.6875 0.28125q0.28125 0.265625 0.28125 0.6875q0 0.40625 -0.28125 0.703125q-0.28125 0.28125 -0.6875 0.28125zm2.8191528 9.65625l0 -8.15625l1.28125 0l0 1.296875l0.078125 0q0.203125 -0.5 0.578125 -0.828125q0.375 -0.34375 0.875 -0.515625q0.515625 -0.1875 1.03125 -0.1875q0.234375 0 0.34375 0.015625q0.125 0 0.234375 0.03125l0 1.40625q-0.15625 -0.03125 -0.34375 -0.046875q-0.171875 -0.03125 -0.390625 -0.03125q-0.6875 0 -1.21875 0.3125q-0.53125 0.3125 -0.828125 0.875q-0.28125 0.5625 -0.28125 1.296875l0 4.53125l-1.359375 0zm5.5 -8.15625l4.78125 0l0 1.234375l-4.78125 0l0 -1.234375zm1.421875 6.015625l0 -8.328125l1.359375 0l0 7.984375q0 0.640625 0.265625 1.0q0.265625 0.34375 0.875 0.34375q0.265625 0 0.484375 -0.078125q0.234375 -0.078125 0.40625 -0.1875l0 1.328125q-0.203125 0.09375 -0.453125 0.140625q-0.25 0.0625 -0.671875 0.0625q-1.015625 0 -1.640625 -0.59375q-0.625 -0.609375 -0.625 -1.671875zm7.9512634 2.390625q-1.5 0 -2.265625 -0.875q-0.765625 -0.875 -0.765625 -2.40625l0 -5.125l1.359375 0l0 4.921875q0 1.21875 0.5625 1.75q0.5625 0.515625 1.390625 0.515625q0.71875 0 1.25 -0.375q0.53125 -0.390625 0.8125 -0.96875q0.296875 -0.59375 0.296875 -1.234375l0 -4.609375l1.359375 0l0 8.15625l-1.296875 0l0 -1.1875l-0.0625 0q-0.203125 0.390625 -0.625 0.71875q-0.40625 0.328125 -0.921875 0.515625q-0.515625 0.203125 -1.09375 0.203125zm8.536652 0q-0.90625 0 -1.59375 -0.34375q-0.6875 -0.359375 -1.078125 -0.96875q-0.390625 -0.625 -0.390625 -1.40625q0 -0.890625 0.453125 -1.5q0.46875 -0.625 1.25 -0.9375q0.796875 -0.3125 1.734375 -0.3125q0.546875 0 1.0 0.09375q0.46875 0.078125 0.8125 0.203125q0.34375 0.125 0.515625 0.234375l0 -0.5q0 -0.921875 -0.65625 -1.46875q-0.640625 -0.546875 -1.59375 -0.546875q-0.671875 0 -1.265625 0.296875q-0.578125 0.296875 -0.90625 0.828125l-1.03125 -0.765625q0.328125 -0.484375 0.796875 -0.828125q0.484375 -0.359375 1.09375 -0.546875q0.625 -0.203125 1.3125 -0.203125q1.671875 0 2.609375 0.890625q0.9375 0.875 0.9375 2.359375l0 5.171875l-1.296875 0l0 -1.171875l-0.0625 0q-0.203125 0.359375 -0.59375 0.6875q-0.375 0.328125 -0.90625 0.53125q-0.515625 0.203125 -1.140625 0.203125zm0.140625 -1.1875q0.703125 0 1.28125 -0.34375q0.578125 -0.359375 0.921875 -0.953125q0.359375 -0.59375 0.359375 -1.296875q-0.359375 -0.265625 -0.921875 -0.421875q-0.546875 -0.15625 -1.203125 -0.15625q-1.15625 0 -1.703125 0.484375q-0.546875 0.46875 -0.546875 1.171875q0 0.671875 0.5 1.09375q0.515625 0.421875 1.3125 0.421875zm5.761627 0.9375l0 -11.453125l1.359375 0l0 11.453125l-1.359375 0zm12.40863 0.25q-1.265625 0 -2.34375 -0.453125q-1.078125 -0.453125 -1.890625 -1.25q-0.8125 -0.8125 -1.265625 -1.90625q-0.4375 -1.109375 -0.4375 -2.375q0 -1.28125 0.4375 -2.359375q0.453125 -1.09375 1.265625 -1.890625q0.8125 -0.8125 1.890625 -1.265625q1.078125 -0.46875 2.34375 -0.46875q0.875 0 1.640625 0.234375q0.765625 0.21875 1.40625 0.640625q0.640625 0.40625 1.140625 1.0l-0.96875 0.953125q-0.4375 -0.53125 -0.921875 -0.859375q-0.484375 -0.34375 -1.0625 -0.5q-0.5625 -0.171875 -1.234375 -0.171875q-1.234375 0 -2.28125 0.578125q-1.03125 0.578125 -1.65625 1.625q-0.625 1.046875 -0.625 2.484375q0 1.4375 0.625 2.5q0.625 1.046875 1.65625 1.625q1.046875 0.5625 2.28125 0.5625q0.75 0 1.375 -0.203125q0.640625 -0.203125 1.171875 -0.578125q0.546875 -0.390625 0.984375 -0.921875l1.0 0.953125q-0.5 0.59375 -1.203125 1.0625q-0.6875 0.46875 -1.53125 0.734375q-0.84375 0.25 -1.796875 0.25zm9.645386 0q-1.234375 0 -2.1875 -0.5625q-0.9375 -0.578125 -1.46875 -1.5625q-0.53125 -0.984375 -0.53125 -2.203125q0 -1.21875 0.53125 -2.203125q0.53125 -0.984375 1.46875 -1.5625q0.953125 -0.578125 2.1875 -0.578125q1.234375 0 2.171875 0.59375q0.953125 0.578125 1.484375 1.5625q0.53125 0.984375 0.53125 2.1875q0 1.21875 -0.53125 2.203125q-0.53125 0.984375 -1.484375 1.5625q-0.9375 0.5625 -2.171875 0.5625zm0 -1.21875q0.734375 0 1.375 -0.375q0.65625 -0.375 1.046875 -1.0625q0.40625 -0.703125 0.40625 -1.671875q0 -0.984375 -0.40625 -1.671875q-0.390625 -0.703125 -1.046875 -1.0625q-0.640625 -0.375 -1.375 -0.375q-0.734375 0 -1.390625 0.375q-0.65625 0.359375 -1.0625 1.0625q-0.390625 0.6875 -0.390625 1.671875q0 0.96875 0.390625 1.671875q0.40625 0.6875 1.0625 1.0625q0.65625 0.375 1.390625 0.375zm5.6260376 0.96875l0 -8.15625l1.28125 0l0 1.203125l0.078125 0q0.3125 -0.59375 1.03125 -1.03125q0.734375 -0.4375 1.609375 -0.4375q1.5 0 2.25 0.875q0.765625 0.875 0.765625 2.3125l0 5.234375l-1.359375 0l0 -5.03125q0 -1.171875 -0.578125 -1.65625q-0.5625 -0.5 -1.453125 -0.5q-0.671875 0 -1.1875 0.375q-0.515625 0.375 -0.796875 0.96875q-0.28125 0.59375 -0.28125 1.25l0 4.59375l-1.359375 0zm8.013519 -8.15625l4.78125 0l0 1.234375l-4.78125 0l0 -1.234375zm1.421875 6.015625l0 -8.328125l1.359375 0l0 7.984375q0 0.640625 0.265625 1.0q0.265625 0.34375 0.875 0.34375q0.265625 0 0.484375 -0.078125q0.234375 -0.078125 0.40625 -0.1875l0 1.328125q-0.203125 0.09375 -0.453125 0.140625q-0.25 0.0625 -0.671875 0.0625q-1.015625 0 -1.640625 -0.59375q-0.625 -0.609375 -0.625 -1.671875zm4.9806213 2.140625l0 -8.15625l1.28125 0l0 1.3125l0.078125 0q0.15625 -0.46875 0.53125 -0.8125q0.375 -0.34375 0.859375 -0.546875q0.484375 -0.203125 0.96875 -0.203125q0.375 0 0.578125 0.046875q0.203125 0.046875 0.390625 0.125l0 1.46875q-0.265625 -0.125 -0.5625 -0.1875q-0.296875 -0.078125 -0.59375 -0.078125q-0.59375 0 -1.09375 0.34375q-0.5 0.328125 -0.796875 0.890625q-0.28125 0.5625 -0.28125 1.234375l0 4.5625l-1.359375 0zm9.27002 0.25q-1.234375 0 -2.1875 -0.5625q-0.9375 -0.578125 -1.46875 -1.5625q-0.53125 -0.984375 -0.53125 -2.203125q0 -1.21875 0.53125 -2.203125q0.53125 -0.984375 1.46875 -1.5625q0.953125 -0.578125 2.1875 -0.578125q1.234375 0 2.171875 0.59375q0.953125 0.578125 1.484375 1.5625q0.53125 0.984375 0.53125 2.1875q0 1.21875 -0.53125 2.203125q-0.53125 0.984375 -1.484375 1.5625q-0.9375 0.5625 -2.171875 0.5625zm0 -1.21875q0.734375 0 1.375 -0.375q0.65625 -0.375 1.046875 -1.0625q0.40625 -0.703125 0.40625 -1.671875q0 -0.984375 -0.40625 -1.671875q-0.390625 -0.703125 -1.046875 -1.0625q-0.640625 -0.375 -1.375 -0.375q-0.734375 0 -1.390625 0.375q-0.65625 0.359375 -1.0625 1.0625q-0.390625 0.6875 -0.390625 1.671875q0 0.96875 0.390625 1.671875q0.40625 0.6875 1.0625 1.0625q0.65625 0.375 1.390625 0.375zm5.706024 0.96875l0 -11.453125l1.359375 0l0 11.453125l-1.359375 0zm3.376007 0l0 -11.453125l1.359375 0l0 11.453125l-1.359375 0zm6.9210205 0.25q-1.1875 0 -2.109375 -0.546875q-0.921875 -0.5625 -1.4375 -1.53125q-0.515625 -0.984375 -0.515625 -2.234375q0 -1.171875 0.484375 -2.15625q0.484375 -1.0 1.375 -1.59375q0.890625 -0.609375 2.09375 -0.609375q1.21875 0 2.078125 0.546875q0.875 0.53125 1.34375 1.484375q0.484375 0.9375 0.484375 2.15625q0 0.109375 -0.015625 0.21875q0 0.109375 -0.015625 0.1875l-7.03125 0l0 -1.109375l5.609375 0q-0.015625 -0.34375 -0.15625 -0.734375q-0.125 -0.390625 -0.421875 -0.734375q-0.296875 -0.34375 -0.75 -0.5625q-0.453125 -0.21875 -1.125 -0.21875q-0.796875 0 -1.390625 0.40625q-0.578125 0.40625 -0.890625 1.125q-0.3125 0.703125 -0.3125 1.59375q0 1.03125 0.390625 1.734375q0.40625 0.6875 1.03125 1.03125q0.640625 0.328125 1.328125 0.328125q0.890625 0 1.46875 -0.421875q0.59375 -0.4375 0.953125 -1.0625l1.140625 0.5625q-0.46875 0.9375 -1.375 1.546875q-0.890625 0.59375 -2.234375 0.59375zm5.3829956 -0.25l0 -8.15625l1.28125 0l0 1.3125l0.078125 0q0.15625 -0.46875 0.53125 -0.8125q0.375 -0.34375 0.859375 -0.546875q0.484375 -0.203125 0.96875 -0.203125q0.375 0 0.578125 0.046875q0.203125 0.046875 0.390625 0.125l0 1.46875q-0.265625 -0.125 -0.5625 -0.1875q-0.296875 -0.078125 -0.59375 -0.078125q-0.59375 0 -1.09375 0.34375q-0.5 0.328125 -0.796875 0.890625q-0.28125 0.5625 -0.28125 1.234375l0 4.5625l-1.359375 0z" fill-rule="nonzero"/></g><g filter="url(#shadowFilter-p.9)"><use xlink:href="#p.9" transform="matrix(1.0 0.0 0.0 1.0 0.0 2.0)"/></g><defs><filter id="shadowFilter-p.9" filterUnits="userSpaceOnUse"><feGaussianBlur in="SourceAlpha" stdDeviation="2.0" result="blur"/><feComponentTransfer in="blur" color-interpolation-filters="sRGB"><feFuncR type="linear" slope="0" intercept="0.0"/><feFuncG type="linear" slope="0" intercept="0.0"/><feFuncB type="linear" slope="0" intercept="0.0"/><feFuncA type="linear" slope="0.5" intercept="0"/></feComponentTransfer></filter></defs><g id="p.9"><path fill="#1155cc" d="m277.77325 544.50085l0 0c0 -5.2562866 4.261017 -9.517273 9.517242 -9.517273l235.35922 0c2.524109 0 4.9448853 1.0026855 6.7296753 2.7875366c1.7848511 1.7848511 2.7875366 4.2055664 2.7875366 6.7297363l0 38.06781c0 5.2562256 -4.2609863 9.517273 -9.517212 9.517273l-235.35922 0c-5.2562256 0 -9.517242 -4.2610474 -9.517242 -9.517273z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m277.77325 544.50085l0 0c0 -5.2562866 4.261017 -9.517273 9.517242 -9.517273l235.35922 0c2.524109 0 4.9448853 1.0026855 6.7296753 2.7875366c1.7848511 1.7848511 2.7875366 4.2055664 2.7875366 6.7297363l0 38.06781c0 5.2562256 -4.2609863 9.517273 -9.517212 9.517273l-235.35922 0c-5.2562256 0 -9.517242 -4.2610474 -9.517242 -9.517273z" fill-rule="evenodd"/><path fill="#000000" d="m348.32324 569.3948l-4.0625 -11.453125l1.515625 0l2.828125 8.296875l0.375 1.140625l0.078125 0l0.390625 -1.140625l2.96875 -8.296875l1.5 0l-4.1875 11.453125l-1.40625 0zm6.635376 0l0 -8.15625l1.359375 0l0 8.15625l-1.359375 0zm0.671875 -9.65625q-0.40625 0 -0.703125 -0.28125q-0.28125 -0.296875 -0.28125 -0.703125q0 -0.421875 0.28125 -0.6875q0.296875 -0.28125 0.703125 -0.28125q0.40625 0 0.6875 0.28125q0.28125 0.265625 0.28125 0.6875q0 0.40625 -0.28125 0.703125q-0.28125 0.28125 -0.6875 0.28125zm2.8191528 9.65625l0 -8.15625l1.28125 0l0 1.296875l0.078125 0q0.203125 -0.5 0.578125 -0.828125q0.375 -0.34375 0.875 -0.515625q0.515625 -0.1875 1.03125 -0.1875q0.234375 0 0.34375 0.015625q0.125 0 0.234375 0.03125l0 1.40625q-0.15625 -0.03125 -0.34375 -0.046875q-0.171875 -0.03125 -0.390625 -0.03125q-0.6875 0 -1.21875 0.3125q-0.53125 0.3125 -0.828125 0.875q-0.28125 0.5625 -0.28125 1.296875l0 4.53125l-1.359375 0zm5.5 -8.15625l4.78125 0l0 1.234375l-4.78125 0l0 -1.234375zm1.421875 6.015625l0 -8.328125l1.359375 0l0 7.984375q0 0.640625 0.265625 1.0q0.265625 0.34375 0.875 0.34375q0.265625 0 0.484375 -0.078125q0.234375 -0.078125 0.40625 -0.1875l0 1.328125q-0.203125 0.09375 -0.453125 0.140625q-0.25 0.0625 -0.671875 0.0625q-1.015625 0 -1.640625 -0.59375q-0.625 -0.609375 -0.625 -1.671875zm7.9512634 2.390625q-1.5 0 -2.265625 -0.875q-0.765625 -0.875 -0.765625 -2.40625l0 -5.125l1.359375 0l0 4.921875q0 1.21875 0.5625 1.75q0.5625 0.515625 1.390625 0.515625q0.71875 0 1.25 -0.375q0.53125 -0.390625 0.8125 -0.96875q0.296875 -0.59375 0.296875 -1.234375l0 -4.609375l1.359375 0l0 8.15625l-1.296875 0l0 -1.1875l-0.0625 0q-0.203125 0.390625 -0.625 0.71875q-0.40625 0.328125 -0.921875 0.515625q-0.515625 0.203125 -1.09375 0.203125zm8.536652 0q-0.90625 0 -1.59375 -0.34375q-0.6875 -0.359375 -1.078125 -0.96875q-0.390625 -0.625 -0.390625 -1.40625q0 -0.890625 0.453125 -1.5q0.46875 -0.625 1.25 -0.9375q0.796875 -0.3125 1.734375 -0.3125q0.546875 0 1.0 0.09375q0.46875 0.078125 0.8125 0.203125q0.34375 0.125 0.515625 0.234375l0 -0.5q0 -0.921875 -0.65625 -1.46875q-0.640625 -0.546875 -1.59375 -0.546875q-0.671875 0 -1.265625 0.296875q-0.578125 0.296875 -0.90625 0.828125l-1.03125 -0.765625q0.328125 -0.484375 0.796875 -0.828125q0.484375 -0.359375 1.09375 -0.546875q0.625 -0.203125 1.3125 -0.203125q1.671875 0 2.609375 0.890625q0.9375 0.875 0.9375 2.359375l0 5.171875l-1.296875 0l0 -1.171875l-0.0625 0q-0.203125 0.359375 -0.59375 0.6875q-0.375 0.328125 -0.90625 0.53125q-0.515625 0.203125 -1.140625 0.203125zm0.140625 -1.1875q0.703125 0 1.28125 -0.34375q0.578125 -0.359375 0.921875 -0.953125q0.359375 -0.59375 0.359375 -1.296875q-0.359375 -0.265625 -0.921875 -0.421875q-0.546875 -0.15625 -1.203125 -0.15625q-1.15625 0 -1.703125 0.484375q-0.546875 0.46875 -0.546875 1.171875q0 0.671875 0.5 1.09375q0.515625 0.421875 1.3125 0.421875zm5.761627 0.9375l0 -11.453125l1.359375 0l0 11.453125l-1.359375 0zm7.3536377 0l0 -11.453125l1.359375 0l0 10.15625l5.0 0l0 1.296875l-6.359375 0zm8.003387 0l0 -8.15625l1.359375 0l0 8.15625l-1.359375 0zm0.671875 -9.65625q-0.40625 0 -0.703125 -0.28125q-0.28125 -0.296875 -0.28125 -0.703125q0 -0.421875 0.28125 -0.6875q0.296875 -0.28125 0.703125 -0.28125q0.40625 0 0.6875 0.28125q0.28125 0.265625 0.28125 0.6875q0 0.40625 -0.28125 0.703125q-0.28125 0.28125 -0.6875 0.28125zm2.8191528 9.65625l0 -8.15625l1.28125 0l0 1.203125l0.078125 0q0.3125 -0.59375 1.03125 -1.03125q0.734375 -0.4375 1.609375 -0.4375q1.5 0 2.25 0.875q0.765625 0.875 0.765625 2.3125l0 5.234375l-1.359375 0l0 -5.03125q0 -1.171875 -0.578125 -1.65625q-0.5625 -0.5 -1.453125 -0.5q-0.671875 0 -1.1875 0.375q-0.515625 0.375 -0.796875 0.96875q-0.28125 0.59375 -0.28125 1.25l0 4.59375l-1.359375 0zm8.976013 0l0 -11.453125l1.359375 0l0 11.453125l-1.359375 0zm0.5 -1.65625l0 -1.75l4.6875 -4.75l1.734375 0l0 0.0625l-6.421875 6.4375zm4.890625 1.65625l-2.953125 -4.390625l0.96875 -0.9375l3.609375 5.265625l0 0.0625l-1.625 0zm6.6670227 0l0 -11.453125l1.359375 0l0 10.15625l5.0 0l0 1.296875l-6.359375 0zm10.472137 0.25q-0.90625 0 -1.59375 -0.34375q-0.6875 -0.359375 -1.078125 -0.96875q-0.390625 -0.625 -0.390625 -1.40625q0 -0.890625 0.453125 -1.5q0.46875 -0.625 1.25 -0.9375q0.796875 -0.3125 1.734375 -0.3125q0.546875 0 1.0 0.09375q0.46875 0.078125 0.8125 0.203125q0.34375 0.125 0.515625 0.234375l0 -0.5q0 -0.921875 -0.65625 -1.46875q-0.640625 -0.546875 -1.59375 -0.546875q-0.671875 0 -1.265625 0.296875q-0.578125 0.296875 -0.90625 0.828125l-1.03125 -0.765625q0.328125 -0.484375 0.796875 -0.828125q0.484375 -0.359375 1.09375 -0.546875q0.625 -0.203125 1.3125 -0.203125q1.671875 0 2.609375 0.890625q0.9375 0.875 0.9375 2.359375l0 5.171875l-1.296875 0l0 -1.171875l-0.0625 0q-0.203125 0.359375 -0.59375 0.6875q-0.375 0.328125 -0.90625 0.53125q-0.515625 0.203125 -1.140625 0.203125zm0.140625 -1.1875q0.703125 0 1.28125 -0.34375q0.578125 -0.359375 0.921875 -0.953125q0.359375 -0.59375 0.359375 -1.296875q-0.359375 -0.265625 -0.921875 -0.421875q-0.546875 -0.15625 -1.203125 -0.15625q-1.15625 0 -1.703125 0.484375q-0.546875 0.46875 -0.546875 1.171875q0 0.671875 0.5 1.09375q0.515625 0.421875 1.3125 0.421875zm7.9297485 3.984375q-0.046875 0.109375 -0.109375 0.234375q-0.0625 0.140625 -0.078125 0.171875l-1.40625 0q0.09375 -0.203125 0.203125 -0.453125q0.109375 -0.25 0.265625 -0.59375q0.09375 -0.21875 0.171875 -0.390625q0.09375 -0.171875 0.1875 -0.390625q0.109375 -0.21875 0.25 -0.53125l1.125 -2.4375l0.296875 -0.75l2.46875 -6.0625l1.46875 0l-4.21875 9.734375q-0.0625 0.15625 -0.203125 0.46875q-0.140625 0.3125 -0.265625 0.59375q-0.109375 0.296875 -0.15625 0.40625zm0.296875 -3.390625l-3.453125 -7.8125l1.46875 0l2.5625 6.0625l0.140625 0l-0.71875 1.75zm9.048004 0.59375q-1.1875 0 -2.109375 -0.546875q-0.921875 -0.5625 -1.4375 -1.53125q-0.515625 -0.984375 -0.515625 -2.234375q0 -1.171875 0.484375 -2.15625q0.484375 -1.0 1.375 -1.59375q0.890625 -0.609375 2.09375 -0.609375q1.21875 0 2.078125 0.546875q0.875 0.53125 1.34375 1.484375q0.484375 0.9375 0.484375 2.15625q0 0.109375 -0.015625 0.21875q0 0.109375 -0.015625 0.1875l-7.03125 0l0 -1.109375l5.609375 0q-0.015625 -0.34375 -0.15625 -0.734375q-0.125 -0.390625 -0.421875 -0.734375q-0.296875 -0.34375 -0.75 -0.5625q-0.453125 -0.21875 -1.125 -0.21875q-0.796875 0 -1.390625 0.40625q-0.578125 0.40625 -0.890625 1.125q-0.3125 0.703125 -0.3125 1.59375q0 1.03125 0.390625 1.734375q0.40625 0.6875 1.03125 1.03125q0.640625 0.328125 1.328125 0.328125q0.890625 0 1.46875 -0.421875q0.59375 -0.4375 0.953125 -1.0625l1.140625 0.5625q-0.46875 0.9375 -1.375 1.546875q-0.890625 0.59375 -2.234375 0.59375zm5.383026 -0.25l0 -8.15625l1.28125 0l0 1.3125l0.078125 0q0.15625 -0.46875 0.53125 -0.8125q0.375 -0.34375 0.859375 -0.546875q0.484375 -0.203125 0.96875 -0.203125q0.375 0 0.578125 0.046875q0.203125 0.046875 0.390625 0.125l0 1.46875q-0.265625 -0.125 -0.5625 -0.1875q-0.296875 -0.078125 -0.59375 -0.078125q-0.59375 0 -1.09375 0.34375q-0.5 0.328125 -0.796875 0.890625q-0.28125 0.5625 -0.28125 1.234375l0 4.5625l-1.359375 0z" fill-rule="nonzero"/></g><path fill="#a2c4c9" d="m462.61346 235.04298l0 0c0 -4.8590393 3.9390564 -8.798065 8.798096 -8.798065l43.947144 0c2.333374 0 4.571228 0.92692566 6.2211914 2.576889c1.6499634 1.6499634 2.5769043 3.8877869 2.5769043 6.221176l0 35.19124c0 4.85907 -3.9390259 8.798096 -8.798096 8.798096l-43.947144 0c-4.8590393 0 -8.798096 -3.9390259 -8.798096 -8.798096z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m462.61346 235.04298l0 0c0 -4.8590393 3.9390564 -8.798065 8.798096 -8.798065l43.947144 0c2.333374 0 4.571228 0.92692566 6.2211914 2.576889c1.6499634 1.6499634 2.5769043 3.8877869 2.5769043 6.221176l0 35.19124c0 4.85907 -3.9390259 8.798096 -8.798096 8.798096l-43.947144 0c-4.8590393 0 -8.798096 -3.9390259 -8.798096 -8.798096z" fill-rule="evenodd"/><path fill="#000000" d="m490.619 257.23672q-0.3125 0 -0.546875 -0.21875q-0.21875 -0.234375 -0.21875 -0.5625q0 -0.3125 0.21875 -0.53123474q0.234375 -0.21875 0.546875 -0.21875q0.328125 0 0.546875 0.21875q0.234375 0.21873474 0.234375 0.53123474q0 0.328125 -0.234375 0.5625q-0.21875 0.21875 -0.546875 0.21875zm2.765625 0q-0.3125 0 -0.546875 -0.21875q-0.21875 -0.234375 -0.21875 -0.5625q0 -0.3125 0.21875 -0.53123474q0.234375 -0.21875 0.546875 -0.21875q0.328125 0 0.546875 0.21875q0.234375 0.21873474 0.234375 0.53123474q0 0.328125 -0.234375 0.5625q-0.21875 0.21875 -0.546875 0.21875zm2.75 0q-0.3125 0 -0.546875 -0.21875q-0.21875 -0.234375 -0.21875 -0.5625q0 -0.3125 0.21875 -0.53123474q0.234375 -0.21875 0.546875 -0.21875q0.328125 0 0.546875 0.21875q0.234375 0.21873474 0.234375 0.53123474q0 0.328125 -0.234375 0.5625q-0.21875 0.21875 -0.546875 0.21875z" fill-rule="nonzero"/><path fill="#a2c4c9" d="m446.68536 122.657425l0 0c0 -4.68219 3.7956848 -8.4778595 8.477875 -8.4778595l57.060028 0c2.2484741 0 4.404846 0.89320374 5.994751 2.4831085c1.5899048 1.5899048 2.4830933 3.7462845 2.4830933 5.994751l0 33.910416c0 4.682205 -3.7956543 8.4778595 -8.477844 8.4778595l-57.060028 0c-4.68219 0 -8.477875 -3.7956543 -8.477875 -8.4778595z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m446.68536 122.657425l0 0c0 -4.68219 3.7956848 -8.4778595 8.477875 -8.4778595l57.060028 0c2.2484741 0 4.404846 0.89320374 5.994751 2.4831085c1.5899048 1.5899048 2.4830933 3.7462845 2.4830933 5.994751l0 33.910416c0 4.682205 -3.7956543 8.4778595 -8.477844 8.4778595l-57.060028 0c-4.68219 0 -8.477875 -3.7956543 -8.477875 -8.4778595z" fill-rule="evenodd"/><path fill="#000000" d="m480.01547 145.56639q-0.4375 0 -0.734375 -0.296875q-0.296875 -0.296875 -0.296875 -0.71875q0 -0.421875 0.296875 -0.71875q0.296875 -0.296875 0.734375 -0.296875q0.4375 0 0.71875 0.296875q0.296875 0.296875 0.296875 0.71875q0 0.421875 -0.296875 0.71875q-0.28125 0.296875 -0.71875 0.296875zm3.6875 0q-0.4375 0 -0.734375 -0.296875q-0.296875 -0.296875 -0.296875 -0.71875q0 -0.421875 0.296875 -0.71875q0.296875 -0.296875 0.734375 -0.296875q0.4375 0 0.71875 0.296875q0.296875 0.296875 0.296875 0.71875q0 0.421875 -0.296875 0.71875q-0.28125 0.296875 -0.71875 0.296875zm3.671875 0q-0.4375 0 -0.734375 -0.296875q-0.296875 -0.296875 -0.296875 -0.71875q0 -0.421875 0.296875 -0.71875q0.296875 -0.296875 0.734375 -0.296875q0.4375 0 0.71875 0.296875q0.296875 0.296875 0.296875 0.71875q0 0.421875 -0.296875 0.71875q-0.28125 0.296875 -0.71875 0.296875z" fill-rule="nonzero"/><path fill="#000000" fill-opacity="0.0" d="m268.4268 284.34842l0 23.811005" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m268.4268 284.34842l0 23.811005" fill-rule="evenodd"/><g filter="url(#shadowFilter-p.10)"><use xlink:href="#p.10" transform="matrix(1.0 0.0 0.0 1.0 0.0 2.0)"/></g><defs><filter id="shadowFilter-p.10" filterUnits="userSpaceOnUse"><feGaussianBlur in="SourceAlpha" stdDeviation="2.0" result="blur"/><feComponentTransfer in="blur" color-interpolation-filters="sRGB"><feFuncR type="linear" slope="0" intercept="0.0"/><feFuncG type="linear" slope="0" intercept="0.0"/><feFuncB type="linear" slope="0" intercept="0.0"/><feFuncA type="linear" slope="0.5" intercept="0"/></feComponentTransfer></filter></defs><g id="p.10"><path fill="#3c78d8" d="m4.8992295 393.27774l0 0c0 -5.256256 4.2610183 -9.517273 9.51725 -9.517273l508.0206 0c2.52417 0 4.9448853 1.0027161 6.7297363 2.7875366c1.7848511 1.7848511 2.7875366 4.205597 2.7875366 6.7297363l0 38.06784c0 5.2562256 -4.2609863 9.517273 -9.517273 9.517273l-508.0206 0c-5.2562323 0 -9.51725 -4.2610474 -9.51725 -9.517273z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m4.8992295 393.27774l0 0c0 -5.256256 4.2610183 -9.517273 9.51725 -9.517273l508.0206 0c2.52417 0 4.9448853 1.0027161 6.7297363 2.7875366c1.7848511 1.7848511 2.7875366 4.205597 2.7875366 6.7297363l0 38.06784c0 5.2562256 -4.2609863 9.517273 -9.517273 9.517273l-508.0206 0c-5.2562323 0 -9.51725 -4.2610474 -9.51725 -9.517273z" fill-rule="evenodd"/><path fill="#000000" d="m220.21194 418.17166l0 -11.453125l1.359375 0l0 11.453125l-1.359375 0zm0.71875 -5.21875l0 -1.296875l6.84375 0l0 1.296875l-6.84375 0zm6.53125 5.21875l0 -11.453125l1.359375 0l0 11.453125l-1.359375 0zm9.133026 0.25q-1.265625 0 -2.34375 -0.453125q-1.078125 -0.453125 -1.890625 -1.25q-0.8125 -0.8125 -1.265625 -1.90625q-0.4375 -1.109375 -0.4375 -2.375q0 -1.28125 0.4375 -2.359375q0.453125 -1.09375 1.265625 -1.890625q0.8125 -0.8125 1.890625 -1.265625q1.078125 -0.46875 2.34375 -0.46875q0.875 0 1.640625 0.234375q0.765625 0.21875 1.40625 0.640625q0.640625 0.40625 1.140625 1.0l-0.96875 0.953125q-0.4375 -0.53125 -0.921875 -0.859375q-0.484375 -0.34375 -1.0625 -0.5q-0.5625 -0.171875 -1.234375 -0.171875q-1.234375 0 -2.28125 0.578125q-1.03125 0.578125 -1.65625 1.625q-0.625 1.046875 -0.625 2.484375q0 1.4375 0.625 2.5q0.625 1.046875 1.65625 1.625q1.046875 0.5625 2.28125 0.5625q0.75 0 1.375 -0.203125q0.640625 -0.203125 1.171875 -0.578125q0.546875 -0.390625 0.984375 -0.921875l1.0 0.953125q-0.5 0.59375 -1.203125 1.0625q-0.6875 0.46875 -1.53125 0.734375q-0.84375 0.25 -1.796875 0.25zm6.481018 -0.25l0 -11.453125l1.359375 0l0 11.453125l-1.359375 0zm9.33577 0l0 -10.640625l1.359375 0l0 10.640625l-1.359375 0zm-3.203125 -10.15625l0 -1.296875l7.7656097 0l0 1.296875l-7.7656097 0zm8.241745 10.15625l0 -8.15625l1.28125 0l0 1.3125l0.078125 0q0.15625 -0.46875 0.53125 -0.8125q0.375 -0.34375 0.859375 -0.546875q0.484375 -0.203125 0.96875 -0.203125q0.375 0 0.578125 0.046875q0.203125 0.046875 0.390625 0.125l0 1.46875q-0.265625 -0.125 -0.5625 -0.1875q-0.296875 -0.078125 -0.59375 -0.078125q-0.59375 0 -1.09375 0.34375q-0.5 0.328125 -0.796875 0.890625q-0.28125 0.5625 -0.28125 1.234375l0 4.5625l-1.359375 0zm8.273773 0.25q-0.90625 0 -1.59375 -0.34375q-0.6875 -0.359375 -1.078125 -0.96875q-0.390625 -0.625 -0.390625 -1.40625q0 -0.890625 0.453125 -1.5q0.46875 -0.625 1.25 -0.9375q0.796875 -0.3125 1.734375 -0.3125q0.546875 0 1.0 0.09375q0.46875 0.078125 0.8125 0.203125q0.34375 0.125 0.515625 0.234375l0 -0.5q0 -0.921875 -0.65625 -1.46875q-0.640625 -0.546875 -1.59375 -0.546875q-0.671875 0 -1.265625 0.296875q-0.578125 0.296875 -0.90625 0.828125l-1.03125 -0.765625q0.328125 -0.484375 0.796875 -0.828125q0.484375 -0.359375 1.09375 -0.546875q0.625 -0.203125 1.3125 -0.203125q1.671875 0 2.609375 0.890625q0.9375 0.875 0.9375 2.359375l0 5.171875l-1.296875 0l0 -1.171875l-0.0625 0q-0.203125 0.359375 -0.59375 0.6875q-0.375 0.328125 -0.90625 0.53125q-0.515625 0.203125 -1.140625 0.203125zm0.140625 -1.1875q0.703125 0 1.28125 -0.34375q0.578125 -0.359375 0.921875 -0.953125q0.359375 -0.59375 0.359375 -1.296875q-0.359375 -0.265625 -0.921875 -0.421875q-0.546875 -0.15625 -1.203125 -0.15625q-1.15625 0 -1.703125 0.484375q-0.546875 0.46875 -0.546875 1.171875q0 0.671875 0.5 1.09375q0.515625 0.421875 1.3125 0.421875zm5.7616577 0.9375l0 -8.15625l1.28125 0l0 1.203125l0.078125 0q0.3125 -0.59375 1.03125 -1.03125q0.734375 -0.4375 1.609375 -0.4375q1.5 0 2.25 0.875q0.765625 0.875 0.765625 2.3125l0 5.234375l-1.359375 0l0 -5.03125q0 -1.171875 -0.578125 -1.65625q-0.5625 -0.5 -1.453125 -0.5q-0.671875 0 -1.1875 0.375q-0.515625 0.375 -0.796875 0.96875q-0.28125 0.59375 -0.28125 1.25l0 4.59375l-1.359375 0zm11.739746 0.25q-0.921875 0 -1.625 -0.296875q-0.6875 -0.296875 -1.140625 -0.796875q-0.453125 -0.5 -0.671875 -1.09375l1.203125 -0.546875q0.328125 0.734375 0.9375 1.140625q0.609375 0.40625 1.390625 0.40625q0.75 0 1.25 -0.296875q0.515625 -0.3125 0.515625 -0.90625q0 -0.375 -0.21875 -0.625q-0.203125 -0.25 -0.609375 -0.421875q-0.390625 -0.171875 -0.96875 -0.3125l-1.0 -0.265625q-0.5625 -0.15625 -1.078125 -0.4375q-0.515625 -0.296875 -0.828125 -0.75q-0.3125 -0.453125 -0.3125 -1.109375q0 -0.734375 0.421875 -1.265625q0.4375 -0.53125 1.140625 -0.8125q0.703125 -0.28125 1.515625 -0.28125q0.703125 0 1.3125 0.203125q0.625 0.203125 1.078125 0.59375q0.46875 0.390625 0.703125 0.96875l-1.171875 0.546875q-0.3125 -0.609375 -0.828125 -0.84375q-0.5 -0.25 -1.125 -0.25q-0.671875 0 -1.171875 0.296875q-0.5 0.296875 -0.5 0.8125q0 0.515625 0.40625 0.765625q0.40625 0.25 1.0 0.421875l1.1875 0.296875q1.203125 0.3125 1.8125 0.90625q0.609375 0.59375 0.609375 1.46875q0 0.765625 -0.4375 1.328125q-0.4375 0.546875 -1.171875 0.859375q-0.734375 0.296875 -1.625 0.296875zm4.6442566 3.203125l0 -11.609375l1.28125 0l0 1.21875l0.078125 0q0.21875 -0.390625 0.625 -0.71875q0.40625 -0.34375 0.953125 -0.546875q0.546875 -0.21875 1.203125 -0.21875q1.109375 0 1.984375 0.5625q0.890625 0.5625 1.40625 1.546875q0.515625 0.96875 0.515625 2.234375q0 1.265625 -0.515625 2.25q-0.515625 0.96875 -1.40625 1.53125q-0.875 0.546875 -1.984375 0.546875q-0.984375 0 -1.71875 -0.4375q-0.734375 -0.453125 -1.0625 -1.015625l-0.078125 0l0.078125 1.125l0 3.53125l-1.359375 0zm4.0 -4.421875q0.703125 0 1.3125 -0.375q0.609375 -0.390625 0.984375 -1.09375q0.390625 -0.703125 0.390625 -1.640625q0 -0.96875 -0.390625 -1.65625q-0.375 -0.703125 -0.984375 -1.078125q-0.609375 -0.375 -1.3125 -0.375q-0.71875 0 -1.328125 0.375q-0.609375 0.375 -1.0 1.078125q-0.390625 0.6875 -0.390625 1.65625q0 0.953125 0.390625 1.65625q0.390625 0.6875 1.0 1.078125q0.609375 0.375 1.328125 0.375zm9.382019 1.21875q-1.234375 0 -2.1875 -0.5625q-0.9375 -0.578125 -1.46875 -1.5625q-0.53125 -0.984375 -0.53125 -2.203125q0 -1.21875 0.53125 -2.203125q0.53125 -0.984375 1.46875 -1.5625q0.953125 -0.578125 2.1875 -0.578125q1.234375 0 2.171875 0.59375q0.953125 0.578125 1.484375 1.5625q0.53125 0.984375 0.53125 2.1875q0 1.21875 -0.53125 2.203125q-0.53125 0.984375 -1.484375 1.5625q-0.9375 0.5625 -2.171875 0.5625zm0 -1.21875q0.734375 0 1.375 -0.375q0.65625 -0.375 1.046875 -1.0625q0.40625 -0.703125 0.40625 -1.671875q0 -0.984375 -0.40625 -1.671875q-0.390625 -0.703125 -1.046875 -1.0625q-0.640625 -0.375 -1.375 -0.375q-0.734375 0 -1.390625 0.375q-0.65625 0.359375 -1.0625 1.0625q-0.390625 0.6875 -0.390625 1.671875q0 0.96875 0.390625 1.671875q0.40625 0.6875 1.0625 1.0625q0.65625 0.375 1.390625 0.375zm5.626007 0.96875l0 -8.15625l1.28125 0l0 1.296875l0.078125 0q0.203125 -0.5 0.578125 -0.828125q0.375 -0.34375 0.875 -0.515625q0.515625 -0.1875 1.03125 -0.1875q0.234375 0 0.34375 0.015625q0.125 0 0.234375 0.03125l0 1.40625q-0.15625 -0.03125 -0.34375 -0.046875q-0.171875 -0.03125 -0.390625 -0.03125q-0.6875 0 -1.21875 0.3125q-0.53125 0.3125 -0.828125 0.875q-0.28125 0.5625 -0.28125 1.296875l0 4.53125l-1.359375 0zm5.5 -8.15625l4.78125 0l0 1.234375l-4.78125 0l0 -1.234375zm1.421875 6.015625l0 -8.328125l1.359375 0l0 7.984375q0 0.640625 0.265625 1.0q0.265625 0.34375 0.875 0.34375q0.265625 0 0.484375 -0.078125q0.234375 -0.078125 0.40625 -0.1875l0 1.328125q-0.203125 0.09375 -0.453125 0.140625q-0.25 0.0625 -0.671875 0.0625q-1.015625 0 -1.640625 -0.59375q-0.625 -0.609375 -0.625 -1.671875z" fill-rule="nonzero"/></g><path fill="#000000" fill-opacity="0.0" d="m268.4268 365.25128l0 18.519684" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m268.4268 365.25128l0 18.519684" fill-rule="evenodd"/><path fill="#a4c2f4" d="m205.13545 82.27259l314.42523 0c3.2869873 0 6.439392 1.3057632 8.763672 3.6300278c2.3242188 2.3242722 3.630005 5.4766617 3.630005 8.763672l0 12.3937c0 0.0015640259 -0.0012817383 0.0028305054 -0.0028076172 0.0028305054l-339.20978 -0.0028305054l0 0c-0.0015563965 0 -0.002822876 -0.0012664795 -0.002822876 -0.002822876l0.002822876 -12.390877l0 0c0 -6.8448486 5.5488586 -12.3937 12.393707 -12.3937z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m205.13545 82.27259l314.42523 0c3.2869873 0 6.439392 1.3057632 8.763672 3.6300278c2.3242188 2.3242722 3.630005 5.4766617 3.630005 8.763672l0 12.3937c0 0.0015640259 -0.0012817383 0.0028305054 -0.0028076172 0.0028305054l-339.20978 -0.0028305054l0 0c-0.0015563965 0 -0.002822876 -0.0012664795 -0.002822876 -0.002822876l0.002822876 -12.390877l0 0c0 -6.8448486 5.5488586 -12.3937 12.393707 -12.3937z" fill-rule="evenodd"/><path fill="#000000" d="m339.0376 99.98258l0 -10.484375l3.96875 0q1.046875 0 1.59375 0.09375q0.765625 0.125 1.28125 0.484375q0.53125 0.359375 0.84375 1.015625q0.328125 0.65625 0.328125 1.4375q0 1.328125 -0.859375 2.265625q-0.84375 0.921875 -3.078125 0.921875l-2.6875 0l0 4.265625l-1.390625 0zm1.390625 -5.5l2.71875 0q1.34375 0 1.90625 -0.5q0.5625 -0.5 0.5625 -1.40625q0 -0.671875 -0.328125 -1.140625q-0.328125 -0.46875 -0.875 -0.609375q-0.359375 -0.09375 -1.296875 -0.09375l-2.6875 0l0 3.75zm8.213104 5.5l0 -7.59375l1.15625 0l0 1.140625q0.453125 -0.796875 0.828125 -1.046875q0.375 -0.265625 0.8125 -0.265625q0.65625 0 1.328125 0.40625l-0.4375 1.203125q-0.46875 -0.28125 -0.953125 -0.28125q-0.421875 0 -0.765625 0.25q-0.328125 0.25 -0.46875 0.703125q-0.21875 0.6875 -0.21875 1.5l0 3.984375l-1.28125 0zm4.4118958 -3.796875q0 -2.109375 1.171875 -3.125q0.984375 -0.84375 2.390625 -0.84375q1.578125 0 2.5625 1.03125q1.0 1.015625 1.0 2.828125q0 1.46875 -0.4375 2.3125q-0.4375 0.828125 -1.28125 1.296875q-0.84375 0.46875 -1.84375 0.46875q-1.59375 0 -2.578125 -1.015625q-0.984375 -1.03125 -0.984375 -2.953125zm1.328125 0q0 1.453125 0.625 2.1875q0.640625 0.71875 1.609375 0.71875q0.96875 0 1.59375 -0.71875q0.640625 -0.734375 0.640625 -2.234375q0 -1.40625 -0.640625 -2.125q-0.640625 -0.734375 -1.59375 -0.734375q-0.96875 0 -1.609375 0.71875q-0.625 0.71875 -0.625 2.1875zm7.619873 3.796875l0 -6.59375l-1.140625 0l0 -1.0l1.140625 0l0 -0.8125q0 -0.765625 0.125 -1.140625q0.1875 -0.5 0.65625 -0.8125q0.46875 -0.3125 1.3125 -0.3125q0.546875 0 1.203125 0.125l-0.1875 1.125q-0.40625 -0.0625 -0.765625 -0.0625q-0.578125 0 -0.828125 0.25q-0.234375 0.25 -0.234375 0.9375l0 0.703125l1.46875 0l0 1.0l-1.46875 0l0 6.59375l-1.28125 0zm3.7594604 -9.015625l0 -1.46875l1.296875 0l0 1.46875l-1.296875 0zm0 9.015625l0 -7.59375l1.296875 0l0 7.59375l-1.296875 0zm3.2249146 0l0 -10.484375l1.28125 0l0 10.484375l-1.28125 0zm8.490509 -2.453125l1.328125 0.171875q-0.3125 1.171875 -1.171875 1.8125q-0.84375 0.640625 -2.171875 0.640625q-1.671875 0 -2.65625 -1.015625q-0.96875 -1.03125 -0.96875 -2.890625q0 -1.921875 0.984375 -2.96875q1.0 -1.0625 2.578125 -1.0625q1.515625 0 2.484375 1.03125q0.96875 1.03125 0.96875 2.921875q0 0.109375 -0.015625 0.34375l-5.65625 0q0.0625 1.25 0.703125 1.921875q0.640625 0.65625 1.59375 0.65625q0.703125 0 1.203125 -0.359375q0.5 -0.375 0.796875 -1.203125zm-4.234375 -2.078125l4.25 0q-0.09375 -0.953125 -0.484375 -1.4375q-0.625 -0.75 -1.609375 -0.75q-0.875 0 -1.484375 0.59375q-0.609375 0.59375 -0.671875 1.59375zm6.666748 2.265625l1.265625 -0.203125q0.109375 0.765625 0.59375 1.171875q0.5 0.40625 1.375 0.40625q0.890625 0 1.3125 -0.359375q0.4375 -0.359375 0.4375 -0.84375q0 -0.4375 -0.375 -0.6875q-0.265625 -0.171875 -1.3125 -0.4375q-1.421875 -0.359375 -1.96875 -0.609375q-0.546875 -0.265625 -0.828125 -0.734375q-0.28125 -0.46875 -0.28125 -1.015625q0 -0.515625 0.21875 -0.9375q0.234375 -0.4375 0.640625 -0.734375q0.296875 -0.21875 0.8125 -0.359375q0.53125 -0.15625 1.125 -0.15625q0.890625 0 1.5625 0.265625q0.671875 0.25 1.0 0.6875q0.328125 0.4375 0.4375 1.171875l-1.25 0.171875q-0.09375 -0.578125 -0.5 -0.90625q-0.40625 -0.34375 -1.15625 -0.34375q-0.890625 0 -1.28125 0.296875q-0.375 0.296875 -0.375 0.6875q0 0.25 0.15625 0.453125q0.15625 0.203125 0.5 0.34375q0.1875 0.078125 1.140625 0.328125q1.359375 0.359375 1.890625 0.59375q0.546875 0.234375 0.859375 0.6875q0.3125 0.4375 0.3125 1.09375q0 0.640625 -0.375 1.21875q-0.375 0.5625 -1.09375 0.875q-0.703125 0.3125 -1.59375 0.3125q-1.484375 0 -2.265625 -0.609375q-0.765625 -0.625 -0.984375 -1.828125z" fill-rule="nonzero"/><path fill="#6d9eeb" d="m17.29293 195.78148l502.26773 0c3.2869873 0 6.439392 1.3057556 8.763672 3.6300201c2.3242188 2.3242798 3.630005 5.4766693 3.630005 8.763672l0 12.393707c0 0.0024261475 -0.001953125 0.0043945312 -0.0043945312 0.0043945312l-527.0507 -0.0043945312l0 0c-0.0024256706 0 -0.004392147 -0.0019683838 -0.004392147 -0.0043945312l0.004392147 -12.389313l0 0c0 -6.8448486 5.5488486 -12.393692 12.393702 -12.393692z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m17.29293 195.78148l502.26773 0c3.2869873 0 6.439392 1.3057556 8.763672 3.6300201c2.3242188 2.3242798 3.630005 5.4766693 3.630005 8.763672l0 12.393707c0 0.0024261475 -0.001953125 0.0043945312 -0.0043945312 0.0043945312l-527.0507 -0.0043945312l0 0c-0.0024256706 0 -0.004392147 -0.0019683838 -0.004392147 -0.0043945312l0.004392147 -12.389313l0 0c0 -6.8448486 5.5488486 -12.393692 12.393702 -12.393692z" fill-rule="evenodd"/><path fill="#000000" d="m239.0048 213.49147l0 -10.484375l3.96875 0q1.046875 0 1.59375 0.09375q0.765625 0.125 1.28125 0.484375q0.53125 0.359375 0.84375 1.015625q0.328125 0.65625 0.328125 1.4375q0 1.328125 -0.859375 2.265625q-0.84375 0.921875 -3.078125 0.921875l-2.6875 0l0 4.265625l-1.390625 0zm1.390625 -5.5l2.71875 0q1.34375 0 1.90625 -0.5q0.5625 -0.5 0.5625 -1.40625q0 -0.671875 -0.328125 -1.140625q-0.328125 -0.46875 -0.875 -0.609375q-0.359375 -0.09375 -1.296875 -0.09375l-2.6875 0l0 3.75zm8.213104 5.5l0 -7.59375l1.15625 0l0 1.140625q0.453125 -0.796875 0.828125 -1.046875q0.375 -0.265625 0.8125 -0.265625q0.65625 0 1.328125 0.40625l-0.4375 1.203125q-0.46875 -0.28125 -0.953125 -0.28125q-0.421875 0 -0.765625 0.25q-0.328125 0.25 -0.46875 0.703125q-0.21875 0.6875 -0.21875 1.5l0 3.984375l-1.28125 0zm4.4118958 -3.796875q0 -2.109375 1.171875 -3.125q0.984375 -0.84375 2.3906097 -0.84375q1.578125 0 2.5625 1.03125q1.0 1.015625 1.0 2.828125q0 1.46875 -0.4375 2.3125q-0.4375 0.828125 -1.28125 1.296875q-0.84375 0.46875 -1.84375 0.46875q-1.5937347 0 -2.5781097 -1.015625q-0.984375 -1.03125 -0.984375 -2.953125zm1.328125 0q0 1.453125 0.625 2.1875q0.640625 0.71875 1.6093597 0.71875q0.96875 0 1.59375 -0.71875q0.640625 -0.734375 0.640625 -2.234375q0 -1.40625 -0.640625 -2.125q-0.640625 -0.734375 -1.59375 -0.734375q-0.96873474 0 -1.6093597 0.71875q-0.625 0.71875 -0.625 2.1875zm10.119858 2.640625l0.1875 1.140625q-0.546875 0.109375 -0.984375 0.109375q-0.6875 0 -1.078125 -0.21875q-0.390625 -0.21875 -0.546875 -0.578125q-0.15625 -0.359375 -0.15625 -1.515625l0 -4.375l-0.953125 0l0 -1.0l0.953125 0l0 -1.890625l1.28125 -0.765625l0 2.65625l1.296875 0l0 1.0l-1.296875 0l0 4.4375q0 0.546875 0.0625 0.71875q0.078125 0.15625 0.21875 0.25q0.15625 0.078125 0.453125 0.078125q0.203125 0 0.5625 -0.046875zm0.77508545 -2.640625q0 -2.109375 1.171875 -3.125q0.984375 -0.84375 2.390625 -0.84375q1.578125 0 2.5625 1.03125q1.0 1.015625 1.0 2.828125q0 1.46875 -0.4375 2.3125q-0.4375 0.828125 -1.28125 1.296875q-0.84375 0.46875 -1.84375 0.46875q-1.59375 0 -2.578125 -1.015625q-0.984375 -1.03125 -0.984375 -2.953125zm1.328125 0q0 1.453125 0.625 2.1875q0.640625 0.71875 1.609375 0.71875q0.96875 0 1.59375 -0.71875q0.640625 -0.734375 0.640625 -2.234375q0 -1.40625 -0.640625 -2.125q-0.640625 -0.734375 -1.59375 -0.734375q-0.96875 0 -1.609375 0.71875q-0.625 0.71875 -0.625 2.1875zm12.260498 1.015625l1.265625 0.15625q-0.203125 1.3125 -1.0625 2.0625q-0.84375 0.734375 -2.09375 0.734375q-1.5625 0 -2.515625 -1.015625q-0.9375 -1.03125 -0.9375 -2.921875q0 -1.234375 0.40625 -2.15625q0.40625 -0.921875 1.234375 -1.375q0.84375 -0.46875 1.8125 -0.46875q1.25 0 2.03125 0.625q0.78125 0.625 1.015625 1.765625l-1.265625 0.203125q-0.171875 -0.765625 -0.625 -1.15625q-0.453125 -0.390625 -1.09375 -0.390625q-0.984375 0 -1.59375 0.703125q-0.609375 0.703125 -0.609375 2.203125q0 1.53125 0.578125 2.234375q0.59375 0.6875 1.546875 0.6875q0.75 0 1.265625 -0.453125q0.515625 -0.46875 0.640625 -1.4375zm1.890625 -1.015625q0 -2.109375 1.171875 -3.125q0.984375 -0.84375 2.390625 -0.84375q1.578125 0 2.5625 1.03125q1.0 1.015625 1.0 2.828125q0 1.46875 -0.4375 2.3125q-0.4375 0.828125 -1.28125 1.296875q-0.84375 0.46875 -1.84375 0.46875q-1.59375 0 -2.578125 -1.015625q-0.984375 -1.03125 -0.984375 -2.953125zm1.328125 0q0 1.453125 0.625 2.1875q0.640625 0.71875 1.609375 0.71875q0.96875 0 1.59375 -0.71875q0.640625 -0.734375 0.640625 -2.234375q0 -1.40625 -0.640625 -2.125q-0.640625 -0.734375 -1.59375 -0.734375q-0.96875 0 -1.609375 0.71875q-0.625 0.71875 -0.625 2.1875zm7.2760925 3.796875l0 -10.484375l1.28125 0l0 10.484375l-1.28125 0zm2.771759 -2.265625l1.265625 -0.203125q0.109375 0.765625 0.59375 1.171875q0.5 0.40625 1.375 0.40625q0.890625 0 1.3125 -0.359375q0.4375 -0.359375 0.4375 -0.84375q0 -0.4375 -0.375 -0.6875q-0.265625 -0.171875 -1.3125 -0.4375q-1.421875 -0.359375 -1.96875 -0.609375q-0.546875 -0.265625 -0.828125 -0.734375q-0.28125 -0.46875 -0.28125 -1.015625q0 -0.515625 0.21875 -0.9375q0.234375 -0.4375 0.640625 -0.734375q0.296875 -0.21875 0.8125 -0.359375q0.53125 -0.15625 1.125 -0.15625q0.890625 0 1.5625 0.265625q0.671875 0.25 1.0 0.6875q0.328125 0.4375 0.4375 1.171875l-1.25 0.171875q-0.09375 -0.578125 -0.5 -0.90625q-0.40625 -0.34375 -1.15625 -0.34375q-0.890625 0 -1.28125 0.296875q-0.375 0.296875 -0.375 0.6875q0 0.25 0.15625 0.453125q0.15625 0.203125 0.5 0.34375q0.1875 0.078125 1.140625 0.328125q1.359375 0.359375 1.890625 0.59375q0.546875 0.234375 0.859375 0.6875q0.3125 0.4375 0.3125 1.09375q0 0.640625 -0.375 1.21875q-0.375 0.5625 -1.09375 0.875q-0.703125 0.3125 -1.59375 0.3125q-1.484375 0 -2.265625 -0.609375q-0.765625 -0.625 -0.984375 -1.828125z" fill-rule="nonzero"/></g></svg>
diff --git a/docs/mkdocs/src/index.md b/docs/mkdocs/src/index.md
index a6bf2ae..c81f7ff 100644
--- a/docs/mkdocs/src/index.md
+++ b/docs/mkdocs/src/index.md
@@ -8,8 +8,7 @@ The project initially only supported BLE (Bluetooth Low Energy), but support for
eventually added. Support for BLE is therefore currently somewhat more advanced than for Classic.
!!! warning
- This project is still very much experimental and in an alpha state where a lot of things are still missing or broken, and what's there changes frequently.
- Also, there are still a few hardcoded values/parameters in some of the examples and apps which need to be changed (those will eventually be command line arguments, as appropriate)
+ This project is still in an early state of development where some things are still missing or broken, and what's implemented may change and evolve frequently.
Overview
--------
@@ -163,4 +162,3 @@ Future features to be considered include:
* Bindings for languages other than Python
* RPC interface to expose most of the API for remote use
* (...suggest anything you want...)
-
diff --git a/docs/mkdocs/src/platforms/android.md b/docs/mkdocs/src/platforms/android.md
index 872edc7..4b08d88 100644
--- a/docs/mkdocs/src/platforms/android.md
+++ b/docs/mkdocs/src/platforms/android.md
@@ -2,30 +2,31 @@
===================================
Using Bumble with Android is not about running the Bumble stack on the Android
-OS itself, but rather using Bumble with the Bluetooth support of the Android
+OS itself, but rather using Bumble with the Bluetooth support of the Android
emulator.
The two main use cases are:
* Connecting the Bumble host stack to the Android emulator's virtual controller.
- * Using Bumble as an HCI bridge to connect the Android emulator to a physical
- Bluetooth controller, such as a USB dongle
+ * Using Bumble as an HCI bridge to connect the Android emulator to a physical
+ Bluetooth controller, such as a USB dongle, or other HCI transport.
!!! warning
Bluetooth support in the Android emulator is a recent feature that may still
be evolving. The information contained here be somewhat out of sync with the
version of the emulator you are using.
- You will need version 31.3.8.0 or later.
+ You will need version 33.1.4.0 or later.
-The Android emulator supports Bluetooth in two ways: either by exposing virtual
+The Android emulator supports Bluetooth in two ways: either by exposing virtual
Bluetooth controllers to which you can connect a virtual Bluetooth host stack, or
-by exposing an way to connect your own virtual controller to the Android Bluetooth
+by exposing a way to connect your own virtual controller to the Android Bluetooth
stack via a virtual HCI interface.
-Both ways are controlled via gRPC requests to the Android emulator.
+Both ways are controlled via gRPC requests to the Android emulator controller and/or
+from the Android emulator.
## Launching the Emulator
-If the version of the emulator you are running does not yet support enabling
+If the version of the emulator you are running does not yet support enabling
Bluetooth support by default or automatically, you must launch the emulator from
the command line.
@@ -33,52 +34,86 @@ the command line.
For details on how to launch the Android emulator from the command line,
visit [this Android Studio user guide page](https://developer.android.com/studio/run/emulator-commandline)
-The `-grpc <port>` command line option may be used to select a gRPC port other than the default.
+The `-packet-streamer-endpoint <endpoint>` command line option may be used to enable
+Bluetooth emulation and tell the emulator which virtual controller to connect to.
-## Connecting to Root Canal
+## Connecting to Netsim
-The Android emulator's virtual Bluetooth controller is called **Root Canal**.
-Multiple instances of Root Canal virtual controllers can be instantiated, they
-communicate link layer packets between them, thus creating a virtual radio network.
-Configuring a Bumble Device instance to use Root Canal as a virtual controller
+If the emulator doesn't have Bluetooth emulation enabled by default, use the
+`-packet-streamer-endpoint default` option to tell it to connect to Netsim.
+If Netsim is not running, the emulator will start it automatically.
+
+The Android emulator's virtual Bluetooth controller is called **Netsim**.
+Netsim runs as a background process and allows multiple clients to connect to it,
+each connecting to its own virtual controller instance hosted by Netsim. All the
+clients connected to the same Netsim process can then "talk" to each other over a
+virtual radio link layer.
+Netsim supports other wireless protocols than Bluetooth, but the relevant part here
+is Bluetooth. The virtual Bluetooth controller used by Netsim is sometimes referred to
+as **Root Canal**.
+
+Configuring a Bumble Device instance to use netsim as a virtual controller
allows that virtual device to communicate with the Android Bluetooth stack, and
through it with Android applications as well as system-managed profiles.
-To connect a Bumble host stack to a Root Canal virtual controller instance, use
-the bumble `android-emulator` transport in `host` mode (the default).
+To connect a Bumble host stack to a netsim virtual controller instance, use
+the Bumble `android-netsim` transport in `host` mode (the default).
+
+!!! example "Run the example GATT server connected to the emulator via Netsim"
+ ``` shell
+ $ python run_gatt_server.py device1.json android-netsim
+ ```
-!!! example "Run the example GATT server connected to the emulator"
+By default, the Bumble `android-netsim` transport will try to automatically discover
+the port number on which the netsim process is exposing its gRPC server interface. If
+that discovery process fails, or if you want to specify the interface manually, you
+can pass a `hostname` and `port` as parameters to the transport, as: `android-netsim:<host>:<port>`.
+
+!!! example "Run the example GATT server connected to the emulator via Netsim on a localhost, port 8877"
``` shell
- $ python run_gatt_server.py device1.json android-emulator
+ $ python run_gatt_server.py device1.json android-netsim:localhost:8877
```
+### Multiple Instances
+
+If you want to connect multiple Bumble devices to netsim, it may be useful to give each one
+a netsim controller with a specific name. This can be done using the `name=<name>` transport option.
+For example: `android-netsim:localhost:8877,name=bumble1`
+
## Connecting a Custom Virtual Controller
This is an advanced use case, which may not be officially supported, but should work in recent
versions of the emulator.
-You will likely need to start the emulator from the command line, in order to specify the `-forward-vhci` option (unless the emulator offers a way to control that feature from a user/ui menu).
-!!! example "Launch the emulator with VHCI forwarding"
- In this example, we launch an emulator AVD named "Tiramisu"
+The first step is to run the Bumble HCI bridge, specifying netsim as the "host" end of the
+bridge, and another controller (typically a USB Bluetooth dongle, but any other supported
+transport can work as well) as the "controller" end of the bridge.
+
+To connect a virtual controller to the Android Bluetooth stack, use the bumble `android-netsim` transport in `controller` mode. For example, with port number 8877, the transport name would be: `android-netsim:_:8877,mode=controller`.
+
+!!! example "Connect the Android emulator to the first USB Bluetooth dongle, using the `hci_bridge` application"
```shell
- $ emulator -forward-vhci -avd Tiramisu
+ $ bumble-hci-bridge android-netsim:_:8877,mode=controller usb:0
```
-!!! tip
- Attaching a virtual controller use the VHCI forwarder while the Android Bluetooth stack
- is running isn't supported. So you need to disable Bluetooth in your running Android guest
- before attaching the virtual controller, then re-enable it once attached.
+Then, you can start the emulator and tell it to connect to this bridge, instead of netsim.
+You will likely need to start the emulator from the command line, in order to specify the `-packet-streamer-endpoint <hostname>:<port>` option (unless the emulator offers a way to control that feature from a user/ui menu).
-To connect a virtual controller to the Android Bluetooth stack, use the bumble `android-emulator` transport in `controller` mode. For example, using the default gRPC port, the transport name would be: `android-emulator:mode=controller`.
-
-!!! example "Connect the Android emulator to the first USB Bluetooth dongle, using the `hci_bridge` application"
+!!! example "Launch the emulator with a netsim replacement"
+ In this example, we launch an emulator AVD named "Tiramisu", with a Bumble HCI bridge running
+ on port 8877.
```shell
- $ bumble-hci-bridge android-emulator:mode=controller usb:0
+ $ emulator -packet-streamer-endpoint localhost:8877 -avd Tiramisu
```
+!!! tip
+ Attaching a virtual controller while the Android Bluetooth stack is running may not be well supported. So you may need to disable Bluetooth in your running Android guest
+ before attaching the virtual controller, then re-enable it once attached.
+
+
## Other Tools
The `show` application that's included with Bumble can be used to parse and pretty-print the HCI packets
-from an Android HCI "snoop log" (see [this page](https://source.android.com/devices/bluetooth/verifying_debugging)
+from an Android HCI "snoop log" (see [this page](https://source.android.com/devices/bluetooth/verifying_debugging)
for details on how to obtain HCI snoop logs from an Android device).
Use the `--format snoop` option to specify that the file is in that specific format.
@@ -86,4 +121,3 @@ Use the `--format snoop` option to specify that the file is in that specific for
```shell
$ bumble-show --format snoop btsnoop_hci.log
```
-
diff --git a/docs/mkdocs/src/platforms/linux.md b/docs/mkdocs/src/platforms/linux.md
index 6468cd9..77f46f8 100644
--- a/docs/mkdocs/src/platforms/linux.md
+++ b/docs/mkdocs/src/platforms/linux.md
@@ -1,47 +1,85 @@
:material-linux: LINUX PLATFORM
===============================
-In addition to all the standard functionality available from the project by running the python tools and/or writing your own apps by leveraging the API, it is also possible on Linux hosts to interface the Bumble stack with the native BlueZ stack, and with Bluetooth controllers.
-
-Using Bumble With BlueZ
------------------------
+Using Bumble With Physical Bluetooth Controllers
+------------------------------------------------
-A Bumble virtual controller can be attached to the BlueZ stack.
-Attaching a controller to BlueZ can be done by either simulating a UART HCI interface, or by using the VHCI driver interface if available.
-In both cases, the controller can run locally on the Linux host, or remotely on a different host, with a bridge between the remote controller and the local BlueZ host, which may be useful when the BlueZ stack is running on an embedded system, or a host on which running the Bumble controller is not convenient.
+A Bumble application can interface with a local Bluetooth controller on a Linux host.
+The 3 main types of physical Bluetooth controllers are:
-### Using VHCI
+ * Bluetooth USB Dongle
+ * HCI over UART (via a serial port)
+ * Kernel-managed Bluetooth HCI (HCI Sockets)
-With the [VHCI transport](../transports/vhci.md) you can attach a Bumble virtual controller to the BlueZ stack. Once attached, the controller will appear just like any other controller, and thus can be used with the standard BlueZ tools.
+!!! tip "Conflicts with the kernel and BlueZ"
+ If your use a USB dongle that is recognized by your kernel as a supported Bluetooth device, it is
+ likely that the kernel driver will claim that USB device and attach it to the BlueZ stack.
+ If you want to claim ownership of it to use with Bumble, you will need to set the state of the corresponding HCI interface as `DOWN`.
+ HCI interfaces are numbered, starting from 0 (i.e `hci0`, `hci1`, ...).
-!!! example "Attaching a virtual controller"
- With the example app `run_controller.py`:
+ For example, to bring `hci0` down:
```
- PYTHONPATH=. python3 examples/run_controller.py F6:F7:F8:F9:FA:FB examples/device1.json vhci
- ```
-
- You should see a 'Virtual Bus' controller. For example:
- ```
- $ hciconfig
- hci0: Type: Primary Bus: Virtual
- BD Address: F6:F7:F8:F9:FA:FB ACL MTU: 27:64 SCO MTU: 0:0
- UP RUNNING
- RX bytes:0 acl:0 sco:0 events:43 errors:0
- TX bytes:274 acl:0 sco:0 commands:43 errors:0
+ $ sudo hciconfig hci0 down
```
- And scanning for devices should show the virtual 'Bumble' device that's running as part of the `run_controller.py` example app:
+ You can use the `hciconfig` command with no arguments to get a list of HCI interfaces seen by
+ the kernel.
+
+ Also, if `bluetoothd` is running on your system, it will likely re-claim the interface after you
+ close it, so you may need to bring the interface back `UP` before using it again, or to disable
+ `bluetoothd` altogether (see the section further below about BlueZ and `bluetoothd`).
+
+### Using a USB Dongle
+
+See the [USB Transport page](../transports/usb.md) for general information on how to use HCI USB controllers.
+
+!!! tip "USB Permissions"
+ By default, when running as a regular user, you won't have the permission to use
+ arbitrary USB devices.
+ You can change the permissions for a specific USB device based on its bus number and
+ device number (you can use `lsusb` to find the Bus and Device numbers for your Bluetooth
+ dongle).
+
+ Example:
```
- pi@raspberrypi:~ $ sudo hcitool -i hci2 lescan
- LE Scan ...
- F0:F1:F2:F3:F4:F5 Bumble
+ $ sudo chmod o+w /dev/bus/usb/001/004
```
+ This will change the permissions for Device 4 on Bus 1.
+
+ Note that the USB Bus number and Device number may change depending on where you plug the USB
+ dongle and what other USB devices and hubs are also plugged in.
+
+ If you need to make the permission changes permanent across reboots, you can create a `udev`
+ rule for your specific Bluetooth dongle. Visit [this Arch Linux Wiki page](https://wiki.archlinux.org/title/udev) for a
+ good overview of how you may do that.
+
+### Using HCI over UART
+
+See the [Serial Transport page](../transports/serial.md) for general information on how to use HCI over a UART (serial port).
### Using HCI Sockets
HCI sockets provide a way to send/receive HCI packets to/from a Bluetooth controller managed by the kernel.
-The HCI device referenced by an `hci-socket` transport (`hciX`, where `X` is an integer, with `hci0` being the first controller device, and so on) must be in the `DOWN` state before it can be opened as a transport.
-You can bring a HCI controller `UP` or `DOWN` with `hciconfig`.
+See the [HCI Socket Transport page](../transports/hci_socket.md) for details on the `hci-socket` tansport syntax.
+
+The HCI device referenced by an `hci-socket` transport (`hci<X>`, where `<X>` is an integer, with `hci0` being the first controller device, and so on) must be in the `DOWN` state before it can be opened as a transport.
+You can bring a HCI controller `UP` or `DOWN` with `hciconfig hci<X> up` and `hciconfig hci<X> up`.
+
+!!! tip "HCI Socket Permissions"
+ By default, when running as a regular user, you won't have the permission to use
+ an HCI socket to a Bluetooth controller (you may see an exception like `PermissionError: [Errno 1] Operation not permitted`).
+
+ If you want to run without using `sudo`, you need to manage the capabilities by adding the appropriate entries in `/etc/security/capability.conf` to grant a user or group the `cap_net_admin` capability.
+ See [this manpage](https://manpages.ubuntu.com/manpages/bionic/man5/capability.conf.5.html) for details.
+
+ Alternatively, if you are just experimenting temporarily, the `capsh` command may be useful in order
+ to execute a single command with enhanced permissions, as in this example:
+
+
+ ```
+ $ sudo capsh --caps="cap_net_admin+eip cap_setpcap,cap_setuid,cap_setgid+ep" --keep=1 --user=$USER --addamb=cap_net_admin -- -c "<path/to/executable> <executable-args>"
+ ```
+ Where `<path/to/executable>` is the path to your `python3` executable or to one of the Bumble bundled command-line applications.
!!! tip "List all available controllers"
The command
@@ -56,45 +94,32 @@ You can bring a HCI controller `UP` or `DOWN` with `hciconfig`.
pi@raspberrypi:~ $ hciconfig
hci1: Type: Primary Bus: USB
BD Address: 00:16:A4:5A:40:F2 ACL MTU: 1021:8 SCO MTU: 64:1
- DOWN
+ DOWN
RX bytes:84056 acl:0 sco:0 events:51 errors:0
TX bytes:1980 acl:0 sco:0 commands:90 errors:0
hci0: Type: Primary Bus: UART
BD Address: DC:A6:32:75:2C:97 ACL MTU: 1021:8 SCO MTU: 64:1
- DOWN
+ DOWN
RX bytes:68038 acl:0 sco:0 events:692 errors:0
TX bytes:20105 acl:0 sco:0 commands:843 errors:0
```
!!! tip "Disabling `bluetoothd`"
- When the Bluetooth daemon, `bluetoothd`, is running, it will try to use any HCI controller attached to the BlueZ stack, automatically. This means that whenever an HCI socket transport is released, it is likely that `bluetoothd` will take it over, so you will get a "device busy" condition (ex: `OSError: [Errno 16] Device or resource busy`). If that happens, you can always use
+ When the Bluetooth daemon, `bluetoothd`, is running, it will try to use any HCI controller attached to the BlueZ stack, automatically. This means that whenever an HCI socket transport is released, it is likely that `bluetoothd` will take it over, so you will get a "device busy" condition (ex: `OSError: [Errno 16] Device or resource busy`). If that happens, you can always use
```
$ hciconfig hci0 down
- ```
- (or `hciX` with `X` being the index of the controller device you want to use), but a simpler solution is to just stop the `bluetoothd` daemon, with a command like:
+ ```
+ (or `hci<X>` with `<X>` being the index of the controller device you want to use), but a simpler solution is to just stop the `bluetoothd` daemon, with a command like:
```
$ sudo systemctl stop bluetooth.service
```
You can always re-start the daemon with
```
$ sudo systemctl start bluetooth.service
- ```
-### Using a Simulated UART HCI
-
-### Bridge to a Remote Controller
-
-
-Using Bumble With Bluetooth Controllers
----------------------------------------
-
-A Bumble application can interface with a local Bluetooth controller.
-If your Bluetooth controller is a standard HCI USB controller, see the [USB Transport page](../transports/usb.md) for details on how to use HCI USB controllers.
-If your Bluetooth controller is a standard HCI UART controller, see the [Serial Transport page](../transports/serial.md).
-Alternatively, a Bumble Host object can communicate with one of the platform's controllers via an HCI Socket.
-
-`<details to be filled in>`
+Bumble on the Raspberry Pi
+--------------------------
### Raspberry Pi 4 :fontawesome-brands-raspberry-pi:
@@ -102,9 +127,10 @@ You can use the Bluetooth controller either via the kernel, or directly to the d
#### Via The Kernel
-Use an HCI Socket transport
+Use an HCI Socket transport (see section above)
#### Directly
+
In order to use the Bluetooth controller directly on a Raspberry Pi 4 board, you need to ensure that it isn't being used by the BlueZ stack (which it probably is by default).
```
@@ -136,3 +162,45 @@ should detach the controller from the stack, after which you can use the HCI UAR
python3 run_scanner.py serial:/dev/serial1,3000000
```
+
+Using Bumble With BlueZ
+-----------------------
+
+In addition to all the standard functionality available from the project by running the python tools and/or writing your own apps by leveraging the API, it is also possible on Linux hosts to interface the Bumble stack with the native BlueZ stack, and with Bluetooth controllers.
+
+A Bumble virtual controller can be attached to the BlueZ stack.
+Attaching a controller to BlueZ can be done by either simulating a UART HCI interface, or by using the VHCI driver interface if available.
+In both cases, the controller can run locally on the Linux host, or remotely on a different host, with a bridge between the remote controller and the local BlueZ host, which may be useful when the BlueZ stack is running on an embedded system, or a host on which running the Bumble controller is not convenient.
+
+### Using VHCI
+
+With the [VHCI transport](../transports/vhci.md) you can attach a Bumble virtual controller to the BlueZ stack. Once attached, the controller will appear just like any other controller, and thus can be used with the standard BlueZ tools.
+
+!!! example "Attaching a virtual controller"
+ With the example app `run_controller.py`:
+ ```
+ python3 examples/run_controller.py F6:F7:F8:F9:FA:FB examples/device1.json vhci
+ ```
+
+ You should see a 'Virtual Bus' controller. For example:
+ ```
+ $ hciconfig
+ hci0: Type: Primary Bus: Virtual
+ BD Address: F6:F7:F8:F9:FA:FB ACL MTU: 27:64 SCO MTU: 0:0
+ UP RUNNING
+ RX bytes:0 acl:0 sco:0 events:43 errors:0
+ TX bytes:274 acl:0 sco:0 commands:43 errors:0
+ ```
+
+ And scanning for devices should show the virtual 'Bumble' device that's running as part of the `run_controller.py` example app:
+ ```
+ pi@raspberrypi:~ $ sudo hcitool -i hci2 lescan
+ LE Scan ...
+ F0:F1:F2:F3:F4:F5 Bumble
+ ```
+
+ ```
+
+### Using a Simulated UART HCI
+
+### Bridge to a Remote Controller
diff --git a/docs/mkdocs/src/platforms/macos.md b/docs/mkdocs/src/platforms/macos.md
index 7c5bc32..2133ad6 100644
--- a/docs/mkdocs/src/platforms/macos.md
+++ b/docs/mkdocs/src/platforms/macos.md
@@ -11,4 +11,3 @@ To do that, use the following command:
sudo nvram bluetoothHostControllerSwitchBehavior="never"
```
A reboot shouldn't be necessary after that. See [Tech Note 2295](https://developer.apple.com/library/archive/technotes/tn2295/_index.html)
-
diff --git a/docs/mkdocs/src/platforms/windows.md b/docs/mkdocs/src/platforms/windows.md
index 2157695..330f1ab 100644
--- a/docs/mkdocs/src/platforms/windows.md
+++ b/docs/mkdocs/src/platforms/windows.md
@@ -7,7 +7,7 @@ USB HCI
To use a Bluetooth USB dongle on Windows, you need a USB dongle that does not require a vendor Windows driver (the dongle will be used directly through the [`WinUSB`](https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/winusb) driver rather than through a vendor-supplied Windows driver).
In order to use the dongle, the `WinUSB` driver must be assigned to the USB device. It is likely that, by default, when you first plug in the dongle, it will be recognized by Windows as a Bluetooth USB device, and Windows will try to use it with its native Bluetooth stack. You will need to switch the driver, which can be done easily with the [Zadig tool](https://zadig.akeo.ie/).
-In the Zadig tool, select your USB dongle device, and associate it with WinUSB.
+In the Zadig tool, select your USB dongle device, and associate it with WinUSB.
Once the WinUSB driver is correctly assigned to your device, you can confirm that by checking the settings with the Windows Device Manager control panel. Your device should appear under "Universal Serial Bus Device" (not under "Bluetooth"), and inspecting the driver details, you should see `winusb.sys` in the list of driver files.
![USB Driver Details](winusb_driver.png)
diff --git a/docs/mkdocs/src/transports/android_emulator.md b/docs/mkdocs/src/transports/android_emulator.md
index d903394..974ba4f 100644
--- a/docs/mkdocs/src/transports/android_emulator.md
+++ b/docs/mkdocs/src/transports/android_emulator.md
@@ -1,21 +1,41 @@
ANDROID EMULATOR TRANSPORT
==========================
-The Android emulator transport either connects, as a host, to a "Root Canal" virtual controller
-("host" mode), or attaches a virtual controller to the Android Bluetooth host stack ("controller" mode).
+!!! warning
+ Bluetooth support in the Android emulator has recently changed. The older mode, using
+ the `android-emulator` transport name with Bumble, while still implemented, is now
+ obsolete, and may not be supported by recent versions of the emulator.
+ Use the `android-netsim` transport name instead.
+
+
+The Android "netsim" transport either connects, as a host, to a **Netsim** virtual controller
+("host" mode), or acts as a virtual controller itself ("controller" mode) accepting host
+connections.
## Moniker
-The moniker syntax for an Android Emulator transport is: `android-emulator:[mode=<host|controller>][mode=<host|controller>]`.
-Both the `mode=<host|controller>` and `mode=<host|controller>` parameters are optional (so the moniker `android-emulator` by itself is a valid moniker, which will create a transport in `host` mode, connected to `localhost` on the default gRPC port for the emulator)
+The moniker syntax for an Android Emulator "netsim" transport is: `android-netsim:[<host>:<port>][<options>]`,
+where `<options>` is a ','-separated list of `<name>=<value>` pairs`.
+The `mode` parameter name can specify running as a host or a controller, and `<hostname>:<port>` can specify a host name (or IP address) and TCP port number on which to reach the gRPC server for the emulator (in "host" mode), or to accept gRPC connections (in "controller" mode).
+Both the `mode=<host|controller>` and `<hostname>:<port>` parameters are optional (so the moniker `android-netsim` by itself is a valid moniker, which will create a transport in `host` mode, connected to `localhost` on the default gRPC port for the Netsim background process).
+
+!!! example Example
+ `android-netsim`
+ connect as a host to Netsim on the gRPC port discovered automatically.
!!! example Example
- `android-emulator`
- connect as a host to the emulator on localhost:8554
+ `android-netsim:_:8555,mode=controller`
+ Run as a controller, accepting gRPC connection on port 8555.
!!! example Example
- `android-emulator:mode=controller`
- connect as a controller to the emulator on localhost:8554
+ `android-netsim:localhost:8555`
+ connect as a host to Netsim on localhost:8555
!!! example Example
- `android-emulator:localhost:8555`
- connect as a host to the emulator on localhost:8555
+ `android-netsim:localhost:8555`
+ connect as a host to Netsim on localhost:8555
+
+!!! example Example
+ `android-netsim:name=bumble1234`
+ connect as a host to Netsim on the discovered gRPC port, using `bumble1234` as the
+ controller instance name.
+
diff --git a/docs/mkdocs/src/transports/file.md b/docs/mkdocs/src/transports/file.md
index d20154f..b283137 100644
--- a/docs/mkdocs/src/transports/file.md
+++ b/docs/mkdocs/src/transports/file.md
@@ -8,5 +8,5 @@ This is typically used to open a PTY, or unix driver, not for real files.
The moniker for a File transport is `file:<path>`
!!! example
- `file:/dev/ttys001`
- Opens the pseudo terminal `/dev/ttys001` as a transport \ No newline at end of file
+ `file:/dev/ttys001`
+ Opens the pseudo terminal `/dev/ttys001` as a transport
diff --git a/docs/mkdocs/src/transports/hci_socket.md b/docs/mkdocs/src/transports/hci_socket.md
index 58cdbfb..c79de36 100644
--- a/docs/mkdocs/src/transports/hci_socket.md
+++ b/docs/mkdocs/src/transports/hci_socket.md
@@ -10,8 +10,8 @@ An HCI Socket can send/receive HCI packets to/from a Bluetooth HCI controller ma
The moniker for an HCI Socket transport is either just `hci-socket` (to use the default/first Bluetooth controller), or `hci-socket:<index>` where `<index>` is the 0-based index of a Bluetooth controller device.
!!! example
- `hci-socket`
+ `hci-socket`
Use an HCI socket to the first Bluetooth controller (`hci0 on Linux`)
!!! tip "On Linux"
- See the [Linux Platform](../platforms/linux.md) page for details on how to use HCI sockets on Linux \ No newline at end of file
+ See the [Linux Platform](../platforms/linux.md) page for details on how to use HCI sockets on Linux
diff --git a/docs/mkdocs/src/transports/index.md b/docs/mkdocs/src/transports/index.md
index 70827c1..feb57e5 100644
--- a/docs/mkdocs/src/transports/index.md
+++ b/docs/mkdocs/src/transports/index.md
@@ -16,5 +16,6 @@ Several types of transports are supported:
* [PTY](pty.md): a PTY (pseudo terminal) is used to send/receive HCI packets. This is convenient to expose a virtual controller as if it were an HCI UART
* [VHCI](vhci.md): used to attach a virtual controller to a Bluetooth stack on platforms that support it.
* [HCI Socket](hci_socket.md): an HCI socket, on platforms that support it, to send/receive HCI packets to/from an HCI controller managed by the OS.
- * [Android Emulator](android_emulator.md): a gRPC connection to an Android emulator is used to setup either an HCI interface to the emulator's "Root Canal" virtual controller, or attach a virtual controller to the Android Bluetooth host stack.
+ * [Android Emulator](android_emulator.md): a gRPC connection to the Android emulator's "netsim"
+ virtual controller, or from the Android emulator, is used to setup either an HCI interface to the emulator's "netsim" virtual controller, or serve as a virtual controller for the Android Bluetooth host stack.
* [File](file.md): HCI packets are read/written to a file-like node in the filesystem.
diff --git a/docs/mkdocs/src/transports/pty.md b/docs/mkdocs/src/transports/pty.md
index fafa3c9..2c85050 100644
--- a/docs/mkdocs/src/transports/pty.md
+++ b/docs/mkdocs/src/transports/pty.md
@@ -8,5 +8,5 @@ The moniker syntax for a PTY transport is: `pty[:path]`.
Where `path`, is used, is the path name where a symbolic link to the PTY will be created for convenience (the link will be removed when the transport is closed or when the process exits).
!!! example
- `pty:virtual_hci`
+ `pty:virtual_hci`
Creates a PTY entry and a symbolic link, named `virtual_hci`, linking to the PTY
diff --git a/docs/mkdocs/src/transports/serial.md b/docs/mkdocs/src/transports/serial.md
index 3ce2e38..acc2c0d 100644
--- a/docs/mkdocs/src/transports/serial.md
+++ b/docs/mkdocs/src/transports/serial.md
@@ -8,5 +8,5 @@ The moniker syntax for a serial transport is: `serial:<device-path>[,<speed>]`
When `<speed>` is omitted, the default value of 1000000 is used
!!! example
- `serial:/dev/tty.usbmodem0006839912172,1000000`
+ `serial:/dev/tty.usbmodem0006839912172,1000000`
Opens the serial port `/dev/tty.usbmodem0006839912172` at `1000000`bps
diff --git a/docs/mkdocs/src/transports/tcp_client.md b/docs/mkdocs/src/transports/tcp_client.md
index 39fb477..a5a4154 100644
--- a/docs/mkdocs/src/transports/tcp_client.md
+++ b/docs/mkdocs/src/transports/tcp_client.md
@@ -7,5 +7,5 @@ The TCP Client transport uses an outgoing TCP connection to a host:port address.
The moniker syntax for a TCP client transport is: `tcp-client:<remote-host>:<remote-port>`
!!! example
- `tcp-client:127.0.0.1:9001`
- Connects to port 9001 on the local host \ No newline at end of file
+ `tcp-client:127.0.0.1:9001`
+ Connects to port 9001 on the local host
diff --git a/docs/mkdocs/src/transports/tcp_server.md b/docs/mkdocs/src/transports/tcp_server.md
index 3af8ff0..966308e 100644
--- a/docs/mkdocs/src/transports/tcp_server.md
+++ b/docs/mkdocs/src/transports/tcp_server.md
@@ -5,9 +5,9 @@ The TCP Client transport uses an incoming TCP connection to a host:port address.
## Moniker
The moniker syntax for a TCP server transport is: `tcp-server:<local-host>:<local-port>`
-where `<local-host>` may be the address of a local network interface, or `_` to accept
+where `<local-host>` may be the address of a local network interface, or `_` to accept
connections on all local network interfaces.
!!! example
- `tcp-server:_:9001`
- Waits for and accepts connections on port `9001` \ No newline at end of file
+ `tcp-server:_:9001`
+ Waits for and accepts connections on port `9001`
diff --git a/docs/mkdocs/src/transports/udp.md b/docs/mkdocs/src/transports/udp.md
index 4238bc8..ad9c245 100644
--- a/docs/mkdocs/src/transports/udp.md
+++ b/docs/mkdocs/src/transports/udp.md
@@ -7,5 +7,5 @@ The UDP transport is a UDP socket, receiving packets on a specified port number,
The moniker syntax for a UDP transport is: `udp:<local-host>:<local-port>,<remote-host>:<remote-port>`.
!!! example
- `udp:0.0.0.0:9000,127.0.0.1:9001`
+ `udp:0.0.0.0:9000,127.0.0.1:9001`
UDP transport where packets are received on port `9000` and sent to `127.0.0.1` on port `9001`
diff --git a/docs/mkdocs/src/transports/usb.md b/docs/mkdocs/src/transports/usb.md
index f35259b..e400630 100644
--- a/docs/mkdocs/src/transports/usb.md
+++ b/docs/mkdocs/src/transports/usb.md
@@ -4,16 +4,70 @@ USB TRANSPORT
The USB transport interfaces with a local Bluetooth USB dongle.
## Moniker
-The moniker for a USB transport is either `usb:<index>` or `usb:<vendor>:<product>`
-with `<index>` as the 0-based index to select amongst all the devices that appear to be supporting Bluetooth HCI (0 being the first one), or where `<vendor>` and `<product>` are a vendor ID and product ID in hexadecimal.
+The moniker for a USB transport is either:
-!!! example
- `usb:04b4:f901`
- Use the USB dongle with `vendor` equal to `04b4` and `product` equal to `f901`
+ * `usb:<index>`
+ * `usb:<vendor>:<product>`
+ * `usb:<vendor>:<product>/<serial-number>`
+ * `usb:<vendor>:<product>#<index>`
+
+with `<index>` as a 0-based index (0 being the first one) to select amongst all the matching devices when there are more than one.
+In the `usb:<index>` form, matching devices are the ones supporting Bluetooth HCI, as declared by their Class, Subclass and Protocol.
+In the `usb:<vendor>:<product>#<index>` form, matching devices are the ones with the specified `<vendor>` and `<product>` identification.
+
+`<vendor>` and `<product>` are a vendor ID and product ID in hexadecimal.
+
+In addition, if the moniker ends with the symbol "!", the device will be used in "forced" mode:
+the first USB interface of the device will be used, regardless of the interface class/subclass.
+This may be useful for some devices that use a custom class/subclass but may nonetheless work as-is.
+
+!!! examples
+ `usb:04b4:f901`
+ The USB dongle with `<vendor>` equal to `04b4` and `<product>` equal to `f901`
+
+ `usb:0`
+ The first Bluetooth HCI dongle that's declared as such by Class/Subclass/Protocol
+
+ `usb:04b4:f901/0016A45B05D8`
+ The USB dongle with `<vendor>` equal to `04b4`, `<product>` equal to `f901` and `<serial>` equal to `0016A45B05D8`
+
+ `usb:04b4:f901/#1`
+ The second USB dongle with `<vendor>` equal to `04b4` and `<product>` equal to `f901`
+
+ `usb:0B05:17CB!`
+ The BT USB dongle vendor=0B05 and product=17CB, in "forced" mode.
- `usb:0`
- Use the first Bluetooth dongle
## Alternative
The library includes two different implementations of the USB transport, implemented using different python bindings for `libusb`.
Using the transport prefix `pyusb:` instead of `usb:` selects the implementation based on [PyUSB](https://pypi.org/project/pyusb/), using the synchronous API of `libusb`, whereas the default implementation is based on [libusb1](https://pypi.org/project/libusb1/), using the asynchronous API of `libusb`. In order to use the alternative PyUSB-based implementation, you need to ensure that you have installed that python module, as it isn't installed by default as a dependency of Bumble.
+
+## Libusb
+
+The `libusb-1.0` shared library is required to use both `usb` and `pyusb` transports. This library should be installed automatically with Bumble, as part of the `libusb_package` Python package.
+If your OS or architecture is not supported by `libusb_package`, you can install a system-wide library with `brew install libusb` for Mac or `apt install libusb-1.0-0` for Linux.
+
+## Listing Available USB Devices
+
+### With `usb_probe`
+You can use the [`usb_probe`](../apps_and_tools/usb_probe.md) tool to list all the USB devices attached to your host computer.
+The tool will also show the `usb:XXX` transport name(s) you can use to reference each device.
+
+
+### With `lsusb`
+On Linux and macOS, the `lsusb` tool serves a similar purpose to Bumble's own `usb_probe` tool (without the Bumble specifics)
+
+#### Installing lsusb
+
+On Mac: `brew install lsusb`
+On Linux: `sudo apt-get install usbutils`
+
+#### Using lsusb
+
+```
+$ lsusb
+Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
+Bus 003 Device 014: ID 0b05:17cb ASUSTek Computer, Inc. Broadcom BCM20702A0 Bluetooth
+```
+
+The device id for the Bluetooth interface in this case is `0b05:17cb`.
diff --git a/docs/mkdocs/src/transports/vhci.md b/docs/mkdocs/src/transports/vhci.md
index 9d967c4..4d192f2 100644
--- a/docs/mkdocs/src/transports/vhci.md
+++ b/docs/mkdocs/src/transports/vhci.md
@@ -10,5 +10,5 @@ The VHCI transport allows attaching a virtual controller to the Bluetooth stack
The moniker for a VHCI transport is either just `vhci` (to use the default VHCI device path at `/dev/vhci`), or `vhci:<path>` where `<path>` is the path of a VHCI device.
!!! example
- `vhci`
- Attaches a virtual controller transport to `/dev/vhci` \ No newline at end of file
+ `vhci`
+ Attaches a virtual controller transport to `/dev/vhci`
diff --git a/docs/mkdocs/src/transports/ws_client.md b/docs/mkdocs/src/transports/ws_client.md
index 4238bc8..ad9c245 100644
--- a/docs/mkdocs/src/transports/ws_client.md
+++ b/docs/mkdocs/src/transports/ws_client.md
@@ -7,5 +7,5 @@ The UDP transport is a UDP socket, receiving packets on a specified port number,
The moniker syntax for a UDP transport is: `udp:<local-host>:<local-port>,<remote-host>:<remote-port>`.
!!! example
- `udp:0.0.0.0:9000,127.0.0.1:9001`
+ `udp:0.0.0.0:9000,127.0.0.1:9001`
UDP transport where packets are received on port `9000` and sent to `127.0.0.1` on port `9001`
diff --git a/docs/mkdocs/src/transports/ws_server.md b/docs/mkdocs/src/transports/ws_server.md
index 4238bc8..ad9c245 100644
--- a/docs/mkdocs/src/transports/ws_server.md
+++ b/docs/mkdocs/src/transports/ws_server.md
@@ -7,5 +7,5 @@ The UDP transport is a UDP socket, receiving packets on a specified port number,
The moniker syntax for a UDP transport is: `udp:<local-host>:<local-port>,<remote-host>:<remote-port>`.
!!! example
- `udp:0.0.0.0:9000,127.0.0.1:9001`
+ `udp:0.0.0.0:9000,127.0.0.1:9001`
UDP transport where packets are received on port `9000` and sent to `127.0.0.1` on port `9001`
diff --git a/docs/mkdocs/src/use_cases/use_case_1.md b/docs/mkdocs/src/use_cases/use_case_1.md
index 3b738ac..587122e 100644
--- a/docs/mkdocs/src/use_cases/use_case_1.md
+++ b/docs/mkdocs/src/use_cases/use_case_1.md
@@ -11,4 +11,4 @@ Write a python application (ex: a GATT client that will connect to a hear rate s
| Python || Host |<-- HCI -->| Controller |{...radio...}| Device |
| App || | Transport | | | |
+--------++--------+ +------------+ +-----------+
-``` \ No newline at end of file
+```
diff --git a/docs/mkdocs/src/use_cases/use_case_2.md b/docs/mkdocs/src/use_cases/use_case_2.md
index 6875a03..cbcc4f3 100644
--- a/docs/mkdocs/src/use_cases/use_case_2.md
+++ b/docs/mkdocs/src/use_cases/use_case_2.md
@@ -11,4 +11,4 @@ Connect a native Bluetooth application, running on a host with Bluetooth stack t
| Bluetooth |<-- HCI -->| Virtual |<== Local or ==>| Virtual || Host || Python |
| App | Transport | Controller | Remote | Controller || || App |
+-----------+ +------------+ Link +------------++--------++--------+
-``` \ No newline at end of file
+```
diff --git a/docs/mkdocs/src/use_cases/use_case_3.md b/docs/mkdocs/src/use_cases/use_case_3.md
index 0cf477d..6336641 100644
--- a/docs/mkdocs/src/use_cases/use_case_3.md
+++ b/docs/mkdocs/src/use_cases/use_case_3.md
@@ -11,4 +11,4 @@ Connect an emulated Bluetooth device (ex: an Android emulator, or an embedded de
| Bluetooth |<-- HCI -->| Virtual |<== Local or ==>| Virtual || Host || Python |
| Device | Transport | Controller | Remote | Controller || || App |
+-----------+ +------------+ Link +------------++--------++--------+
-``` \ No newline at end of file
+```
diff --git a/docs/mkdocs/src/use_cases/use_case_4.md b/docs/mkdocs/src/use_cases/use_case_4.md
index 762f974..7bb237f 100644
--- a/docs/mkdocs/src/use_cases/use_case_4.md
+++ b/docs/mkdocs/src/use_cases/use_case_4.md
@@ -6,9 +6,9 @@ USE CASE 4
Connect two emulated Bluetooth device (ex: an Android emulator, or an embedded device emulator) to each other
```
-+-----------+ +------------+ +------------+ +-----------+
++-----------+ +------------+ +------------+ +-----------+
| Emulated | | Bumble | Bumble | Bumble | | Emulated |
| Bluetooth |<-- HCI -->| Virtual |<== Local or ==>| Virtual |<-- HCI -->| Bluetooth |
| Device | Transport | Controller | Remote | Controller | Transport | Device |
+-----------+ +------------+ Link +------------+ +-----------+
-``` \ No newline at end of file
+```
diff --git a/docs/mkdocs/src/use_cases/use_case_5.md b/docs/mkdocs/src/use_cases/use_case_5.md
index 7232105..2c2fc73 100644
--- a/docs/mkdocs/src/use_cases/use_case_5.md
+++ b/docs/mkdocs/src/use_cases/use_case_5.md
@@ -17,4 +17,4 @@ Write several python applications (ex: a GATT client that will connect to a hear
| Python || Host || Controller |<--+ +-->| Controller || Host || Python |
| App || || | | || || App |
+--------++--------++------------+ +------------++--------++--------+
-``` \ No newline at end of file
+```
diff --git a/docs/mkdocs/src/use_cases/use_case_6.md b/docs/mkdocs/src/use_cases/use_case_6.md
index f27a184..1e81bcc 100644
--- a/docs/mkdocs/src/use_cases/use_case_6.md
+++ b/docs/mkdocs/src/use_cases/use_case_6.md
@@ -6,9 +6,9 @@ USE CASE 6
It can be useful to connect an emulated device (like a phone simulator, or an emulated embedded device) to a physical controller in order to connect to other Bluetooth devices. By doing this via a Bumble HCI bridge, it becomes easy to inspect the HCI packets exchanged with the controller, and possibly filter/change them if needed (for example to support vendor-specific HCI extensions).
```
-+-----------+ +--------+ +------------+ +-----------+
++-----------+ +--------+ +------------+ +-----------+
| Emulated | | Bumble | | Physical | | Bluetooth |
| Bluetooth |<-- HCI -->| HCI |<-- HCI -->| Controller |{...radio...}| Device |
| Device | Transport | Bridge | Transport | | | |
+-----------+ +--------+ +------------+ +-----------+
-``` \ No newline at end of file
+```
diff --git a/examples/a2dp_sink1.json b/examples/a2dp_sink1.json
index 61ce80d..8603194 100644
--- a/examples/a2dp_sink1.json
+++ b/examples/a2dp_sink1.json
@@ -1,5 +1,6 @@
{
"name": "Bumble Speaker",
+ "address": "F0:F1:F2:F3:F4:F5",
"class_of_device": 2360324,
"keystore": "JsonKeyStore"
}
diff --git a/examples/asha_sink1.json b/examples/asha_sink1.json
new file mode 100644
index 0000000..badef8b
--- /dev/null
+++ b/examples/asha_sink1.json
@@ -0,0 +1,5 @@
+{
+ "name": "Bumble Aid Left",
+ "address": "F1:F2:F3:F4:F5:F6",
+ "keystore": "JsonKeyStore"
+}
diff --git a/examples/asha_sink2.json b/examples/asha_sink2.json
new file mode 100644
index 0000000..785d406
--- /dev/null
+++ b/examples/asha_sink2.json
@@ -0,0 +1,5 @@
+{
+ "name": "Bumble Aid Right",
+ "address": "F7:F8:F9:FA:FB:FC",
+ "keystore": "JsonKeyStore"
+}
diff --git a/examples/async_runner.py b/examples/async_runner.py
index d0d1a12..9e71899 100644
--- a/examples/async_runner.py
+++ b/examples/async_runner.py
@@ -80,6 +80,7 @@ async def main():
await my_work_queue2.run()
print("MAIN: end (should never get here)")
+
# -----------------------------------------------------------------------------
-logging.basicConfig(level = os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
+logging.basicConfig(level=os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
asyncio.run(main())
diff --git a/examples/battery_client.py b/examples/battery_client.py
index 888b23e..3cf11b4 100644
--- a/examples/battery_client.py
+++ b/examples/battery_client.py
@@ -19,8 +19,8 @@ import asyncio
import sys
import os
import logging
-from colors import color
-from bumble.device import Device, Peer
+from bumble.colors import color
+from bumble.device import Device
from bumble.transport import open_transport
from bumble.profiles.battery_service import BatteryServiceProxy
@@ -43,30 +43,28 @@ async def main():
# Connect to the peer
target_address = sys.argv[2]
print(f'=== Connecting to {target_address}...')
- connection = await device.connect(target_address)
- print(f'=== Connected to {connection}')
+ async with device.connect_as_gatt(target_address) as peer:
+ print(f'=== Connected to {peer}')
+ battery_service = peer.create_service_proxy(BatteryServiceProxy)
- # Discover the Battery Service
- peer = Peer(connection)
- print('=== Discovering Battery Service')
- battery_service = await peer.discover_and_create_service_proxy(BatteryServiceProxy)
+ # Check that the service was found
+ if not battery_service:
+ print('!!! Service not found')
+ return
- # Check that the service was found
- if not battery_service:
- print('!!! Service not found')
- return
+ # Subscribe to and read the battery level
+ if battery_service.battery_level:
+ await battery_service.battery_level.subscribe(
+ lambda value: print(
+ f'{color("Battery Level Update:", "green")} {value}'
+ )
+ )
+ value = await battery_service.battery_level.read_value()
+ print(f'{color("Initial Battery Level:", "green")} {value}')
- # Subscribe to and read the battery level
- if battery_service.battery_level:
- await battery_service.battery_level.subscribe(
- lambda value: print(f'{color("Battery Level Update:", "green")} {value}')
- )
- value = await battery_service.battery_level.read_value()
- print(f'{color("Initial Battery Level:", "green")} {value}')
-
- await hci_source.wait_for_termination()
+ await peer.sustain()
# -----------------------------------------------------------------------------
-logging.basicConfig(level = os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
+logging.basicConfig(level=os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
asyncio.run(main())
diff --git a/examples/battery_server.py b/examples/battery_server.py
index 3fabf0d..b7f941f 100644
--- a/examples/battery_server.py
+++ b/examples/battery_server.py
@@ -38,17 +38,25 @@ async def main():
async with await open_transport_or_link(sys.argv[2]) as (hci_source, hci_sink):
device = Device.from_config_file_with_hci(sys.argv[1], hci_source, hci_sink)
- # Add a Device Information Service and Battery Service to the GATT sever
+ # Add a Battery Service to the GATT sever
battery_service = BatteryService(lambda _: random.randint(0, 100))
device.add_service(battery_service)
# Set the advertising data
device.advertising_data = bytes(
- AdvertisingData([
- (AdvertisingData.COMPLETE_LOCAL_NAME, bytes('Bumble Battery', 'utf-8')),
- (AdvertisingData.INCOMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS, bytes(battery_service.uuid)),
- (AdvertisingData.APPEARANCE, struct.pack('<H', 0x0340))
- ])
+ AdvertisingData(
+ [
+ (
+ AdvertisingData.COMPLETE_LOCAL_NAME,
+ bytes('Bumble Battery', 'utf-8'),
+ ),
+ (
+ AdvertisingData.INCOMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS,
+ bytes(battery_service.uuid),
+ ),
+ (AdvertisingData.APPEARANCE, struct.pack('<H', 0x0340)),
+ ]
+ )
)
# Go!
@@ -58,9 +66,11 @@ async def main():
# Notify every 3 seconds
while True:
await asyncio.sleep(3.0)
- await device.notify_subscribers(battery_service.battery_level_characteristic)
+ await device.notify_subscribers(
+ battery_service.battery_level_characteristic
+ )
# -----------------------------------------------------------------------------
-logging.basicConfig(level = os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
+logging.basicConfig(level=os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
asyncio.run(main())
diff --git a/examples/device_information_client.py b/examples/device_information_client.py
index ed5892b..416aa2f 100644
--- a/examples/device_information_client.py
+++ b/examples/device_information_client.py
@@ -19,7 +19,7 @@ import asyncio
import sys
import os
import logging
-from colors import color
+from bumble.colors import color
from bumble.device import Device, Peer
from bumble.profiles.device_information_service import DeviceInformationServiceProxy
from bumble.transport import open_transport
@@ -28,7 +28,9 @@ from bumble.transport import open_transport
# -----------------------------------------------------------------------------
async def main():
if len(sys.argv) != 3:
- print('Usage: device_information_client.py <transport-spec> <bluetooth-address>')
+ print(
+ 'Usage: device_information_client.py <transport-spec> <bluetooth-address>'
+ )
print('example: device_information_client.py usb:0 E1:CA:72:48:C4:E8')
return
@@ -49,7 +51,9 @@ async def main():
# Discover the Device Information service
peer = Peer(connection)
print('=== Discovering Device Information Service')
- device_information_service = await peer.discover_service_and_create_proxy(DeviceInformationServiceProxy)
+ device_information_service = await peer.discover_service_and_create_proxy(
+ DeviceInformationServiceProxy
+ )
# Check that the service was found
if device_information_service is None:
@@ -58,23 +62,53 @@ async def main():
# Read and print the fields
if device_information_service.manufacturer_name is not None:
- print(color('Manufacturer Name: ', 'green'), await device_information_service.manufacturer_name.read_value())
+ print(
+ color('Manufacturer Name: ', 'green'),
+ await device_information_service.manufacturer_name.read_value(),
+ )
if device_information_service.model_number is not None:
- print(color('Model Number: ', 'green'), await device_information_service.model_number.read_value())
+ print(
+ color('Model Number: ', 'green'),
+ await device_information_service.model_number.read_value(),
+ )
if device_information_service.serial_number is not None:
- print(color('Serial Number: ', 'green'), await device_information_service.serial_number.read_value())
+ print(
+ color('Serial Number: ', 'green'),
+ await device_information_service.serial_number.read_value(),
+ )
if device_information_service.hardware_revision is not None:
- print(color('Hardware Revision: ', 'green'), await device_information_service.hardware_revision.read_value())
+ print(
+ color('Hardware Revision: ', 'green'),
+ await device_information_service.hardware_revision.read_value(),
+ )
if device_information_service.firmware_revision is not None:
- print(color('Firmware Revision: ', 'green'), await device_information_service.firmware_revision.read_value())
+ print(
+ color('Firmware Revision: ', 'green'),
+ await device_information_service.firmware_revision.read_value(),
+ )
if device_information_service.software_revision is not None:
- print(color('Software Revision: ', 'green'), await device_information_service.software_revision.read_value())
+ print(
+ color('Software Revision: ', 'green'),
+ await device_information_service.software_revision.read_value(),
+ )
if device_information_service.system_id is not None:
- print(color('System ID: ', 'green'), await device_information_service.system_id.read_value())
- if device_information_service.ieee_regulatory_certification_data_list is not None:
- print(color('Regulatory Certification:', 'green'), (await device_information_service.ieee_regulatory_certification_data_list.read_value()).hex())
+ print(
+ color('System ID: ', 'green'),
+ await device_information_service.system_id.read_value(),
+ )
+ if (
+ device_information_service.ieee_regulatory_certification_data_list
+ is not None
+ ):
+ print(
+ color('Regulatory Certification:', 'green'),
+ (
+ # pylint: disable-next=line-too-long
+ await device_information_service.ieee_regulatory_certification_data_list.read_value()
+ ).hex(),
+ )
# -----------------------------------------------------------------------------
-logging.basicConfig(level = os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
+logging.basicConfig(level=os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
asyncio.run(main())
diff --git a/examples/device_information_server.py b/examples/device_information_server.py
index 9c3b6b1..d437cae 100644
--- a/examples/device_information_server.py
+++ b/examples/device_information_server.py
@@ -39,21 +39,26 @@ async def main():
# Add a Device Information Service to the GATT sever
device_information_service = DeviceInformationService(
- manufacturer_name = 'ACME',
- model_number = 'AB-102',
- serial_number = '7654321',
- hardware_revision = '1.1.3',
- software_revision = '2.5.6',
- system_id = (0x123456, 0x8877665544)
+ manufacturer_name='ACME',
+ model_number='AB-102',
+ serial_number='7654321',
+ hardware_revision='1.1.3',
+ software_revision='2.5.6',
+ system_id=(0x123456, 0x8877665544),
)
device.add_service(device_information_service)
# Set the advertising data
device.advertising_data = bytes(
- AdvertisingData([
- (AdvertisingData.COMPLETE_LOCAL_NAME, bytes('Bumble Device', 'utf-8')),
- (AdvertisingData.APPEARANCE, struct.pack('<H', 0x0340))
- ])
+ AdvertisingData(
+ [
+ (
+ AdvertisingData.COMPLETE_LOCAL_NAME,
+ bytes('Bumble Device', 'utf-8'),
+ ),
+ (AdvertisingData.APPEARANCE, struct.pack('<H', 0x0340)),
+ ]
+ )
)
# Go!
@@ -61,6 +66,7 @@ async def main():
await device.start_advertising(auto_restart=True)
await hci_source.wait_for_termination()
+
# -----------------------------------------------------------------------------
-logging.basicConfig(level = os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
+logging.basicConfig(level=os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
asyncio.run(main())
diff --git a/examples/heart_rate_client.py b/examples/heart_rate_client.py
new file mode 100644
index 0000000..ecfcffb
--- /dev/null
+++ b/examples/heart_rate_client.py
@@ -0,0 +1,74 @@
+# Copyright 2021-2022 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# -----------------------------------------------------------------------------
+# Imports
+# -----------------------------------------------------------------------------
+import asyncio
+import sys
+import os
+import logging
+from bumble.colors import color
+from bumble.device import Device
+from bumble.transport import open_transport
+from bumble.profiles.heart_rate_service import HeartRateServiceProxy
+
+
+# -----------------------------------------------------------------------------
+async def main():
+ if len(sys.argv) != 3:
+ print('Usage: heart_rate_client.py <transport-spec> <bluetooth-address>')
+ print('example: heart_rate_client.py usb:0 E1:CA:72:48:C4:E8')
+ return
+
+ print('<<< connecting to HCI...')
+ async with await open_transport(sys.argv[1]) as (hci_source, hci_sink):
+ print('<<< connected')
+
+ # Create and start a device
+ device = Device.with_hci('Bumble', 'F0:F1:F2:F3:F4:F5', hci_source, hci_sink)
+ await device.power_on()
+
+ # Connect to the peer
+ target_address = sys.argv[2]
+ print(f'=== Connecting to {target_address}...')
+ async with device.connect_as_gatt(target_address) as peer:
+ print(f'=== Connected to {peer}')
+
+ heart_rate_service = peer.create_service_proxy(HeartRateServiceProxy)
+
+ # Check that the service was found
+ if not heart_rate_service:
+ print('!!! Service not found')
+ return
+
+ # Read the body sensor location
+ if heart_rate_service.body_sensor_location:
+ location = await heart_rate_service.body_sensor_location.read_value()
+ print(color('Sensor Location:', 'green'), location)
+
+ # Subscribe to the heart rate measurement
+ if heart_rate_service.heart_rate_measurement:
+ await heart_rate_service.heart_rate_measurement.subscribe(
+ lambda value: print(
+ f'{color("Heart Rate Measurement:", "green")} {value}'
+ )
+ )
+
+ await peer.sustain()
+
+
+# -----------------------------------------------------------------------------
+logging.basicConfig(level=os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
+asyncio.run(main())
diff --git a/examples/heart_rate_server.py b/examples/heart_rate_server.py
new file mode 100644
index 0000000..32f53b1
--- /dev/null
+++ b/examples/heart_rate_server.py
@@ -0,0 +1,115 @@
+# Copyright 2021-2022 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# -----------------------------------------------------------------------------
+# Imports
+# -----------------------------------------------------------------------------
+import sys
+import time
+import math
+import random
+import struct
+import logging
+import asyncio
+import os
+
+from bumble.core import AdvertisingData
+from bumble.device import Device
+from bumble.transport import open_transport_or_link
+from bumble.profiles.device_information_service import DeviceInformationService
+from bumble.profiles.heart_rate_service import HeartRateService
+
+
+# -----------------------------------------------------------------------------
+async def main():
+ if len(sys.argv) != 3:
+ print('Usage: python heart_rate_server.py <device-config> <transport-spec>')
+ print('example: python heart_rate_server.py device1.json usb:0')
+ return
+
+ async with await open_transport_or_link(sys.argv[2]) as (hci_source, hci_sink):
+ device = Device.from_config_file_with_hci(sys.argv[1], hci_source, hci_sink)
+
+ # Keep track of accumulated expended energy
+ energy_start_time = time.time()
+
+ def reset_energy_expended():
+ nonlocal energy_start_time
+ energy_start_time = time.time()
+
+ # Add a Device Information Service and Heart Rate Service to the GATT sever
+ device_information_service = DeviceInformationService(
+ manufacturer_name='ACME',
+ model_number='HR-102',
+ serial_number='7654321',
+ hardware_revision='1.1.3',
+ software_revision='2.5.6',
+ system_id=(0x123456, 0x8877665544),
+ )
+
+ heart_rate_service = HeartRateService(
+ read_heart_rate_measurement=lambda _: HeartRateService.HeartRateMeasurement(
+ heart_rate=100 + int(50 * math.sin(time.time() * math.pi / 60)),
+ sensor_contact_detected=random.choice((True, False, None)),
+ energy_expended=random.choice(
+ (int((time.time() - energy_start_time) * 100), None)
+ ),
+ rr_intervals=random.choice(
+ (
+ (
+ random.randint(900, 1100) / 1000,
+ random.randint(900, 1100) / 1000,
+ ),
+ None,
+ )
+ ),
+ ),
+ body_sensor_location=HeartRateService.BodySensorLocation.WRIST,
+ reset_energy_expended=lambda _: reset_energy_expended(),
+ )
+
+ device.add_services([device_information_service, heart_rate_service])
+
+ # Set the advertising data
+ device.advertising_data = bytes(
+ AdvertisingData(
+ [
+ (
+ AdvertisingData.COMPLETE_LOCAL_NAME,
+ bytes('Bumble Heart', 'utf-8'),
+ ),
+ (
+ AdvertisingData.INCOMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS,
+ bytes(heart_rate_service.uuid),
+ ),
+ (AdvertisingData.APPEARANCE, struct.pack('<H', 0x0340)),
+ ]
+ )
+ )
+
+ # Go!
+ await device.power_on()
+ await device.start_advertising(auto_restart=True)
+
+ # Notify every 3 seconds
+ while True:
+ await asyncio.sleep(3.0)
+ await device.notify_subscribers(
+ heart_rate_service.heart_rate_measurement_characteristic
+ )
+
+
+# -----------------------------------------------------------------------------
+logging.basicConfig(level=os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
+asyncio.run(main())
diff --git a/examples/hfp_handsfree.html b/examples/hfp_handsfree.html
index ab1ce3d..a86fc4a 100644
--- a/examples/hfp_handsfree.html
+++ b/examples/hfp_handsfree.html
@@ -76,4 +76,4 @@ input, label {
}
</script>
</body>
-</html> \ No newline at end of file
+</html>
diff --git a/examples/hfp_handsfree.json b/examples/hfp_handsfree.json
index 5d46a80..50d7841 100644
--- a/examples/hfp_handsfree.json
+++ b/examples/hfp_handsfree.json
@@ -1,4 +1,6 @@
{
"name": "Bumble Hands-Free",
- "class_of_device": 2360324
+ "class_of_device": 2360324,
+ "keystore": "JsonKeyStore",
+ "le_enabled": false
}
diff --git a/examples/keyboard.html b/examples/keyboard.html
index 979de5e..6ad83a7 100644
--- a/examples/keyboard.html
+++ b/examples/keyboard.html
@@ -58,4 +58,4 @@
}
</script>
</body>
-</html> \ No newline at end of file
+</html>
diff --git a/examples/keyboard.py b/examples/keyboard.py
index ddb9f0f..314a805 100644
--- a/examples/keyboard.py
+++ b/examples/keyboard.py
@@ -20,9 +20,9 @@ import sys
import os
import logging
import struct
-import websockets
import json
-from colors import color
+import websockets
+from bumble.colors import color
from bumble.core import AdvertisingData
from bumble.device import Device, Connection, Peer
@@ -34,8 +34,8 @@ from bumble.gatt import (
Characteristic,
CharacteristicValue,
GATT_DEVICE_INFORMATION_SERVICE,
- GATT_DEVICE_HUMAN_INTERFACE_DEVICE_SERVICE,
- GATT_DEVICE_BATTERY_SERVICE,
+ GATT_HUMAN_INTERFACE_DEVICE_SERVICE,
+ GATT_BATTERY_SERVICE,
GATT_BATTERY_LEVEL_CHARACTERISTIC,
GATT_MANUFACTURER_NAME_STRING_CHARACTERISTIC,
GATT_REPORT_CHARACTERISTIC,
@@ -43,59 +43,95 @@ from bumble.gatt import (
GATT_PROTOCOL_MODE_CHARACTERISTIC,
GATT_HID_INFORMATION_CHARACTERISTIC,
GATT_HID_CONTROL_POINT_CHARACTERISTIC,
- GATT_REPORT_REFERENCE_DESCRIPTOR
+ GATT_REPORT_REFERENCE_DESCRIPTOR,
)
# -----------------------------------------------------------------------------
# Protocol Modes
-HID_BOOT_PROTOCOL = 0x00
+HID_BOOT_PROTOCOL = 0x00
HID_REPORT_PROTOCOL = 0x01
# Report Types
-HID_INPUT_REPORT = 0x01
-HID_OUTPUT_REPORT = 0x02
+HID_INPUT_REPORT = 0x01
+HID_OUTPUT_REPORT = 0x02
HID_FEATURE_REPORT = 0x03
# Report Map
-HID_KEYBOARD_REPORT_MAP = bytes([
- 0x05, 0x01, # Usage Page (Generic Desktop Ctrls)
- 0x09, 0x06, # Usage (Keyboard)
- 0xA1, 0x01, # Collection (Application)
- 0x85, 0x01, # . Report ID (1)
- 0x05, 0x07, # . Usage Page (Kbrd/Keypad)
- 0x19, 0xE0, # . Usage Minimum (0xE0)
- 0x29, 0xE7, # . Usage Maximum (0xE7)
- 0x15, 0x00, # . Logical Minimum (0)
- 0x25, 0x01, # . Logical Maximum (1)
- 0x75, 0x01, # . Report Size (1)
- 0x95, 0x08, # . Report Count (8)
- 0x81, 0x02, # . Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
- 0x95, 0x01, # . Report Count (1)
- 0x75, 0x08, # . Report Size (8)
- 0x81, 0x01, # . Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
- 0x95, 0x06, # . Report Count (6)
- 0x75, 0x08, # . Report Size (8)
- 0x15, 0x00, # . Logical Minimum (0x00)
- 0x25, 0x94, # . Logical Maximum (0x94)
- 0x05, 0x07, # . Usage Page (Kbrd/Keypad)
- 0x19, 0x00, # . Usage Minimum (0x00)
- 0x29, 0x94, # . Usage Maximum (0x94)
- 0x81, 0x00, # . Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
- 0x95, 0x05, # . Report Count (5)
- 0x75, 0x01, # . Report Size (1)
- 0x05, 0x08, # . Usage Page (LEDs)
- 0x19, 0x01, # . Usage Minimum (Num Lock)
- 0x29, 0x05, # . Usage Maximum (Kana)
- 0x91, 0x02, # . Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
- 0x95, 0x01, # . Report Count (1)
- 0x75, 0x03, # . Report Size (3)
- 0x91, 0x01, # . Output (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
- 0xC0 # End Collection
-])
+HID_KEYBOARD_REPORT_MAP = bytes(
+ # pylint: disable=line-too-long
+ [
+ 0x05,
+ 0x01, # Usage Page (Generic Desktop Controls)
+ 0x09,
+ 0x06, # Usage (Keyboard)
+ 0xA1,
+ 0x01, # Collection (Application)
+ 0x85,
+ 0x01, # . Report ID (1)
+ 0x05,
+ 0x07, # . Usage Page (Keyboard/Keypad)
+ 0x19,
+ 0xE0, # . Usage Minimum (0xE0)
+ 0x29,
+ 0xE7, # . Usage Maximum (0xE7)
+ 0x15,
+ 0x00, # . Logical Minimum (0)
+ 0x25,
+ 0x01, # . Logical Maximum (1)
+ 0x75,
+ 0x01, # . Report Size (1)
+ 0x95,
+ 0x08, # . Report Count (8)
+ 0x81,
+ 0x02, # . Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+ 0x95,
+ 0x01, # . Report Count (1)
+ 0x75,
+ 0x08, # . Report Size (8)
+ 0x81,
+ 0x01, # . Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
+ 0x95,
+ 0x06, # . Report Count (6)
+ 0x75,
+ 0x08, # . Report Size (8)
+ 0x15,
+ 0x00, # . Logical Minimum (0x00)
+ 0x25,
+ 0x94, # . Logical Maximum (0x94)
+ 0x05,
+ 0x07, # . Usage Page (Keyboard/Keypad)
+ 0x19,
+ 0x00, # . Usage Minimum (0x00)
+ 0x29,
+ 0x94, # . Usage Maximum (0x94)
+ 0x81,
+ 0x00, # . Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
+ 0x95,
+ 0x05, # . Report Count (5)
+ 0x75,
+ 0x01, # . Report Size (1)
+ 0x05,
+ 0x08, # . Usage Page (LEDs)
+ 0x19,
+ 0x01, # . Usage Minimum (Num Lock)
+ 0x29,
+ 0x05, # . Usage Maximum (Kana)
+ 0x91,
+ 0x02, # . Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+ 0x95,
+ 0x01, # . Report Count (1)
+ 0x75,
+ 0x03, # . Report Size (3)
+ 0x91,
+ 0x01, # . Output (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+ 0xC0, # End Collection
+ ]
+)
# -----------------------------------------------------------------------------
+# pylint: disable=invalid-overridden-method
class ServerListener(Device.Listener, Connection.Listener):
def __init__(self, device):
self.device = device
@@ -111,7 +147,7 @@ class ServerListener(Device.Listener, Connection.Listener):
# -----------------------------------------------------------------------------
-def on_hid_control_point_write(connection, value):
+def on_hid_control_point_write(_connection, value):
print(f'Control Point Write: {value}')
@@ -126,52 +162,69 @@ async def keyboard_host(device, peer_address):
connection = await device.connect(peer_address)
await connection.pair()
peer = Peer(connection)
- await peer.discover_service(GATT_DEVICE_HUMAN_INTERFACE_DEVICE_SERVICE)
- hid_services = peer.get_services_by_uuid(GATT_DEVICE_HUMAN_INTERFACE_DEVICE_SERVICE)
+ await peer.discover_service(GATT_HUMAN_INTERFACE_DEVICE_SERVICE)
+ hid_services = peer.get_services_by_uuid(GATT_HUMAN_INTERFACE_DEVICE_SERVICE)
if not hid_services:
print(color('!!! No HID service', 'red'))
return
await peer.discover_characteristics()
- protocol_mode_characteristics = peer.get_characteristics_by_uuid(GATT_PROTOCOL_MODE_CHARACTERISTIC)
+ protocol_mode_characteristics = peer.get_characteristics_by_uuid(
+ GATT_PROTOCOL_MODE_CHARACTERISTIC
+ )
if not protocol_mode_characteristics:
print(color('!!! No Protocol Mode characteristic', 'red'))
return
protocol_mode_characteristic = protocol_mode_characteristics[0]
- hid_information_characteristics = peer.get_characteristics_by_uuid(GATT_HID_INFORMATION_CHARACTERISTIC)
+ hid_information_characteristics = peer.get_characteristics_by_uuid(
+ GATT_HID_INFORMATION_CHARACTERISTIC
+ )
if not hid_information_characteristics:
print(color('!!! No HID Information characteristic', 'red'))
return
hid_information_characteristic = hid_information_characteristics[0]
- report_map_characteristics = peer.get_characteristics_by_uuid(GATT_REPORT_MAP_CHARACTERISTIC)
+ report_map_characteristics = peer.get_characteristics_by_uuid(
+ GATT_REPORT_MAP_CHARACTERISTIC
+ )
if not report_map_characteristics:
print(color('!!! No Report Map characteristic', 'red'))
return
report_map_characteristic = report_map_characteristics[0]
- control_point_characteristics = peer.get_characteristics_by_uuid(GATT_HID_CONTROL_POINT_CHARACTERISTIC)
+ control_point_characteristics = peer.get_characteristics_by_uuid(
+ GATT_HID_CONTROL_POINT_CHARACTERISTIC
+ )
if not control_point_characteristics:
print(color('!!! No Control Point characteristic', 'red'))
return
# control_point_characteristic = control_point_characteristics[0]
- report_characteristics = peer.get_characteristics_by_uuid(GATT_REPORT_CHARACTERISTIC)
+ report_characteristics = peer.get_characteristics_by_uuid(
+ GATT_REPORT_CHARACTERISTIC
+ )
if not report_characteristics:
print(color('!!! No Report characteristic', 'red'))
return
for i, characteristic in enumerate(report_characteristics):
print(color('REPORT:', 'yellow'), characteristic)
- if characteristic.properties & Characteristic.NOTIFY:
+ if characteristic.properties & Characteristic.Properties.NOTIFY:
await peer.discover_descriptors(characteristic)
- report_reference_descriptor = characteristic.get_descriptor(GATT_REPORT_REFERENCE_DESCRIPTOR)
+ report_reference_descriptor = characteristic.get_descriptor(
+ GATT_REPORT_REFERENCE_DESCRIPTOR
+ )
if report_reference_descriptor:
report_reference = await peer.read_value(report_reference_descriptor)
print(color(' Report Reference:', 'blue'), report_reference.hex())
else:
report_reference = bytes([0, 0])
- await peer.subscribe(characteristic, lambda value, param=f'[{i}] {report_reference.hex()}': on_report(param, value))
+ await peer.subscribe(
+ characteristic,
+ lambda value, param=f'[{i}] {report_reference.hex()}': on_report(
+ param, value
+ ),
+ )
protocol_mode = await peer.read_value(protocol_mode_characteristic)
print(f'Protocol Mode: {protocol_mode.hex()}')
@@ -188,81 +241,97 @@ async def keyboard_device(device, command):
# Create an 'input report' characteristic to send keyboard reports to the host
input_report_characteristic = Characteristic(
GATT_REPORT_CHARACTERISTIC,
- Characteristic.READ | Characteristic.WRITE | Characteristic.NOTIFY,
+ Characteristic.Properties.READ
+ | Characteristic.Properties.WRITE
+ | Characteristic.Properties.NOTIFY,
Characteristic.READABLE | Characteristic.WRITEABLE,
bytes([0, 0, 0, 0, 0, 0, 0, 0]),
[
- Descriptor(GATT_REPORT_REFERENCE_DESCRIPTOR, Descriptor.READABLE, bytes([0x01, HID_INPUT_REPORT]))
- ]
+ Descriptor(
+ GATT_REPORT_REFERENCE_DESCRIPTOR,
+ Descriptor.READABLE,
+ bytes([0x01, HID_INPUT_REPORT]),
+ )
+ ],
)
# Create an 'output report' characteristic to receive keyboard reports from the host
output_report_characteristic = Characteristic(
GATT_REPORT_CHARACTERISTIC,
- Characteristic.READ | Characteristic.WRITE | Characteristic.WRITE_WITHOUT_RESPONSE,
+ Characteristic.Properties.READ
+ | Characteristic.Properties.WRITE
+ | Characteristic.WRITE_WITHOUT_RESPONSE,
Characteristic.READABLE | Characteristic.WRITEABLE,
bytes([0]),
[
- Descriptor(GATT_REPORT_REFERENCE_DESCRIPTOR, Descriptor.READABLE, bytes([0x01, HID_OUTPUT_REPORT]))
- ]
+ Descriptor(
+ GATT_REPORT_REFERENCE_DESCRIPTOR,
+ Descriptor.READABLE,
+ bytes([0x01, HID_OUTPUT_REPORT]),
+ )
+ ],
)
# Add the services to the GATT sever
- device.add_services([
- Service(
- GATT_DEVICE_INFORMATION_SERVICE,
- [
- Characteristic(
- GATT_MANUFACTURER_NAME_STRING_CHARACTERISTIC,
- Characteristic.READ,
- Characteristic.READABLE,
- 'Bumble'
- )
- ]
- ),
- Service(
- GATT_DEVICE_HUMAN_INTERFACE_DEVICE_SERVICE,
- [
- Characteristic(
- GATT_PROTOCOL_MODE_CHARACTERISTIC,
- Characteristic.READ,
- Characteristic.READABLE,
- bytes([HID_REPORT_PROTOCOL])
- ),
- Characteristic(
- GATT_HID_INFORMATION_CHARACTERISTIC,
- Characteristic.READ,
- Characteristic.READABLE,
- bytes([0x11, 0x01, 0x00, 0x03]) # bcdHID=1.1, bCountryCode=0x00, Flags=RemoteWake|NormallyConnectable
- ),
- Characteristic(
- GATT_HID_CONTROL_POINT_CHARACTERISTIC,
- Characteristic.WRITE_WITHOUT_RESPONSE,
- Characteristic.WRITEABLE,
- CharacteristicValue(write=on_hid_control_point_write)
- ),
- Characteristic(
- GATT_REPORT_MAP_CHARACTERISTIC,
- Characteristic.READ,
- Characteristic.READABLE,
- HID_KEYBOARD_REPORT_MAP
- ),
- input_report_characteristic,
- output_report_characteristic
- ]
- ),
- Service(
- GATT_DEVICE_BATTERY_SERVICE,
- [
- Characteristic(
- GATT_BATTERY_LEVEL_CHARACTERISTIC,
- Characteristic.READ,
- Characteristic.READABLE,
- bytes([100])
- )
- ]
- )
- ])
+ device.add_services(
+ [
+ Service(
+ GATT_DEVICE_INFORMATION_SERVICE,
+ [
+ Characteristic(
+ GATT_MANUFACTURER_NAME_STRING_CHARACTERISTIC,
+ Characteristic.Properties.READ,
+ Characteristic.READABLE,
+ 'Bumble',
+ )
+ ],
+ ),
+ Service(
+ GATT_HUMAN_INTERFACE_DEVICE_SERVICE,
+ [
+ Characteristic(
+ GATT_PROTOCOL_MODE_CHARACTERISTIC,
+ Characteristic.Properties.READ,
+ Characteristic.READABLE,
+ bytes([HID_REPORT_PROTOCOL]),
+ ),
+ Characteristic(
+ GATT_HID_INFORMATION_CHARACTERISTIC,
+ Characteristic.Properties.READ,
+ Characteristic.READABLE,
+ # bcdHID=1.1, bCountryCode=0x00,
+ # Flags=RemoteWake|NormallyConnectable
+ bytes([0x11, 0x01, 0x00, 0x03]),
+ ),
+ Characteristic(
+ GATT_HID_CONTROL_POINT_CHARACTERISTIC,
+ Characteristic.WRITE_WITHOUT_RESPONSE,
+ Characteristic.WRITEABLE,
+ CharacteristicValue(write=on_hid_control_point_write),
+ ),
+ Characteristic(
+ GATT_REPORT_MAP_CHARACTERISTIC,
+ Characteristic.Properties.READ,
+ Characteristic.READABLE,
+ HID_KEYBOARD_REPORT_MAP,
+ ),
+ input_report_characteristic,
+ output_report_characteristic,
+ ],
+ ),
+ Service(
+ GATT_BATTERY_SERVICE,
+ [
+ Characteristic(
+ GATT_BATTERY_LEVEL_CHARACTERISTIC,
+ Characteristic.Properties.READ,
+ Characteristic.READABLE,
+ bytes([100]),
+ )
+ ],
+ ),
+ ]
+ )
# Debug print
for attribute in device.gatt_server.attributes:
@@ -270,13 +339,20 @@ async def keyboard_device(device, command):
# Set the advertising data
device.advertising_data = bytes(
- AdvertisingData([
- (AdvertisingData.COMPLETE_LOCAL_NAME, bytes('Bumble Keyboard', 'utf-8')),
- (AdvertisingData.INCOMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS,
- bytes(GATT_DEVICE_HUMAN_INTERFACE_DEVICE_SERVICE)),
- (AdvertisingData.APPEARANCE, struct.pack('<H', 0x03C1)),
- (AdvertisingData.FLAGS, bytes([0x05]))
- ])
+ AdvertisingData(
+ [
+ (
+ AdvertisingData.COMPLETE_LOCAL_NAME,
+ bytes('Bumble Keyboard', 'utf-8'),
+ ),
+ (
+ AdvertisingData.INCOMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS,
+ bytes(GATT_HUMAN_INTERFACE_DEVICE_SERVICE),
+ ),
+ (AdvertisingData.APPEARANCE, struct.pack('<H', 0x03C1)),
+ (AdvertisingData.FLAGS, bytes([0x05])),
+ ]
+ )
)
# Attach a listener
@@ -288,7 +364,7 @@ async def keyboard_device(device, command):
if command == 'web':
# Start a Websocket server to receive events from a web page
- async def serve(websocket, path):
+ async def serve(websocket, _path):
while True:
try:
message = await websocket.recv()
@@ -301,16 +377,24 @@ async def keyboard_device(device, command):
key = parsed['key']
if len(key) == 1:
code = ord(key)
- if code >= ord('a') and code <= ord('z'):
+ if ord('a') <= code <= ord('z'):
hid_code = 0x04 + code - ord('a')
- input_report_characteristic.value = bytes([0, 0, hid_code, 0, 0, 0, 0, 0])
- await device.notify_subscribers(input_report_characteristic)
+ input_report_characteristic.value = bytes(
+ [0, 0, hid_code, 0, 0, 0, 0, 0]
+ )
+ await device.notify_subscribers(
+ input_report_characteristic
+ )
elif message_type == 'keyup':
- input_report_characteristic.value = bytes.fromhex('0000000000000000')
+ input_report_characteristic.value = bytes.fromhex(
+ '0000000000000000'
+ )
await device.notify_subscribers(input_report_characteristic)
except websockets.exceptions.ConnectionClosedOK:
pass
+
+ # pylint: disable-next=no-member
await websockets.serve(serve, 'localhost', 8989)
await asyncio.get_event_loop().create_future()
else:
@@ -321,7 +405,9 @@ async def keyboard_device(device, command):
# Keypress for the letter
keycode = 0x04 + letter - 0x61
- input_report_characteristic.value = bytes([0, 0, keycode, 0, 0, 0, 0, 0])
+ input_report_characteristic.value = bytes(
+ [0, 0, keycode, 0, 0, 0, 0, 0]
+ )
await device.notify_subscribers(input_report_characteristic)
# Key release
@@ -332,13 +418,20 @@ async def keyboard_device(device, command):
# -----------------------------------------------------------------------------
async def main():
if len(sys.argv) < 4:
- print('Usage: python keyboard.py <device-config> <transport-spec> <command>')
- print(' where <command> is one of:')
- print(' connect <address> (run a keyboard host, connecting to a keyboard)')
- print(' web (run a keyboard with keypress input from a web page, see keyboard.html')
- print(' sim (run a keyboard simulation, emitting a canned sequence of keystrokes')
+ print(
+ 'Usage: python keyboard.py <device-config> <transport-spec> <command>'
+ ' where <command> is one of:\n'
+ ' connect <address> (run a keyboard host, connecting to a keyboard)\n'
+ ' web (run a keyboard with keypress input from a web page, '
+ 'see keyboard.html\n'
+ )
+ print(
+ ' sim (run a keyboard simulation, emitting a canned sequence of keystrokes'
+ )
print('example: python keyboard.py keyboard.json usb:0 sim')
- print('example: python keyboard.py keyboard.json usb:0 connect A0:A1:A2:A3:A4:A5')
+ print(
+ 'example: python keyboard.py keyboard.json usb:0 connect A0:A1:A2:A3:A4:A5'
+ )
return
async with await open_transport_or_link(sys.argv[2]) as (hci_source, hci_sink):
@@ -349,11 +442,11 @@ async def main():
if command == 'connect':
# Run as a Keyboard host
await keyboard_host(device, sys.argv[4])
- elif command in {'sim', 'web'}:
+ elif command in ('sim', 'web'):
# Run as a keyboard device
await keyboard_device(device, command)
# -----------------------------------------------------------------------------
-logging.basicConfig(level = os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
+logging.basicConfig(level=os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
asyncio.run(main())
diff --git a/examples/run_a2dp_info.py b/examples/run_a2dp_info.py
index 0d6f66b..2f21cfa 100644
--- a/examples/run_a2dp_info.py
+++ b/examples/run_a2dp_info.py
@@ -20,19 +20,16 @@ import sys
import os
import logging
-from colors import color
+from bumble.colors import color
from bumble.device import Device
from bumble.transport import open_transport_or_link
from bumble.core import (
BT_BR_EDR_TRANSPORT,
BT_AVDTP_PROTOCOL_ID,
BT_AUDIO_SINK_SERVICE,
- BT_L2CAP_PROTOCOL_ID
-)
-from bumble.avdtp import (
- Protocol as AVDTP_Protocol,
- find_avdtp_service_with_connection
+ BT_L2CAP_PROTOCOL_ID,
)
+from bumble.avdtp import Protocol as AVDTP_Protocol
from bumble.a2dp import make_audio_source_service_sdp_records
from bumble.sdp import (
Client as SDP_Client,
@@ -40,7 +37,7 @@ from bumble.sdp import (
DataElement,
SDP_PROTOCOL_DESCRIPTOR_LIST_ATTRIBUTE_ID,
SDP_BLUETOOTH_PROFILE_DESCRIPTOR_LIST_ATTRIBUTE_ID,
- SDP_SERVICE_CLASS_ID_LIST_ATTRIBUTE_ID
+ SDP_SERVICE_CLASS_ID_LIST_ATTRIBUTE_ID,
)
@@ -48,11 +45,14 @@ from bumble.sdp import (
def sdp_records():
service_record_handle = 0x00010001
return {
- service_record_handle: make_audio_source_service_sdp_records(service_record_handle)
+ service_record_handle: make_audio_source_service_sdp_records(
+ service_record_handle
+ )
}
# -----------------------------------------------------------------------------
+# pylint: disable-next=too-many-nested-blocks
async def find_a2dp_service(device, connection):
# Connect to the SDP Server
sdp_client = SDP_Client(device)
@@ -64,8 +64,8 @@ async def find_a2dp_service(device, connection):
[
SDP_PROTOCOL_DESCRIPTOR_LIST_ATTRIBUTE_ID,
SDP_BLUETOOTH_PROFILE_DESCRIPTOR_LIST_ATTRIBUTE_ID,
- SDP_SERVICE_CLASS_ID_LIST_ATTRIBUTE_ID
- ]
+ SDP_SERVICE_CLASS_ID_LIST_ATTRIBUTE_ID,
+ ],
)
print(color('==================================', 'blue'))
@@ -78,8 +78,7 @@ async def find_a2dp_service(device, connection):
# Service classes
service_class_id_list = ServiceAttribute.find_attribute_in_list(
- attribute_list,
- SDP_SERVICE_CLASS_ID_LIST_ATTRIBUTE_ID
+ attribute_list, SDP_SERVICE_CLASS_ID_LIST_ATTRIBUTE_ID
)
if service_class_id_list:
if service_class_id_list.value:
@@ -89,8 +88,7 @@ async def find_a2dp_service(device, connection):
# Protocol info
protocol_descriptor_list = ServiceAttribute.find_attribute_in_list(
- attribute_list,
- SDP_PROTOCOL_DESCRIPTOR_LIST_ATTRIBUTE_ID
+ attribute_list, SDP_PROTOCOL_DESCRIPTOR_LIST_ATTRIBUTE_ID
)
if protocol_descriptor_list:
print(color(' Protocol:', 'green'))
@@ -103,27 +101,38 @@ async def find_a2dp_service(device, connection):
if len(protocol_descriptor.value) >= 2:
avdtp_version_major = protocol_descriptor.value[1].value >> 8
avdtp_version_minor = protocol_descriptor.value[1].value & 0xFF
- print(f'{color(" AVDTP Version:", "cyan")} {avdtp_version_major}.{avdtp_version_minor}')
+ print(
+ f'{color(" AVDTP Version:", "cyan")} '
+ f'{avdtp_version_major}.{avdtp_version_minor}'
+ )
service_version = (avdtp_version_major, avdtp_version_minor)
# Profile info
bluetooth_profile_descriptor_list = ServiceAttribute.find_attribute_in_list(
- attribute_list,
- SDP_BLUETOOTH_PROFILE_DESCRIPTOR_LIST_ATTRIBUTE_ID
+ attribute_list, SDP_BLUETOOTH_PROFILE_DESCRIPTOR_LIST_ATTRIBUTE_ID
)
if bluetooth_profile_descriptor_list:
if bluetooth_profile_descriptor_list.value:
- if bluetooth_profile_descriptor_list.value[0].type == DataElement.SEQUENCE:
- bluetooth_profile_descriptors = bluetooth_profile_descriptor_list.value
+ if (
+ bluetooth_profile_descriptor_list.value[0].type
+ == DataElement.SEQUENCE
+ ):
+ bluetooth_profile_descriptors = (
+ bluetooth_profile_descriptor_list.value
+ )
else:
- # Sometimes, instead of a list of lists, we just find a list. Fix that
+ # Sometimes, instead of a list of lists, we just find a list.
+ # Fix that.
bluetooth_profile_descriptors = [bluetooth_profile_descriptor_list]
print(color(' Profiles:', 'green'))
for bluetooth_profile_descriptor in bluetooth_profile_descriptors:
version_major = bluetooth_profile_descriptor.value[1].value >> 8
version_minor = bluetooth_profile_descriptor.value[1].value & 0xFF
- print(f' {bluetooth_profile_descriptor.value[0].value} - version {version_major}.{version_minor}')
+ print(
+ f' {bluetooth_profile_descriptor.value[0].value}'
+ f' - version {version_major}.{version_minor}'
+ )
await sdp_client.disconnect()
return service_version
@@ -147,7 +156,8 @@ async def main():
# Start the controller
await device.power_on()
- # Setup the SDP to expose a SRC service, in case the remote device queries us back
+ # Setup the SDP to expose a SRC service, in case the remote device queries us
+ # back
device.sdp_service_records = sdp_records()
# Connect to a peer
@@ -184,5 +194,5 @@ async def main():
# -----------------------------------------------------------------------------
-logging.basicConfig(level = os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
+logging.basicConfig(level=os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
asyncio.run(main())
diff --git a/examples/run_a2dp_sink.py b/examples/run_a2dp_sink.py
index bc193a1..b20f0d6 100644
--- a/examples/run_a2dp_sink.py
+++ b/examples/run_a2dp_sink.py
@@ -20,7 +20,6 @@ import sys
import os
import logging
-from colors import color
from bumble.device import Device
from bumble.transport import open_transport_or_link
from bumble.core import BT_BR_EDR_TRANSPORT
@@ -28,7 +27,7 @@ from bumble.avdtp import (
AVDTP_AUDIO_MEDIA_TYPE,
Protocol,
Listener,
- MediaCodecCapabilities
+ MediaCodecCapabilities,
)
from bumble.a2dp import (
make_audio_sink_service_sdp_records,
@@ -39,19 +38,19 @@ from bumble.a2dp import (
SBC_LOUDNESS_ALLOCATION_METHOD,
SBC_STEREO_CHANNEL_MODE,
SBC_JOINT_STEREO_CHANNEL_MODE,
- SbcMediaCodecInformation
+ SbcMediaCodecInformation,
)
-Context = {
- 'output': None
-}
+Context = {'output': None}
# -----------------------------------------------------------------------------
def sdp_records():
service_record_handle = 0x00010001
return {
- service_record_handle: make_audio_sink_service_sdp_records(service_record_handle)
+ service_record_handle: make_audio_sink_service_sdp_records(
+ service_record_handle
+ )
}
@@ -59,22 +58,25 @@ def sdp_records():
def codec_capabilities():
# NOTE: this shouldn't be hardcoded, but passed on the command line instead
return MediaCodecCapabilities(
- media_type = AVDTP_AUDIO_MEDIA_TYPE,
- media_codec_type = A2DP_SBC_CODEC_TYPE,
- media_codec_information = SbcMediaCodecInformation.from_lists(
- sampling_frequencies = [48000, 44100, 32000, 16000],
- channel_modes = [
+ media_type=AVDTP_AUDIO_MEDIA_TYPE,
+ media_codec_type=A2DP_SBC_CODEC_TYPE,
+ media_codec_information=SbcMediaCodecInformation.from_lists(
+ sampling_frequencies=[48000, 44100, 32000, 16000],
+ channel_modes=[
SBC_MONO_CHANNEL_MODE,
SBC_DUAL_CHANNEL_MODE,
SBC_STEREO_CHANNEL_MODE,
- SBC_JOINT_STEREO_CHANNEL_MODE
+ SBC_JOINT_STEREO_CHANNEL_MODE,
],
- block_lengths = [4, 8, 12, 16],
- subbands = [4, 8],
- allocation_methods = [SBC_LOUDNESS_ALLOCATION_METHOD, SBC_SNR_ALLOCATION_METHOD],
- minimum_bitpool_value = 2,
- maximum_bitpool_value = 53
- )
+ block_lengths=[4, 8, 12, 16],
+ subbands=[4, 8],
+ allocation_methods=[
+ SBC_LOUDNESS_ALLOCATION_METHOD,
+ SBC_SNR_ALLOCATION_METHOD,
+ ],
+ minimum_bitpool_value=2,
+ maximum_bitpool_value=53,
+ ),
)
@@ -87,10 +89,10 @@ def on_avdtp_connection(server):
# -----------------------------------------------------------------------------
def on_rtp_packet(packet):
- header = packet.payload[0]
- fragmented = header >> 7
- start = (header >> 6) & 0x01
- last = (header >> 5) & 0x01
+ header = packet.payload[0]
+ fragmented = header >> 7
+ # start = (header >> 6) & 0x01
+ # last = (header >> 5) & 0x01
number_of_frames = header & 0x0F
if fragmented:
@@ -104,7 +106,10 @@ def on_rtp_packet(packet):
# -----------------------------------------------------------------------------
async def main():
if len(sys.argv) < 4:
- print('Usage: run_a2dp_sink.py <device-config> <transport-spec> <sbc-file> [<bt-addr>]')
+ print(
+ 'Usage: run_a2dp_sink.py <device-config> <transport-spec> <sbc-file> '
+ '[<bt-addr>]'
+ )
print('example: run_a2dp_sink.py classic1.json usb:0 output.sbc')
return
@@ -133,7 +138,9 @@ async def main():
# Connect to the source
target_address = sys.argv[4]
print(f'=== Connecting to {target_address}...')
- connection = await device.connect(target_address, transport=BT_BR_EDR_TRANSPORT)
+ connection = await device.connect(
+ target_address, transport=BT_BR_EDR_TRANSPORT
+ )
print(f'=== Connected to {connection.peer_address}!')
# Request authentication
@@ -159,5 +166,5 @@ async def main():
# -----------------------------------------------------------------------------
-logging.basicConfig(level = os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
+logging.basicConfig(level=os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
asyncio.run(main())
diff --git a/examples/run_a2dp_source.py b/examples/run_a2dp_source.py
index 45abad9..2443518 100644
--- a/examples/run_a2dp_source.py
+++ b/examples/run_a2dp_source.py
@@ -20,7 +20,7 @@ import sys
import os
import logging
-from colors import color
+from bumble.colors import color
from bumble.device import Device
from bumble.transport import open_transport_or_link
from bumble.core import BT_BR_EDR_TRANSPORT
@@ -30,7 +30,7 @@ from bumble.avdtp import (
MediaCodecCapabilities,
MediaPacketPump,
Protocol,
- Listener
+ Listener,
)
from bumble.a2dp import (
SBC_JOINT_STEREO_CHANNEL_MODE,
@@ -38,7 +38,7 @@ from bumble.a2dp import (
make_audio_source_service_sdp_records,
A2DP_SBC_CODEC_TYPE,
SbcMediaCodecInformation,
- SbcPacketSource
+ SbcPacketSource,
)
@@ -46,31 +46,36 @@ from bumble.a2dp import (
def sdp_records():
service_record_handle = 0x00010001
return {
- service_record_handle: make_audio_source_service_sdp_records(service_record_handle)
+ service_record_handle: make_audio_source_service_sdp_records(
+ service_record_handle
+ )
}
# -----------------------------------------------------------------------------
def codec_capabilities():
- # NOTE: this shouldn't be hardcoded, but should be inferred from the input file instead
+ # NOTE: this shouldn't be hardcoded, but should be inferred from the input file
+ # instead
return MediaCodecCapabilities(
- media_type = AVDTP_AUDIO_MEDIA_TYPE,
- media_codec_type = A2DP_SBC_CODEC_TYPE,
- media_codec_information = SbcMediaCodecInformation.from_discrete_values(
- sampling_frequency = 44100,
- channel_mode = SBC_JOINT_STEREO_CHANNEL_MODE,
- block_length = 16,
- subbands = 8,
- allocation_method = SBC_LOUDNESS_ALLOCATION_METHOD,
- minimum_bitpool_value = 2,
- maximum_bitpool_value = 53
- )
+ media_type=AVDTP_AUDIO_MEDIA_TYPE,
+ media_codec_type=A2DP_SBC_CODEC_TYPE,
+ media_codec_information=SbcMediaCodecInformation.from_discrete_values(
+ sampling_frequency=44100,
+ channel_mode=SBC_JOINT_STEREO_CHANNEL_MODE,
+ block_length=16,
+ subbands=8,
+ allocation_method=SBC_LOUDNESS_ALLOCATION_METHOD,
+ minimum_bitpool_value=2,
+ maximum_bitpool_value=53,
+ ),
)
# -----------------------------------------------------------------------------
def on_avdtp_connection(read_function, protocol):
- packet_source = SbcPacketSource(read_function, protocol.l2cap_channel.mtu, codec_capabilities())
+ packet_source = SbcPacketSource(
+ read_function, protocol.l2cap_channel.mtu, codec_capabilities()
+ )
packet_pump = MediaPacketPump(packet_source.packets)
protocol.add_source(packet_source.codec_capabilities, packet_pump)
@@ -83,14 +88,18 @@ async def stream_packets(read_function, protocol):
print('@@@', endpoint)
# Select a sink
- sink = protocol.find_remote_sink_by_codec(AVDTP_AUDIO_MEDIA_TYPE, A2DP_SBC_CODEC_TYPE)
+ sink = protocol.find_remote_sink_by_codec(
+ AVDTP_AUDIO_MEDIA_TYPE, A2DP_SBC_CODEC_TYPE
+ )
if sink is None:
print(color('!!! no SBC sink found', 'red'))
return
print(f'### Selected sink: {sink.seid}')
# Stream the packets
- packet_source = SbcPacketSource(read_function, protocol.l2cap_channel.mtu, codec_capabilities())
+ packet_source = SbcPacketSource(
+ read_function, protocol.l2cap_channel.mtu, codec_capabilities()
+ )
packet_pump = MediaPacketPump(packet_source.packets)
source = protocol.add_source(packet_source.codec_capabilities, packet_pump)
stream = await protocol.create_stream(source, sink)
@@ -107,8 +116,13 @@ async def stream_packets(read_function, protocol):
# -----------------------------------------------------------------------------
async def main():
if len(sys.argv) < 4:
- print('Usage: run_a2dp_source.py <device-config> <transport-spec> <sbc-file> [<bluetooth-address>]')
- print('example: run_a2dp_source.py classic1.json usb:0 test.sbc E1:CA:72:48:C4:E8')
+ print(
+ 'Usage: run_a2dp_source.py <device-config> <transport-spec> <sbc-file> '
+ '[<bluetooth-address>]'
+ )
+ print(
+ 'example: run_a2dp_source.py classic1.json usb:0 test.sbc E1:CA:72:48:C4:E8'
+ )
return
print('<<< connecting to HCI...')
@@ -126,7 +140,8 @@ async def main():
await device.power_on()
with open(sys.argv[3], 'rb') as sbc_file:
- # NOTE: this should be using asyncio file reading, but blocking reads are good enough for testing
+ # NOTE: this should be using asyncio file reading, but blocking reads are
+ # good enough for testing
async def read(byte_count):
return sbc_file.read(byte_count)
@@ -134,7 +149,9 @@ async def main():
# Connect to a peer
target_address = sys.argv[4]
print(f'=== Connecting to {target_address}...')
- connection = await device.connect(target_address, transport=BT_BR_EDR_TRANSPORT)
+ connection = await device.connect(
+ target_address, transport=BT_BR_EDR_TRANSPORT
+ )
print(f'=== Connected to {connection.peer_address}!')
# Request authentication
@@ -148,7 +165,9 @@ async def main():
print('*** Encryption on')
# Look for an A2DP service
- avdtp_version = await find_avdtp_service_with_connection(device, connection)
+ avdtp_version = await find_avdtp_service_with_connection(
+ device, connection
+ )
if not avdtp_version:
print(color('!!! no A2DP service found'))
return
@@ -161,7 +180,9 @@ async def main():
else:
# Create a listener to wait for AVDTP connections
listener = Listener(Listener.create_registrar(device), version=(1, 2))
- listener.on('connection', lambda protocol: on_avdtp_connection(read, protocol))
+ listener.on(
+ 'connection', lambda protocol: on_avdtp_connection(read, protocol)
+ )
# Become connectable and wait for a connection
await device.set_discoverable(True)
@@ -171,5 +192,5 @@ async def main():
# -----------------------------------------------------------------------------
-logging.basicConfig(level = os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
+logging.basicConfig(level=os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
asyncio.run(main())
diff --git a/examples/run_advertiser.py b/examples/run_advertiser.py
index 5201356..56b1b8b 100644
--- a/examples/run_advertiser.py
+++ b/examples/run_advertiser.py
@@ -16,33 +16,47 @@
# Imports
# -----------------------------------------------------------------------------
import asyncio
+import logging
import sys
import os
+from bumble.device import AdvertisingType, Device
+from bumble.hci import Address
-from bumble.hci import *
-from bumble.controller import *
-from bumble.device import *
-from bumble.transport import *
-from bumble.host import *
from bumble.transport import open_transport_or_link
# -----------------------------------------------------------------------------
async def main():
- if len(sys.argv) != 3:
- print('Usage: run_advertiser.py <config-file> <transport-spec>')
- print('example: run_advertiser.py device1.json link-relay:ws://localhost:8888/test')
+ if len(sys.argv) < 3:
+ print(
+ 'Usage: run_advertiser.py <config-file> <transport-spec> [type] [address]'
+ )
+ print('example: run_advertiser.py device1.json usb:0')
return
+ if len(sys.argv) >= 4:
+ advertising_type = AdvertisingType(int(sys.argv[3]))
+ else:
+ advertising_type = AdvertisingType.UNDIRECTED_CONNECTABLE_SCANNABLE
+
+ if advertising_type.is_directed:
+ if len(sys.argv) < 5:
+ print('<address> required for directed advertising')
+ return
+ target = Address(sys.argv[4])
+ else:
+ target = None
+
print('<<< connecting to HCI...')
async with await open_transport_or_link(sys.argv[2]) as (hci_source, hci_sink):
print('<<< connected')
device = Device.from_config_file_with_hci(sys.argv[1], hci_source, hci_sink)
await device.power_on()
- await device.start_advertising()
+ await device.start_advertising(advertising_type=advertising_type, target=target)
await hci_source.wait_for_termination()
+
# -----------------------------------------------------------------------------
-logging.basicConfig(level = os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
+logging.basicConfig(level=os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
asyncio.run(main())
diff --git a/examples/run_asha_sink.py b/examples/run_asha_sink.py
new file mode 100644
index 0000000..3e4955d
--- /dev/null
+++ b/examples/run_asha_sink.py
@@ -0,0 +1,202 @@
+# Copyright 2021-2022 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# -----------------------------------------------------------------------------
+# Imports
+# -----------------------------------------------------------------------------
+import asyncio
+import struct
+import sys
+import os
+import logging
+
+from bumble.core import AdvertisingData
+from bumble.device import Device
+from bumble.transport import open_transport_or_link
+from bumble.core import UUID
+from bumble.gatt import Service, Characteristic, CharacteristicValue
+
+
+# -----------------------------------------------------------------------------
+# Constants
+# -----------------------------------------------------------------------------
+ASHA_SERVICE = UUID.from_16_bits(0xFDF0, 'Audio Streaming for Hearing Aid')
+ASHA_READ_ONLY_PROPERTIES_CHARACTERISTIC = UUID(
+ '6333651e-c481-4a3e-9169-7c902aad37bb', 'ReadOnlyProperties'
+)
+ASHA_AUDIO_CONTROL_POINT_CHARACTERISTIC = UUID(
+ 'f0d4de7e-4a88-476c-9d9f-1937b0996cc0', 'AudioControlPoint'
+)
+ASHA_AUDIO_STATUS_CHARACTERISTIC = UUID(
+ '38663f1a-e711-4cac-b641-326b56404837', 'AudioStatus'
+)
+ASHA_VOLUME_CHARACTERISTIC = UUID('00e4ca9e-ab14-41e4-8823-f9e70c7e91df', 'Volume')
+ASHA_LE_PSM_OUT_CHARACTERISTIC = UUID(
+ '2d410339-82b6-42aa-b34e-e2e01df8cc1a', 'LE_PSM_OUT'
+)
+
+
+# -----------------------------------------------------------------------------
+async def main():
+ if len(sys.argv) != 4:
+ print(
+ 'Usage: python run_asha_sink.py <device-config> <transport-spec> '
+ '<audio-file>'
+ )
+ print('example: python run_asha_sink.py device1.json usb:0 audio_out.g722')
+ return
+
+ audio_out = open(sys.argv[3], 'wb')
+
+ async with await open_transport_or_link(sys.argv[2]) as (hci_source, hci_sink):
+ device = Device.from_config_file_with_hci(sys.argv[1], hci_source, hci_sink)
+
+ # Handler for audio control commands
+ def on_audio_control_point_write(_connection, value):
+ print('--- AUDIO CONTROL POINT Write:', value.hex())
+ opcode = value[0]
+ if opcode == 1:
+ # Start
+ audio_type = ('Unknown', 'Ringtone', 'Phone Call', 'Media')[value[2]]
+ print(
+ f'### START: codec={value[1]}, audio_type={audio_type}, '
+ f'volume={value[3]}, otherstate={value[4]}'
+ )
+ elif opcode == 2:
+ print('### STOP')
+ elif opcode == 3:
+ print(f'### STATUS: connected={value[1]}')
+
+ # Respond with a status
+ asyncio.create_task(
+ device.notify_subscribers(audio_status_characteristic, force=True)
+ )
+
+ # Handler for volume control
+ def on_volume_write(_connection, value):
+ print('--- VOLUME Write:', value[0])
+
+ # Register an L2CAP CoC server
+ def on_coc(channel):
+ def on_data(data):
+ print('<<< Voice data received:', data.hex())
+ audio_out.write(data)
+
+ channel.sink = on_data
+
+ psm = device.register_l2cap_channel_server(0, on_coc, 8)
+ print(f'### LE_PSM_OUT = {psm}')
+
+ # Add the ASHA service to the GATT server
+ read_only_properties_characteristic = Characteristic(
+ ASHA_READ_ONLY_PROPERTIES_CHARACTERISTIC,
+ Characteristic.Properties.READ,
+ Characteristic.READABLE,
+ bytes(
+ [
+ 0x01, # Version
+ 0x00, # Device Capabilities [Left, Monaural]
+ 0x01,
+ 0x02,
+ 0x03,
+ 0x04,
+ 0x05,
+ 0x06,
+ 0x07,
+ 0x08, # HiSyncId
+ 0x01, # Feature Map [LE CoC audio output streaming supported]
+ 0x00,
+ 0x00, # Render Delay
+ 0x00,
+ 0x00, # RFU
+ 0x02,
+ 0x00, # Codec IDs [G.722 at 16 kHz]
+ ]
+ ),
+ )
+ audio_control_point_characteristic = Characteristic(
+ ASHA_AUDIO_CONTROL_POINT_CHARACTERISTIC,
+ Characteristic.Properties.WRITE | Characteristic.WRITE_WITHOUT_RESPONSE,
+ Characteristic.WRITEABLE,
+ CharacteristicValue(write=on_audio_control_point_write),
+ )
+ audio_status_characteristic = Characteristic(
+ ASHA_AUDIO_STATUS_CHARACTERISTIC,
+ Characteristic.Properties.READ | Characteristic.Properties.NOTIFY,
+ Characteristic.READABLE,
+ bytes([0]),
+ )
+ volume_characteristic = Characteristic(
+ ASHA_VOLUME_CHARACTERISTIC,
+ Characteristic.WRITE_WITHOUT_RESPONSE,
+ Characteristic.WRITEABLE,
+ CharacteristicValue(write=on_volume_write),
+ )
+ le_psm_out_characteristic = Characteristic(
+ ASHA_LE_PSM_OUT_CHARACTERISTIC,
+ Characteristic.Properties.READ,
+ Characteristic.READABLE,
+ struct.pack('<H', psm),
+ )
+ device.add_service(
+ Service(
+ ASHA_SERVICE,
+ [
+ read_only_properties_characteristic,
+ audio_control_point_characteristic,
+ audio_status_characteristic,
+ volume_characteristic,
+ le_psm_out_characteristic,
+ ],
+ )
+ )
+
+ # Set the advertising data
+ device.advertising_data = bytes(
+ AdvertisingData(
+ [
+ (AdvertisingData.COMPLETE_LOCAL_NAME, bytes(device.name, 'utf-8')),
+ (AdvertisingData.FLAGS, bytes([0x06])),
+ (
+ AdvertisingData.INCOMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS,
+ bytes(ASHA_SERVICE),
+ ),
+ (
+ AdvertisingData.SERVICE_DATA_16_BIT_UUID,
+ bytes(ASHA_SERVICE)
+ + bytes(
+ [
+ 0x01, # Protocol Version
+ 0x00, # Capability
+ 0x01,
+ 0x02,
+ 0x03,
+ 0x04, # Truncated HiSyncID
+ ]
+ ),
+ ),
+ ]
+ )
+ )
+
+ # Go!
+ await device.power_on()
+ await device.start_advertising(auto_restart=True)
+
+ await hci_source.wait_for_termination()
+
+
+# -----------------------------------------------------------------------------
+logging.basicConfig(level=os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
+asyncio.run(main())
diff --git a/examples/run_classic_connect.py b/examples/run_classic_connect.py
index d6842fe..bb46bf7 100644
--- a/examples/run_classic_connect.py
+++ b/examples/run_classic_connect.py
@@ -19,19 +19,26 @@ import asyncio
import sys
import os
import logging
-from colors import color
+from bumble.colors import color
from bumble.device import Device
from bumble.transport import open_transport_or_link
from bumble.core import BT_BR_EDR_TRANSPORT, BT_L2CAP_PROTOCOL_ID
-from bumble.sdp import Client as SDP_Client, SDP_PUBLIC_BROWSE_ROOT, SDP_ALL_ATTRIBUTES_RANGE
+from bumble.sdp import (
+ Client as SDP_Client,
+ SDP_PUBLIC_BROWSE_ROOT,
+ SDP_ALL_ATTRIBUTES_RANGE,
+)
# -----------------------------------------------------------------------------
async def main():
if len(sys.argv) < 3:
- print('Usage: run_classic_connect.py <device-config> <transport-spec> <bluetooth-address>')
- print('example: run_classic_connect.py classic1.json usb:04b4:f901 E1:CA:72:48:C4:E8')
+ print(
+ 'Usage: run_classic_connect.py <device-config> <transport-spec> '
+ '<bluetooth-addresses..>'
+ )
+ print('example: run_classic_connect.py classic1.json usb:0 E1:CA:72:48:C4:E8')
return
print('<<< connecting to HCI...')
@@ -43,8 +50,7 @@ async def main():
device.classic_enabled = True
await device.power_on()
- # Connect to a peer
- target_address = sys.argv[3]
+ async def connect(target_address):
print(f'=== Connecting to {target_address}...')
connection = await device.connect(target_address, transport=BT_BR_EDR_TRANSPORT)
print(f'=== Connected to {connection.peer_address}!')
@@ -54,28 +60,52 @@ async def main():
await sdp_client.connect(connection)
# List all services in the root browse group
- service_record_handles = await sdp_client.search_services([SDP_PUBLIC_BROWSE_ROOT])
+ service_record_handles = await sdp_client.search_services(
+ [SDP_PUBLIC_BROWSE_ROOT]
+ )
print(color('\n==================================', 'blue'))
print(color('SERVICES:', 'yellow'), service_record_handles)
# For each service in the root browse group, get all its attributes
for service_record_handle in service_record_handles:
- attributes = await sdp_client.get_attributes(service_record_handle, [SDP_ALL_ATTRIBUTES_RANGE])
+ attributes = await sdp_client.get_attributes(
+ service_record_handle, [SDP_ALL_ATTRIBUTES_RANGE]
+ )
print(color(f'SERVICE {service_record_handle:04X} attributes:', 'yellow'))
for attribute in attributes:
- print(' ', attribute.to_string(color=True))
+ print(' ', attribute.to_string(with_colors=True))
# Search for services with an L2CAP service attribute
- search_result = await sdp_client.search_attributes([BT_L2CAP_PROTOCOL_ID], [SDP_ALL_ATTRIBUTES_RANGE])
+ search_result = await sdp_client.search_attributes(
+ [BT_L2CAP_PROTOCOL_ID], [SDP_ALL_ATTRIBUTES_RANGE]
+ )
print(color('\n==================================', 'blue'))
print(color('SEARCH RESULTS:', 'yellow'))
for attribute_list in search_result:
print(color('SERVICE:', 'green'))
- print(' ' + '\n '.join([attribute.to_string(color=True) for attribute in attribute_list]))
+ print(
+ ' '
+ + '\n '.join(
+ [
+ attribute.to_string(with_colors=True)
+ for attribute in attribute_list
+ ]
+ )
+ )
await sdp_client.disconnect()
await hci_source.wait_for_termination()
+ # Connect to a peer
+ target_addresses = sys.argv[3:]
+ await asyncio.wait(
+ [
+ asyncio.create_task(connect(target_address))
+ for target_address in target_addresses
+ ]
+ )
+
+
# -----------------------------------------------------------------------------
-logging.basicConfig(level = os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
+logging.basicConfig(level=os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
asyncio.run(main())
diff --git a/examples/run_classic_discoverable.py b/examples/run_classic_discoverable.py
index 5cdbc27..076a9ec 100644
--- a/examples/run_classic_discoverable.py
+++ b/examples/run_classic_discoverable.py
@@ -30,48 +30,62 @@ from bumble.sdp import (
SDP_SERVICE_RECORD_HANDLE_ATTRIBUTE_ID,
SDP_SERVICE_CLASS_ID_LIST_ATTRIBUTE_ID,
SDP_PROTOCOL_DESCRIPTOR_LIST_ATTRIBUTE_ID,
- SDP_BLUETOOTH_PROFILE_DESCRIPTOR_LIST_ATTRIBUTE_ID
+ SDP_BLUETOOTH_PROFILE_DESCRIPTOR_LIST_ATTRIBUTE_ID,
)
from bumble.core import (
BT_AUDIO_SINK_SERVICE,
BT_L2CAP_PROTOCOL_ID,
BT_AVDTP_PROTOCOL_ID,
- BT_ADVANCED_AUDIO_DISTRIBUTION_SERVICE
+ BT_ADVANCED_AUDIO_DISTRIBUTION_SERVICE,
)
# -----------------------------------------------------------------------------
SDP_SERVICE_RECORDS = {
0x00010001: [
- ServiceAttribute(SDP_SERVICE_RECORD_HANDLE_ATTRIBUTE_ID, DataElement.unsigned_integer_32(0x00010001)),
- ServiceAttribute(SDP_BROWSE_GROUP_LIST_ATTRIBUTE_ID, DataElement.sequence([
- DataElement.uuid(SDP_PUBLIC_BROWSE_ROOT)
- ])),
+ ServiceAttribute(
+ SDP_SERVICE_RECORD_HANDLE_ATTRIBUTE_ID,
+ DataElement.unsigned_integer_32(0x00010001),
+ ),
+ ServiceAttribute(
+ SDP_BROWSE_GROUP_LIST_ATTRIBUTE_ID,
+ DataElement.sequence([DataElement.uuid(SDP_PUBLIC_BROWSE_ROOT)]),
+ ),
ServiceAttribute(
SDP_SERVICE_CLASS_ID_LIST_ATTRIBUTE_ID,
- DataElement.sequence([DataElement.uuid(BT_AUDIO_SINK_SERVICE)])
+ DataElement.sequence([DataElement.uuid(BT_AUDIO_SINK_SERVICE)]),
),
ServiceAttribute(
SDP_PROTOCOL_DESCRIPTOR_LIST_ATTRIBUTE_ID,
- DataElement.sequence([
- DataElement.sequence([
- DataElement.uuid(BT_L2CAP_PROTOCOL_ID),
- DataElement.unsigned_integer_16(25)
- ]),
- DataElement.sequence([
- DataElement.uuid(BT_AVDTP_PROTOCOL_ID),
- DataElement.unsigned_integer_16(256)
- ])
- ])
+ DataElement.sequence(
+ [
+ DataElement.sequence(
+ [
+ DataElement.uuid(BT_L2CAP_PROTOCOL_ID),
+ DataElement.unsigned_integer_16(25),
+ ]
+ ),
+ DataElement.sequence(
+ [
+ DataElement.uuid(BT_AVDTP_PROTOCOL_ID),
+ DataElement.unsigned_integer_16(256),
+ ]
+ ),
+ ]
+ ),
),
ServiceAttribute(
SDP_BLUETOOTH_PROFILE_DESCRIPTOR_LIST_ATTRIBUTE_ID,
- DataElement.sequence([
- DataElement.sequence([
- DataElement.uuid(BT_ADVANCED_AUDIO_DISTRIBUTION_SERVICE),
- DataElement.unsigned_integer_16(256)
- ])
- ])
- )
+ DataElement.sequence(
+ [
+ DataElement.sequence(
+ [
+ DataElement.uuid(BT_ADVANCED_AUDIO_DISTRIBUTION_SERVICE),
+ DataElement.unsigned_integer_16(256),
+ ]
+ )
+ ]
+ ),
+ ),
]
}
@@ -99,6 +113,7 @@ async def main():
await hci_source.wait_for_termination()
+
# -----------------------------------------------------------------------------
-logging.basicConfig(level = os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
+logging.basicConfig(level=os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
asyncio.run(main())
diff --git a/examples/run_classic_discovery.py b/examples/run_classic_discovery.py
index b0ab5ee..569c8b3 100644
--- a/examples/run_classic_discovery.py
+++ b/examples/run_classic_discovery.py
@@ -19,7 +19,7 @@ import asyncio
import sys
import os
import logging
-from colors import color
+from bumble.colors import color
from bumble.device import Device
from bumble.transport import open_transport_or_link
@@ -28,17 +28,28 @@ from bumble.core import DeviceClass
# -----------------------------------------------------------------------------
class DiscoveryListener(Device.Listener):
- def on_inquiry_result(self, address, class_of_device, eir_data, rssi):
- service_classes, major_device_class, minor_device_class = DeviceClass.split_class_of_device(class_of_device)
+ def on_inquiry_result(self, address, class_of_device, data, rssi):
+ (
+ service_classes,
+ major_device_class,
+ minor_device_class,
+ ) = DeviceClass.split_class_of_device(class_of_device)
separator = '\n '
print(f'>>> {color(address, "yellow")}:')
print(f' Device Class (raw): {class_of_device:06X}')
- print(f' Device Major Class: {DeviceClass.major_device_class_name(major_device_class)}')
- print(f' Device Minor Class: {DeviceClass.minor_device_class_name(major_device_class, minor_device_class)}')
- print(f' Device Services: {", ".join(DeviceClass.service_class_labels(service_classes))}')
+ major_class_name = DeviceClass.major_device_class_name(major_device_class)
+ print(' Device Major Class: ' f'{major_class_name}')
+ minor_class_name = DeviceClass.minor_device_class_name(
+ major_device_class, minor_device_class
+ )
+ print(' Device Minor Class: ' f'{minor_class_name}')
+ print(
+ ' Device Services: '
+ f'{", ".join(DeviceClass.service_class_labels(service_classes))}'
+ )
print(f' RSSI: {rssi}')
- if eir_data.ad_structures:
- print(f' {eir_data.to_string(separator)}')
+ if data.ad_structures:
+ print(f' {data.to_string(separator)}')
# -----------------------------------------------------------------------------
@@ -59,6 +70,7 @@ async def main():
await hci_source.wait_for_termination()
+
# -----------------------------------------------------------------------------
-logging.basicConfig(level = os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
+logging.basicConfig(level=os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
asyncio.run(main())
diff --git a/examples/run_connect_and_encrypt.py b/examples/run_connect_and_encrypt.py
index 0ee868a..b541a0e 100644
--- a/examples/run_connect_and_encrypt.py
+++ b/examples/run_connect_and_encrypt.py
@@ -27,8 +27,13 @@ from bumble.transport import open_transport_or_link
# -----------------------------------------------------------------------------
async def main():
if len(sys.argv) < 3:
- print('Usage: run_connect_and_encrypt.py <device-config> <transport-spec> <bluetooth-address>')
- print('example: run_connect_and_encrypt.py device1.json usb:0 E1:CA:72:48:C4:E8')
+ print(
+ 'Usage: run_connect_and_encrypt.py <device-config> <transport-spec> '
+ '<bluetooth-address>'
+ )
+ print(
+ 'example: run_connect_and_encrypt.py device1.json usb:0 E1:CA:72:48:C4:E8'
+ )
return
print('<<< connecting to HCI...')
@@ -53,6 +58,7 @@ async def main():
await hci_source.wait_for_termination()
+
# -----------------------------------------------------------------------------
-logging.basicConfig(level = os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
+logging.basicConfig(level=os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
asyncio.run(main())
diff --git a/examples/run_controller.py b/examples/run_controller.py
index d8295d4..596ac8b 100644
--- a/examples/run_controller.py
+++ b/examples/run_controller.py
@@ -20,20 +20,32 @@ import asyncio
import sys
import os
-from bumble.hci import *
-from bumble.controller import *
-from bumble.host import *
-from bumble.device import *
-from bumble.transport import *
-from bumble.link import *
+from bumble.gatt import (
+ GATT_CHARACTERISTIC_USER_DESCRIPTION_DESCRIPTOR,
+ GATT_DEVICE_INFORMATION_SERVICE,
+ GATT_MANUFACTURER_NAME_STRING_CHARACTERISTIC,
+ Characteristic,
+ Descriptor,
+ Service,
+)
+from bumble.device import Device
+from bumble.host import Host
+from bumble.controller import Controller
+from bumble.link import LocalLink
from bumble.transport import open_transport_or_link
# -----------------------------------------------------------------------------
async def main():
if len(sys.argv) != 4:
- print('Usage: run_controller.py <controller-address> <device-config> <transport-spec>')
- print('example: run_controller.py F2:F3:F4:F5:F6:F7 device1.json udp:0.0.0.0:22333,172.16.104.161:22333')
+ print(
+ 'Usage: run_controller.py <controller-address> <device-config> '
+ '<transport-spec>'
+ )
+ print(
+ 'example: run_controller.py F2:F3:F4:F5:F6:F7 device1.json '
+ 'udp:0.0.0.0:22333,172.16.104.161:22333'
+ )
return
print('>>> connecting to HCI...')
@@ -44,11 +56,13 @@ async def main():
link = LocalLink()
# Create a first controller using the packet source/sink as its host interface
- controller1 = Controller('C1', host_source = hci_source, host_sink = hci_sink, link = link)
+ controller1 = Controller(
+ 'C1', host_source=hci_source, host_sink=hci_sink, link=link
+ )
controller1.random_address = sys.argv[1]
# Create a second controller using the same link
- controller2 = Controller('C2', link = link)
+ controller2 = Controller('C2', link=link)
# Create a host for the second controller
host = Host()
@@ -59,17 +73,21 @@ async def main():
device.host = host
# Add some basic services to the device's GATT server
- descriptor = Descriptor(GATT_CHARACTERISTIC_USER_DESCRIPTION_DESCRIPTOR, Descriptor.READABLE, 'My Description')
+ descriptor = Descriptor(
+ GATT_CHARACTERISTIC_USER_DESCRIPTION_DESCRIPTOR,
+ Descriptor.READABLE,
+ 'My Description',
+ )
manufacturer_name_characteristic = Characteristic(
GATT_MANUFACTURER_NAME_STRING_CHARACTERISTIC,
- Characteristic.READ,
+ Characteristic.Properties.READ,
Characteristic.READABLE,
"Fitbit",
- [descriptor]
+ [descriptor],
+ )
+ device_info_service = Service(
+ GATT_DEVICE_INFORMATION_SERVICE, [manufacturer_name_characteristic]
)
- device_info_service = Service(GATT_DEVICE_INFORMATION_SERVICE, [
- manufacturer_name_characteristic
- ])
device.add_service(device_info_service)
# Debug print
@@ -82,6 +100,7 @@ async def main():
await hci_source.wait_for_termination()
+
# -----------------------------------------------------------------------------
-logging.basicConfig(level = os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
+logging.basicConfig(level=os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
asyncio.run(main())
diff --git a/examples/run_controller_with_scanner.py b/examples/run_controller_with_scanner.py
index 88bc1f8..9603cff 100644
--- a/examples/run_controller_with_scanner.py
+++ b/examples/run_controller_with_scanner.py
@@ -19,7 +19,7 @@ import logging
import asyncio
import sys
import os
-from colors import color
+from bumble.colors import color
from bumble.device import Device
from bumble.controller import Controller
@@ -29,15 +29,19 @@ from bumble.transport import open_transport_or_link
# -----------------------------------------------------------------------------
class ScannerListener(Device.Listener):
- def on_advertisement(self, address, ad_data, rssi, connectable):
- address_type_string = ('P', 'R', 'PI', 'RI')[address.address_type]
- address_color = 'yellow' if connectable else 'red'
+ def on_advertisement(self, advertisement):
+ address_type_string = ('P', 'R', 'PI', 'RI')[advertisement.address.address_type]
+ address_color = 'yellow' if advertisement.is_connectable else 'red'
if address_type_string.startswith('P'):
type_color = 'green'
else:
type_color = 'cyan'
- print(f'>>> {color(address, address_color)} [{color(address_type_string, type_color)}]: RSSI={rssi}, {ad_data}')
+ print(
+ f'>>> {color(advertisement.address, address_color)} '
+ f'[{color(address_type_string, type_color)}]: '
+ f'RSSI={advertisement.rssi}, {advertisement.data}'
+ )
# -----------------------------------------------------------------------------
@@ -55,20 +59,25 @@ async def main():
link = LocalLink()
# Create a first controller using the packet source/sink as its host interface
- controller1 = Controller('C1', host_source = hci_source, host_sink = hci_sink, link = link)
+ controller1 = Controller(
+ 'C1', host_source=hci_source, host_sink=hci_sink, link=link
+ )
controller1.address = 'E0:E1:E2:E3:E4:E5'
# Create a second controller using the same link
- controller2 = Controller('C2', link = link)
+ controller2 = Controller('C2', link=link)
# Create a device with a scanner listener
- device = Device.with_hci('Bumble', 'F0:F1:F2:F3:F4:F5', controller2, controller2)
+ device = Device.with_hci(
+ 'Bumble', 'F0:F1:F2:F3:F4:F5', controller2, controller2
+ )
device.listener = ScannerListener()
await device.power_on()
await device.start_scanning()
await hci_source.wait_for_termination()
+
# -----------------------------------------------------------------------------
-logging.basicConfig(level = os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
+logging.basicConfig(level=os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
asyncio.run(main())
diff --git a/examples/run_device_with_snooper.py b/examples/run_device_with_snooper.py
new file mode 100644
index 0000000..69a187f
--- /dev/null
+++ b/examples/run_device_with_snooper.py
@@ -0,0 +1,51 @@
+# Copyright 2021-2023 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# -----------------------------------------------------------------------------
+# Imports
+# -----------------------------------------------------------------------------
+import asyncio
+import sys
+import os
+import logging
+from bumble.colors import color
+
+from bumble.device import Device
+from bumble.transport import open_transport_or_link
+from bumble.snoop import BtSnooper
+
+# -----------------------------------------------------------------------------
+async def main():
+ if len(sys.argv) != 3:
+ print('Usage: run_device_with_snooper.py <transport-spec> <snoop-file>')
+ print('example: run_device_with_snooper.py usb:0 btsnoop.log')
+ return
+
+ print('<<< connecting to HCI...')
+ async with await open_transport_or_link(sys.argv[1]) as (hci_source, hci_sink):
+ print('<<< connected')
+
+ device = Device.with_hci('Bumble', 'F0:F1:F2:F3:F4:F5', hci_source, hci_sink)
+
+ with open(sys.argv[2], "wb") as snoop_file:
+ device.host.snooper = BtSnooper(snoop_file)
+ await device.power_on()
+ await device.start_scanning()
+
+ await hci_source.wait_for_termination()
+
+
+# -----------------------------------------------------------------------------
+logging.basicConfig(level=os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
+asyncio.run(main())
diff --git a/examples/run_gatt_client.py b/examples/run_gatt_client.py
index 5af86fb..dcf8a1b 100644
--- a/examples/run_gatt_client.py
+++ b/examples/run_gatt_client.py
@@ -19,7 +19,7 @@ import asyncio
import sys
import os
import logging
-from colors import color
+from bumble.colors import color
from bumble.core import ProtocolError
from bumble.device import Device, Peer
@@ -34,6 +34,7 @@ class Listener(Device.Listener):
self.device = device
@AsyncRunner.run_in_task()
+ # pylint: disable=invalid-overridden-method
async def on_connection(self, connection):
print(f'=== Connected to {connection}')
@@ -70,7 +71,10 @@ class Listener(Device.Listener):
# -----------------------------------------------------------------------------
async def main():
if len(sys.argv) < 3:
- print('Usage: run_gatt_client.py <device-config> <transport-spec> [<bluetooth-address>]')
+ print(
+ 'Usage: run_gatt_client.py <device-config> <transport-spec> '
+ '[<bluetooth-address>]'
+ )
print('example: run_gatt_client.py device1.json usb:0 E1:CA:72:48:C4:E8')
return
@@ -93,6 +97,7 @@ async def main():
await asyncio.get_running_loop().create_future()
+
# -----------------------------------------------------------------------------
-logging.basicConfig(level = os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
+logging.basicConfig(level=os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
asyncio.run(main())
diff --git a/examples/run_gatt_client_and_server.py b/examples/run_gatt_client_and_server.py
index 940b1a8..609fe18 100644
--- a/examples/run_gatt_client_and_server.py
+++ b/examples/run_gatt_client_and_server.py
@@ -18,7 +18,7 @@
import asyncio
import os
import logging
-from colors import color
+from bumble.colors import color
from bumble.core import ProtocolError
from bumble.controller import Controller
@@ -32,7 +32,7 @@ from bumble.gatt import (
show_services,
GATT_CHARACTERISTIC_USER_DESCRIPTION_DESCRIPTOR,
GATT_MANUFACTURER_NAME_STRING_CHARACTERISTIC,
- GATT_DEVICE_INFORMATION_SERVICE
+ GATT_DEVICE_INFORMATION_SERVICE,
)
@@ -48,32 +48,36 @@ async def main():
link = LocalLink()
# Setup a stack for the client
- client_controller = Controller("client controller", link = link)
+ client_controller = Controller("client controller", link=link)
client_host = Host()
client_host.controller = client_controller
- client_device = Device("client", address = 'F0:F1:F2:F3:F4:F5', host = client_host)
+ client_device = Device("client", address='F0:F1:F2:F3:F4:F5', host=client_host)
await client_device.power_on()
# Setup a stack for the server
- server_controller = Controller("server controller", link = link)
+ server_controller = Controller("server controller", link=link)
server_host = Host()
server_host.controller = server_controller
- server_device = Device("server", address = 'F6:F7:F8:F9:FA:FB', host = server_host)
+ server_device = Device("server", address='F6:F7:F8:F9:FA:FB', host=server_host)
server_device.listener = ServerListener()
await server_device.power_on()
# Add a few entries to the device's GATT server
- descriptor = Descriptor(GATT_CHARACTERISTIC_USER_DESCRIPTION_DESCRIPTOR, Descriptor.READABLE, 'My Description')
+ descriptor = Descriptor(
+ GATT_CHARACTERISTIC_USER_DESCRIPTION_DESCRIPTOR,
+ Descriptor.READABLE,
+ 'My Description',
+ )
manufacturer_name_characteristic = Characteristic(
GATT_MANUFACTURER_NAME_STRING_CHARACTERISTIC,
- Characteristic.READ,
+ Characteristic.Properties.READ,
Characteristic.READABLE,
"Fitbit",
- [descriptor]
+ [descriptor],
+ )
+ device_info_service = Service(
+ GATT_DEVICE_INFORMATION_SERVICE, [manufacturer_name_characteristic]
)
- device_info_service = Service(GATT_DEVICE_INFORMATION_SERVICE, [
- manufacturer_name_characteristic
- ])
server_device.add_service(device_info_service)
# Connect the client to the server
@@ -109,6 +113,7 @@ async def main():
await asyncio.get_running_loop().create_future()
+
# -----------------------------------------------------------------------------
-logging.basicConfig(level = os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
+logging.basicConfig(level=os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
asyncio.run(main())
diff --git a/examples/run_gatt_server.py b/examples/run_gatt_server.py
index 099d589..46d42a2 100644
--- a/examples/run_gatt_server.py
+++ b/examples/run_gatt_server.py
@@ -22,10 +22,7 @@ import logging
from bumble.device import Device, Connection
from bumble.transport import open_transport_or_link
-from bumble.att import (
- ATT_Error,
- ATT_INSUFFICIENT_ENCRYPTION_ERROR
-)
+from bumble.att import ATT_Error, ATT_INSUFFICIENT_ENCRYPTION_ERROR
from bumble.gatt import (
Service,
Characteristic,
@@ -33,7 +30,7 @@ from bumble.gatt import (
Descriptor,
GATT_CHARACTERISTIC_USER_DESCRIPTION_DESCRIPTOR,
GATT_MANUFACTURER_NAME_STRING_CHARACTERISTIC,
- GATT_DEVICE_INFORMATION_SERVICE
+ GATT_DEVICE_INFORMATION_SERVICE,
)
@@ -63,8 +60,8 @@ def my_custom_read_with_error(connection):
print('----- READ from', connection, '[returning error]')
if connection.is_encrypted:
return bytes([123])
- else:
- raise ATT_Error(ATT_INSUFFICIENT_ENCRYPTION_ERROR)
+
+ raise ATT_Error(ATT_INSUFFICIENT_ENCRYPTION_ERROR)
def my_custom_write_with_error(connection, value):
@@ -76,7 +73,10 @@ def my_custom_write_with_error(connection, value):
# -----------------------------------------------------------------------------
async def main():
if len(sys.argv) < 3:
- print('Usage: run_gatt_server.py <device-config> <transport-spec> [<bluetooth-address>]')
+ print(
+ 'Usage: run_gatt_server.py <device-config> <transport-spec> '
+ '[<bluetooth-address>]'
+ )
print('example: run_gatt_server.py device1.json usb:0 E1:CA:72:48:C4:E8')
return
@@ -89,39 +89,45 @@ async def main():
device.listener = Listener(device)
# Add a few entries to the device's GATT server
- descriptor = Descriptor(GATT_CHARACTERISTIC_USER_DESCRIPTION_DESCRIPTOR, Descriptor.READABLE, 'My Description')
+ descriptor = Descriptor(
+ GATT_CHARACTERISTIC_USER_DESCRIPTION_DESCRIPTOR,
+ Descriptor.READABLE,
+ 'My Description',
+ )
manufacturer_name_characteristic = Characteristic(
GATT_MANUFACTURER_NAME_STRING_CHARACTERISTIC,
- Characteristic.READ,
+ Characteristic.Properties.READ,
Characteristic.READABLE,
'Fitbit',
- [descriptor]
+ [descriptor],
+ )
+ device_info_service = Service(
+ GATT_DEVICE_INFORMATION_SERVICE, [manufacturer_name_characteristic]
)
- device_info_service = Service(GATT_DEVICE_INFORMATION_SERVICE, [
- manufacturer_name_characteristic
- ])
custom_service1 = Service(
'50DB505C-8AC4-4738-8448-3B1D9CC09CC5',
[
Characteristic(
'D901B45B-4916-412E-ACCA-376ECB603B2C',
- Characteristic.READ | Characteristic.WRITE,
+ Characteristic.Properties.READ | Characteristic.Properties.WRITE,
Characteristic.READABLE | Characteristic.WRITEABLE,
- CharacteristicValue(read=my_custom_read, write=my_custom_write)
+ CharacteristicValue(read=my_custom_read, write=my_custom_write),
),
Characteristic(
'552957FB-CF1F-4A31-9535-E78847E1A714',
- Characteristic.READ | Characteristic.WRITE,
+ Characteristic.Properties.READ | Characteristic.Properties.WRITE,
Characteristic.READABLE | Characteristic.WRITEABLE,
- CharacteristicValue(read=my_custom_read_with_error, write=my_custom_write_with_error)
+ CharacteristicValue(
+ read=my_custom_read_with_error, write=my_custom_write_with_error
+ ),
),
Characteristic(
'486F64C6-4B5F-4B3B-8AFF-EDE134A8446A',
- Characteristic.READ | Characteristic.NOTIFY,
+ Characteristic.Properties.READ | Characteristic.Properties.NOTIFY,
Characteristic.READABLE,
- 'hello'
- )
- ]
+ 'hello',
+ ),
+ ],
)
device.add_services([device_info_service, custom_service1])
@@ -142,6 +148,7 @@ async def main():
await hci_source.wait_for_termination()
+
# -----------------------------------------------------------------------------
-logging.basicConfig(level = os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
+logging.basicConfig(level=os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
asyncio.run(main())
diff --git a/examples/run_hfp_gateway.py b/examples/run_hfp_gateway.py
index 69db0c1..63a2a7c 100644
--- a/examples/run_hfp_gateway.py
+++ b/examples/run_hfp_gateway.py
@@ -20,10 +20,16 @@ import sys
import os
import logging
-from colors import color
+from bumble.colors import color
+
+import bumble.core
from bumble.device import Device
from bumble.transport import open_transport_or_link
-from bumble.core import ConnectionError, BT_BR_EDR_TRANSPORT
+from bumble.core import (
+ BT_HANDSFREE_SERVICE,
+ BT_RFCOMM_PROTOCOL_ID,
+ BT_BR_EDR_TRANSPORT,
+)
from bumble.rfcomm import Client
from bumble.sdp import (
Client as SDP_Client,
@@ -31,16 +37,13 @@ from bumble.sdp import (
ServiceAttribute,
SDP_PROTOCOL_DESCRIPTOR_LIST_ATTRIBUTE_ID,
SDP_SERVICE_CLASS_ID_LIST_ATTRIBUTE_ID,
- SDP_BLUETOOTH_PROFILE_DESCRIPTOR_LIST_ATTRIBUTE_ID
-)
-from bumble.hci import (
- BT_HANDSFREE_SERVICE,
- BT_RFCOMM_PROTOCOL_ID
+ SDP_BLUETOOTH_PROFILE_DESCRIPTOR_LIST_ATTRIBUTE_ID,
)
from bumble.hfp import HfpProtocol
# -----------------------------------------------------------------------------
+# pylint: disable-next=too-many-nested-blocks
async def list_rfcomm_channels(device, connection):
# Connect to the SDP Server
sdp_client = SDP_Client(device)
@@ -52,49 +55,72 @@ async def list_rfcomm_channels(device, connection):
[
SDP_PROTOCOL_DESCRIPTOR_LIST_ATTRIBUTE_ID,
SDP_BLUETOOTH_PROFILE_DESCRIPTOR_LIST_ATTRIBUTE_ID,
- SDP_SERVICE_CLASS_ID_LIST_ATTRIBUTE_ID
- ]
+ SDP_SERVICE_CLASS_ID_LIST_ATTRIBUTE_ID,
+ ],
)
print(color('==================================', 'blue'))
print(color('Handsfree Services:', 'yellow'))
rfcomm_channels = []
+ # pylint: disable-next=too-many-nested-blocks
for attribute_list in search_result:
# Look for the RFCOMM Channel number
protocol_descriptor_list = ServiceAttribute.find_attribute_in_list(
- attribute_list,
- SDP_PROTOCOL_DESCRIPTOR_LIST_ATTRIBUTE_ID
+ attribute_list, SDP_PROTOCOL_DESCRIPTOR_LIST_ATTRIBUTE_ID
)
if protocol_descriptor_list:
for protocol_descriptor in protocol_descriptor_list.value:
if len(protocol_descriptor.value) >= 2:
if protocol_descriptor.value[0].value == BT_RFCOMM_PROTOCOL_ID:
print(color('SERVICE:', 'green'))
- print(color(' RFCOMM Channel:', 'cyan'), protocol_descriptor.value[1].value)
+ print(
+ color(' RFCOMM Channel:', 'cyan'),
+ protocol_descriptor.value[1].value,
+ )
rfcomm_channels.append(protocol_descriptor.value[1].value)
# List profiles
- bluetooth_profile_descriptor_list = ServiceAttribute.find_attribute_in_list(
- attribute_list,
- SDP_BLUETOOTH_PROFILE_DESCRIPTOR_LIST_ATTRIBUTE_ID
+ bluetooth_profile_descriptor_list = (
+ ServiceAttribute.find_attribute_in_list(
+ attribute_list,
+ SDP_BLUETOOTH_PROFILE_DESCRIPTOR_LIST_ATTRIBUTE_ID,
+ )
)
if bluetooth_profile_descriptor_list:
if bluetooth_profile_descriptor_list.value:
- if bluetooth_profile_descriptor_list.value[0].type == DataElement.SEQUENCE:
- bluetooth_profile_descriptors = bluetooth_profile_descriptor_list.value
+ if (
+ bluetooth_profile_descriptor_list.value[0].type
+ == DataElement.SEQUENCE
+ ):
+ bluetooth_profile_descriptors = (
+ bluetooth_profile_descriptor_list.value
+ )
else:
- # Sometimes, instead of a list of lists, we just find a list. Fix that
- bluetooth_profile_descriptors = [bluetooth_profile_descriptor_list]
+ # Sometimes, instead of a list of lists, we just
+ # find a list. Fix that
+ bluetooth_profile_descriptors = [
+ bluetooth_profile_descriptor_list
+ ]
print(color(' Profiles:', 'green'))
- for bluetooth_profile_descriptor in bluetooth_profile_descriptors:
- version_major = bluetooth_profile_descriptor.value[1].value >> 8
- version_minor = bluetooth_profile_descriptor.value[1].value & 0xFF
- print(f' {bluetooth_profile_descriptor.value[0].value} - version {version_major}.{version_minor}')
+ for (
+ bluetooth_profile_descriptor
+ ) in bluetooth_profile_descriptors:
+ version_major = (
+ bluetooth_profile_descriptor.value[1].value >> 8
+ )
+ version_minor = (
+ bluetooth_profile_descriptor.value[1].value
+ & 0xFF
+ )
+ print(
+ ' '
+ f'{bluetooth_profile_descriptor.value[0].value}'
+ f' - version {version_major}.{version_minor}'
+ )
# List service classes
service_class_id_list = ServiceAttribute.find_attribute_in_list(
- attribute_list,
- SDP_SERVICE_CLASS_ID_LIST_ATTRIBUTE_ID
+ attribute_list, SDP_SERVICE_CLASS_ID_LIST_ATTRIBUTE_ID
)
if service_class_id_list:
if service_class_id_list.value:
@@ -109,9 +135,14 @@ async def list_rfcomm_channels(device, connection):
# -----------------------------------------------------------------------------
async def main():
if len(sys.argv) < 4:
- print('Usage: run_hfp_gateway.py <device-config> <transport-spec> <bluetooth-address>')
- print(' specifying a channel number, or "discover" to list all RFCOMM channels')
- print('example: run_hfp_gateway.py hfp_gateway.json usb:04b4:f901 E1:CA:72:48:C4:E8')
+ print(
+ 'Usage: run_hfp_gateway.py <device-config> <transport-spec> '
+ '<bluetooth-address>'
+ )
+ print(
+ ' specifying a channel number, or "discover" to list all RFCOMM channels'
+ )
+ print('example: run_hfp_gateway.py hfp_gateway.json usb:0 E1:CA:72:48:C4:E8')
return
print('<<< connecting to HCI...')
@@ -158,7 +189,7 @@ async def main():
try:
session = await rfcomm_mux.open_dlc(channel)
print('### Session open', session)
- except ConnectionError as error:
+ except bumble.core.ConnectionError as error:
print(f'### Session open failed: {error}')
await rfcomm_mux.disconnect()
print('@@@ Disconnected from RFCOMM server')
@@ -173,7 +204,11 @@ async def main():
protocol.send_response_line('+BRSF: 30')
protocol.send_response_line('OK')
elif line.startswith('AT+CIND=?'):
- protocol.send_response_line('+CIND: ("call",(0,1)),("callsetup",(0-3)),("service",(0-1)),("signal",(0-5)),("roam",(0,1)),("battchg",(0-5)),("callheld",(0-2))')
+ protocol.send_response_line(
+ '+CIND: ("call",(0,1)),("callsetup",(0-3)),("service",(0-1)),'
+ '("signal",(0-5)),("roam",(0,1)),("battchg",(0-5)),'
+ '("callheld",(0-2))'
+ )
protocol.send_response_line('OK')
elif line.startswith('AT+CIND?'):
protocol.send_response_line('+CIND: 0,0,1,4,1,5,0')
@@ -193,7 +228,9 @@ async def main():
elif line.startswith('AT+BIA='):
protocol.send_response_line('OK')
elif line.startswith('AT+BVRA='):
- protocol.send_response_line('+BVRA: 1,1,12AA,1,1,"Message 1 from Janina"')
+ protocol.send_response_line(
+ '+BVRA: 1,1,12AA,1,1,"Message 1 from Janina"'
+ )
elif line.startswith('AT+XEVENT='):
protocol.send_response_line('OK')
elif line.startswith('AT+XAPL='):
@@ -204,6 +241,7 @@ async def main():
await hci_source.wait_for_termination()
+
# -----------------------------------------------------------------------------
-logging.basicConfig(level = os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
+logging.basicConfig(level=os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
asyncio.run(main())
diff --git a/examples/run_hfp_handsfree.py b/examples/run_hfp_handsfree.py
index cf7a053..cef29c0 100644
--- a/examples/run_hfp_handsfree.py
+++ b/examples/run_hfp_handsfree.py
@@ -19,26 +19,26 @@ import asyncio
import sys
import os
import logging
-import websockets
import json
+import websockets
from bumble.device import Device
from bumble.transport import open_transport_or_link
-from bumble.rfcomm import Server as RfommServer
+from bumble.rfcomm import Server as RfcommServer
from bumble.sdp import (
DataElement,
ServiceAttribute,
SDP_SERVICE_RECORD_HANDLE_ATTRIBUTE_ID,
SDP_SERVICE_CLASS_ID_LIST_ATTRIBUTE_ID,
SDP_PROTOCOL_DESCRIPTOR_LIST_ATTRIBUTE_ID,
- SDP_BLUETOOTH_PROFILE_DESCRIPTOR_LIST_ATTRIBUTE_ID
+ SDP_BLUETOOTH_PROFILE_DESCRIPTOR_LIST_ATTRIBUTE_ID,
)
from bumble.core import (
BT_GENERIC_AUDIO_SERVICE,
BT_HANDSFREE_SERVICE,
BT_L2CAP_PROTOCOL_ID,
- BT_RFCOMM_PROTOCOL_ID
+ BT_RFCOMM_PROTOCOL_ID,
)
from bumble.hfp import HfpProtocol
@@ -49,36 +49,44 @@ def make_sdp_records(rfcomm_channel):
0x00010001: [
ServiceAttribute(
SDP_SERVICE_RECORD_HANDLE_ATTRIBUTE_ID,
- DataElement.unsigned_integer_32(0x00010001)
+ DataElement.unsigned_integer_32(0x00010001),
),
ServiceAttribute(
SDP_SERVICE_CLASS_ID_LIST_ATTRIBUTE_ID,
- DataElement.sequence([
- DataElement.uuid(BT_HANDSFREE_SERVICE),
- DataElement.uuid(BT_GENERIC_AUDIO_SERVICE)
- ])
+ DataElement.sequence(
+ [
+ DataElement.uuid(BT_HANDSFREE_SERVICE),
+ DataElement.uuid(BT_GENERIC_AUDIO_SERVICE),
+ ]
+ ),
),
ServiceAttribute(
SDP_PROTOCOL_DESCRIPTOR_LIST_ATTRIBUTE_ID,
- DataElement.sequence([
- DataElement.sequence([
- DataElement.uuid(BT_L2CAP_PROTOCOL_ID)
- ]),
- DataElement.sequence([
- DataElement.uuid(BT_RFCOMM_PROTOCOL_ID),
- DataElement.unsigned_integer_8(rfcomm_channel)
- ])
- ])
+ DataElement.sequence(
+ [
+ DataElement.sequence([DataElement.uuid(BT_L2CAP_PROTOCOL_ID)]),
+ DataElement.sequence(
+ [
+ DataElement.uuid(BT_RFCOMM_PROTOCOL_ID),
+ DataElement.unsigned_integer_8(rfcomm_channel),
+ ]
+ ),
+ ]
+ ),
),
ServiceAttribute(
SDP_BLUETOOTH_PROFILE_DESCRIPTOR_LIST_ATTRIBUTE_ID,
- DataElement.sequence([
- DataElement.sequence([
- DataElement.uuid(BT_HANDSFREE_SERVICE),
- DataElement.unsigned_integer_16(0x0105)
- ])
- ])
- )
+ DataElement.sequence(
+ [
+ DataElement.sequence(
+ [
+ DataElement.uuid(BT_HANDSFREE_SERVICE),
+ DataElement.unsigned_integer_16(0x0105),
+ ]
+ )
+ ]
+ ),
+ ),
]
}
@@ -89,7 +97,7 @@ class UiServer:
async def start(self):
# Start a Websocket server to receive events from a web page
- async def serve(websocket, path):
+ async def serve(websocket, _path):
while True:
try:
message = await websocket.recv()
@@ -103,6 +111,8 @@ class UiServer:
except websockets.exceptions.ConnectionClosedOK:
pass
+
+ # pylint: disable=no-member
await websockets.serve(serve, 'localhost', 8989)
@@ -111,7 +121,7 @@ async def protocol_loop(protocol):
await protocol.initialize_service()
while True:
- await(protocol.next_line())
+ await (protocol.next_line())
# -----------------------------------------------------------------------------
@@ -138,7 +148,7 @@ async def main():
device.classic_enabled = True
# Create and register a server
- rfcomm_server = RfommServer(device)
+ rfcomm_server = RfcommServer(device)
# Listen for incoming DLC connections
channel_number = rfcomm_server.listen(on_dlc)
@@ -160,6 +170,7 @@ async def main():
await hci_source.wait_for_termination()
+
# -----------------------------------------------------------------------------
-logging.basicConfig(level = os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
+logging.basicConfig(level=os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
asyncio.run(main())
diff --git a/examples/run_notifier.py b/examples/run_notifier.py
index f52b56c..5f6def3 100644
--- a/examples/run_notifier.py
+++ b/examples/run_notifier.py
@@ -23,10 +23,7 @@ import logging
from bumble.device import Device, Connection
from bumble.transport import open_transport_or_link
-from bumble.gatt import (
- Service,
- Characteristic
-)
+from bumble.gatt import Service, Characteristic
# -----------------------------------------------------------------------------
@@ -41,19 +38,29 @@ class Listener(Device.Listener, Connection.Listener):
def on_disconnection(self, reason):
print(f'### Disconnected, reason={reason}')
- def on_characteristic_subscription(self, connection, characteristic, notify_enabled, indicate_enabled):
+ def on_characteristic_subscription(
+ self, connection, characteristic, notify_enabled, indicate_enabled
+ ):
print(
- f'$$$ Characteristic subscription for handle {characteristic.handle} from {connection}: '
+ f'$$$ Characteristic subscription for handle {characteristic.handle} '
+ f'from {connection}: '
f'notify {"enabled" if notify_enabled else "disabled"}, '
f'indicate {"enabled" if indicate_enabled else "disabled"}'
)
# -----------------------------------------------------------------------------
+# Alternative way to listen for subscriptions
+# -----------------------------------------------------------------------------
+def on_my_characteristic_subscription(peer, enabled):
+ print(f'### My characteristic from {peer}: {"enabled" if enabled else "disabled"}')
+
+
+# -----------------------------------------------------------------------------
async def main():
if len(sys.argv) < 3:
- print('Usage: run_gatt_server.py <device-config> <transport-spec>')
- print('example: run_gatt_server.py device1.json usb:0')
+ print('Usage: run_notifier.py <device-config> <transport-spec>')
+ print('example: run_notifier.py device1.json usb:0')
return
print('<<< connecting to HCI...')
@@ -67,25 +74,28 @@ async def main():
# Add a few entries to the device's GATT server
characteristic1 = Characteristic(
'486F64C6-4B5F-4B3B-8AFF-EDE134A8446A',
- Characteristic.READ | Characteristic.NOTIFY,
+ Characteristic.Properties.READ | Characteristic.Properties.NOTIFY,
Characteristic.READABLE,
- bytes([0x40])
+ bytes([0x40]),
)
characteristic2 = Characteristic(
'8EBDEBAE-0017-418E-8D3B-3A3809492165',
- Characteristic.READ | Characteristic.INDICATE,
+ Characteristic.Properties.READ | Characteristic.Properties.INDICATE,
Characteristic.READABLE,
- bytes([0x41])
+ bytes([0x41]),
)
characteristic3 = Characteristic(
'8EBDEBAE-0017-418E-8D3B-3A3809492165',
- Characteristic.READ | Characteristic.NOTIFY | Characteristic.INDICATE,
+ Characteristic.Properties.READ
+ | Characteristic.Properties.NOTIFY
+ | Characteristic.Properties.INDICATE,
Characteristic.READABLE,
- bytes([0x42])
+ bytes([0x42]),
)
+ characteristic3.on('subscription', on_my_characteristic_subscription)
custom_service = Service(
'50DB505C-8AC4-4738-8448-3B1D9CC09CC5',
- [characteristic1, characteristic2, characteristic3]
+ [characteristic1, characteristic2, characteristic3],
)
device.add_services([custom_service])
@@ -116,5 +126,5 @@ async def main():
# -----------------------------------------------------------------------------
-logging.basicConfig(level = os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
+logging.basicConfig(level=os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
asyncio.run(main())
diff --git a/examples/run_rfcomm_client.py b/examples/run_rfcomm_client.py
index 83ef848..9a94278 100644
--- a/examples/run_rfcomm_client.py
+++ b/examples/run_rfcomm_client.py
@@ -20,10 +20,16 @@ import sys
import os
import logging
-from colors import color
+from bumble.colors import color
+
+import bumble.core
from bumble.device import Device
from bumble.transport import open_transport_or_link
-from bumble.core import ConnectionError, BT_BR_EDR_TRANSPORT
+from bumble.core import (
+ BT_L2CAP_PROTOCOL_ID,
+ BT_RFCOMM_PROTOCOL_ID,
+ BT_BR_EDR_TRANSPORT,
+)
from bumble.rfcomm import Client
from bumble.sdp import (
Client as SDP_Client,
@@ -31,9 +37,8 @@ from bumble.sdp import (
ServiceAttribute,
SDP_PROTOCOL_DESCRIPTOR_LIST_ATTRIBUTE_ID,
SDP_SERVICE_CLASS_ID_LIST_ATTRIBUTE_ID,
- SDP_BLUETOOTH_PROFILE_DESCRIPTOR_LIST_ATTRIBUTE_ID
+ SDP_BLUETOOTH_PROFILE_DESCRIPTOR_LIST_ATTRIBUTE_ID,
)
-from bumble.hci import BT_L2CAP_PROTOCOL_ID, BT_RFCOMM_PROTOCOL_ID
# -----------------------------------------------------------------------------
@@ -48,47 +53,70 @@ async def list_rfcomm_channels(device, connection):
[
SDP_PROTOCOL_DESCRIPTOR_LIST_ATTRIBUTE_ID,
SDP_BLUETOOTH_PROFILE_DESCRIPTOR_LIST_ATTRIBUTE_ID,
- SDP_SERVICE_CLASS_ID_LIST_ATTRIBUTE_ID
- ]
+ SDP_SERVICE_CLASS_ID_LIST_ATTRIBUTE_ID,
+ ],
)
print(color('==================================', 'blue'))
print(color('RFCOMM Services:', 'yellow'))
+ # pylint: disable-next=too-many-nested-blocks
for attribute_list in search_result:
# Look for the RFCOMM Channel number
protocol_descriptor_list = ServiceAttribute.find_attribute_in_list(
- attribute_list,
- SDP_PROTOCOL_DESCRIPTOR_LIST_ATTRIBUTE_ID
+ attribute_list, SDP_PROTOCOL_DESCRIPTOR_LIST_ATTRIBUTE_ID
)
if protocol_descriptor_list:
for protocol_descriptor in protocol_descriptor_list.value:
if len(protocol_descriptor.value) >= 2:
if protocol_descriptor.value[0].value == BT_RFCOMM_PROTOCOL_ID:
print(color('SERVICE:', 'green'))
- print(color(' RFCOMM Channel:', 'cyan'), protocol_descriptor.value[1].value)
+ print(
+ color(' RFCOMM Channel:', 'cyan'),
+ protocol_descriptor.value[1].value,
+ )
# List profiles
- bluetooth_profile_descriptor_list = ServiceAttribute.find_attribute_in_list(
- attribute_list,
- SDP_BLUETOOTH_PROFILE_DESCRIPTOR_LIST_ATTRIBUTE_ID
+ bluetooth_profile_descriptor_list = (
+ ServiceAttribute.find_attribute_in_list(
+ attribute_list,
+ SDP_BLUETOOTH_PROFILE_DESCRIPTOR_LIST_ATTRIBUTE_ID,
+ )
)
if bluetooth_profile_descriptor_list:
if bluetooth_profile_descriptor_list.value:
- if bluetooth_profile_descriptor_list.value[0].type == DataElement.SEQUENCE:
- bluetooth_profile_descriptors = bluetooth_profile_descriptor_list.value
+ if (
+ bluetooth_profile_descriptor_list.value[0].type
+ == DataElement.SEQUENCE
+ ):
+ bluetooth_profile_descriptors = (
+ bluetooth_profile_descriptor_list.value
+ )
else:
- # Sometimes, instead of a list of lists, we just find a list. Fix that
- bluetooth_profile_descriptors = [bluetooth_profile_descriptor_list]
+ # Sometimes, instead of a list of lists, we just
+ # find a list. Fix that
+ bluetooth_profile_descriptors = [
+ bluetooth_profile_descriptor_list
+ ]
print(color(' Profiles:', 'green'))
- for bluetooth_profile_descriptor in bluetooth_profile_descriptors:
- version_major = bluetooth_profile_descriptor.value[1].value >> 8
- version_minor = bluetooth_profile_descriptor.value[1].value & 0xFF
- print(f' {bluetooth_profile_descriptor.value[0].value} - version {version_major}.{version_minor}')
+ for (
+ bluetooth_profile_descriptor
+ ) in bluetooth_profile_descriptors:
+ version_major = (
+ bluetooth_profile_descriptor.value[1].value >> 8
+ )
+ version_minor = (
+ bluetooth_profile_descriptor.value[1].value
+ & 0xFF
+ )
+ print(
+ ' '
+ f'{bluetooth_profile_descriptor.value[0].value}'
+ f' - version {version_major}.{version_minor}'
+ )
# List service classes
service_class_id_list = ServiceAttribute.find_attribute_in_list(
- attribute_list,
- SDP_SERVICE_CLASS_ID_LIST_ATTRIBUTE_ID
+ attribute_list, SDP_SERVICE_CLASS_ID_LIST_ATTRIBUTE_ID
)
if service_class_id_list:
if service_class_id_list.value:
@@ -98,14 +126,16 @@ async def list_rfcomm_channels(device, connection):
await sdp_client.disconnect()
+
# -----------------------------------------------------------------------------
class TcpServerProtocol(asyncio.Protocol):
def __init__(self, rfcomm_session):
self.rfcomm_session = rfcomm_session
+ self.transport = None
def connection_made(self, transport):
- peername = transport.get_extra_info('peername')
- print(f'<<< TCP Server: connection from {peername}')
+ peer_name = transport.get_extra_info('peer_name')
+ print(f'<<< TCP Server: connection from {peer_name}')
self.transport = transport
self.rfcomm_session.sink = self.rfcomm_data_received
@@ -137,9 +167,14 @@ async def tcp_server(tcp_port, rfcomm_session):
# -----------------------------------------------------------------------------
async def main():
if len(sys.argv) < 5:
- print('Usage: run_rfcomm_client.py <device-config> <transport-spec> <bluetooth-address> <channel>|discover [tcp-port]')
- print(' specifying a channel number, or "discover" to list all RFCOMM channels')
- print('example: run_rfcomm_client.py classic1.json usb:04b4:f901 E1:CA:72:48:C4:E8 8')
+ print(
+ 'Usage: run_rfcomm_client.py <device-config> <transport-spec> '
+ '<bluetooth-address> <channel>|discover [tcp-port]'
+ )
+ print(
+ ' specifying a channel number, or "discover" to list all RFCOMM channels'
+ )
+ print('example: run_rfcomm_client.py classic1.json usb:0 E1:CA:72:48:C4:E8 8')
return
print('<<< connecting to HCI...')
@@ -173,7 +208,7 @@ async def main():
print('*** Encryption on')
# Create a client and start it
- print('@@@ Starting to RFCOMM client...')
+ print('@@@ Starting RFCOMM client...')
rfcomm_client = Client(device, connection)
rfcomm_mux = await rfcomm_client.start()
print('@@@ Started')
@@ -183,7 +218,7 @@ async def main():
try:
session = await rfcomm_mux.open_dlc(channel)
print('### Session open', session)
- except ConnectionError as error:
+ except bumble.core.ConnectionError as error:
print(f'### Session open failed: {error}')
await rfcomm_mux.disconnect()
print('@@@ Disconnected from RFCOMM server')
@@ -192,10 +227,11 @@ async def main():
if len(sys.argv) == 6:
# A TCP port was specified, start listening
tcp_port = int(sys.argv[5])
- asyncio.get_running_loop().create_task(tcp_server(tcp_port, session))
+ asyncio.create_task(tcp_server(tcp_port, session))
await hci_source.wait_for_termination()
+
# -----------------------------------------------------------------------------
-logging.basicConfig(level = os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
+logging.basicConfig(level=os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
asyncio.run(main())
diff --git a/examples/run_rfcomm_server.py b/examples/run_rfcomm_server.py
index a239ceb..71feca9 100644
--- a/examples/run_rfcomm_server.py
+++ b/examples/run_rfcomm_server.py
@@ -22,7 +22,7 @@ import logging
from bumble.device import Device
from bumble.transport import open_transport_or_link
-from bumble.core import UUID
+from bumble.core import BT_L2CAP_PROTOCOL_ID, BT_RFCOMM_PROTOCOL_ID, UUID
from bumble.rfcomm import Server
from bumble.sdp import (
DataElement,
@@ -31,31 +31,42 @@ from bumble.sdp import (
SDP_SERVICE_RECORD_HANDLE_ATTRIBUTE_ID,
SDP_BROWSE_GROUP_LIST_ATTRIBUTE_ID,
SDP_SERVICE_CLASS_ID_LIST_ATTRIBUTE_ID,
- SDP_PROTOCOL_DESCRIPTOR_LIST_ATTRIBUTE_ID
+ SDP_PROTOCOL_DESCRIPTOR_LIST_ATTRIBUTE_ID,
)
-from bumble.hci import BT_L2CAP_PROTOCOL_ID, BT_RFCOMM_PROTOCOL_ID
# -----------------------------------------------------------------------------
def sdp_records(channel):
return {
0x00010001: [
- ServiceAttribute(SDP_SERVICE_RECORD_HANDLE_ATTRIBUTE_ID, DataElement.unsigned_integer_32(0x00010001)),
- ServiceAttribute(SDP_BROWSE_GROUP_LIST_ATTRIBUTE_ID, DataElement.sequence([
- DataElement.uuid(SDP_PUBLIC_BROWSE_ROOT)
- ])),
- ServiceAttribute(SDP_SERVICE_CLASS_ID_LIST_ATTRIBUTE_ID, DataElement.sequence([
- DataElement.uuid(UUID('E6D55659-C8B4-4B85-96BB-B1143AF6D3AE'))
- ])),
- ServiceAttribute(SDP_PROTOCOL_DESCRIPTOR_LIST_ATTRIBUTE_ID, DataElement.sequence([
- DataElement.sequence([
- DataElement.uuid(BT_L2CAP_PROTOCOL_ID)
- ]),
- DataElement.sequence([
- DataElement.uuid(BT_RFCOMM_PROTOCOL_ID),
- DataElement.unsigned_integer_8(channel)
- ])
- ]))
+ ServiceAttribute(
+ SDP_SERVICE_RECORD_HANDLE_ATTRIBUTE_ID,
+ DataElement.unsigned_integer_32(0x00010001),
+ ),
+ ServiceAttribute(
+ SDP_BROWSE_GROUP_LIST_ATTRIBUTE_ID,
+ DataElement.sequence([DataElement.uuid(SDP_PUBLIC_BROWSE_ROOT)]),
+ ),
+ ServiceAttribute(
+ SDP_SERVICE_CLASS_ID_LIST_ATTRIBUTE_ID,
+ DataElement.sequence(
+ [DataElement.uuid(UUID('E6D55659-C8B4-4B85-96BB-B1143AF6D3AE'))]
+ ),
+ ),
+ ServiceAttribute(
+ SDP_PROTOCOL_DESCRIPTOR_LIST_ATTRIBUTE_ID,
+ DataElement.sequence(
+ [
+ DataElement.sequence([DataElement.uuid(BT_L2CAP_PROTOCOL_ID)]),
+ DataElement.sequence(
+ [
+ DataElement.uuid(BT_RFCOMM_PROTOCOL_ID),
+ DataElement.unsigned_integer_8(channel),
+ ]
+ ),
+ ]
+ ),
+ ),
]
}
@@ -113,6 +124,7 @@ async def main():
await hci_source.wait_for_termination()
+
# -----------------------------------------------------------------------------
-logging.basicConfig(level = os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
+logging.basicConfig(level=os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
asyncio.run(main())
diff --git a/examples/run_scanner.py b/examples/run_scanner.py
index feed88f..bdd7fba 100644
--- a/examples/run_scanner.py
+++ b/examples/run_scanner.py
@@ -19,7 +19,7 @@ import asyncio
import sys
import os
import logging
-from colors import color
+from bumble.colors import color
from bumble.device import Device
from bumble.transport import open_transport_or_link
@@ -35,35 +35,44 @@ async def main():
print('<<< connecting to HCI...')
async with await open_transport_or_link(sys.argv[1]) as (hci_source, hci_sink):
print('<<< connected')
- filter_duplicates = (len(sys.argv) == 3 and sys.argv[2] == 'filter')
+ filter_duplicates = len(sys.argv) == 3 and sys.argv[2] == 'filter'
device = Device.with_hci('Bumble', 'F0:F1:F2:F3:F4:F5', hci_source, hci_sink)
@device.on('advertisement')
- def _(address, ad_data, rssi, connectable):
- address_type_string = ('PUBLIC', 'RANDOM', 'PUBLIC_ID', 'RANDOM_ID')[address.address_type]
- address_color = 'yellow' if connectable else 'red'
+ def _(advertisement):
+ address_type_string = ('PUBLIC', 'RANDOM', 'PUBLIC_ID', 'RANDOM_ID')[
+ advertisement.address.address_type
+ ]
+ address_color = 'yellow' if advertisement.is_connectable else 'red'
address_qualifier = ''
if address_type_string.startswith('P'):
type_color = 'cyan'
else:
- if address.is_static:
+ if advertisement.address.is_static:
type_color = 'green'
address_qualifier = '(static)'
- elif address.is_resolvable:
+ elif advertisement.address.is_resolvable:
type_color = 'magenta'
address_qualifier = '(resolvable)'
else:
type_color = 'white'
separator = '\n '
- print(f'>>> {color(address, address_color)} [{color(address_type_string, type_color)}]{address_qualifier}:{separator}RSSI:{rssi}{separator}{ad_data.to_string(separator)}')
+ print(
+ f'>>> {color(advertisement.address, address_color)} '
+ f'[{color(address_type_string, type_color)}]'
+ f'{address_qualifier}:{separator}RSSI:{advertisement.rssi}'
+ f'{separator}'
+ f'{advertisement.data.to_string(separator)}'
+ )
await device.power_on()
await device.start_scanning(filter_duplicates=filter_duplicates)
await hci_source.wait_for_termination()
+
# -----------------------------------------------------------------------------
-logging.basicConfig(level = os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
+logging.basicConfig(level=os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
asyncio.run(main())
diff --git a/pyproject.toml b/pyproject.toml
index 6eca00c..8662723 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -3,3 +3,85 @@ requires = ["setuptools>=52", "wheel", "setuptools_scm>=6.2"]
build-backend = "setuptools.build_meta"
[tool.setuptools_scm]
+write_to = "bumble/_version.py"
+
+[tool.pytest.ini_options]
+pythonpath = "."
+testpaths = [
+ "tests"
+]
+
+[tool.pylint.master]
+init-hook = 'import sys; sys.path.append(".")'
+ignore-paths = [
+ '.*_pb2(_grpc)?.py'
+]
+
+[tool.pylint.messages_control]
+max-line-length = "88"
+
+disable = [
+ "broad-except",
+ "fixme",
+ "logging-fstring-interpolation",
+ "logging-not-lazy",
+ "no-member", # Temporary until pylint works better with class/method decorators
+ "no-value-for-parameter", # Temporary until pylint works better with class/method decorators
+ "missing-class-docstring",
+ "missing-function-docstring",
+ "missing-module-docstring",
+ "too-few-public-methods",
+ "too-many-arguments",
+ "too-many-branches",
+ "too-many-instance-attributes",
+ "too-many-lines",
+ "too-many-locals",
+ "too-many-public-methods",
+ "too-many-statements",
+]
+
+[tool.pylint.main]
+ignore="pandora" # FIXME: pylint does not support stubs yet:
+
+[tool.pylint.typecheck]
+signature-mutators="AsyncRunner.run_in_task"
+
+[tool.black]
+skip-string-normalization = true
+extend-exclude = '''
+(
+ .*_pb2(_grpc)?.py # exclude autogenerated Protocol Buffer files anywhere in the project
+)
+'''
+
+[tool.mypy]
+exclude = ['bumble/transport/grpc_protobuf']
+
+[[tool.mypy.overrides]]
+module = "bumble.transport.grpc_protobuf.*"
+ignore_errors = true
+
+[[tool.mypy.overrides]]
+module = "aioconsole.*"
+ignore_missing_imports = true
+
+[[tool.mypy.overrides]]
+module = "construct.*"
+ignore_missing_imports = true
+
+[[tool.mypy.overrides]]
+module = "grpc.*"
+ignore_missing_imports = true
+
+[[tool.mypy.overrides]]
+module = "serial_asyncio.*"
+ignore_missing_imports = true
+
+[[tool.mypy.overrides]]
+module = "usb.*"
+ignore_missing_imports = true
+
+[[tool.mypy.overrides]]
+module = "usb1.*"
+ignore_missing_imports = true
+
diff --git a/scripts/process_android_emulator_protos.sh b/scripts/process_android_emulator_protos.sh
new file mode 100644
index 0000000..d5070df
--- /dev/null
+++ b/scripts/process_android_emulator_protos.sh
@@ -0,0 +1,16 @@
+# Invoke this script with an argument pointing to where the Android emulator .proto files are
+# (for example, ~/Library/Android/sdk/emulator/lib on a mac, or
+# $AOSP/external/qemu/android/android-grpc/python/aemu-grpc/src/aemu/proto from the AOSP sources)
+PROTOC_OUT=bumble/transport/grpc_protobuf
+
+proto_files=(emulated_bluetooth.proto emulated_bluetooth_vhci.proto emulated_bluetooth_packets.proto emulated_bluetooth_device.proto grpc_endpoint_description.proto)
+for proto_file in "${proto_files[@]}"
+do
+ python -m grpc_tools.protoc -I$1 --proto_path=bumble/transport --python_out=$PROTOC_OUT --pyi_out=$PROTOC_OUT --grpc_python_out=$PROTOC_OUT $1/$proto_file
+done
+
+python_files=(emulated_bluetooth_pb2_grpc.py emulated_bluetooth_pb2.py emulated_bluetooth_packets_pb2.py emulated_bluetooth_vhci_pb2_grpc.py emulated_bluetooth_vhci_pb2.py emulated_bluetooth_device_pb2.py grpc_endpoint_description_pb2.py)
+for python_file in "${python_files[@]}"
+do
+ sed -i 's/^import .*_pb2 as/from . \0/' $PROTOC_OUT/$python_file
+done \ No newline at end of file
diff --git a/scripts/process_android_netsim_protos.sh b/scripts/process_android_netsim_protos.sh
new file mode 100644
index 0000000..5a26602
--- /dev/null
+++ b/scripts/process_android_netsim_protos.sh
@@ -0,0 +1,14 @@
+# Invoke this script with an argument pointing to where the AOSP `tools/netsim/src/proto` is
+PROTOC_OUT=bumble/transport/grpc_protobuf
+
+proto_files=(common.proto packet_streamer.proto hci_packet.proto startup.proto)
+for proto_file in "${proto_files[@]}"
+do
+ python -m grpc_tools.protoc -I$1 --proto_path=bumble/transport --python_out=$PROTOC_OUT --pyi_out=$PROTOC_OUT --grpc_python_out=$PROTOC_OUT $1/$proto_file
+done
+
+python_files=(packet_streamer_pb2_grpc.py packet_streamer_pb2.py hci_packet_pb2.py startup_pb2.py)
+for python_file in "${python_files[@]}"
+do
+ sed -i 's/^import .*_pb2 as/from . \0/' $PROTOC_OUT/$python_file
+done
diff --git a/setup.cfg b/setup.cfg
index 1711d7c..45c7264 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -16,25 +16,26 @@
name = bumble
use_scm_version = True
description = Bluetooth Stack for Apps, Emulation, Test and Experimentation
+long_description = file: README.md
+long_description_content_type = text/markdown
author = Google
author_email = tbd@tbd.com
url = https://github.com/google/bumble
[options]
python_requires = >=3.8
-packages = bumble, bumble.transport, bumble.apps, bumble.apps.link_relay
+packages = bumble, bumble.transport, bumble.profiles, bumble.apps, bumble.apps.link_relay, bumble.pandora
package_dir =
bumble = bumble
bumble.apps = apps
+include-package-data = True
install_requires =
- aioconsole >= 0.4.1
- ansicolors >= 1.1
appdirs >= 1.4
- bitstruct >= 8.12
click >= 7.1.2; platform_system!='Emscripten'
cryptography == 35; platform_system!='Emscripten'
- grpcio >= 1.46; platform_system!='Emscripten'
+ grpcio == 1.51.1; platform_system!='Emscripten'
libusb1 >= 2.0.1; platform_system!='Emscripten'
+ libusb-package == 1.0.26.1; platform_system!='Emscripten'
prompt_toolkit >= 3.0.16; platform_system!='Emscripten'
protobuf >= 3.12.4
pyee >= 8.2.2
@@ -42,27 +43,48 @@ install_requires =
pyserial >= 3.5; platform_system!='Emscripten'
pyusb >= 1.2; platform_system!='Emscripten'
websockets >= 8.1; platform_system!='Emscripten'
+ prettytable >= 3.6.0
+ humanize >= 4.6.0
+ bt-test-interfaces >= 0.0.2
[options.entry_points]
console_scripts =
bumble-console = bumble.apps.console:main
+ bumble-controller-info = bumble.apps.controller_info:main
bumble-gatt-dump = bumble.apps.gatt_dump:main
bumble-hci-bridge = bumble.apps.hci_bridge:main
+ bumble-l2cap-bridge = bumble.apps.l2cap_bridge:main
bumble-pair = bumble.apps.pair:main
bumble-scan = bumble.apps.scan:main
bumble-show = bumble.apps.show:main
bumble-unbond = bumble.apps.unbond:main
+ bumble-usb-probe = bumble.apps.usb_probe:main
bumble-link-relay = bumble.apps.link_relay.link_relay:main
+ bumble-bench = bumble.apps.bench:main
+ bumble-pandora-server = bumble.apps.pandora_server:main
+
+[options.package_data]
+* = py.typed, *.pyi
[options.extras_require]
+build =
+ build >= 0.7
test =
pytest >= 6.2
pytest-asyncio >= 0.17
+ pytest-html >= 3.2.0
+ coverage >= 6.4
development =
- invoke >= 1.4
- build >= 0.7
+ black == 22.10
+ grpcio-tools >= 1.51.1
+ invoke >= 1.7.3
+ mypy == 1.2.0
nox >= 2022
+ pylint == 2.15.8
+ types-appdirs >= 1.4.3
+ types-invoke >= 1.7.3
+ types-protobuf >= 4.21.0
documentation =
- mkdocs >= 1.2.3
- mkdocs-material >= 8.1.9
+ mkdocs >= 1.4.0
+ mkdocs-material >= 8.5.6
mkdocstrings[python] >= 0.19.0
diff --git a/setup.py b/setup.py
index 16ecaca..1380bc9 100644
--- a/setup.py
+++ b/setup.py
@@ -13,4 +13,5 @@
# limitations under the License.
from setuptools import setup
+
setup()
diff --git a/tasks.py b/tasks.py
index c368291..3a3a01a 100644
--- a/tasks.py
+++ b/tasks.py
@@ -15,43 +15,165 @@
"""
Invoke tasks
"""
+
+# -----------------------------------------------------------------------------
+# Imports
+# -----------------------------------------------------------------------------
import os
-from invoke import task, Collection
+from invoke import task, call, Collection
+from invoke.exceptions import Exit, UnexpectedExit
+
+# -----------------------------------------------------------------------------
ROOT_DIR = os.path.dirname(os.path.realpath(__file__))
ns = Collection()
+
+# -----------------------------------------------------------------------------
+# Build
+# -----------------------------------------------------------------------------
build_tasks = Collection()
-ns.add_collection(build_tasks, name='build')
+ns.add_collection(build_tasks, name="build")
+# -----------------------------------------------------------------------------
@task
-def build(ctx):
- ctx.run('python -m build')
+def build(ctx, install=False):
+ if install:
+ ctx.run('python -m pip install .[build]')
-build_tasks.add_task(build, default=True, name='build')
+ ctx.run("python -m build")
-test_tasks = Collection()
-ns.add_collection(test_tasks, name='test')
+# -----------------------------------------------------------------------------
@task
-def test(ctx, filter=None, junit=False):
+def release_build(ctx):
+ build(ctx, install=True)
+
+
+# -----------------------------------------------------------------------------
+@task
+def mkdocs(ctx):
+ ctx.run("mkdocs build -f docs/mkdocs/mkdocs.yml")
+
+
+# -----------------------------------------------------------------------------
+build_tasks.add_task(build, default=True)
+build_tasks.add_task(release_build, name="release")
+build_tasks.add_task(mkdocs, name="mkdocs")
+
+
+# -----------------------------------------------------------------------------
+# Test
+# -----------------------------------------------------------------------------
+test_tasks = Collection()
+ns.add_collection(test_tasks, name="test")
+
+
+# -----------------------------------------------------------------------------
+@task(incrementable=["verbose"])
+def test(ctx, match=None, junit=False, install=False, html=False, verbose=0):
+ # Install the package before running the tests
+ if install:
+ ctx.run("python -m pip install .[test]")
+
args = ""
if junit:
args += "--junit-xml test-results.xml"
- if filter is not None:
- args += " -k '{}'".format(filter)
- ctx.run('python -m pytest {} {}'
- .format(os.path.join(ROOT_DIR, "tests"), args))
+ if match is not None:
+ args += f" -k '{match}'"
+ if html:
+ args += " --html results.html"
+ if verbose > 0:
+ args += f" -{'v' * verbose}"
+ ctx.run(f"python -m pytest {os.path.join(ROOT_DIR, 'tests')} {args}")
-test_tasks.add_task(test, name='test', default=True)
+# -----------------------------------------------------------------------------
+@task
+def release_test(ctx):
+ test(ctx, install=True)
+
+# -----------------------------------------------------------------------------
+test_tasks.add_task(test, default=True)
+test_tasks.add_task(release_test, name="release")
+
+# -----------------------------------------------------------------------------
+# Project
+# -----------------------------------------------------------------------------
+project_tasks = Collection()
+ns.add_collection(project_tasks, name="project")
+
+
+# -----------------------------------------------------------------------------
@task
-def mkdocs(ctx):
- ctx.run('mkdocs build -f docs/mkdocs/mkdocs.yml')
+def lint(ctx, disable='C,R', errors_only=False):
+ options = []
+ if disable:
+ options.append(f"--disable={disable}")
+ if errors_only:
+ options.append("-E")
+
+ if errors_only:
+ qualifier = ' (errors only)'
+ else:
+ qualifier = f' (disabled: {disable})' if disable else ''
+
+ print(f">>> Running the linter{qualifier}...")
+ try:
+ ctx.run(f"pylint {' '.join(options)} bumble apps examples tasks.py")
+ print("The linter is happy. ✅ 😊 ðŸ'")
+ except UnexpectedExit as exc:
+ print("Please check your code against the linter messages. âŒ")
+ raise Exit(code=1) from exc
+
+
+# -----------------------------------------------------------------------------
+@task
+def format_code(ctx, check=False, diff=False):
+ options = []
+ if check:
+ options.append("--check")
+ if diff:
+ options.append("--diff")
+
+ print(">>> Running the formatter...")
+ try:
+ ctx.run(f"black -S {' '.join(options)} .")
+ except UnexpectedExit as exc:
+ print("Please run 'invoke project.format' or 'black .' to format the code. âŒ")
+ raise Exit(code=1) from exc
+
+
+# -----------------------------------------------------------------------------
+@task
+def check_types(ctx):
+ checklist = ["apps", "bumble", "examples", "tests", "tasks.py"]
+ try:
+ ctx.run(f"mypy {' '.join(checklist)}")
+ except UnexpectedExit as exc:
+ print("Please check your code against the mypy messages.")
+ raise Exit(code=1) from exc
+
+
+# -----------------------------------------------------------------------------
+@task(
+ pre=[
+ call(format_code, check=True),
+ call(lint, errors_only=True),
+ call(check_types),
+ test,
+ ]
+)
+def pre_commit(_ctx):
+ print("All good!")
-ns.add_task(mkdocs)
+# -----------------------------------------------------------------------------
+project_tasks.add_task(lint)
+project_tasks.add_task(format_code, name="format")
+project_tasks.add_task(check_types, name="check-types")
+project_tasks.add_task(pre_commit)
diff --git a/tests/a2dp_test.py b/tests/a2dp_test.py
index e09694d..92f7915 100644
--- a/tests/a2dp_test.py
+++ b/tests/a2dp_test.py
@@ -21,6 +21,7 @@ import os
import pytest
from bumble.controller import Controller
+from bumble.core import BT_BR_EDR_TRANSPORT
from bumble.link import LocalLink
from bumble.device import Device
from bumble.host import Host
@@ -35,7 +36,7 @@ from bumble.avdtp import (
MediaPacket,
AVDTP_AUDIO_MEDIA_TYPE,
AVDTP_TSEP_SNK,
- A2DP_SBC_CODEC_TYPE
+ A2DP_SBC_CODEC_TYPE,
)
from bumble.a2dp import (
SbcMediaCodecInformation,
@@ -44,7 +45,7 @@ from bumble.a2dp import (
SBC_STEREO_CHANNEL_MODE,
SBC_JOINT_STEREO_CHANNEL_MODE,
SBC_LOUDNESS_ALLOCATION_METHOD,
- SBC_SNR_ALLOCATION_METHOD
+ SBC_SNR_ALLOCATION_METHOD,
)
# -----------------------------------------------------------------------------
@@ -58,20 +59,21 @@ class TwoDevices:
def __init__(self):
self.connections = [None, None]
+ addresses = ['F0:F1:F2:F3:F4:F5', 'F5:F4:F3:F2:F1:F0']
self.link = LocalLink()
self.controllers = [
- Controller('C1', link = self.link),
- Controller('C2', link = self.link)
+ Controller('C1', link=self.link, public_address=addresses[0]),
+ Controller('C2', link=self.link, public_address=addresses[1]),
]
self.devices = [
Device(
- address = 'F0:F1:F2:F3:F4:F5',
- host = Host(self.controllers[0], AsyncPipeSink(self.controllers[0]))
+ address=addresses[0],
+ host=Host(self.controllers[0], AsyncPipeSink(self.controllers[0])),
),
Device(
- address = 'F5:F4:F3:F2:F1:F0',
- host = Host(self.controllers[1], AsyncPipeSink(self.controllers[1]))
- )
+ address=addresses[1],
+ host=Host(self.controllers[1], AsyncPipeSink(self.controllers[1])),
+ ),
]
self.paired = [None, None]
@@ -79,6 +81,9 @@ class TwoDevices:
def on_connection(self, which, connection):
self.connections[which] = connection
+ def on_paired(self, which, keys):
+ self.paired[which] = keys
+
# -----------------------------------------------------------------------------
@pytest.mark.asyncio
@@ -87,57 +92,73 @@ async def test_self_connection():
two_devices = TwoDevices()
# Attach listeners
- two_devices.devices[0].on('connection', lambda connection: two_devices.on_connection(0, connection))
- two_devices.devices[1].on('connection', lambda connection: two_devices.on_connection(1, connection))
+ two_devices.devices[0].on(
+ 'connection', lambda connection: two_devices.on_connection(0, connection)
+ )
+ two_devices.devices[1].on(
+ 'connection', lambda connection: two_devices.on_connection(1, connection)
+ )
+
+ # Enable Classic connections
+ two_devices.devices[0].classic_enabled = True
+ two_devices.devices[1].classic_enabled = True
# Start
await two_devices.devices[0].power_on()
await two_devices.devices[1].power_on()
# Connect the two devices
- await two_devices.devices[0].connect(two_devices.devices[1].random_address)
+ await asyncio.gather(
+ two_devices.devices[0].connect(
+ two_devices.devices[1].public_address, transport=BT_BR_EDR_TRANSPORT
+ ),
+ two_devices.devices[1].accept(two_devices.devices[0].public_address),
+ )
# Check the post conditions
- assert(two_devices.connections[0] is not None)
- assert(two_devices.connections[1] is not None)
+ assert two_devices.connections[0] is not None
+ assert two_devices.connections[1] is not None
# -----------------------------------------------------------------------------
def source_codec_capabilities():
return MediaCodecCapabilities(
- media_type = AVDTP_AUDIO_MEDIA_TYPE,
- media_codec_type = A2DP_SBC_CODEC_TYPE,
- media_codec_information = SbcMediaCodecInformation.from_discrete_values(
- sampling_frequency = 44100,
- channel_mode = SBC_JOINT_STEREO_CHANNEL_MODE,
- block_length = 16,
- subbands = 8,
- allocation_method = SBC_LOUDNESS_ALLOCATION_METHOD,
- minimum_bitpool_value = 2,
- maximum_bitpool_value = 53
- )
+ media_type=AVDTP_AUDIO_MEDIA_TYPE,
+ media_codec_type=A2DP_SBC_CODEC_TYPE,
+ media_codec_information=SbcMediaCodecInformation.from_discrete_values(
+ sampling_frequency=44100,
+ channel_mode=SBC_JOINT_STEREO_CHANNEL_MODE,
+ block_length=16,
+ subbands=8,
+ allocation_method=SBC_LOUDNESS_ALLOCATION_METHOD,
+ minimum_bitpool_value=2,
+ maximum_bitpool_value=53,
+ ),
)
# -----------------------------------------------------------------------------
def sink_codec_capabilities():
return MediaCodecCapabilities(
- media_type = AVDTP_AUDIO_MEDIA_TYPE,
- media_codec_type = A2DP_SBC_CODEC_TYPE,
- media_codec_information = SbcMediaCodecInformation.from_lists(
- sampling_frequencies = [48000, 44100, 32000, 16000],
- channel_modes = [
+ media_type=AVDTP_AUDIO_MEDIA_TYPE,
+ media_codec_type=A2DP_SBC_CODEC_TYPE,
+ media_codec_information=SbcMediaCodecInformation.from_lists(
+ sampling_frequencies=[48000, 44100, 32000, 16000],
+ channel_modes=[
SBC_MONO_CHANNEL_MODE,
SBC_DUAL_CHANNEL_MODE,
SBC_STEREO_CHANNEL_MODE,
- SBC_JOINT_STEREO_CHANNEL_MODE
+ SBC_JOINT_STEREO_CHANNEL_MODE,
],
- block_lengths = [4, 8, 12, 16],
- subbands = [4, 8],
- allocation_methods = [SBC_LOUDNESS_ALLOCATION_METHOD, SBC_SNR_ALLOCATION_METHOD],
- minimum_bitpool_value = 2,
- maximum_bitpool_value = 53
- )
+ block_lengths=[4, 8, 12, 16],
+ subbands=[4, 8],
+ allocation_methods=[
+ SBC_LOUDNESS_ALLOCATION_METHOD,
+ SBC_SNR_ALLOCATION_METHOD,
+ ],
+ minimum_bitpool_value=2,
+ maximum_bitpool_value=53,
+ ),
)
@@ -145,6 +166,9 @@ def sink_codec_capabilities():
@pytest.mark.asyncio
async def test_source_sink_1():
two_devices = TwoDevices()
+ # Enable Classic connections
+ two_devices.devices[0].classic_enabled = True
+ two_devices.devices[1].classic_enabled = True
await two_devices.devices[0].power_on()
await two_devices.devices[1].power_on()
@@ -164,21 +188,32 @@ async def test_source_sink_1():
listener = Listener(Listener.create_registrar(two_devices.devices[1]))
listener.on('connection', on_avdtp_connection)
- connection = await two_devices.devices[0].connect(two_devices.devices[1].random_address)
+ async def make_connection():
+ connections = await asyncio.gather(
+ two_devices.devices[0].connect(
+ two_devices.devices[1].public_address, BT_BR_EDR_TRANSPORT
+ ),
+ two_devices.devices[1].accept(two_devices.devices[0].public_address),
+ )
+ return connections[0]
+
+ connection = await make_connection()
client = await Protocol.connect(connection)
endpoints = await client.discover_remote_endpoints()
- assert(len(endpoints) == 1)
+ assert len(endpoints) == 1
remote_sink = list(endpoints)[0]
- assert(remote_sink.in_use == 0)
- assert(remote_sink.media_type == AVDTP_AUDIO_MEDIA_TYPE)
- assert(remote_sink.tsep == AVDTP_TSEP_SNK)
+ assert remote_sink.in_use == 0
+ assert remote_sink.media_type == AVDTP_AUDIO_MEDIA_TYPE
+ assert remote_sink.tsep == AVDTP_TSEP_SNK
async def generate_packets(packet_count):
sequence_number = 0
timestamp = 0
for i in range(packet_count):
payload = bytes([sequence_number % 256])
- packet = MediaPacket(2, 0, 0, 0, sequence_number, timestamp, 0, [], 96, payload)
+ packet = MediaPacket(
+ 2, 0, 0, 0, sequence_number, timestamp, 0, [], 96, payload
+ )
packet.timestamp_seconds = timestamp / 44100
timestamp += 10
sequence_number += 1
@@ -192,50 +227,49 @@ async def test_source_sink_1():
source = client.add_source(source_codec_capabilities(), pump)
stream = await client.create_stream(source, remote_sink)
await stream.start()
- assert(stream.state == AVDTP_STREAMING_STATE)
- assert(stream.local_endpoint.in_use == 1)
- assert(stream.rtp_channel is not None)
- assert(sink.in_use == 1)
- assert(sink.stream is not None)
- assert(sink.stream.state == AVDTP_STREAMING_STATE)
+ assert stream.state == AVDTP_STREAMING_STATE
+ assert stream.local_endpoint.in_use == 1
+ assert stream.rtp_channel is not None
+ assert sink.in_use == 1
+ assert sink.stream is not None
+ assert sink.stream.state == AVDTP_STREAMING_STATE
await rtp_packets_fully_received
await stream.close()
- assert(stream.rtp_channel is None)
- assert(source.in_use == 0)
- assert(source.stream.state == AVDTP_IDLE_STATE)
- assert(sink.in_use == 0)
- assert(sink.stream.state == AVDTP_IDLE_STATE)
+ assert stream.rtp_channel is None
+ assert source.in_use == 0
+ assert source.stream.state == AVDTP_IDLE_STATE
+ assert sink.in_use == 0
+ assert sink.stream.state == AVDTP_IDLE_STATE
# Send packets manually
rtp_packets_fully_received = asyncio.get_running_loop().create_future()
rtp_packets_expected = 3
rtp_packets = []
source_packets = [
- MediaPacket(2, 0, 0, 0, i, i * 10, 0, [], 96, bytes([i]))
- for i in range(3)
+ MediaPacket(2, 0, 0, 0, i, i * 10, 0, [], 96, bytes([i])) for i in range(3)
]
source = client.add_source(source_codec_capabilities(), None)
stream = await client.create_stream(source, remote_sink)
await stream.start()
- assert(stream.state == AVDTP_STREAMING_STATE)
- assert(stream.local_endpoint.in_use == 1)
- assert(stream.rtp_channel is not None)
- assert(sink.in_use == 1)
- assert(sink.stream is not None)
- assert(sink.stream.state == AVDTP_STREAMING_STATE)
+ assert stream.state == AVDTP_STREAMING_STATE
+ assert stream.local_endpoint.in_use == 1
+ assert stream.rtp_channel is not None
+ assert sink.in_use == 1
+ assert sink.stream is not None
+ assert sink.stream.state == AVDTP_STREAMING_STATE
stream.send_media_packet(source_packets[0])
stream.send_media_packet(source_packets[1])
stream.send_media_packet(source_packets[2])
await stream.close()
- assert(stream.rtp_channel is None)
- assert(len(rtp_packets) == 3)
- assert(source.in_use == 0)
- assert(source.stream.state == AVDTP_IDLE_STATE)
- assert(sink.in_use == 0)
- assert(sink.stream.state == AVDTP_IDLE_STATE)
+ assert stream.rtp_channel is None
+ assert len(rtp_packets) == 3
+ assert source.in_use == 0
+ assert source.stream.state == AVDTP_IDLE_STATE
+ assert sink.in_use == 0
+ assert sink.stream.state == AVDTP_IDLE_STATE
# -----------------------------------------------------------------------------
@@ -246,5 +280,5 @@ async def run_test_self():
# -----------------------------------------------------------------------------
if __name__ == '__main__':
- logging.basicConfig(level = os.environ.get('BUMBLE_LOGLEVEL', 'INFO').upper())
+ logging.basicConfig(level=os.environ.get('BUMBLE_LOGLEVEL', 'INFO').upper())
asyncio.run(run_test_self())
diff --git a/tests/avdtp_test.py b/tests/avdtp_test.py
index d14e4fa..1ca5254 100644
--- a/tests/avdtp_test.py
+++ b/tests/avdtp_test.py
@@ -28,7 +28,7 @@ from bumble.avdtp import (
Set_Configuration_Command,
Set_Configuration_Response,
ServiceCapabilities,
- MediaCodecCapabilities
+ MediaCodecCapabilities,
)
@@ -37,24 +37,28 @@ def test_messages():
capabilities = [
ServiceCapabilities(AVDTP_MEDIA_TRANSPORT_SERVICE_CATEGORY),
MediaCodecCapabilities(
- media_type = AVDTP_AUDIO_MEDIA_TYPE,
- media_codec_type = A2DP_SBC_CODEC_TYPE,
- media_codec_information = bytes.fromhex('211502fa')
+ media_type=AVDTP_AUDIO_MEDIA_TYPE,
+ media_codec_type=A2DP_SBC_CODEC_TYPE,
+ media_codec_information=bytes.fromhex('211502fa'),
),
- ServiceCapabilities(AVDTP_DELAY_REPORTING_SERVICE_CATEGORY)
+ ServiceCapabilities(AVDTP_DELAY_REPORTING_SERVICE_CATEGORY),
]
message = Get_Capabilities_Response(capabilities)
- parsed = Message.create(AVDTP_GET_CAPABILITIES, Message.RESPONSE_ACCEPT, message.payload)
- assert(message.payload == parsed.payload)
+ parsed = Message.create(
+ AVDTP_GET_CAPABILITIES, Message.RESPONSE_ACCEPT, message.payload
+ )
+ assert message.payload == parsed.payload
message = Set_Configuration_Command(3, 4, capabilities)
parsed = Message.create(AVDTP_SET_CONFIGURATION, Message.COMMAND, message.payload)
- assert(message.payload == parsed.payload)
+ assert message.payload == parsed.payload
# -----------------------------------------------------------------------------
def test_rtp():
- packet = bytes.fromhex('8060000103141c6a000000000a9cbd2adbfe75443333542210037eeeed5f76dfbbbb57ddb890eed5f76e2ad3958613d3d04a5f596fc2b54d613a6a95570b4b49c2d0955ac710ca6abb293bb4580d5896b106cd6a7c4b557d8bb73aac56b8e633aa161447caa86585ae4cbc9576cc9cbd2a54fe7443322064221000b44a5cd51929bc96328916b1694e1f3611d6b6928dbf554b01e96d23a6ad879834d99326a649b94ca6adbeab1311e372a3aa3468e9582d2d9c857da28e5b76a2d363089367432930a0160af22d48911bc46cea549cbd2a03fe754332206532210054cf1d3d9260d3bc9895566f124b22c4b3cb6bc66648cf9b21e1613a48b3592466e90cee3424cc6cc56d2f569b12145234c6bd73560c95ad9c584c9d6c26552cea9905da55b3eab182c40e2dae64b46c328ba64d9cbd2a3cde74433220643211001e8d1ad6210d5c26b296d40d298a29b073b46bb4542ceb1aea011612c6df64c731068d49b56bb48afb2456ea9b5903222bb63b8b1a60c52896325a22aad781486cdb36269d9dc6dd38d9acf5b0e9328e0b23542c9cbd2adffe744323206432200095731b2a62604accea58da8ee6aba6d6fc9169ab66a824527412a66ac6c5c41d12c85295673c3263848c88ae934f62619c46ed2adccaaeb3eac70c396bb28cb8cecaf22423c548cd4adca92d30d1370ba34a772d9cbd2a3efe6442221064322100cc932cd12222dcd854d6da8d09330d2708b392a3997ec8a2f30b9312b8c562d9353513eda7733c4b835176eeca695909cc10d08614574d36cac669c583e68d9778daca9b92d6e4bb5cd008ef3562aa52332bc54a9cbd2a1efe6443332064322100a6e91a6ddc58a3a4b966a3452cb6d0b9c5334d2b695929128dcd6123b8b366d491122fd545f9b96cf769d530d2e2646b15c6a43695b12d33aa214e622e45b1ac132309a39eddc82caad35115b3d2350c5c6dcd749cbd2a9c7e654332207433110086ed5b68531a54c6e7bb052d15add1b204bd62568d8922d3379418b9c4e202482909ab712a744d81f392fa94193d62293ac6dfa7278f79b451c70c3b4b2b64d70f0b3463323c46f598ecd70d35e5a743282307099cbd2ae9fe654332106432110082acdb4aca734b843b6699f491ad3a511aab6db2344eeed386d0aa34c49c4b0a4b2aa59ec98bba6419b06310d2f9626c42a7466728f0ca0f1db579b46c0a701264e59153535228dc6497492dac722596138bd74a9cbd2a0b7e655432107432110056a8d22a62d643b428e513b52ea4a66c7a41991719370c8d9664ce2bca685dd2690b1c368c5dce36d26b38d10e0c672343ca8c25c58d0d5c568de433b7561c61268aaf83260b4b868dca8ee6dc6ba573abcb5093')
+ packet = bytes.fromhex(
+ '8060000103141c6a000000000a9cbd2adbfe75443333542210037eeeed5f76dfbbbb57ddb890eed5f76e2ad3958613d3d04a5f596fc2b54d613a6a95570b4b49c2d0955ac710ca6abb293bb4580d5896b106cd6a7c4b557d8bb73aac56b8e633aa161447caa86585ae4cbc9576cc9cbd2a54fe7443322064221000b44a5cd51929bc96328916b1694e1f3611d6b6928dbf554b01e96d23a6ad879834d99326a649b94ca6adbeab1311e372a3aa3468e9582d2d9c857da28e5b76a2d363089367432930a0160af22d48911bc46cea549cbd2a03fe754332206532210054cf1d3d9260d3bc9895566f124b22c4b3cb6bc66648cf9b21e1613a48b3592466e90cee3424cc6cc56d2f569b12145234c6bd73560c95ad9c584c9d6c26552cea9905da55b3eab182c40e2dae64b46c328ba64d9cbd2a3cde74433220643211001e8d1ad6210d5c26b296d40d298a29b073b46bb4542ceb1aea011612c6df64c731068d49b56bb48afb2456ea9b5903222bb63b8b1a60c52896325a22aad781486cdb36269d9dc6dd38d9acf5b0e9328e0b23542c9cbd2adffe744323206432200095731b2a62604accea58da8ee6aba6d6fc9169ab66a824527412a66ac6c5c41d12c85295673c3263848c88ae934f62619c46ed2adccaaeb3eac70c396bb28cb8cecaf22423c548cd4adca92d30d1370ba34a772d9cbd2a3efe6442221064322100cc932cd12222dcd854d6da8d09330d2708b392a3997ec8a2f30b9312b8c562d9353513eda7733c4b835176eeca695909cc10d08614574d36cac669c583e68d9778daca9b92d6e4bb5cd008ef3562aa52332bc54a9cbd2a1efe6443332064322100a6e91a6ddc58a3a4b966a3452cb6d0b9c5334d2b695929128dcd6123b8b366d491122fd545f9b96cf769d530d2e2646b15c6a43695b12d33aa214e622e45b1ac132309a39eddc82caad35115b3d2350c5c6dcd749cbd2a9c7e654332207433110086ed5b68531a54c6e7bb052d15add1b204bd62568d8922d3379418b9c4e202482909ab712a744d81f392fa94193d62293ac6dfa7278f79b451c70c3b4b2b64d70f0b3463323c46f598ecd70d35e5a743282307099cbd2ae9fe654332106432110082acdb4aca734b843b6699f491ad3a511aab6db2344eeed386d0aa34c49c4b0a4b2aa59ec98bba6419b06310d2f9626c42a7466728f0ca0f1db579b46c0a701264e59153535228dc6497492dac722596138bd74a9cbd2a0b7e655432107432110056a8d22a62d643b428e513b52ea4a66c7a41991719370c8d9664ce2bca685dd2690b1c368c5dce36d26b38d10e0c672343ca8c25c58d0d5c568de433b7561c61268aaf83260b4b868dca8ee6dc6ba573abcb5093'
+ )
media_packet = MediaPacket.from_bytes(packet)
print(media_packet)
@@ -62,4 +66,4 @@ def test_rtp():
# -----------------------------------------------------------------------------
if __name__ == '__main__':
test_messages()
- test_rtp() \ No newline at end of file
+ test_rtp()
diff --git a/tests/core_test.py b/tests/core_test.py
index f4bdd83..6c9d0c3 100644
--- a/tests/core_test.py
+++ b/tests/core_test.py
@@ -15,30 +15,58 @@
# -----------------------------------------------------------------------------
# Imports
# -----------------------------------------------------------------------------
-from bumble.core import AdvertisingData
-
+from bumble.core import AdvertisingData, UUID, get_dict_key_by_value
# -----------------------------------------------------------------------------
def test_ad_data():
data = bytes([2, AdvertisingData.TX_POWER_LEVEL, 123])
ad = AdvertisingData.from_bytes(data)
ad_bytes = bytes(ad)
- assert(data == ad_bytes)
- assert(ad.get(AdvertisingData.COMPLETE_LOCAL_NAME) is None)
- assert(ad.get(AdvertisingData.TX_POWER_LEVEL) == bytes([123]))
- assert(ad.get(AdvertisingData.COMPLETE_LOCAL_NAME, return_all=True) == [])
- assert(ad.get(AdvertisingData.TX_POWER_LEVEL, return_all=True) == [bytes([123])])
+ assert data == ad_bytes
+ assert ad.get(AdvertisingData.COMPLETE_LOCAL_NAME, raw=True) is None
+ assert ad.get(AdvertisingData.TX_POWER_LEVEL, raw=True) == bytes([123])
+ assert ad.get_all(AdvertisingData.COMPLETE_LOCAL_NAME, raw=True) == []
+ assert ad.get_all(AdvertisingData.TX_POWER_LEVEL, raw=True) == [bytes([123])]
data2 = bytes([2, AdvertisingData.TX_POWER_LEVEL, 234])
ad.append(data2)
ad_bytes = bytes(ad)
- assert(ad_bytes == data + data2)
- assert(ad.get(AdvertisingData.COMPLETE_LOCAL_NAME) is None)
- assert(ad.get(AdvertisingData.TX_POWER_LEVEL) == bytes([123]))
- assert(ad.get(AdvertisingData.COMPLETE_LOCAL_NAME, return_all=True) == [])
- assert(ad.get(AdvertisingData.TX_POWER_LEVEL, return_all=True) == [bytes([123]), bytes([234])])
+ assert ad_bytes == data + data2
+ assert ad.get(AdvertisingData.COMPLETE_LOCAL_NAME, raw=True) is None
+ assert ad.get(AdvertisingData.TX_POWER_LEVEL, raw=True) == bytes([123])
+ assert ad.get_all(AdvertisingData.COMPLETE_LOCAL_NAME, raw=True) == []
+ assert ad.get_all(AdvertisingData.TX_POWER_LEVEL, raw=True) == [
+ bytes([123]),
+ bytes([234]),
+ ]
+
+
+# -----------------------------------------------------------------------------
+def test_get_dict_key_by_value():
+ dictionary = {"A": 1, "B": 2}
+ assert get_dict_key_by_value(dictionary, 1) == "A"
+ assert get_dict_key_by_value(dictionary, 2) == "B"
+ assert get_dict_key_by_value(dictionary, 3) is None
+
+
+# -----------------------------------------------------------------------------
+def test_uuid_to_hex_str() -> None:
+ assert UUID("b5ea").to_hex_str() == "B5EA"
+ assert UUID("df5ce654").to_hex_str() == "DF5CE654"
+ assert (
+ UUID("df5ce654-e059-11ed-b5ea-0242ac120002").to_hex_str()
+ == "DF5CE654E05911EDB5EA0242AC120002"
+ )
+ assert UUID("b5ea").to_hex_str('-') == "B5EA"
+ assert UUID("df5ce654").to_hex_str('-') == "DF5CE654"
+ assert (
+ UUID("df5ce654-e059-11ed-b5ea-0242ac120002").to_hex_str('-')
+ == "DF5CE654-E059-11ED-B5EA-0242AC120002"
+ )
# -----------------------------------------------------------------------------
if __name__ == '__main__':
- test_ad_data() \ No newline at end of file
+ test_ad_data()
+ test_get_dict_key_by_value()
+ test_uuid_to_hex_str()
diff --git a/tests/decoder_test.py b/tests/decoder_test.py
new file mode 100644
index 0000000..3be2c63
--- /dev/null
+++ b/tests/decoder_test.py
@@ -0,0 +1,47 @@
+# Copyright 2023 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# -----------------------------------------------------------------------------
+# Imports
+# -----------------------------------------------------------------------------
+import hashlib
+import os
+from bumble.decoder import G722Decoder
+
+
+# -----------------------------------------------------------------------------
+def test_decode_file():
+ decoder = G722Decoder()
+ output_bytes = bytearray()
+
+ with open(
+ os.path.join(os.path.dirname(__file__), 'g722_sample.g722'), 'rb'
+ ) as file:
+ file_content = file.read()
+ frame_length = 80
+ data_length = int(len(file_content) / frame_length)
+
+ for i in range(0, data_length):
+ decoded_data = decoder.decode_frame(
+ file_content[i * frame_length : i * frame_length + frame_length]
+ )
+ output_bytes.extend(decoded_data)
+
+ result = hashlib.md5(output_bytes).hexdigest()
+ assert result == 'b58e0cdd012d12f5633fc796c3b0fbd4'
+
+
+# -----------------------------------------------------------------------------
+if __name__ == '__main__':
+ test_decode_file()
diff --git a/tests/device_test.py b/tests/device_test.py
new file mode 100644
index 0000000..1bcd0d0
--- /dev/null
+++ b/tests/device_test.py
@@ -0,0 +1,267 @@
+# Copyright 2021-2022 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# -----------------------------------------------------------------------------
+# Imports
+# -----------------------------------------------------------------------------
+import asyncio
+import logging
+import os
+from types import LambdaType
+import pytest
+
+from bumble.core import BT_BR_EDR_TRANSPORT
+from bumble.device import Connection, Device
+from bumble.host import Host
+from bumble.hci import (
+ HCI_ACCEPT_CONNECTION_REQUEST_COMMAND,
+ HCI_COMMAND_STATUS_PENDING,
+ HCI_CREATE_CONNECTION_COMMAND,
+ HCI_SUCCESS,
+ Address,
+ HCI_Command_Complete_Event,
+ HCI_Command_Status_Event,
+ HCI_Connection_Complete_Event,
+ HCI_Connection_Request_Event,
+ HCI_Packet,
+)
+from bumble.gatt import (
+ GATT_GENERIC_ACCESS_SERVICE,
+ GATT_CHARACTERISTIC_ATTRIBUTE_TYPE,
+ GATT_DEVICE_NAME_CHARACTERISTIC,
+ GATT_APPEARANCE_CHARACTERISTIC,
+)
+
+# -----------------------------------------------------------------------------
+# Logging
+# -----------------------------------------------------------------------------
+logger = logging.getLogger(__name__)
+
+
+# -----------------------------------------------------------------------------
+class Sink:
+ def __init__(self, flow):
+ self.flow = flow
+ next(self.flow)
+
+ def on_packet(self, packet):
+ self.flow.send(packet)
+
+
+# -----------------------------------------------------------------------------
+@pytest.mark.asyncio
+async def test_device_connect_parallel():
+ d0 = Device(host=Host(None, None))
+ d1 = Device(host=Host(None, None))
+ d2 = Device(host=Host(None, None))
+
+ # enable classic
+ d0.classic_enabled = True
+ d1.classic_enabled = True
+ d2.classic_enabled = True
+
+ # set public addresses
+ d0.public_address = Address(
+ 'F0:F1:F2:F3:F4:F5', address_type=Address.PUBLIC_DEVICE_ADDRESS
+ )
+ d1.public_address = Address(
+ 'F5:F4:F3:F2:F1:F0', address_type=Address.PUBLIC_DEVICE_ADDRESS
+ )
+ d2.public_address = Address(
+ 'F5:F4:F3:F3:F4:F5', address_type=Address.PUBLIC_DEVICE_ADDRESS
+ )
+
+ def d0_flow():
+ packet = HCI_Packet.from_bytes((yield))
+ assert packet.name == 'HCI_CREATE_CONNECTION_COMMAND'
+ assert packet.bd_addr == d1.public_address
+
+ d0.host.on_hci_packet(
+ HCI_Command_Status_Event(
+ status=HCI_COMMAND_STATUS_PENDING,
+ num_hci_command_packets=1,
+ command_opcode=HCI_CREATE_CONNECTION_COMMAND,
+ )
+ )
+
+ d1.host.on_hci_packet(
+ HCI_Connection_Request_Event(
+ bd_addr=d0.public_address,
+ class_of_device=0,
+ link_type=HCI_Connection_Complete_Event.ACL_LINK_TYPE,
+ )
+ )
+
+ packet = HCI_Packet.from_bytes((yield))
+ assert packet.name == 'HCI_CREATE_CONNECTION_COMMAND'
+ assert packet.bd_addr == d2.public_address
+
+ d0.host.on_hci_packet(
+ HCI_Command_Status_Event(
+ status=HCI_COMMAND_STATUS_PENDING,
+ num_hci_command_packets=1,
+ command_opcode=HCI_CREATE_CONNECTION_COMMAND,
+ )
+ )
+
+ d2.host.on_hci_packet(
+ HCI_Connection_Request_Event(
+ bd_addr=d0.public_address,
+ class_of_device=0,
+ link_type=HCI_Connection_Complete_Event.ACL_LINK_TYPE,
+ )
+ )
+
+ assert (yield) == None
+
+ def d1_flow():
+ packet = HCI_Packet.from_bytes((yield))
+ assert packet.name == 'HCI_ACCEPT_CONNECTION_REQUEST_COMMAND'
+
+ d1.host.on_hci_packet(
+ HCI_Command_Complete_Event(
+ num_hci_command_packets=1,
+ command_opcode=HCI_ACCEPT_CONNECTION_REQUEST_COMMAND,
+ return_parameters=b"\x00",
+ )
+ )
+
+ d1.host.on_hci_packet(
+ HCI_Connection_Complete_Event(
+ status=HCI_SUCCESS,
+ connection_handle=0x100,
+ bd_addr=d0.public_address,
+ link_type=HCI_Connection_Complete_Event.ACL_LINK_TYPE,
+ encryption_enabled=True,
+ )
+ )
+
+ d0.host.on_hci_packet(
+ HCI_Connection_Complete_Event(
+ status=HCI_SUCCESS,
+ connection_handle=0x100,
+ bd_addr=d1.public_address,
+ link_type=HCI_Connection_Complete_Event.ACL_LINK_TYPE,
+ encryption_enabled=True,
+ )
+ )
+
+ assert (yield) == None
+
+ def d2_flow():
+ packet = HCI_Packet.from_bytes((yield))
+ assert packet.name == 'HCI_ACCEPT_CONNECTION_REQUEST_COMMAND'
+
+ d2.host.on_hci_packet(
+ HCI_Command_Complete_Event(
+ num_hci_command_packets=1,
+ command_opcode=HCI_ACCEPT_CONNECTION_REQUEST_COMMAND,
+ return_parameters=b"\x00",
+ )
+ )
+
+ d2.host.on_hci_packet(
+ HCI_Connection_Complete_Event(
+ status=HCI_SUCCESS,
+ connection_handle=0x101,
+ bd_addr=d0.public_address,
+ link_type=HCI_Connection_Complete_Event.ACL_LINK_TYPE,
+ encryption_enabled=True,
+ )
+ )
+
+ d0.host.on_hci_packet(
+ HCI_Connection_Complete_Event(
+ status=HCI_SUCCESS,
+ connection_handle=0x101,
+ bd_addr=d2.public_address,
+ link_type=HCI_Connection_Complete_Event.ACL_LINK_TYPE,
+ encryption_enabled=True,
+ )
+ )
+
+ assert (yield) == None
+
+ d0.host.set_packet_sink(Sink(d0_flow()))
+ d1.host.set_packet_sink(Sink(d1_flow()))
+ d2.host.set_packet_sink(Sink(d2_flow()))
+
+ [c01, c02, a10, a20] = await asyncio.gather(
+ *[
+ asyncio.create_task(
+ d0.connect(d1.public_address, transport=BT_BR_EDR_TRANSPORT)
+ ),
+ asyncio.create_task(
+ d0.connect(d2.public_address, transport=BT_BR_EDR_TRANSPORT)
+ ),
+ asyncio.create_task(d1.accept(peer_address=d0.public_address)),
+ asyncio.create_task(d2.accept()),
+ ]
+ )
+
+ assert type(c01) == Connection
+ assert type(c02) == Connection
+ assert type(a10) == Connection
+ assert type(a20) == Connection
+
+ assert c01.handle == a10.handle and c01.handle == 0x100
+ assert c02.handle == a20.handle and c02.handle == 0x101
+
+
+# -----------------------------------------------------------------------------
+@pytest.mark.asyncio
+async def test_flush():
+ d0 = Device(host=Host(None, None))
+ task = d0.abort_on('flush', asyncio.sleep(10000))
+ await d0.host.flush()
+ try:
+ await task
+ assert False
+ except asyncio.CancelledError:
+ pass
+
+
+# -----------------------------------------------------------------------------
+def test_gatt_services_with_gas():
+ device = Device(host=Host(None, None))
+
+ # there should be one service and two chars, therefore 5 attributes
+ assert len(device.gatt_server.attributes) == 5
+ assert device.gatt_server.attributes[0].uuid == GATT_GENERIC_ACCESS_SERVICE
+ assert device.gatt_server.attributes[1].type == GATT_CHARACTERISTIC_ATTRIBUTE_TYPE
+ assert device.gatt_server.attributes[2].uuid == GATT_DEVICE_NAME_CHARACTERISTIC
+ assert device.gatt_server.attributes[3].type == GATT_CHARACTERISTIC_ATTRIBUTE_TYPE
+ assert device.gatt_server.attributes[4].uuid == GATT_APPEARANCE_CHARACTERISTIC
+
+
+# -----------------------------------------------------------------------------
+def test_gatt_services_without_gas():
+ device = Device(host=Host(None, None), generic_access_service=False)
+
+ # there should be no services
+ assert len(device.gatt_server.attributes) == 0
+
+
+# -----------------------------------------------------------------------------
+async def run_test_device():
+ await test_device_connect_parallel()
+ await test_flush()
+ await test_gatt_services_with_gas()
+ await test_gatt_services_without_gas()
+
+
+# -----------------------------------------------------------------------------
+if __name__ == '__main__':
+ logging.basicConfig(level=os.environ.get('BUMBLE_LOGLEVEL', 'INFO').upper())
+ asyncio.run(run_test_device())
diff --git a/tests/g722_sample.g722 b/tests/g722_sample.g722
new file mode 100644
index 0000000..432cd6c
--- /dev/null
+++ b/tests/g722_sample.g722
@@ -0,0 +1 @@
+Œ „ „  , /š1"9)§1 ²,¢/¾¢½ÍY_ý~|ûýÿýÿÿú~ÚxøØ|øÿÚYùÿ^ÛVZÓX|’¿ÏÕ_—WÞxû•Ñ:»TpzÑÛ³{þ}øüù^~îõµ²ßùùz¶ío}»nµ}ôØnñ?÷ýï÷ùx]øo³Zûþ_ü:–08Λµ\þ´îÎÚuÚpïNß½VÕzòYžú¶\ÖÖ¿ÿwœüØøнÞ×Ûó]ÓqÝSûŽ{ß:Y²þÊ\zY¿Þ—x^~ÿÞØ~ŽÙøÖûú˜í~só´.¸j—wñ]xyíêu—oôøðîxq–z¼0{ÿôœÿ6ÝînÔÕÚyÛö:Ò{XÚ^YÝkTŽxœ^~VÑ_Ú™Þ×Þ®ÙOý0Þ|ûÕû[›0«ù\Ù2½sœñ³W[Þv’uèu¸xp;ò™»ýlÿ¼ð¿ú|ÚñpÜ»ZÚ>>XÕŽ_ØÝ×õ³YÏUØUõìõRÕ>Þ–œpùRx”ø÷Z¾ú_tu2ù.Yò˜™m¯÷ýr~˜^_èö^u÷÷ù¹Ôù¿PÝqñoxÞ´×=þmì¹zÎx¶Ó}Þµš’Ü÷Z}¸ØZùók»üÑØïÖØ8öZøß÷šýiv–ðvúuÛu—Ð_×s–Xú~Û“²ÖUŸûÚyÜÎvÒØÞwù™›¶{sî¹ö°_x²÷ð»ÙrÝpxÿ{tîy°ý?Yj¿YÐÞ³œ×ÔXóÞýtºLÕ^Ôs–µÚþßs[.úöúün5×ÿÖ¾ÓÑÙÕ zÕQžßšTÚÑóõø—|óžsüyqõšôm–ò³u½sóô´t^ðúÕðëwÞ´°ö¿ñþ÷;ÖÿsÖßÛ[¸˜ÐzùX¹—{Þ´RÝm›Wî™ÑìÚ_zÙ\rþUœtõø——p¿^s\µY˜]š~~sóu½ØÍ{/ÏúYÿÜoØŸ¸ÔwÛ_šøÓUôúõÿÙötð¹zõq|¿æ´vïò›þûôóü²^8Ùóôÿu°5õÞüÝÞ;ÒÞÜUZû›Ú›þ]ÙØþ~TóX5úœ•ÛþÜ[k–œt{Õ{ë™íòvßúžk¾š,Ü›oÕ×tÚúÛp]Ï<œU‘øîÚ{]Õ<Ú6}w»^ù_Z÷÷ñqÿÑ?oµ[qøP^±—]óîÿÍ“9Õ]ùÜÜÝXßîŸÿí½~óÚò®¿rò4|ý™_¶pquóýnž_óû«òxí{¾öø:¸ó1™ñ^Q]”^—~QÛòü[UÓ|›_º×þ]\™ü×UÝÍÛxÒW;×VÐþþ_íÜ–¸ÿv÷ôv;]±1o4zÝqöórþë\+Wsòºøt/uÙ·êW²sûÚöyü]5ÿ[¶Ø×z¾WšŸ±Ø~T×pôÛ²Ó_<wÖ]ûþUÔ|—>Ü^sŒ™Î}WþU‘šÖöØÓý}ÑY˜xõýñ[tñßz²ßº_¹oŸoùØî]ö®öõ4îv_vîïv¹þ|ô}µ+Þs½û“üî?ÛîœÝ{zwVzÞê—Óú}ò•¿QÐ{—úžÛtØÖ×ú–}sr}ôuT›xu[Ú»[{\™ýñÛS±=›s÷9wøÞ·¼èßÝhtýøòwúï2ÞW¹rõ‘ïyºßtÕqtÓsº‘Ü\Þú\ÔyMPÝŸúÓú‘ÓœöúþÖ[Ñ_´–2|[Ÿÿ][¿süø_رÜ9îßß]öõo[ž¯ùþqì°õô^ð¸ö¼.ð<soÙroØùr¼Þrü3V-Ö|–>|ùyõòÔÑyÝx5œzYÝÛwÙò˵»[Øv½ÏžÖ¹sTzÙÜÜ4roÛwõ6¯õtyïßsž¯°ðýßoÞò}ÿôÕ•Ü>Þy—SõÎw¼÷Wÿ/Ð]¶í—[þzYóÖùÚ?ÖÙÚTÏVÙùøZÖs•›¼YÚwx“ûò\Ï~_šž³“ÛÚ}þܘûÚ{Xÿg”\÷_ùxñÝðµ»ûöqÕò/]¹º[ín~ð³´ý~xªñ]ùrþômù¹Ÿ÷\j¶ö´Úp»ômzl×}ôûõ÷¹ZÔøöWõ9œ’]^÷žÕõØÐØ{ÖÞÒÜžÖÙ{’Q¿Úûtùל}vqûwšYøôýûðŒ6/Õù³qß¼ïØ[¿ÿ.Ô}ü[PÒ²Û_ûÕ_˜8Ï3ÛÚÛ¼÷~1_[”÷õýøüòÝ[v´oxžÿnÝ?ÛóüÒNüþÎôZÐœ“TÖ—Ô˜Þ×Sww½wŸ}”^tywú½|XxiŸ?èløüå²÷øsÿuóú¹<núÞúñz¾qµ^nŸ÷}´îôtîêšy¯ðœýpzÚõ«ÛÞñ´}[2¹?ÓoûÖyÐWÖ}Ýß•~WxU—XÖÚXŸŸýß]Ï|µ×_ùî_ôX—î[ØŸöVt^™¾ßÎ8~×÷öø‘;Ö__V·ÜVö2ÙtœÞúSïÚþ¼ìÝßtrøÑùôœù­,lœ-üWðtìösöÙór_¶´ü¾x´<÷î¾ôüÚ÷=÷/ýÚ±²ÿöSrÝzxl®ÕÙ}ùÌú»RöëÙø´QšßÑ_ö–w›uÎÙüTØüýÜÞÔT”VüÙVqœ´ºÙÞßW}h\ÔkjÒ¾òñØ×mr¾ß,´rØùŸ¿ù[ò¬t8ÝrÖWzwÜzó·ýØð®X¼ªݵlõÙuwÿßú»ôþÖwŠQ^Ó™Ý]›Ýw×–ü¹ÓöÔ^õ5ÿYöÖÖr³~øi¸ÚxšÜþS÷Üõ_X±ë˜|›¿ÔÖqÿ}ö÷“ÿÙYrQú+«;ß{ùQÐÚûÔºªõØÞ8šÚUÖZös²ôÜY^ü6ß^®»¬ñkvøùõÛßrë.²ìßíñœÜ¼ZtZx¯÷Ý,ô~Û°Õ_w~mðš>_ÿÓÕ8ù’ðŸwÕœ\RÎÝVWôØU³Z¸™×ZÓÖü]žßu›]ÑY\œÐž¸ïYÛòØÏZVu×¾?±\s9{Õϵ]œôüoÞwÜ~¼tû|zjnz¯ýÝž2ò¹qìoùöoÑWô_õ_òñúöžžñ»Õûø(w’øüüúÙ_sÏn±zÚ¿·XÓ}øÞ–ÿݺy]óšÖÕmÚ¼ÙÔÙÿÖÙ¾ßÜ oyÕòš›ÞsÐ|r”ºt•RÚ_ûÙûy÷Û±Üux¾Ÿ“_ySìz²›ÛöÒuiÕ_zš|Ú–6Úu¿]ÙîéyÚr}ÿžšj¶YüµWþ]öÛyßÓ}]Û.Õ6ïU¼´ªöWp'ýwíðôïpîø´µú{ù­ôšuôüõûZ×Ø}ÞX»_”ÒŸž[P[ìØ xµ^R\×ýØ—<»ßõ[Ñ~XUÿ½ÚþÝ´•ûýQОœðüØÛ÷6NÖpw‘õößYÜo•÷[t7¯úqóÜ{•r¾þðpnÚü^غoÔz±T^rU²¹û-jõwÛuùµú÷ôó]ù¶oXý¯YŽõ>™ÿ\pq\ÞŸÕ|ÜÒ2ßxð½ÝùÿØõ~o{¿šë}Üzüݳ¾k±öõïýß{|öžò§Õþkîöš2\Zÿ•rºóþÕÝÖ¶øVùû•{vs–vþ“ÔݾY“_X×îV”WWžr’SÛS\U×™Ó×Ò°]ÿöü\žÞÔSmwš7ö–_¿ú×T÷~×}ùöÞU~–}rrz»stÚuÙ?Ýp¿¸lpvò±òß|æ=nòx2r¼k|ôpúð3ûn¶÷^¶ry|«Üÿsõ:Ôñzš7ÒuöÍ]6ÒxšùV¿Û—ýUy^ÔÐûXØ››ôÒüXýwS–ÜÝßÎÙ±ÜÑóz”ÿ|6_¾WžóžTøíW9ÛøÞݸÿiöòÿòuü´-·óÝsõ¸¯úUïüwXð°>ßvôZïýÛ_¬üØù³ÜXðØ’ó™Þý_îT–/—ÜzýÚÒzóœØsÔTܼ—šÖYRüÝ–ûØ^Ôûšû–_œÞ™öÕÐîû\þUó.×÷üòò]³.Yyò›Ýí[˜¬-¼-ÓkÚxóÛ1þøq}xìw¶wÓÞýpr¾ÛöYÛîœß?š´÷[¼ßß7}™T{—ZÞû:×õoÚTRšÓY}]ÙÖüWÔx›–¿Ó.Üþ^üÚ{¸Oltö>|øð{îñy²Ö¿Ûv±þxÚl§õøÞW—wo¹×ñóXû÷ý·lóÛºw½ßðÜÔY—þöûÓß}þ˜³öuxQŸs6ºmžûüXtù}ó×}SÝT›YÑ8}ø˜S¿RRXUV—¾zP\>ÚÕxžZ|¸ÏTÞí–×ñ}R[²xZZùX]î0똱³ùæô5ßyyr?³xîßø7·9[ñzžÞªn²nú\^sû}²õwÞû¶6ÜõØY_õœWZ³]^½8yÓwüý¹ÜQÒsVÝÙ’Ÿ×q–ÿÚûÝ[ŽúÒî=÷TÔSÔ˜u±ýó{\U׸œÐœøYño¿YYÿ^ýô½Xs|]”ÛTœTÚøíÛyó|\öóqüð]¿r/]ðø3¬qlõÝ·uw«_ï:xûît›]µû•üùžÿÜÓüÕ»ÙùþØ\{¾þýôÖ²r» üzÿ ðÚ×ßwZ~[—ô÷RØÓ1TÛtXRÖ¾[Þ•±×Ù7Sô¾õmuYúõžïu÷ußv´÷vôõª4Ýóú3ÜvµuùÞÖ¶÷ï–_rܼòp½qóÝ­Öøjýßr÷Ó½þš÷®ÕZÝW ÿxXX˜™]úZ‘õÝJ^Ý}úS¿û[•÷•žžÝù~ÞT|•X°¹¾Ó÷xtÝëZí‘ñîX«\ôwqü_±3^ÙñíxØZí–]íZ¼[•xžÞušÚò[Tû+Ú]U}Xñ÷•ÖZy¹ŸuÞÝi\ÚWñ~Zªð¯*ºX÷~ñ\þÜ^ùÖü7:]X˜ËÐÊXØv·}´]óÞöúýº¾ú.ò^½º÷ïZÖÌLÎø_q¯m:qpï½±´öms¹úÝÙxþò2õöÌ×_Ûúxöw¹x·ûvøn¶výöVØØVu›øîK‘ÕÙÚtž:Þû³_õøqøð™]Ù˜SýôòµJØÑü×Ö=÷¿õõvóþîôì²ß:ô:Ópý˜zñôsNšÞ]yV¹¸òûpxöóïwv¼[vø•˜^÷òº|Ҙ˜ž]›ù×tûym½öºó­õß<Ý}pÏõÓðn¹XÛÏVßœWþ×7›y9ÿø+ùëßz·Õý´úÐW­ñsXÎSùØøÓœï~û›ñw6îü÷ûvÞ»]Ø5›Ÿÿjz¸ÌÉœ}—x¾U÷zõ_ñÿ÷õô¹9öœžÜúØü[ìëSÙMS<ùÝÕ›,y:}ú¾éýí0ÕzµwR»3Ñí9øü\ÎÖÖõ_‘|¶ÝußüóuµóßòVuy›Ø“·ÚøVlxÚÍP“ÛýÝÛoÝý³þôì¶<ñötº¹Zü¼{upx6N–Ï{ûZû•qö4ñ}ëûr¶xõÛrÖ7÷Tžk\V×ÑœþÒ{úøÞX¶ìwúèØY.º|SÞ2š}¼ÞòÖ^OÙ™Ú¾´Õ_ö-ÜÚ¬ìuq®ÖttÜû\0·Wuøy\“T’zØUÝvýÖ+Õúòv¼ïtÞ¾¹›ý×^ßzÝî³ÐS[ÖÜŠzužøùû{ú¯–-óZö>ôR[õ\žºóúR;OUÞÌZ½>|ízùôr^õ§ú•óô\[¶_]¬ìVYßXÚPV¼[¹s{ü°rtº²ñöù/Ýö^úýV3ù’[–ÑÚU~ÒXþrùu°ø°÷ïøÛ²úÖ{YüVïïØ×}Õ–Û{˜vóW¯øû}ò<ê\ùžÛðÑ™öÖ4ôXZ½ÑP}–ZÛx­vÞírÿ÷·ðñ_µutÚ½z2Ñì»ÐzÒ[˜ZÚÛë|õyòq¹~ôµÛì5ÓW»<ÖØò__7×M_—Þö›mþ<q¾°ñ½wð~üyÐô˜‘uûZìšR0’ÐXSÞ›¹è{ÜovvùyõrºÚtùTS°¿_Wµr—ØV=ÑÑÞ­žÚroúôrurôþ³õô\T{Þyž|vž™’žÍÕx’}÷vò{û÷ynYöq²[œ~Îô³Qû>Ò{žÙTÏüÔÛ¸;wšñìóÕsõ|Ÿqò”ظvÑ]tu™ÖÝÕØM³~Òðñ|r¾î·ûšì²ZðÚXø—8ûÒôTP[Õ×õ“sþróv^±6ø­:¼³Z¾›üÝþ~w7]ÕÑZÕÚSWs°þõìúúïÜq¾þn¿Y™¾öמvS|tXùLÐÖþVù•¹ìø¼ìm½µsxô{þtW½êPÑø²|ßQšÕZÔ›Ôšùö]¼vòׯòùužÒpðѸô“YöœÞ_“Ü^ÕÓÿ›vŸ­øn}¸éuøvõ|™û1üz×Ôë^’sÙXSZz’{¸Þþ0víœïøù1~Þžüq×ö–ÞþyÝÍq’’ßÛw•<°ßî|{ry÷ùïW´šß\w{–Tü«SÛØRú_žvônÙp»qiÙ_êüº™øvSùùÖ6½}VX”yÑÒšvó•µèÝ|ªÙu¶wÝrW÷º_Ó÷Ú\zÜÖ›¿ØÓ>›ïÞÜîòÙóqö´ïTžö_rÑ:”Ûv^ú‘|ÔÍøþt}´õ0óØõí¸uw]üüý–øûÕ8›÷yÖRYÔνžw¸õoóòtýöòñº÷ùz“rþÖ6u—9›UQÚÖ]“(îVßnìÿÚ/»ûZ}íŸ_Ü_WîÞÛ=ÕÒ˜¿þŸÑûpyxfÖ|îõøÞ]ÚxßWúS¾z¿]œN×z•–öþ[võíºôñ|ßnuýœµUQø¶ÜTöÜ™ûÖÒ~•RX}¶÷5ööôm³µys÷ßò;\ܾ­ÓVµsþ—°ÖÚu{\uîùo¼lüríþ:üÜõZÝ›×ûV~T^—ÜSü}š\V½l·´”uotÖ{ïüÝWñ™›öÓxÝÑ~öÚ»ÓߟúÕ{ëVn-Y¹îùp{xêW¸2žt\—øyÿxø“mXÑxÑ]9ø÷q–ø—Û-ZuÝ8›^ÞÚx²nŽ˜vW¾|ö¾ÎÞ6TÕ÷r½o_¼=›²ÝmËùZÛõß]øv“zkÔ¹¾ß÷Ú¶4Øî¯WômzYÛ}™ñ\ùØ×]~uïÐX6¯ë›üùtw&ݱôq°<9p÷×pó:Ùn~ÚùtÜY9]s›’Ùú|öU—þÛ:”Þ—Ù×\ú^ËxTÛ›˜Y{ÐzÖ}VÝÛ)Ý2–õšßl¯~š{Nôݼwš1_Óp|Ûòñ˜lô5ùVôë|õpß3ø*v¶=r×®ßýõp—m»ûùÕZRöøUßÓöŸ8ZÛ¹z[Þ>~V}yÞ/œÚØöÓþÜSV߳Й7ÑÞ\Õú·žþÝ}Õ÷_Y¼\ûxôwx^.Ò«üvÚ_±j18õ]wÚòz.sòqñZl+ñò5ó[ðñù2·uÛq¾Û¸üíÙ›ÞýÔùkÍÚ¶<œÞÝtôÙØ=PZ~Ù?’ÝÐ_PÛz“ÛßXZ¿XsÒØú~Ô}ú’º^zÙ8Ú1ÿrzÜô2ôôôz-ñuÖö«÷9o6šyµzþnR[u5|uÑú]Oö]ÿU_gþø·éô|kX]Z{¿\¼k›qvÕP‘SPTžz¸lmp2x1ýÑv^–úxmv|i–Ð×N‘RS^ütñ2­ìsü1¿^»Õù.×jõx±Ù^MÏ¿ÍzwÞ.íóusþúÖÝø»þkÚúÐÓQL—ØÙwúo´nwµù¿Sw^“ú÷{wñ¼»\UÏTTÖ=²úïmòvòÛ<ýZ•õo]r¯ûûÞÏ׎VœZ®wøm®~õ?_[xœÓ°r¹uïÝ?^Ô‹þÎ[Ütñ¸+õùº´[ßòMòð|q¯Õ2ÿÓ\Ú˜šŸ´óxmôõß3×\yÜÑê8ßloOîXÒW˜ÔýW|¯ý¹1y^½V›|×·vóZð1ZÒÜÒTTÓþù³þµõ+]×vÿV»º.kß:r¼Ú\QžÞ]ÛµðìÿöyzØÜZqÿ•fsm]ßÒÓ[•þÞm°õyóž~YòPíX0&prØØ^Óߘý|±pºýqýýWØû™>¹}´¤™ÝrÑWþÍÒÙÛôØŸnú{Þ:×¹¾šÔï=~güZmvNýX‘ZþÛ8¶p´rùù¹^ÜtûØ«\ìfÝ¿o\“uÔÕù¹ôðövùøÛ´{’kÞœ(hÔ}tÔÒ~M–¹ÞÿöößñÔUšyY”øÝøgÝ}ÜR[ŒÒ—^ù93¹ó¼ø“ù:Ò-ù~èkQòxÓÝNÜ}y{³pô÷ûÿZÜó9“)=ùe÷uy•ÚÚÔQúõÞðíörú<ÿÙø|Þ1r—è(úRיГð~Xvó~wØ–WÜÙ’t¸ßëú–û¿ÏSQR›ù^ºíù:sœÝWwš:éÙxc[|¶ûÖ>ÙXÙwšðl¹vx»Üüûx­›®k›}0YÐZÖÒÙ¾}<¯ïÿ7u~ÛÜ~:Ü/uÖå/×vþÔUØÑÙùúZ¯û¹óßÙ\Y»<Ú6u–é.ÐúûÑ×ÛÐPؾ{Úí¶wµ¶ÞÜ>ü4Ùn³Õ§ôýÜsRÚÙÑ×Ø~ÿ›l±ßuþ–~›2šo}~è-Wò\\•QÑØ;{ýôszñ]ÙÙ·Þîv¼d2“kZÖ\Ò—œù{Üoß3u_Ü]8|~ø^½äøЯW‘ÞÛLQÞ¼výò÷qrŸ¹šzºñØpv<¤QïØÏx×Õ•]ºžvñy<õ||þ~¼tò¯û§^Ø3WÒø˜ÎÖšùÝyû>ružÝ™zðvÙì6ÙföXt4ÔŸ’œÔxüõíùtqtzØ~·qœpøÖ¤/{u”ÛšÍZ\YûZs¸õ>ÞûYØü0Û|1èïM|ñRÙ”PV^Ú×ôt¹ûwßsœ·÷ŸoórhœÝïÌ{ÒSXÛw¿v÷5n¿uÛ|³6Þ7p×ëñ˜ýïÑÛÎß”Vÿ<qø´õµt\ׯ|ú{¯Ôsj–÷vÓþØÍšÖ|ý¹´óûÿö}Ù¸õ›·ïÛZé}üm”6БÓÕÞwX÷2óvw\¾{Ÿv½n=ÜêsØñÿS\RÛSšßÿô­Ýû1Ýþ}›õ¼ó¶’p.ØuúQŸWOTü<v²õömv^úþó\w²Ys©Üo{“ßÝU‘ÐZ5ú~ôprp¼Üúy2^ܳ2¬ÙìÖZSÍY’ÔžÞøps:ð8ywÕu8÷rÛçW6ûÖXÜÐÕ×ÔÜÞµ6¸q62Ü<v˜mÙ–lq×qßþÚ‘ÑÖ~Ÿï÷ÿ-o;r×vq|üz^ovsw˜]SÕ¿SÓ|ÜøïÜ0¶q²Ý×pô»Õ(]Ú¸zûSRÚÓÏ>Ú›zýð/ýxò^t{WpŸÒw¾>ÞûÿLÍþÒUÏÝ=ôZ­·ö´2ûzý»3Óxtô{ýúûÕXüØþÙyñŸjô&Ùs¶¶þ´xÖùwúýßú›W›ÍW·R_önó4uðúžöžÚyúS™ðûVTû}ÊÜ›\Öñ\òþð7ó5óÝùsvØ?Ÿr˜qyпºÒYþUx~}µö¶ýêör¹î¿vøÐýuÙøô˜ØÓ”Ïñú±Wýôìÿ7øt”÷oÛ™Øú^_ôW˜__ÜKÛ<óзÛõ7y5ÿpz_³ÜÞßõ~X8|™VÿZ–ÓWßüÜ6žûn-øôë»÷0ï}Ööö³|œPsù”ÓþU~”Üöxþl°ü­zŸé÷\ÜwºÙý^ý¿{ËXöÒÞÙú¾\v~nšî±|ÿ]k^½õ»ûßî‘Ûy_“ïYTññz]¸ôñqôoÜúðrÔß¿ÓïzÕ]½¿ÔÓ\9š›rôûý0wx¬üò•þy{ÑÖ6ÜþÛÎÝÜÓØÕøØö¯\ºðõö,øv¹]þµ3L{pöØÓ¸ÔW:ÔRò÷[¶­÷ô7¸îøïùÕuöZœ=´úÕU~Ó]Ó×Û=ÚWntšðöZf?w¸wXôX;”»ú¼ÕØýUÓúÖ<¶ûZµ¯Vóõòõpû~ðýÒòßÿú\’¾Ó•ÔVzþù*4±Þðusö^ûøœ[t]üwV¹PTÕßsünYw°q·ÙvªZ\Ùö—ñPYµ\»úÐR{ŒÓÞ›uù²üs±öx¶µúwþ{=ûýþøÖt½ÚÛ‘ÔÒX×m±³ß®rÝ~°mö]»ûòÙZU¸mš]ýÔþTSÞÙÞXº1¼zèqŸsõ÷ØsúVõw‘UðœwÏûÖ–žU×½¿Ÿôî~_w*r’8úù]Ûò¹’ÖyÖÞQ^x–ÐS—ÞŸôtšò|nvôøòu¸Z-˜Ît¼nÜÿYÎûž™Ý\ÔùÜ·i¹¼îuír\ø3ßýùušÕ4tÓ>[ÞÎÜ—>TþöÝu¸kýÿì¯|ÿ:·Þœ±û\TvýÕÖ×^˜VÛvÒžix¸qÝu¸®úõ|Ù~ÕÖíÖO±TÓÝ”üÛ{ïüq”ò÷]³°ß[Ÿp¸YÝù~ò\Ú[ï X–»Ñßfìžrõš4/n[xÛþ{uKmØÖ.ßžßÓÜ\Ïóû—pµ¿q÷þ¾øsšsÚ½üÙÒw[ïòWXšÒW›û~_un¶ó°úùù}4ô6¾Zù|O{·}n½šÏXýNVqtîµôwvýÿt·ºòºØ–4•ÑxoÜð_ÍÓ\ÖYWx»÷ïºv›òýûWm¹{¹\–{Ëõs›6î‘–þÑÒÞYùt¶2úvõûœœúnôtÝ[ú×ôñZn»O½{ÌVý¿óïµ<ùðúÖõùù´ñY›zÌT1öÛnÚPØžRÏøïšµk¸xµó[¸òõ{8{ßö”Ö{ôöýsSÒÚÿÐry»s´u]²0^×ëvþÿž_ÜSž<´XúÜÓÓÕÚ·Ýù.±üYrr™vîþ;ÿûÚ˜O3Úð^yYŒQÛQÓ?}ò_õ°Ÿ_urœ¹ì®~^Þ6ÑU2òºô›ÜMÑZW”ßoóõóò´}ñ,ôzky·V¸yU\rñ[y[žUÖ\Ï0wr½þyðÞzö6¹m0›Ößv\÷/ß™ÖSQWWÚxòxºXpuÞ3¼õ²r²ÖZú}‘ÚnvuQÔšR“]Ô\>÷ñùÜŸqµó_ô¯öwÝÔ9¸Î÷,mTÜ×VÕÖÙüqŸs÷Ú¹ÿòøû0/mÑ]u¿Íz¨¬Ø”ÕxÔSÜY¶üvünÝŸ0qõ:}¬{WxUy]+³œÑUÛWÒ~]õöÞršüy{î7Xðëþ¹ýŸSmjžÑÔÙ~ÑT^½}òxó×|nðøÿorŸwÖ¼7—]ûgú”P›_×Öœ\ôùzò»ÿ|±±ôõùsqÛÛ>Ý÷qnðùˆÒ9ý”V|-´~˜ºú=ZvïöÝr¹}Xؙߙ¿líÙÏYÒŸÔÿøö÷üßûõõöévZ¬tV›õÙÚ¼liÖ×U‘¸×™Õ¹6wÛo™÷Ý_­vwô7þw˜Ü_û’ïsïÖÐÕ½ÐÑ\Ûz½q¾×òŸ:ðîüpóÚxÚûܳui·ÌØ\”R¿Þnžù»_ûz\éïWòø~\—˜Öés½ÚSVßTŽüÙ9jÜôõzùñº/¶´îØþ?}Ü\]åoÏ~–Ñ¿™þôöÞý9~[y²ôùûî›\úÕTÞ¾©i_νZšVÚú0oYóUøpÕÿ¬3Û+ŸÞ÷˜Óüßs.¹Ú×ÕÔØUv/úøõz»wÙ{¯õïòu¼Ö¾ùÚ»jvÿÒ_ÜTY±ò~þzü²U[î^øj™=ùZÛ=ÍÜ-ðÓØNŸ=MO_ôô[xržtÝìÝ|-±ÝŸvÞþuê}ZÐؘ“ÓÕx´x±öúùë“mº9óps•yý<]’p­ÞßSÞÑV[\{ñ¶ÞµuºÜùúpó1yZò9ÕõÝeü\ÔÖXÔZrî´÷¿ò^ýÞõ6¶í;ŸµÿRÝzómÖÔÛÒÏ×—u¼ôöÝúÿw™Þþn¬Xøðü–6óóÝÝ×ÐÌþÝuï>sžï6UÝnú¹pz[¶ûÕÑwìôÙ»ÑÜ’ÒØy²ñrxk¾ôÿÜ°î±»wûÝWýønš¼Ó:UÏVÖ´yùvu·ñXXpüõïÛóõ“øzþ·”Ð?RÓUÑþŸöøuvñYþú¹8õkžÝñøWÝZôsxœúКÐÎòzµl3ßð{žz²/~ôúý¹œÐvðïUØþXÐQØ÷¯Vq°óR0üWn¹»øõ{Ý^™˜z.Z™[ûRÔOÝ’.]|mr›w”ÿú]5ØpoSõÕ–ú÷ÔžÐÏ–vµððøöûTú»ÿötpõÿÿø]Ðó0¹Ó¿ÜÖQÑ^Ûó5ò2µõz¿:÷Vòëò–vo¾u¸úÞ_ÚûTŒZw”óñs¹-õÜôþ]qöúòö—]4ÔÜï‘yY’ÔR›õÚq³òÛÛpüØÕ-õ__°ø˜Ñ½tvÎXßþ‹Ú“ÞXÛôpó{¼´p[½4ñt3ýWºöü[Ûÿ[ŽØÓRÙš_íò^ðíµ^Üõ·šqÜrtÔX²ý»ÑÝZ“šÕÔÕØtôó·thößo›t{õ¸·6¾\°õþ]~™_ÐÏðTÎ÷»oÜðìþy«ÖÜ:õ~¶ù÷œ•uòÞsTžVÌYn“q¯|÷ýwÝÞ~Ÿzÿ8êPП«P\øÛ]VYœ}Ú«xµ]ñtÚXó\ý2–vy7^õuÒÕVþŒ‘Úsöwø©´ðßxù_ݲÜÿi\^ô8¼ûN™ÜÑRÙÙ|½l°rªxuôùÜšoš6ô¾Vöq½WîÕ>[Ñ“Û–”ßq}ujô¹nÛüt[ø¹úù}ûqÔ>íO=WMYÒ”zÕ=qt­÷õwù÷Z½¶\ó~Xôï—r½ÔývŒÒùŽXT|î9÷ðî;ôvÖ¾ßùY\{w\½møûU[•yÐJ{ó~žéíõ-¾ÿ.\~~™œš\ö~ÒíÿÙ=ÙÔÒÌÓsR[4´µzûrö;øôSº›Z}3ÙüxÞò×XÑ–[YYv²rô­t·w]ÝõøUØô¹Rí¹œtוöŽ×üSûò{~ñmëý¹ö9Ûý÷žÖ–6xwßùôp×øþ—]ût–ïkߪ÷ý¯8þ{™ÚÓý\~óZÝx›“ÛþÛÔÛu–o_n¹žyõ]X™üÕÚvÙZœt¿Tø•ÒtÒÞ·ýñìðyùóô·«WÔ><ÙsÜûõvÙ´ÛR^öòÝßlç™/t½ó÷Ÿù—˜|zرZŸ{yÛÑ]ý[7ýtkþní7õ:Ûp?‘ÝþÔŸsLÚvÓ{ÒÔ”ÞøõwÝq|<ørÓ®?|_P÷xøsTZ›“{VY÷qõöø3²5ÿstñ˜~ÿÞx-ûÕv”ÚuXÙ~­÷¯rßmìüöö¶ÿ=ùW]YÑóù™u’Ø›S{’y3\_s}­y¾øl;Ü~MŸºÍÙnÙšP~T™ØlóÖwûw6´^ns?[\U™õ}šÿ÷ÎÝ1ØÞéüòµ4sprÿsþ\ú’œ_úÖz–ºOÕþÙTlûÛóþq¼}´xo—]ÙüÕÜ_÷8ÌßïÍ^™ï|_tì4öXöðø³=øvۚܬÚTu—ý|Pr,°y¸ìöû÷ßówÙZr—rXŸsØ×>×^”y²úq{vôn•öý\–Óú}–\•ûVQÕ\›xÞÜú1ý*sî{]5õ›TúØêßÜÿ¾Ì_Ú]¼<±¹ìl6pòüétÙ¾ðÛ–«“¿þùÞÕÎzYýùXruuîº÷Ø—2œÝS÷ßÿùÖP–žØ[ÒtñTŸê5íÙqpœ»]WÙõµ\þüN}ÔOwóù;}xüèµþ~¼2Tš7Ñ]´ÚµÙÙZ“ÿ^Um{¼f¼öîðyv¸5Ðß4XÚ¯Ïû{WU–Z^“´xýv{<ìwóôÛ<¶ûOsüU¾ñØÒUØy–|vž8uêlþXïx÷þ¿×yzZþZ؈~üyöºò¿íë¾öwýp‘³]Y¶^uSÔU™ÖØV¬t>ñòúnò7vœ\µ[^ØZóí~Î_×ÔÚš\žµ´öÞm|ºê_¼xÒ¾\_t¸Ï±ÕÓUÖ|Ó÷_oøv:êºöºð2ؾ×ø-{Pu×ßPWþß²U¯xôp¶üéÜß-Û}üZü´ÚîQÕöÓXœ:¸óµµøjyô¸tözÛÚüûQr—ÔÕZÏ|[Yž.õøÛmzö”øô—¸˜ú~ŸÑÚpTLRÓóW{[´4wôî»øøžv›ÝZôóWY¼OSz{Õ2­øspµôô,´V›²wÞÚrXvuÏøZ•_Z2›qqßoíµí›t¯XÕ³ÝZúú[ý\ÒÝ×Î^—´™t7\îyr›ßòŸÓ±QÛ|øY˜ÜÑÛÕO²S½¹yûõ¶ïúú4µsÛUñsRóÿÙ5^Óxû›:ñò|íuþòñÕ6¿ûÕ{›uýþvÌ•ÔWx˜°[o¬ýwsüð¹vTVxýþxtV»ÑO8Xþ.Ÿw|§öüÿ®=Ú|{TYu¿Y_ßÒWÍVÔø»6ðúë÷þÞ´ó_“p\ÝüòØßpTO¿R7“8öð:µðjµï^¹|¼øUùÝòÕ^ÚX•O|õ4¼yº³øjÝvóÓžoÒÿzþßWwÔÎÿÓ\]×4¶úùðøl²ù7¿û]—{ùßõØÎñÚÔRqœY¸®ôö]rüñ4¾XßmU˜¹óÌõóÍW’^¸™zwx«ÿòuõt¹ÝoXûTunÝ×/”ÝÙÓz™=¹õqòwûoüµm™|_²ÚÚ·X•rU×ÒÒy×ýqŸ¹1³öÜ^ïRuœÜMvÿ}ÙÒ\ÕZÌ~ÿÜrµ6뻼÷|vZ®Ž<ö^žvÞ0ØRÚ^”×p°ñôj³ö¾öú{þ_–þy{\q˜þÝÑÚSßük÷y°«w÷SkùzÕ;”Ø7{ÔšõwSÐ×VTúX»Þq±¿þr÷û\›:­ÔÖ6VvÛL—ý’^ü]î?²¿ókX[p\û?M;z×tvXÝ_”—ÕWrüxkð¸î±öú}zö¿ÖñVYm¾ŸÿØÒX“ø½|¸ît´íðýóó;1Sø\txÔyÿ×ÒLß{P­u[ò5ë\î}™7œ}½ü_XÌ×Ï|ßõùlµ´ïý~Ÿöö]K®[^ûÕݽÔÐÿÙ0™ðíó¹úüìr“y™_vž¼þZsvSÙ×zÕ1´{uíðï¿vþúvšîZ]\´ûÝÔÓ_ÓúXú~°²wô÷/ú4þ_V¿yYû“ßw˜ÌPÑYÖY°·Ýôúmì4²Ø³8^û=Sðô]XýX——ÑùÜÛu÷í[ëò»÷î¼9—º7ÖzuVýØUÌÝ™óÝÚoßïz¹ûx²w–ûX“öoØ[Õ׿P‘{Uúºôôwyö°:µ^ÚyuÑ}m[TºW××™Ñõö|îžötnq]ž-»œÛxñ·‘ÕzMSpV}´øp/uó|ïÿ¶û]–+ÑÜxÿþ[ÓyS‘ÿÚv»ýïùoÿ´2u›wø÷½t|Ö·ÔØÓÜ‘Þ|ý4ïWíùô=t´ûVÝ´ýÝÔ~4ÌTüïÚröqøuôïß±]µžQ¼oÙ{Ö•ØÔÕ¾Üþøou›´ßïô;Ûñ_Ø~[ß7]½UVÒþÝ]µñnîšù^ªZz¿üÔœ<rÐÕÝÐùÖÑ«y8óß³w÷\ñÞo›o•Zí]ÝÛRs½Ùuðyî¶\íöÚo¹»òºV:][tß™Ö_Õßô]ßìž=oýmZ›szþU÷ÙS·þ[ßÍ8~Ë_±ÜÕð¸;œ›óÿßúÚ^õ»zÓ_¼~ÙÚyÌÒØûœÙ·Õì{8·ï˜~örù53~zûv—ÜÚxïÕ\úöu}só¹®l´wõ:Zy«]_}ïÝø|ÚÓ7=ñ_p¼œ¯÷m<x¼²ÓÙwØûÜÕÑWÝŸÖ^tÔ[¶_õ¼ýZÙÿ+’ØÖpzÖºVÛÖV˜:þÑvôz›ò7x^ñínÞù³ytÕžðsÞ²R3~Ù\Ú=ö~¼•«uöþþ”yúZp®9Ùqx•ê8·Ô÷þ÷4oNÿv™Y÷zY·Þø´^Ð~–YÛ×1·/þ{^ÔúT<Ô]õô9ÿ“|ÕyöÑt>,Ú~þQtñt´ÚyÊú°{ð\œÖT’ÿÏXôÙÜŸ˜ÚšRZœ_tú¿÷ÖØô¬¬qóðtþÝvø+].tpû6zü)øyòþ¼^ø]³óÖÜkôœþnU<Û[rÔ~Ùý_ߌ»Zϸw·ýZq¿›ú^ìpÙ²1qûÏðï™_wö™uÔôýØ{Ø\^øXظ¾QÛ^ÎöÚÑzq]yùQÏy–^îÖ[wÛvx׸^õ¹”ùº.ø\ñqïúwsµÙu0Ù7ÚTÞxôk™2ó¶²òùÕôò{Zñìù~óyúؽs›õ›ÚþX_Û›_þ÷üUŸ•Þ‘–÷Tš{ógòyœ×˜Ø[Õ[]ûo2î0ñºÖûzuo\–œÎÊÎR›}ðk¯or±ýÚPWr85vó{QÑU™»óîìl°ï\\–Õ_òöñ±r[˜XÞÙtô­qoù6Ô\ÛwÞyu³9ÝÓQÎUSÛ~¸ou³ù¶Ú×ß<v÷òo–ÑÓÜSuö¬ôo¼.ÓøTš{²Þo76xÜMØÐÙ[¹¾ìïûöøY–Uw´súñpöÔ’Q×}–žrp,sÙöû™™Ôyê4õ|ï^7Ê]T¸Ü¾})xøÞü}›ZÕŸd­ÙÞwúz y|ør¶r[^ÖïVÕxì§ÖùµßÛÍ^ßõüû]¬|–Yú=¹™õ&3WÙZõýPÐ_ô÷Ü{÷XVþµyÛþ¦ê|•¼÷Õ”_ø÷²~v´þWyž0ùX¯e¬Ü•|{ÙWT[³Ýw¹÷ž¸Ú›qÿYÖ÷fl~Ó=>ÝÎ×Þýû^¾øôVU›p™WÕx'ðþŒ]5ÕR–Zöø_zõ¹\ß2Ú}ÒòdëÿüuÎWsµyÿpðY÷yxžhæ»{ü[Q“µøºþõ0u]Öw¼{Ò_èèp]ø_ÏÐVþ<v^²´ô–ß6×uÓûèhø›T]TÌ]³Üôô¿r~•ÿþxýP±¨§×ÞÜ_—ŽúüüsX{°ÝUü÷úW¶eìÙÛþÕÕÐZô³]r¿qÖ;ýwŽiêôuTÔß›‘Ñþûzy¿ûò™;¿zÝÖh¥òÝ\Û½ÕОòûzvs5úÛ6¹u›åët»Y™ù˜ÌÖø{ør×møœØ¼ßY¿ðçr˜UÚX×ÍÓ|ÿx]´´š×9ÿY¾Ùö"~~Ü—øÙQÖ»ÝóþûtñÙ}¿ü<¹Xw%nYü˜\šRÕÚtò_¶q¸ô¿ÖðwÚqê«ûUZ¼ØPÎ{žúöýù°ºÖù;ßóR÷éé:–ÕœZÓØY›löZ³õ{Ú»´8Ý]§líÚ]Y]ÑÓ]™y³Zóvú˜ßúß¼V÷e«QvTÖZRÖ}z»ºøxúVØ8ôÙ»ífº×^ÓZPQüºÝû75}Ó·ùÚ^|üæ±9ÝU•}ÒyÚ²¿ôp/Ztþsù»ûú¸æjXÑ\ù»[~ßoýÝó÷Ú=Z¶s•ºšoíòÔVþ—\ÑÛ~¹¸¹|õuøÚßðtÐòú¾gx\TÖX–ZQ™°ÞþùøxûQzršÛñß´(¯×غÝN=}œxñúöwÜû¼wþºu–ífºÙNþÿÐÖúÖ¼ózW°´]Ûp4×ñýüæ8t’”]üÓÝÚúx°¾}ª×}{ºyœyî×ëî7PYÙ–\Îyþ^r|ôñý[ºvßZï_½1ltÝY×>Š¼ý<yß±øzÔó¾yšjûXjîýÙלÕVÜWþ¹´{¼¬úZzvžq±y¨ðßÔ“ÞÓYÕþüöùvõs’ryþ8rrŸq.qšÙÍzWUXÜßµøô±z^ž4ýÞúqq‘uéwO×VÔT•YW»vø¯ÝþÚôß´pyý«3÷ÖY”x™MöÝüív9÷Ø85^þ°ïû´iÝÖR^’ZRÿÛºùù{®¸Ö3÷þô+^ù·jZ<ÏxÚÙœŸõþótû{xíØ^i¹óX¸íùÜYOñž}œÒmº=úØsØtö[wZkš½ÎžRÖøÞÛßßôõúóÖ|ü|¬tÚêWr´|[þŽÖ80žîYn{ùöXð|¹÷ó»8¹ðøÖxÛP^ùÞ™¯\³÷YzgÏü±{›i×v¸þ|¼YÔÎ6ÔØžœô]]tÜ7ÙZ¶ÔÜløÖ*Ww›VTRœÔܺû]¾íüó^1ØWu´-Ý5ö^ì˜0ÐOxûøu“mïÚm»øöYösžv«ûþoŸ÷ÕÜSüwÝZxò¾m¿t}~ø4Õ±í’p¶[\v^]X“יܰ”úò=\]—ÿºOïÕòVö_z]œÒ™ØÓ’qZ~ó¸ùür˜ú¶ßýsúøqô´þÑVÔ‘^ÝYÛ½r™ýï÷·—jþ›îþ^²î>9ØxÞS×tõRu[ÿ4w“çýôòö8tœ­¶Ùnõ_v^ô™ßÚýwšZ´ô–÷l’ÜïØYðÝwþ[~v•Ô8Ú•Ñ~ØŸµÖRpØw¹•uø9ØzøõqU±ýpšÞy>ü]ÏvÛ”îÜ;]wX\º}ÙÞô}›û_ßû´<½ò’tëVßZ¸vgžo_rúøn™4ÝÞ}\rpµø”Nyÿ·™h›}·møtl_ñø¬¬úzl¿–²þßùØÔÿÚ–ZlÚYvŸUXõv|z÷ÛÐÝß•ýÿþÖRØyº_ëwùšl}/xÿýW»ûvÑúÕŒ<ÙSüÌYÚ¶N[ûÞ™ÿºû›|ÙÛ:toüuóp¶Ymröö¯w®úîv¼wmóþ»8öÖ~´rѽqÞºxÕÿûל¹ñ^[vO÷=žY™úÕMpÚ|~Ë|U[×›}ٜӘ{—X|ÞÞR~Ø|–ôWž(˜l~ßxëý8îÔy}o¼·óý×j¸oôöÜó_úl²yýtö›tî<²ÝÛtÛý–²ýÖY|¿˜öWÞûÿ\Ñ1›õÞr“ý¾VÏ;wÓÞÞÒùvÔØñÚ\ôü}½?VóúÐ×|wß“ßXÔÞú¿nŸ}ùì¯x–ô«sð:ýüýtpþ•ÕóÓo³ô}v¬lÿ±úrò´Üv[õ~6XL˜ÓÛþYÞw¸ž{×o–´lxxü[¸×·T‡VÞ|û׿þßxùn¾ÿø|vtnž<žvö]½Ð×ûtÿ\´ìuú¬¶W{ðk:ñôÞ7uÝØÍÛU[ÿwRµ°Ÿyþûþöê¶ÚtwpSQ‘ÙÝýz›zºvÖ0rÐòóÞï´Vº²ÜXËÕÚÛ:ÜõØXó—kœ^ö’úîtÿ=wºþZXÕT¾nšyùþírŸp¼Tùg÷üùV¶iøÐNT9¾xu›ð]óo˜½õ}tuw¹8{kõÓ““Ô˜tûÜw™²úÿòÕØóÜ~0°Ò¾èùNŽÕ˜<Ú{¸Üúð¾ó‘xzü+ÕzøêoÎÒÕRyÛvyÝwŸv°yY3|Yùjš/ër’Ë_×|º{_üùöûüüžþ¿4³SuhåÕÒVÔý:{Þxø¾õt¹¹¿{ö<þ]ñ!öÒZš\XýtÚr{Ø5·ÿw_¶úÜýýh§[’QØZú˜÷_ßrýq¾Ür}ßØÿÛ¯e0“V‘ÝÚ»ÝrÙüùµsÙwôÿ]Ó²%îUÖÔX’_½üÿ[óÜþ3ýú0;ؼ–¹æê^ÓWÚÖÜÝxøy7Yóø¶ö·²úÐ|ùmä³ÔØ|xýö›y·÷ý÷q—U^nkìÙΘØTÓwÚüx\Ûð¹žp±üYÛšµêg[—ÔXÖÕ{|ý½ÝÞïŸ{ñ2“|ÝXëéöÚÓ•R|Ù}¿\sÛô.øÛß÷ä¬TüÖÔWŸ|ûÿ\¶±vùë¿×µUífòW½¾×T¸þ]òûWñ®ÿwîsTÞŸ±(íØ^[›Õ‘ÿÙßz›õøvòwÓ™]¸éhÞ”XY•ØšûÚ{ÿþ÷v¹êw’Ûý9ëf—]ÓÚW˜]ý9ÚYóûü¶p—Y[ùéi›ØUŽþÚ\™ýúvt¼µí’ÿÖõêl¼’t[Ô•Ûß<[{ú_m»²²ð¹ÚþtçìöÏoØXØùÜ¿¿¸¾³özslšZßðélÚYxœÒ–__Tþ^ÜÚmß_²u™Sßgñ›’zÝÒUúQuÝ[³ù¸ò6ZÜ]q*k™Ôöþ“—\Z“óÞ~úxùï÷‘ÿÝ4ën—Þü}QÐ;Ô[žzùÜ·rötn“wÓð&±•šøÛÔÓºœVÝÿúÛx9ø¯\×»Tt%/ÑÚýÖYÛøÞ[7ü|w:òr{‘¶\°æqVÛßY[»×·Z¹ýy÷Þ3u.Üù|®fuTYº“ÜÛyþØ|nWõ¸òûqWxè'×þØÖÔÙyÜÕ8³×¹üõõú•Ü\þ,¦ÕZÚÔV^ÙÞY÷^·~œo½TÕÚ°éð×~ÙÑšÖÛšõüúßqµñúnåòSô]Ñ›úÕ_øõöÜïxv°,žùùêgß>}üÖVûÚ¼3{ß­wÿnõÕ¼?û믖ßúPQ–ØÓÞÛùÝ;ý]ó÷ØÝÖö©qú_M˜ÑÖ]¾žõôßpï–üßzl©_y—ÓÚÓÔØ6¿üð7wl÷Y´úwîhúS²[ÒXÛÜTœõüü´qüñý›²>u%ðY?ù×ÓøßÓ=øö~ùø±5|ŸþÜsºç|Q´ÐÏûW”UsœZ´vßvÞÜßX¶íîÛÝ]¾TV˜Üü·^óþo¶×s½[vjnÔ×ôšÕY—Vy·ÚtsýñôùZµ¸u'÷ØÜ7ÚÖ[ß›Þzñýv°²w{û<u»íé\T¹üV•ÙÚVœz÷ÚoŸt·Yûß{š©èZÒžÚV”VÚ[_ñ¹x»6rX[õöžêm”Øü™N×ÓÞ˜Y½rý}µp™ßmþ[sjtÞúQ—Ú‘ÖÚzŸ÷»öôqßù3øønp±Ù<xT’\“×Ø}û}ûëýé_¯mÿ5^—\Í|ßÏóßn¾±tp?øìôÔêí]yü5:™UXÖ°™õ|ù{õÞúÝo”¸kZ[óŽÝ]Ý”×l×yöt™þß6ù–i»×í’ÝÎ\“ÔZ<xÛõùzÛ5{ywÕmð}úúÔÏ4Û’|V:óßr¹-Ú{ïó>Ü&þvØyRzÔÔu›q²º³þô^{ê½Yôjú3Ú\ÝØÙ|×Yºt¿ó»žëÕtv]òÞ~nò—4ÖUR˜Óûž¼ÿëœþÒoUUõ9{[ïZ›ÜÔÏÝЛuØô0ö]»ž°Öqv[wññÝÞr‘Ñw”R~7ßðk÷žønš7u¿v·l÷ÞtÒ[~T^Žñ_u¶3Õs¶_ô[tµ.\þz¾Ò“ÒÙ~|´ÔpmÿzTwVqÚ÷nŸ~ÙÕÙÉÛøU~÷›,±7zÔú1xÚêÞêü—>QX•\”Úµßómÿ|ôVsÿ~Ûòpÿ³™Û•ÖÒ_ºµóYôêxºì÷|îw8uöû·9ZUöW½Oü›öõ·žõqö×t9üûßúð_¼YŽÛÖÚ[÷ØÖ¸®þ3|ÕòßüºRRjœþÓ\Ï~Y”Ôóv¹ô´xÝ™oõš|m½¸úÞØ×\Ø¿Ñtþuÿì7¿ùjýÿsìµzwµ|X²³ÓX»ðÞyëÕ*²úõ^8ôþ<ið]ÞVö™ÜѺRyXwRìósšU¶úþÙ¸~ÙuÑÑuUÓÿÚ¾ß]Y´µ9›/xþ•-»Ö÷{Jsz»XR½TÙô1[ø2¶8XtÙøwn]ò0Ö6pÖùýÙzú?ð¾®ë×ós~ßÝ­|ùû86y}òO^¹×ô—õßí9xëwxÐ5µÿq[´ÛÜÙÜzRZü—ûô1ßU¸}Ü]ÝoÛ×òßÔX™ÒLUVÖmýú|S¶W9¸{ûøÚ¾7µôñÕù~ÜÛ°o²—(òu÷q0p´yžo]¸9ð_|WOYö™³úyê÷úî÷oÛÿñp´zñy¿~¾¾JÜØÛØ{¿z²úؾSûÏî×ù9ØŽU×S\ÖO÷ÙÛvt¹\Ù“÷[ÚõŸ[ýÛÕÚY•ÿ\û¯Ü2ê;Ÿrú{÷ý7ï26õÔßöÕÛ2Tr0ññhø|ølÿØòÝ90ø4Ø>YÕ^Ó7úÖn÷í/úu¿Zí]ÜZu··u–WòM‘V\“nÿÙçÞÜû=Úܽ÷Zº{OVטÍÝØݲ²ö0õu6ÛòYXðñ\½÷tOÿÖÒRÝ}¸ðlo½øî8“ú{9kVÞ÷ÏÝÑÐœ•Þrt¯»øôtÿÕš]v¹øq]Ô–UÐÜx²ªs÷õÿ/›•vð÷\uíØT—ÖZT÷túïlöý´1×XuóÛõ83Ö]Õ”Ó}¸rú1oÿ´Ú×qøZ³¶¸ÞZÐÍSþ_÷÷wovø·Q];µÝóþ˜QÊ\Õ]ü9±ðq[¸y×ß[òs˜qx·ÕPÖÓÓûÝ¿/òò´wý~Òí³>öyj‘ß\PZZþóºî³vö_<¸_›+ôùvwØÛNX—ôÝsp0ùòÛZ|7Víñqœ~<‰[Ø“î–÷ðrüû•<Ü÷]l¦ÜYÚöÖT•þõùÜ{õö\•Z»÷ýñ¨xTVôѾVßö´´_øXÜžvðÿ³$ñOýwÕTWv¹øøz^{Ýßÿ·<|û©¤ùŒÙóWûÔ6œrv{ÜŸu·[÷^v·æî\”Ù¸yÓÿÚx³Ýq¼üxݽvœ}´x©ä»ËÞŸ{ÖWZúüõ¼Úü[6ÚxÜ^d¨ÖÏ^šÚØSy}¾ßí–|ùÙ]1™<údè]ÑQœ~–™Úºww|ùýûÝžuž0ûÕdå^—T–vWÜXºvvxxóÞœ{³¼wZ|¥èøSZ¼ßÔR¾ßuû|µ6Þ^øõÛ|™gêôÒÙŸÏ[—ÿúyxx÷—6ŸòÚYÿçm·ÒÞ[Ó^–Ýúõ^ÿ0üÙ³?|Ú©åñ\ÒÝü××]÷ýu¸rø{¾»t÷ÜÛì"ü{–Ÿ¹ÙZÜÙºüµþ_s\Ûw|¿ž˜\fkUØ’ý\Ó›Yžôú[õö\Úzþ¾\ž¦«øØQß\OÙQ¿ûû_wøsÖ:ûúz•¬dq\Ú\Õ_6ö=÷´xY¸wÝ÷Ôs%ëX–ÖÚßݘóöu{}®]Ý÷¼²~\~æi8YÒœ[}Ôײx0>wtwÜ|¸s\\©èïSÙP\›Øôýö_»·YÞþ{Z”ÞepW–OÝSZÓXœ¹¸ßÜ·_ÿWxÞ¾ÙþkgÝÑÙ{Ô×Úœq²œøí}úv¾u2ž_êg·ÜÔ—yÝ_ÿ[q°s›o½xvÞvº³[ók«>TOzWZ\ð{–q˜Z¸R{œ}[XîiúUÌZœ\•_q_öw”¿_š±{Y~ød«ÒÖTSöÝÛ|u³úŸz¼úÞßuÜ·¿¼æê~×PÏ{[}øüð-ºš´zÜú}»ü2?qäkÏÚSÚö¾Xóz01Úøö›ôúÜ;³—±é­ÿLRßœÜ_ý¯t™ÞvZ^ý[ÛóÞj«ßÙKTÕX^ü´3Þ|º[ýýœû>(j÷žÌL[YØØño]vøt»~ß´tpÜðdí¾RÔ—ù~Û›3òxu¿øù¿Zß³\um¨ôNQÒ_[ÝÕ<svž¼»ÚuÜúºûÝì¤0ÖнÙÞZÛunþ]ú]žûŸšÝv<÷ejÙÓ××|Øß9î0¼ùüôoÔs»û½i­üÚKÜX\•YضóžØÿv›õÛ²×tmëÛ¾ÏÝоؘ5ï]vÛx¼tØ^;ôø²hìzLÍ^w”Ýwírü:ÿµòÝ~û²{±i«ÛÙPÕÿ~ÔÞ»¸nüÜZrž›^Õv|}-çZÔÎÛÝÚ”U°pý~]7´ŸW»·vÜíè2SÓÙ[ÙÙømð~œð´þ\½{¶ø³çyxTNØS½Ó™Xï>ßw[þòÖX}²œùljÛ;ŒÓ»’šÛþûòºßzþ}¾ÕÞõ~v2ê2Ö•ÔÒzÓ×pqö\õu¶üüž4nÛ¬©óy[ÔUÿÜ[6´ïØzöý7ÛØ_¬Ýý.nxØY‘]ÑÛ­üößñùòܸíÞsyªõ»OØý”TÚpy÷Ýõ;¹wVŸð±²ònzYO>W|P’yóz{^ô}×X—,XÔ´í:ÏÚÕW×]ýúûùv¼öUy²rÿqéø×ÓÜØßÜÙqùz³õwõ¾ªpú_´®òŸPÔ}ÞWþZôúvßò{ôß}Ý%:·~¬ñPÙzÙÕßžõôy¹²÷ý_ño¹õÞqn_ý“üœÓž¼XùxÓtùuÛZÚo7uÖü®s]ÙUÖÚ™þÒê“^îßÝ5öÑóÝ}ýÜÕÔØ·ÒtzÙÿ³Zz_qšqù5óÞ±›<yÖÚ_¼ÜpZ}ñøZ¶»xRúìØý(vÖÿ8ßXÜ÷~~gš¹òð/žv3{ö¯ò½qÚï¾~°ºÓ1ÞÞð_øÞyÛŸŸxÚqòÒyñÞOÜVØ3VžøضZ•×ð•ÏôYÕ[×]ÜÞÛг—_RZ3VÛóY_x½Tr»]úqóz]tµ¶îòšÞúvipvµññ¸+ý´pyÿðwötùøí–9éŸ{õÚ|24ÐûîÕzûÔ^uœ•—ÞÞqR’ÖöVÚ¿}ÓÐô¸tWÖÞšøù[ÙÚÝÚ|®Z|ÙÜWœ3WÛmPÞõØ’mþÚ\Û¿rZ[´Óúõw¿ÿ“w½úÚqû¿ê–øõl¾ønÚjøoý¶[wµëô³~´ù{ö¯øìûì[óz^ßm¶}œÚ–ZòÖõzQÝ}ÿ’öþÙtR—ÿØñTP|³ÖùœÝYýV^Ý]UŸºS¾/™Yë˜÷_vVô^²y˜ViZ³ôõÙ{8ù~ò¾~Úõ}û|ß•Ú÷úô0ü]Óy{ùú÷ñõTþ´ûxZݹûžnYQ\sÕÕØÚw›.ßÔÓ9öVs™qmÖ}q+ÿùî¹ø°óùs°ty+ùzw°nÑù³:]øðûUº·×ÿÔT™WØZ±ýÙø“SÛ—xóY½ÝÐ\ÛYvpUö»TÕ½ž>ôl÷Oo]¹\™wztXÿÞz˜ß1ùïÞ0<ÐÛ8k—¼«ÛøõñzÚüÑ<ôÓ]¯ñ~õñÚ7Wøþvü~s¶uõ”ø«úo×TØ2øxòÙž|ý9»Ýüòz‘ÔØ[Ü|êÚÚóúT™8¾×ü=ɘWø™œøÿLÑ}2U”ñºÔÚùùYtù¾þt^úñ±[š­wúY¹m³îÛ/^ùtpõ­/\zï¶Úzïõv¼tÛpqùöþ·TÞz]_³^9™žÙüwútPû^ŽY¾VÕ]ÝŠT:ØZÚ]þšœýý;Î÷Û_íÑ;ÛY_™^tôýR7~Ô;ï[–ßït¼þ,*wýpm|÷·ïr3ÝimÚô±òžüìwWm¿w_øðÿ—÷}–<÷T[_”ÑÔÿ^ÕrØŽÕüÝØVžØØSzºVð™ÑÙYõú×û]Ÿ[Þw”5qÚòös;¸ðÿ}öW±pô9ÜúhÕÚo¶>ÿm·ÿ;ïÚóðð~v²^ww~ܬ³y•]qÖ¿úñtÒq–×½ý:ÍÜõÖÝÒ¶õRý¹—_ÜÝ0×x¹Õ¸ñÛ{ŸqþûÖòòÕ^¶ûÜSö8óy}|éxÜÓgxž3ûû¿Ô]µ~_±Û»Tü™œÝUžÛÏß•Õ^³UÔÒ9Oú™^^øPÏï]W÷VtºÜñ¼U÷ô¾ºt³yy÷rÿ|t®ïu¸n½rvp³×xònù{swÑÞoßµóy¾™ù›Û­tUÝóš]½vßÎ2÷ÖÛïXÒ{š¼üþÙ_Ö›UÝy]˜Ó3OÞÙý:üøÒ®[˜ØúùÛ;J&U[½ùyÞ}öúµ½=·xþ8ø|ö×ìp’?ô[üÔíWöù~Ñ®‘pÿ}Ï7Zõµš_~“ëß×s×yüVìü4õ[ô¶¹Zn÷Z4övµüv6¶šûsØ42_ïzÛú^þÕ_/[ðôœ[º•[rß;zýÕWVóûÜ»²WÒÔúØYt÷XS¶|ÔÞóXÙ¿^Z¿rúZÖôØüëîôxý9NÖ7ÿ·5o¼×šßØPÔúÕùí=Ô“O~š\Õ[õo]\6´>öhíßü6ô^_±p³ò¼*}ý¯îoïÞ-ðõºñõq|ôòô¼ýqû^¾]·Þß{ŸÚ^{–QœQÙÞØÕÒÜÒþTÓœ<ÚÒW÷Ô”ý»Ò•YYxý×yö”œ¸{Û\-|î›ršqp~ótõq¶øt½ð¯^òšëY}ë}ô5]ôsu°û^yuösxºZwôú—ðîßÞnŸ_žŸ2üîØTÝ}×]úÐ|‘þVÛúÙZ‘ØUVúû”ùÞÒðÜYY;sÒóÚÖë×úÙÔqþÝ~µÞÙ]8ö»\0ü‘vv¸öúêÚXoí|:½mßZ$±ü}Þv×5ò´®ÑûÚ9}|0þßuÒÚo_w–÷¾TØoÜ\ºRüÙ´õÝOµqýèßÐûÞ]úìþ~·~}ß¾ü,{ý<Ÿ|Ú’*ÖÜôôTS÷Žúý¿WÔ—yÙWÛTw–ÕðýÒ^zÿÕSmz¸™5<¹uÝk÷<8nzvéjûú¿Þnø,Þð4]ò}zûó^þÛÛº÷Ò0¹‘ÝùÒ]ýÕÑþ\‰¸ßÚ;ÓÞÚ—²×{Þzþ™ÿýVW¾4yÿñ—6×xïQ´ñÖüsÖÜö|ý-4õVõøüsìظùMv÷Ý­1ü¯ýÔzú¿î<Øòôöé»ýó_o^ñnût1™Ü_Óò{šoßÒý÷Ôô»ù]‹[¿V4ÿÝq˜Ñù[ÑÝ|”ž]Ï{\Vô·ÓØ~Þ’–v‘{šX[>WuùÞù1û÷üWÜy°mðïªoöòZ4þ/°tîî»}ûßv·ºõøøo_ö¿pØuöüX—¿›þÝv[×ývÔŸ9ýӽͿÛ\ÙôõœÜURÔÙMü~—Ü\”ùÒòÛ~¼×X_–R®ÙÝ·ØòÑÖsžÓò^þ—úþÿ×q¼Ö¼qÛ|ßó²÷ü/²8÷p÷ßïW,~1qõÚ¹óœnòûwYxø¶6¸túpw½÷ûÑn¯R÷2ž;ÚÿÿÝ\õÛp>×ÞØÐ]Tp–N2×ÖùÔÿûÏÚÿ9Úø¹2Õ\sØûÚø¶^Yõ÷Õß÷’2­q}×2Ö8œv¬íñ_¹ßzXnó±ÿ[q”Zò}ï=þpÝøøÙ¾ùR[Ÿûò•?xŸú“ZØXÝ÷¶SôxÛÚ‘{ÕzTZÚßÏ¿ïØÕøÿ×}œð3›ó¼úòøï±tzš¿ÛT\¿?ßüÊÖkQùü’Tõ^6wUÞÑù˜R^ü”sš3zqÚrx›þhîÖ2Ýsüzó*t¾7ÐìîXlðòmöpp¾2ú7ó˜ºüñX×o~ø}>ýÖuÝÐÚZ[s×Ø•Z•}Ý¿˜QTQÚØzØZ_VtØU³9Λî;Ô3|{w³Û¶öòØûôöv½Wûùõÿùž<ÛÞñVwx¼w¨žîòÑ<íŸüpZ=oý9ûZœØw¾øzÖZ›|ZÔö6ynµ6pןîX^åÔ÷Ü»þ2^œÞXÿýZnÛÞ¸6;]övÍUm”Ô¶ýWÜ~Û˜ôxŒÞÖúTõUUú\mï9t¯¾t½_Ü\m’š«Þ{ò×Ú<õ[zu®úýémü÷ø^´ô¸Ûøøú4ž×ïÛY_öÕ[—–?–~Óþ\ÓÙ[WUœ{Þ”_úZ·óvMZôY^}¿Ü´öž}{Ôîßµ-¹ßo»~þ?zól^õñ.z¯œ}¿örqnòq±t«VòtÛözŸm¿»úqQ—üþÜÐ7UÚnRÒ}´_ÿ6¶ØòsüøÑ|{Óðv\ÚŸX½Úº\W]ÚñX•.•KõžßÛwÞ[Þ¶ØWÙZ¸ý•þóU}ß\‘úòrØšêœ^ò³óÙzônWè¬}óó•\³ÿýrº5~û¯øšùòY_ór|™uÛöþ\Y–ZûÜÏÜU•~Û°8׶ݑôk\;}ìz›yÙ=Ü{ôÛþ[PÓ¼Ïr~¼ØÚë¸}8.ÐírÚÓüYNžùݽnõ´ì]‘Þ<î~6°êÖÑNÌJZ_úý-ìíó6u×_ýô®¹v°ªô|ÔPRRYý{:ñqöýwš1ï?qléxUÓWR”ؾøtó¸úYüüß1ô~¬çwßÖÞÖÓ•Ôšvõ6ú{»ü^˜Vw¼ø²mèß×ÚT’ÕÐ×r¸öþvºUš½û½VîcÛ¾Ö·^ØuYô·Øzøûÿ_ûß7w.lyÙŸ¿ÝÓÙÖv.Üöö›púŸúŸ´æ*ûW}Ü;ÑÒÝßðt|õÜßs–2›Úñdê_[üÞÎ[ÿ¼1w~ÛyÚ´zÞÛé%Ü—Ú_ÔÑß»zvyóý¼9w™]säêUÚüyÓÓß\óûùz~ü´üšÚ¨c×·ZºY—ZÝÚxº]·ÝÝÛv<›]Úuêí|Ü¿÷Ð ûY1uðø»{ÿõ7›¸W0#~~Üþ\Ò×ÿWùzÿùy[Ý¿·þ[»ë(îR{ÿÏüÞ}¶øöÙ5»9xSy«göZ|öÚÏTØû²ß­{Ù_x³^ø|d©Ø™ùÚÑÎØØÚrzžø¾Wœ_ô=ÿ˜ÚìcÞzÞ¹ÚÕÒߜߴö¿{Ü^ú~÷»þ•é&~Þy~•ÍÕZÜ=òy¶ûÛ_ò¹=ó~[pçª;qÿÓÒœZ|ó{43Yy¿u¶y|:ñäê×þ~ŽRÞ\]6{÷ž^Ü1>˜ú~Qëdò•ÝúÙ P[ù^yùø»”Ü4÷UºúQ~&ê[ܾ>NΖØÛ»[s[þÖ·?]ºüÞ”®dlšÞ÷×OVZýÿõöw|ŸÞ2º^ó|X÷$æݼßÔOÚ\¾ûwù;·¸4x5_^æåóÙø÷UÒ•Y}<ø¸¹^ܘzž[ÿ›R4fïÙW·ÖPMØZz½zõž<¹ö{ûóØt£³ûÞwÜV”Ô}{Ýôö¾ÜÞzú¾>žÙ«eòÝx×ÌPX™<øu½ýžY¿úXºû’ôäi\Xú]ÍM˜]]ó:öÜÚ·úþ¾8~fh³ØþûÕÎÓþ›ö{röyž<4ö¿ty\®cº{ß÷×UÓ}Ûýºöyûú¼yúwüäh<ÿüvÏ‘ØÝ~6rþß¼¾_~\{–ìc_¼þ½›ÐR×}ÿxöÜ]}¼~]¼X£ö\}µÒUÚÜš|¶{^ß½Ÿ|ºVy¦êݽñý’Ï]×Û_¸tùÞùÜy´ÿ4úÚkd«VôóØÑ–^Ù™6ûxöZü¼Ü™·S^¨æÝ]ø{’ÑÓß×}»y÷Zù^5¼xr¾šmãyü~÷TS¸Ü×3ßóž~¾_z¿øYªfyÜxýÔNÕZZúùøZ]ÝÜ™»_ûwäèØòVS•Õ]š¹ö5û~›üÞ¿üU˜çhvÜt¹PNXRßûýÞž]×¾]ÿŸYvãµxº{ÞØQ]Ú™ú·ùöÝ÷¿xüò¿Ÿfçv÷u¶\×ÝÛÚ;Ÿð±^¶yû¾wx³Øq¤êÜz÷ÖVÛÚ\õøß¼ÿÛZW¼W›ìg¿ß¹ßœMÒUW^ÿýt|Ÿvœ]Zü¸ö¤è|ÝüüUŽWØÒvú_qœX´ÜQ¿~×o$²ÓòýÖÒYÔV™üo˜^ó\¾Õ÷žØ¶æq5ºvÞ×—ÞÕVùñövö:ó[7Ùÿ{¼ë¨ðxr~Û–ÓZÔynÙ8s]}»ÕÝû—.*ñüýñ¿NÖ˜‘•øþ\üvþ?Ó}|ZÒ5èiû¸uSßR×õ;\øq|sÝ–ö¶[z+èo×mþ˜SzŽ”q¾v÷ûø´Z¾ÚÛ}j7óÙo_½PÒÖ×پ߼x±__Tw”W¶rònÝqqÔØOßXÛüûz±>ÙØ_ž”vìø~;wWWÑ’öVßù4÷÷š~×2Ýöö+ÕmmxšÕ|ØÖÿú²ró7oþýxzé땼¨pÖWÞ]×^|¾³óܼzßqTÔq©ÜÜó¹œÔŽY”Q^^z¿wõxT¾ñÕNóvÿõ»»×•ÍWTÑŸØ™óö7¿Þ´óÕ~øðÿ*yöÞ]zÕŽX˜Wvvû¶ñ®y½uÝü.pÚ6gÞýú{ÎûØ?tõr¹ðóZòž]¾ï2_qnÚ»—>ÒÓÜ{ÛsŸ«[p||sÙVnß±uø½SúÙÔ ˜ûßÜünóÙÜöݾ]¾2»WôVÐSPÍûÙ[\óöX[±[;ºÞ›ôòz<±TÓ5ÙÏÝ~W²óùøô2·|ðíÖ¶wwóß÷¿¼ÛUý÷UsµðnÝûù.¯Ryì½_ñ~Ù0p×ñV_ß:»w}xëŽð±yÙ¼÷»Uó›Üÿ[—}VÝxÿ˜^ñR_5öžœTsŸ]÷Òû_XÝ’VÚš{SþÔtßVwöS5¸Z9Ùú÷ {³\÷ݯø°ßýï=õ4nÙeÕ:ò¹ÙžóøÓõ{ôÜŸ±ôûUo{}øò_³ú¯Tê|;¸q·Ös¿Ù®Õ¸÷ÖZuôû[ÖôZ3:[Ö½¬·|˜xxTðõÕù\Tº~”Y‘žÙP¶^_—øíÜÓÛøzY0oß|7üpÎ5p¶ôú]OûWŸßÔÐ=TN{T•\ÜR{½ïÓ3ØûxØ·0ÿnw>Y?®Yó;vúšÜÝïý4°tñ:Ùïþ.•vöôpüòzXíŸ|·7ýû¹Ô”iÒxÕÞW[9—ouÜÍýïÛ?{×Öxº\ÝÜÜZvµÖôÿqRònœ¿2lœlsvu÷é«òÝzÚ3ë|œq/ý{úsùÞž8Þ<sÕ9]\Ò}7ÓU>šÓ]YúÕ•WüÔWûЮ‹·Ø¾RüVs×6»×ýÿOð×v½Ýxúœp<óÛ\ùðw”ïYß”uºnÛôÖ˜Y|jû¿ÿZzÝ}·ÿÜp>tnžPíWÞÛ·û´mü2hÔ–ßïk5võú¯|ïu[hp-·8s»yß8ßïZp:oýZœ^oØ]yØÒ1˜ÜÝZþÝZÜ“ÙS•¿UÒ¿S¾R^þ~ŸZÌÿ÷RÜ:ÞßfZÜ8?x9Ùq°r¾ßtì”õðpv{pt¸™´tð]²öÔxYy­ôŸñÚ;zò\Þú½ö[o™:—T™ûÚš¸ûØöÏÜø[·’ÿßÙõWY±OüðR^îÜp—|òX”;X_UÝñP_ºÐßûž·\_º’^Üïôü.ñXþZÝ\ô5Ýï|ôµÕ2TîsÝÙlhš8röÙ~xü¾uë²Þ=î^Ø2ù:Z6\^5URÝÿÓÙú^¾µ4ÓÞïÖ_üðs¹jtô´ìß³±5´énÿzßxÞ\÷zØÙTžù~u5øsÙ¹röÝ™ÞõÐœvMÈXÑÐXXÜ3»ù–ú}õ}¼y¾Ü—ÎHÎÓ’V½øópë÷ó7ZZ9´ñ²øøÛÜÎ’R]þõkîîvµ¼¾Wú÷u7ôsÝU“QÎœÝqmlîwõ¾Û^úvö5stwVÒ“’ÖÝÜu¯o6õ¸ÜÖŸ¾Ûû{·|\QÍÓÖX|õo±´5z˜þöÜ›qðõ™WÛÌOûßovk¸t¾]uÕ¿÷t·ÛÖXŽQÒžÝwyªówW¸w¹×ØskÞû˜\™Q“{ßnºìèuØþñµÙ—pl·ØšþØ“ÖZµ{¾mí|–þût×ÕzëZúWßRÒ¹ywvï9—ôtþNxj·ÝSÙ?SÓÚyøó½ê·–>^ôtTÚ«oý^˜ÛÿÏ\þó´®ð©þÓôw÷\’-*˜XžÔÐ>vøõòmýÖ½³›V_jö|ÒÕÜÑ~Ûrz÷4¬Y”˜ú3}të{ÜO9SUÒ¿ÿîßð1{‘Ü”rØêü±ÑÓ’<_pr¿lóTØØuñ[¸mlp[ÖÿÙR?ß®ðïü꾶wôþ¸ëöûÑVßXÒ;Ÿëòþ¸Ð’òô{Ùq±ôTÍØ×ÜÙ/·ý¶{™ÞNÙpnW¶õ2}PÏ6’{WµnöY¶~\™P~kôyóvšÏœX^öW®ëß\zÒRð(ï×uvZ’ö6_uêý×|¿]—”ú$pÙ}õýWÐÓôû™qnõóS¸}O|³j°ŸÜ6_ÑÐTþô8üìñÿÓ»}Ômfý¿\^õÔŒ^úÞ2[ðïS™»ÚÔÔìæþ×·úÕ»ü4:uðÛÓúžVhåxžýýU|ùuz´mø•»û—Vû&k}ߟù›ÑÑØút{ö-|XÓõ>‘Óö*k?zWÑOÝ~züîó˜ú\Г­gu÷[w¾ÖQUÛ±½8møz•ZµÙ\®§³ÜýxÕÏؘ5zwõõÚÙ]”Î7knùÛüõÜÌR™~¶Û°öþÙ]ºÛÖ©çøôøpšQZ¾w7yð÷Ýú½8“Wt$l]þýu¼Q’_8ºþòß}˜\»ÖO]êf?Ü]µ_×O×þüvúÚ^XœŒð#ׯӵwÞN{q¸]ús×÷Wö”W~ê°ò×÷ßvÞÓt·ýøµü¼_ÔÖè&y»Ûó;ÚQÚ¾r{zø·Úýü>ŽÚñ%r~ôy\P’Ûsþ·ß»Ø~[L_ä«Uy›ô¹Ó’^}öþ¾ú¶Õþ»ÐÙ¬äõ\]ø{×TÏz|¹ø{›™ÿ\“Sõe­¼ßzyÿSVØù±>uqûÖ2ºÚW|e§÷]ôúYÓ>Ypµ;ypÙ^µ\“[r&ïû_ÿÐÎßúÝ;žºÞÖ¼ÓRWi©{W_yRÑ·þŸö]}ÿ”º=Î׫ênß[úúØÐÒŸy·ywÚ™xþ–Rúdçy¾ü÷TÓ}½õ:8uúš;úUØçç9v[ö|ÝÒ[¾4·{ötþØtz”’îgðòÚ¹ûZÓV×÷ž<y{ZÿÔyk¬pYX9]ÐTÚóv|y×9»Ò]näîš?zØÏÙ˜9¾ý÷ý[Ú=\“O4(i_ܾ{[TLY:ý^ô|ú•>º[Q×å¨p¿]øöS×VŸtúó¼]Ù³W¾ íj.|»zÙPRÛ:¾[ñ{^˜[»QÕj¨ïÛ4_úQÒUšøwû·Ø›²ÜOîièõ;øp_–šžyózoñwÜpµzT¾¦¨­þxrþSÜ”›ñ\ùí_Ýû›Ïïkmö{½rÐÖZù[wù:ØYJßôkÝ_~ÿÍN˜V~˜ÿ7|ÔÕ|¿‘ :+n·œµúÖPXßþÜñpßV}y×qgtò~µ¸ÖÒÜÖú›ðòtþÙø³Vßj§µtr;øV”ß|Ú61ryÿÛïÙYµê«¾ôóüßRÜÖÜzôõÝVy~TŽö,oÚrxùÒ•ÑX›µöýþYõüoéqyðó¾×˜UÙlò{ý|qú”Ÿ«ªvzïûúSØ•ZÖûù¯X\xóÓ_ϸ.®ü+[+YWþ–SôWóöý^q½Ôü챺wõm[ÓÖØÜó{ž}ùxšÐsÿ®ÞýõñPÓXNÓÞøû•ø]~×”29rÜ{µí’ÙÚX–|Üpo™ûñö˜Wìísûrñ/U^ýÝ>ípzúsüûÝ+÷2y´íøW[غUø°÷Üù?ÍÙpò:_sýóÒ›XÓwUóx»X|vŽ\wõs—ó÷wÖV™~S÷·ûßò_ñÛΰòö›y°nTQÚßÞ—¸ôv¹y»ø¼ÒÓõín–t®ù÷Ñ—ùØUùýôo–óùž—U.t÷ÛóuòÒÕÔ>×zúßoÙž-˜LÙÿuñ×?ñwXRÚYÝûZôó²<Òÿ:îýumõQ\ÛTxÿÞõp¸u¿Ý›–l,ÜñkWzV×[_Þôîwºñ5ùÔüêvvòõöTxQÜ¿[t³]µò×ðYÍûq5¼^¶-ýQYVœÒ{Þùø:{³Z´PP¾ñ|^[î^wŒTÔÒ™ÙÞþõôµZñÝQœë›´ùúï÷ÔX>”ßõº~î÷õtë¯?ñy{ýì¶Ö^›ßRþ?:Qíúy²ÿ»_môXúßíòÙ|ÖÐÖ~×zøy]ò¿r¾Ü6pX—k\ÜÞÚ–RŽ÷Îþ™vû¿÷¿;ßúöú×÷öuÜWùLPœYÝ™ö´uð·¸iÙõ/_u{îz¾˜ü’zÓYþÚúvÞðøü©üÖ«¹s”9æZþšÚÛYÞû™öõ÷zúp°­þuÙÝî_|ØšÑ|™wÞÜùp¹5õvÔs»ø¹kúZÿÑÔÚÓ~ûXx¯°¹tð|Ó­õ]¼r>þü×NÕÓY×{ô±Vl³:ÿY1úþš/sÖ2YTËüœÕ½öxrsôp¶Wö•|ôyùp{ß®O“–PÛôuò°nž­Þ˜Þ9^7[îùøøWÑÑZYÔ\µs2¹·,ÞZXÞ~ùžz¯û[óPN˜ÒÙýÚ´í{3²ôYšz÷ÝÛóvz¶÷ΖØÔÓØœ|4ðxnµ»¿žpûUî|oðZQòQŸÝý÷ýío¸,²Vy´÷ýÿv°ø«ÓV™TÔع{û÷îœ.Ü7Uþü¹ýußy™OÖÐ×Ôšþ]·±tÙ.\”;TøöÕy{ùoIÔÿÔÔ¹Þûtñ6¶óÞœ=ö¹Zùp°ñÌZyÏ÷Оó^sq:².Ö{·¹}ÛkUòtOz×Rÿ[œ÷{³²ý±/ÖÝ:Ÿ·ýî~y+PÕ×ÝzPÛî^ïùt·2Ù¸ß8{xpzrÌÙ™R^O¸sY~o~³:—z]í5]oKuYÍ^ÝÓ2Zý4t¹5Þzû]]ºvòÛr×]ÜÍÜÔvûts¹m4³ô¿>øß³óX-[RþÏ[›]yúóoÞkô¿µš~ú]íqÔoüXNXŸVuõu.ô1òq¹½|ôßmzsYN÷X•Ø¸´_ìó5öw™}ÜÛtÜøùõÞÊ›R˜Ð½÷Zoy8õ1™Z?|Zøï•øïÍ[WÏ|Ôz¹wxñ´1¸_~ß3|\pòZi“^Ú=×Ý÷šrîoø2·8û\úóÛrð_íßTœÏ<ÖUôù5ízîz¯Ý6Y|ºxXlŸÎúÌÔ–S4üû·úmµöÜ]YÿÚt~¸ÝÌÐÒ•Mø›òÿòô5»—<y]Yzvû1SzÑôÑ}üëv÷±+º¹ž¯Úr^sýøðÛZZÓr_ð\uò¹ï}´¼špžÖïwRnÛÑ]×VóX~o¼/ÝsùVx·[ÿxöûÜ™˜Ê}|к½z«ßðµ0ùYõß^úù¼ôyÎ[UÏ_Ñ;XÞ²|o¹7þ|øZ]¼÷™øîÊYÌ^ÔX/Óðîú±4¿ñÞ¼³ûþ3üvïÑß]‘u•ÔoXqóÿï8¶X6þzWvñ¾ØõS][Š?–XvÕøò}·:¾Þ\~öPþp½\pÓ\ÑR‘ø;Wìï9µt»ù;z|÷yž÷tQyÊ×tSúûüñr/ßr7¼4uXyðÿ´{uÎVÞU÷þ3süêô¶xº<úšó¹ù±ÕÕÔO{”Vñþ4myö7¶ÙXÜtÚ»úþ_pÑV’Ët”\›øq÷õµ8tºU{¸Ö÷û™³ÞÑÕUÎ[ù×ññyròø<»¾_þ¾uZ3ïKû\ŽÛ¿ÔóÚñ²u²ö¼¹[÷zZúïÞ÷~ž’ZUÖÔðuºoÿ+nŸ>÷¼û^üò]ôÓ?ÒÎÙÞÖtº7ö3ï~~¶>ÿUuu×óYÕNYÕÒðüyµx¬2ž˜[ðüSvz»wÝ”šÐÑ|ÔÖ¹ë;~nl´<}½ô|þ½°~÷LÖxÑZô*²öl¬zúµö}mß{ôZVÑZÝ›\hº~îÚ5µÚV]xpTÕ¾9XËzWÞ]ôþ5ï\˜Öl˜ÖûþÝ^ÒšÕÓü~þñtu­ï<ŸñoÙÿðužl~ÙRøþ÷~œ«µs­zy¹÷óÚw]ômûŽZÞzQüs¸u>õò¸Ý:XغµßÛØÉYÛú}pý{¬ö~óVtÿÓõó›YÌvÓ[óSpð¼r5½{ÿ»ÿXøõÝv˜\SV—X×ì¿þ¯~õ)»R<súsývYŸÑÖÛW^ökÝòªx³>{Ùýu½¶ºÕÚÎ6ÕÎÝìÜùøl·>/—úwXYpÞöÿ^¿ÌÚý¸qõ|í®ö=Þ´÷ÒùwÚ´¹WÝÍTÓtžÿ­ÿðôu3Ö±{ѯY|sÙ~šÍW}Ö{þ1µüéôþ:øº\VîyÞwÙÇ8~Z½ûøq_t¶´~™¶öÔ}yz¸œ[MÚÕYô|ò»þñîÝ:ܽÝ¿WûsÔÞÊ{Ò\Þ<÷ïn»yw¾¾^™ôýõvØ’P|Rpü·,¹sî5oÚut¼]òZn÷—þYÒ]Ó4ù,t2÷øX¬Z±¿ßúVÛZÎ~üÙôí\v´p9—ørÔÞzÞö~VÜÍS›“w\ÿxò±t7µóo[[ôõu{Í×\Òpõñø1³õ4š>pÝt}òõZ˜Õ’ÞÓ}ôžq®øöv°õWö<ÿxürú‘ÔŽSY•½¿·õvsôowÛ<p_Xz¶ÜøZÝÍÌÔUÚ¿œûõuñ¶í4¿wq‘ñ±üøyžÏ×ÕÖ}ýØ5uñnÜ®:Ýó?ÖuûÜùúX”ŠÚÙÓ>X}¸w·v}®~V¯Zzsþu—yÕOVY—xÞøs5ô20îÝ®]XöôÞy¿¿ÑÎYÜwTÛðk8ù7í²¼øwq]×mt•NšÿZTRuu·Vq³tù–u3›Wð6^zVÜÓ•Ø×w~=÷yôïµÙt-Ùõ|õ´W–ÙÒþÏ~?w>v÷thóžqr—ø±ÚùòÛOýÚRÞüøxð»÷p°\·4×vnV=óS”VßPžó×ñ8tx2½ÔY®Ý—÷úþ´ÕPÒZÓÙÿÞ«ùóþkž¾lxWôöœv¶’UÒþÏý]ý{°­u°ñ\Ÿüð^Zï{™löØ[RÝ[¿|iüt-³Rw¾õ•wµxzr\Q™›ÓÚ^~úôk=íoÞÛ=¯Ö¼vv½2uÞÌØWÖVÚ3póú0¯T›õøÙ«Û÷ÿõÑÑÛUOø™Ûqô5ù2ZšõZÒñ9Ú2{›ÒÖYÒTø{qm÷2²Uuu–wrñv­»ÒÝþ™Rßõôpjúqî™}:üÕôlß´sÖÕ\Ñ‘|tô÷=ïÝ=˜×·»Ö²pûyu–ÒRûT’|ñon½q–Wó|º½ìõ;{MÖÜzÔmlûý±yÓÚ^¶õvzs¿tUØÏ÷Û{ízöÜœšÎú·ølÝv´T”šPLßé˜×êü1ÔØ6–Ô_öoò{y³U—YÓºøïÔ¯ñxÖ½5¿O<òéñùü´\[ÿÓ·q2öíüUœu¾RZ®¦ùÿ{¸Ø×zSüsòØ^nZVØ<»Ì­ézÛü½ÙЙYÎÜrs–|÷8TÔ7Y‘ojx]|rRÚœ˜}÷oÜßôñ]ö”Õ(æ^yzúºÕZ· >nyt{Z°{R¬OñrlðÕ÷vZÛ^¾—ðõxþ;|ûÕó©éþZ6?ÚØÑ]œ¼ñs]vß<ûyZ’×(æwZ}uÝS”~\¶uûY¿Ú6ÜULœæqüÙ]ùZÐ\Y÷ÿúû–Yö¾‘íeùZµÿÖÑWûTÿöó·þÜô3üž³¦ëÜøtuÿÔ—öX½´õqxÜ[r¹^Î+)òØûu›ÒZßܼìÿX[ý9}P:æôù\÷þS—˜×}\vô{Ò÷ñÕø©lóÒ÷¼]ÏÜÔý|ßwðv—Ý=¯Ø™êhí™ørÖÔTzz—róu¶{t6‘–óiêÜüòÜY_z˜útòvØÕµ9—Ug®výx¿ÝÏR—ÿÛ|ß±ø^Ò=ÿ\³ærx_¸^WWøy}³p·ÕÝw¹Õógîöß½˜NÔTøwØö²½ŸZœøYRõ(èsŸŸþXOSÓy}|}59}|XxhçùõÜüýÖÍWû}¶žô¶¾óîis_»Þ~ÐPÏxyû¿ùû;\?TÑsj¨nØøô^šÎÔþuº}úôö·_”½ãö5~|tÖTÒw_ô\øö²Ùwëëy¼uù[ÓÖ»sûyv÷¹>W™xcûwÿwÓV»ÝwØ^¶_º›ÿÕÙ>)jzÝØ|¿SÑÎ||wW÷Ùžý»_7km÷]Þ|ýTL÷_t¾™õwXº}R˜¶ç±qþ_õýØÎTÜvú=ÿù·:¹üV”îåê|xùöyÚ›ýó;8xû·t¹þRWêg·ü»×ðÑÎÛœx¸ZÿþŸxÝØXö%òÿÿÞ\SOÕþxvš{þ·<òš^êèì~Ûó|÷‘ÐTºôöÛz|¸ùß™Méh±šzÿ}]N\4yZ}}·¿~”Îx)kö¹û{úÜLMy÷ýüwûr·\Øõd¬:ßúõzUŽÔ˜÷·ßùþ÷5úÚVî(ëÖsü7ÜX̹û{Þ{ÞtöZžLÕéí5ºþú|^ÍßóUü¾\·¹~PÏò¯îtü÷ùøO‘Õövþz»xî¼üÚ÷çðsÛñxöXQ¼8ô¸ü¸ö÷w™Q˜ðåô÷}÷{žØR~ú<÷›øù¶]TŒÛªòtöÞyyŽÎ’þ^ýß}yù˜MQ÷ïðñv¼úÔLšxyûÞóº3‘Òßnîrtùþ5ýwÝöÿûüïx·˜óë®ðõz´ñ×URŸùuóÿºôí8ÔÒ÷4ésÞ¶û|yÐÐ<·ÿøzryšOÚ:ì.û~yú\ÑŠT“t_þÝýö·ÙSý-¯|q¼õù×ÒÎÖ:½ùûÿ2³zÖÒßïñp¶üðõ^‹üYz¹»?ñðóÕW_ôíu·~öñüMÖšßù›xszñ•òñ¯\xï½4—QÏ}Ûÿ_ýým¸>ÓÖþò¯ßöýï:”KŸQ˜~ÝYwvôz“˜Zïv{½ñoÿÞÕÏüÛœßïùoþÿR;¯ï;ºk·µõRÑ?þÙýùöð,|ÙÚþòî4½6íòYÑSü›<ÙÝsòv½ŸQØ°lþY-rüžÑÎÖÛYSyû¼qݘ—tðŸ\÷nüWXËžWVÖ{ŸîÝúŸxõ=ôtösu›ØÎ9ØT×oûµ¶wÖxëÝwý,.X\ÕÙ”Sµóøu³_¼ù¼ììÛpò3ÚW_”VÜoÖìõX¾Ù^rñ¸Ýq.½WÖÚÑØß±÷û·û¼kšÛqó|[VÝÌÏ÷–û|ôw”˜9ñ÷×µqô»VÝ–”—×Úvùsûµ}[ªñxÚ,«[|ZöœÌظùzóðí9×nkœ±ï{ÝZüþM•[ý\þòó—®ùÖúp¶˜ÓúXLMÙÙ\Òtò_Ú¬y—ú8süVü”J~Ôý]´pØý.yòqoŸºúýZWÖ¾ÝÓo¶2÷^í¯øôvpô<ùyÙÔ™~Pyyôtÿ²ùqò_ïÛoYz™TÖ[•Xß~0Õy¸{rþôów•x®ŒØ×ÚÕTÙ>ÝxY;œïõkqÖÝÒÜ××_ÿ_ø1ýûÿpìð?o?¹{ÜU}ŒÿYõrSîó[¸°îúuzmÿšv¼Õ‘÷Óü±šõßs¹Ú÷ñö<nÝóÔÛÚÚS–^»™|ø_¯\Óÿ«þú÷s–:úYÏÒÝþŽvùþÜú:»Úôñrþt¼°7LÎú\^üÞø~Ú÷Øœ³òrßï¾ñ}|ÚT_˜ß²ýwþo½ú»êñr}ðø{¿Wñ•Nð¶};øšîßý´k|õöün•üZÕ×z‘mžØ|÷þz=róßòô“ýqRÌS´\Ü“øùû–ùW´oœw™ô}XÌšzW¹sÖ|¯_{[ï6oµð||wÞ[”“ßÖø÷•øúº;^·è´î{øýóXÚÿP÷^xó¸œzjypðm3–ðúX÷óÓ}/ÙUóµô3\öº[ÿÔOZ•YÙÛqœÙ_ººßïôrWïùØÖRÔÑßy™úÜz¾Üò7nøn·ß·×ÚØXÑÙpñ»—w÷2{í²svúøqÕVÚÚœÖtu½žþ\«ßòo´Ýz¹¾SÖQóÝ^öÛ8]~÷î®tZùm‘U¸‘’üûÜy{ž]ß^õ±lñ¶üý7WÕÍÏûߺVöt÷TÒ¬örª×7zt¿ŽYöÑÖtsÝz»ßõ¼x¨ëÙþr_ÛWѺzÿ¾1¶Ûðöðîß/zYÏýüMÒóÛsÞô\¸tñ±½øûZûRÖRÙŸZ³3œW^­øtkû|µ›YÙÑØ•_´üwœÝX»,*÷^ôv:üQ–_SÚðyžlõ^òìj¿úúoÜÔ—¼RZ™þ|óù\“3ûùæü|·ú=TSsє۸yõzúv®õ¶óU;zÑÕÙÖÚ×òÞ2»˜Þòñî~ùúÞP“YZ~Ùö4ž>]Øñgúw—kØ[_ÜOœ\¸/Vþ^ülo¼ïœßn[YÑû’Ÿôwœ²~—}qsôpy~ú8ÝPÕ^Ó9¶Ü-¼þÝónëyò³üñÜYÚÛØ}÷û5šö s¬qý>ÿñ•™ÖÕWÖYýZñü–}2ôøÜyv“ZÝÑÕ[И¬y<›[Zñq{l´—öõÚTÖ5ZÑqsžnV³Õxêv¶wq=“ú»Ð×s^vs³×÷oqóÝyù}”W™UÛ|y¸0ºØvôïïüÝ^ê”Í>SÙ”Þ~¹µ\™Ùô®øð={úùÐÓ·ÍÒu˜þ5¼óRûõêý?w|¶ÕTÖÖ“ZÚöw]—ÖnôòûuÝôtT’ÞÒþÖ°.™yy_íï·ú³üs×x”]˜Rî®ü2Ø[îúíuüÿðrŒ•ø^ZŸöt¹]Rryoºü¼³ÜÜQ~ÕÓ~×ôíZ•U-¼2xw×t6RþÑ[™^»Uð«YÕ·÷uî{ÿÿõ˜Y”ÕyŠðü¾ø¸÷Îó÷0÷Ú¶øuP\RþøóÙô+X/uóß°þ^½y‘ÛÜÎw[÷}±U[³|q´®Óo\¼ßUXUXôSï¸ù¼W3¸ïùÞtøþÐVwŠ:ÿ]ó»?Ô¹ü8ìuûu^™ÌÚ[þY[èò¹vLõ³6ðúû^÷Z–W‘^´{±´÷œÕvùçØuµ×´ÛXÓ~Ó1þÚn°}UØv:tp›û{ÑÓU˜Ðݽì=÷xÖîxs¶û>ÞpŽWÝPÞÞx´mŸôÖ]ë\pðšsÞ;ÑOt˜ÕûÜé¯8»X{¸§üxúqýÑÝQx¼zð¯7Ý•¹movÞïÚ~ŒÖ}Oÿþ×ô¬Z™—wwþßôú–ßYÌÓÕÒ}»ížx›ô÷t²ÝwÿíÐNÿP>\òñ»ü3Ùü'|{øo»ÝØØÕX2³ûð»=növpm×.ÿ[zÎ<×}œ\ò÷¸ž\íõ0^v¸ÿÚLÖÛÎ}™^t³ݘquôú߶ü×X‰YÕ‹4ÕYô¼}ÔÞò]»ýy_{XÑ’‘UÚ^ï¯ýø±ïóþùïúÿÞÔ]x›6§}p¶xò³î÷v}ôpÞÒß3Tú6õó}–y0úúp~–n^Ö[Øt—wøë^Ò{8õñvWõ¸×Z”Ñ—ßz‘òï™7Xÿn¶Ý{ØØ_ÍÞSûÙ°|·þT“ïýóŸÝwÙXZN~Ôx}¶nÝ_>õ½p¬öUtïÙRÔ8×y–7©ºÿ·w÷ìr[qøÞx’Ø{ÎsŸuî·9Ø^puí÷_pqU>“y–Rt¼ps»tØwvryßvÛúUŠù–Õýð1ûºØþÝóòw÷–ýÖÍÝÖþþ­°4špßöm|^òÑÜÖÐV×|Ÿ7p»1^÷÷ùíÛ_ñœÔÍÚÿÐý­4ú0^ÖqrïûnÜ™úÎ~—]W?¬nZ»[5ÞõñŸ³ÛZÐQ>Nؽ÷òÿ1¾Wtõówv߸ÿV_QvØyh²:Ù¼s:u¯»XýõÔÍÿÖRôš­o}ôø¾öïýywUù›ÌÔ–|Û4©t4õQ^°ò÷yÿvýXŽÞÛR:Óoò¼,šÙprùôõ;ûßzNšÜÿ·zx°ìT]øq­]½sÜ{ÒÓ}ŽZûÖ¯wúŸ<øÞul\ž³ÖÖU”QŽ]–6ù_3ÙÛûÝôt_w›ÿ[PÕ×ßÔo/›1}÷üvnøúu|7ŒV›Tzüòﺴyzöul0üö~ÞÑÙpY´öq²2ž¸öùjôØzïÖ}ÖÞÓ™öþ·n¾³Vúß/w›ßnPÑZ\:ý[o·z¾SvøµyþÞÿ>ËV^Sýw¹nŸsÙsöÝ÷ž÷XþYÏ^Óyòî¼o·=ð±¯×÷÷ÞÙ•ÒÝVzØøëšt>]ýuuq˜]xüMMZ˜Nº{±q8»ÜöùrìùÒ©úSY•[ž\Øï-ºù4úÛlñýÝuóÖRú™Õûðî´]ìí¿Twüÿ–ÓÖWUŸúüoŸº5»Wèsûù{ÝÛÖÚÕtù쯺¶ünù{øvß^[‘N^þS°é_šWµîß:;\õýÒXÑYÒ{˜yí±]·öïxŸÝ|ñ˜ÑØ]ØÜ>ò«^Ùòþxî¹öZ¶[ÑÙÕÕXw¾%µxõ÷ðvµøûZWXØ÷ýuî´^6·Õ¯rµýÞú\ÐYY“øÞ¬³Ù9^sõΚ®ÖNVW”ZüÞútô”l}ün=×mÒÜÙÓwÞwn°Û<ò_nuµßrøþÔ‘[ý×°wÿé8œ²õt¶¬÷ÕqúV]TSò½Ü­*Þ\°¯ûôtþ]µßÑTUvÚÜî5¾ÙW³Þ½wÿÔ{yKQÙSÛß{{·ØÛ4û8úõý[ÍUÕ’Ùu|ø­˜>n\²®÷Úò¶ÒÏñÖÙ½uôkµŸØ¯sþqëÚvò>Ò\\Öýqqs´5Õôî[t«~ÿy<֜ӟxtt­}ÚÕò6ðsþz_”ËœÑÚ[»¶tù“]þzüpùYºÓÎÍÖS¹¸ï»Wxð;²qüzž—O]Ùü=pkô×suùu®s_ö›–LÑßû~ðoU–óv¼´íºZß?ÍÓ›ºÜþxìô3ps[j~ø|ÞSTÔ·—üxí½RÝ\°tûîð]_øœOØv~Yq0½ÑìêŸ÷wöZ›xÙÌÝ°û—~uõÕÝn±|t6”Vø¼Tõò×ü´1ØhëÝîù¶W÷ýùOõsw•¹tµWõìï]ò_Z—µÞPT¶ø¿ÕûrŽüoqu¼û×ÚýØNÞv»ÔtüP«î²øøõÙózÔ·ïô~|¨òíh4:x÷Q~»œQ_qøY›òÜÑMólñÛó—^OœÖ™ÜxøÏtŸVÑ™rëYûß{ÑÖßy¶}Û¶6nhmùûº:VœüyYqpt¸oþ÷ѳçì³Ûõ^˜Y_Þ{Øwº^߶VSìçu~×ÿX¿Ý?Þöü\|9”M¶å¬úXÞ]R™Ú|_øwÖ9ŸÙMÛ)g;ß\ÙÕ”[»Ù¶ûû~ý;‘”íäkÛzÖÜV÷^¼øz~_Þ‘ÐùeëÚ?]Õ”šù]ºú_ùz¹X \féuþßyÚ–›ß{½zøwº÷šÑkçsß;½ûSYÞ}úþ|¹txÍìæ±;Ú²|W™›|x½Üù{y»Ísîìu•z>ÔÕÚÛ|]üž{þRÏZ®§›ûYý›ÖTZœ]ûýwyÏ–jiõÞ[ø»UþwÞú|óõ~+*ìùÙû¼^Ù]úüµûuòôôÜ rã·yþ[sÚ_}þ~µ~¾úö¶³òëÞ]\•×^ÿ—ø=|tÓOœqgyÞ|Õ×ýZzßv]¼uÛ“s'ñ·ÕÝ\Ö^ÙÛó|9üýô·ORû(§ÞßþÖ_Û¸òÝ=ysÿÎ?jk8úUÞ}W“|Ÿv½zß2yNÓëêuÿÙ~ÝWšT›0÷Øy²wY’”òfñ¼þ:ZÖÞxsÝtøõø˜Éóh,ß]œ]ÞZT˜xtü½4´Ñ üd­úÙ_z™×ÜV|´ü¾Þv¶Ëõòì/TÝÿÞXÕØšñ¼}÷ú Ôìç~wÖ{Ü—[š4õý}x²Q”°çrýZ_x{’\×2øxþÞí>Òõin»ÜšûÛÚÓš}´ûþzuz’w,æ^??^]TÕ}ó?ûÜtú“ÏÝn©ñÙWûV_Ñ¿ý¹ÿÛt¼×MWjînßß¼]ÒÕZó:ö}r¸üPì¥pù\Üþ|›ØT´m<xµ·ÙUïh©\œÙúZþRšöwúû]ù^–®­éÝÔ×ZžÔ’ôrÚ÷¾Û×T3çt´XSõ\Ú~•73wþzúÞUY3ª)úÖÜXûÙWšûvt<u¾ÔPÕòêq´W×ÝZZ’Swß8½?™WÓÛðêqµVý{ØT—ò¼ì»~¯ÔPýnîk¸{VwšûÚwör¸õº˜Qþvl꼞ÚÝ[] T}ú5ßu|ÒÎú5îðý×]™ßSSÿùuÚ¸O×¾r­®ÖúÕ<tÒ•Ù¸°ôýïÔX¼çvr<÷Ý÷ß=ØUð­x´ò]Yóm*x9Ü^óZÜ’øquµt¼^ÐØn«rsSuýzÞW–u9o½4_ÜOöô¨n~Z<¸ÿTÒñö4ðüÚØ úhív¼½\þûÝO¸µtoØðÌU¸«rvÞœ–óÙÚ•Ù÷±÷\µSÖÓròïÿ[þ^½’Ó»ßðµz¿ÒPkøð»Ø^þ_{Ž·ûxw8ö×ÿ2nôúÜZñyÙS÷úñör~•×uë2ïÛp}uòØÒ=ü±t´®Z\Ôt§ÝñüüüvŸ[Qøú»u¼ÔOù8ðp¿ÔxøÖSOšÞô¿zþ“Ñž+}³Ý÷UuîTÏÿÚöût«W¼?øêðoÜó½ïy¾Óž5²/µvZ|.ínýzº÷}wÎÛÛùž²|ØMôvÞÝÙÔÝ»ORÍÒž]¸ð›Úþ°nÿÚ6}ÝØÍV5¿÷ôôWŸn°q_wœßöùO×Ø}°n×\¹êõr|³[õòßSÑ\ú0«]örê¶ô5ÜþózÕOÚ×;Þmñ¿ñ²óõö^Xú¶UÏšTþq²9Ýqöl±XÞúýyÕÏÓÔß8ñïž}[î±¹öSpÿT Òøþ·uüÛùnvý<ûPôÕ‹ÖÓ]Úrvº~žrµnzܾÿ¼ÿÕRÔ¸mòö\÷mîwøñU¸q^Ó••–ø0ð6yø¹ïqïúü¼ÿÚ’ÍR;Ür±øYq¯y÷XÚÿZ|TÊ“×:^ñs^Ýýí2º>»S÷[>MMÔØ~t®ú¾\ñïxð?ÕÛrZYŽ”•ü·ðìõÛ·sîõx}Øýt_“QUðª{û|±²r²_œÙ÷ÿÙÐNؼ+s{ß·v±põØÚÿýQŽ“Õ|¶ñ1¸Þ]lqºßÓyUÝMJZ™›3w:]^yïx¶ZþSµ¹ÔÍX’|¸íñüýúqñïÝ][¶×x[ O4Þtê7ý»õõo²[Üz^[•NÕ^°qïø9Yô«ýóþ›ÿyØËYÙ~¼©ò[;þqôñÿÚV:yœÊØ“\4ëz[søpµZ\ßõÛOTÕ<õkö²yv®÷þ|™ÕvýÔŒyükq½×uwó¶žÛZÞ=^MØعn®yüÞû/w¹>Ò|yþ“šÊ×òÞpjý[õ4ó:ôÞSrÞþÒÔÑ–v»ou¶˜¿o{òßÝØŸñÚΑܻp¬tùÚúoxµ˜þXØñ׌ ß^wu¨sT¾rö{ºzÔÚ1ŸÑÎU—ÝômôuXt²÷˜þXÛó—ÕK^Õ{öí5žýŸør¹ßÚùûØKØNù_í±p5Ö´nxs›óYúuÞÏW~·)¬t{Zòv0¸yš|øÐ _Õûºlìߘžrßñ»Û~ÞxYÍ Ô–öøê:þÖv~;´ÿ–Zô]NÏQÐZ²x°r;õx¿ùžÛòZJ^Ówûmí·Z÷4¶÷õ6\tòÛTϼZuol­¹¾ðòþyµ^øu’Ñ×]s1´oZÙÿó^¸|º™ûÙMÊ–×|vr÷÷6´õÜúx~þX R”Þöøk|´Yþ/øïšôõ}û—ÑN½ü²ö¯>^×ðp5û~ºß÷ÙNŒÒwñrsØ}wµòšö[øùKÕÕù9öqtÝÐú-·?øõ_v™”Ìvù¸q®ÙØWpð4ß5ß}ûWÍÌÙü8÷sw˜Ó±rxïݺûöÛØŒÏtz¹1­\W}÷²pô}÷½ö×RÍ\ýô³³qÒ6sp®ÙótûPÎYÙøò6¯XÜ.úsú5xÿºWNÏü™|¸q¹”Ð}qruœú]}þÍ‹Ø~ün½ÝSÞ3ðs¼rWøqOØغwön{˜Ö¶noux³×í]˜?96øoô{Nz1­tµ|}yý™ÎÑûzõóךßê62ûYxúÊVÕ~y¹û´ÖN]o¿ô´}ýQLÎõ¿X{²ÚŽZõðt÷üX¸·Ê}y;¸l}Õ×wplsú?.ÛÖVWxµôs³ßÚÙlèóõvýv´8PQ3x2²ïÿ][ðlìr¿t}yø‘½6ýô²ÎV~ò³;vX[üþÍRx{2Ÿ^ÚwíñøÚ¼ŸûY×þuv½qþPN¯m²x²TXvùRÓÜtw^õÑÐØuªuÞÜÜ×TÍüq>~9?LR®.÷ô·RüxºÒÕ_3þ°tw”Ðøhªzû}{ÛnÛS[oü®»´:Ïòökz±Ùú¿_”“x÷8³ZôÓ•¼iíxÜVùüWÑXx²ùñ”Rùínqõ•~Ÿø–PÑ|³Ÿx¾ULT³n÷»ÖØUùZŒÑÝy}ßuÜLÐ9ì.=øÝxôÐüyòyl¶ÕÙ»ël긹^õµÞUÖst®û±uÒ[ëöín?ÜóÔÕ\xòüö~Ðœlêx´”V5ÞSW—ÞºôýßšÎYúmïZÞÙYS”w÷XúýN”üip³ùÔ¾vÖ“Ü:rzt¶ÒV:rìí²ZÞ^wVØ]vöŸúÕ“½él÷ÛùÕ\{›”-öyv¶ÝQgñíóÝü¸öºV×ö2ùöóý×Þ´iì/Þ¸Þ_4ÕRÿß°üüµØÌlí³½xTÖxÛUõ]šxZ˜ÛkúòÞšTÜÔÓp\y÷ÑXðëóòþXÝóš–;ÿnþ?µÛÖYjæôóÙ:[µÛY”w÷¸÷V\õíi-|Úó™Û•Ûw]yúÛ[Ù¯ëð0ØÖ{ŸöPÒxóšþý·Ò—úml+|ŸS÷›}Ïüùß{]ß×™¾iéoýÛ[z]VÔ”|ùœÙŸzN–s®jv}ÙØS“Ûø^Ùý¹ÞUר©l­\[²~ùÛÛxt»zõóž÷ë©)ñ]œü±–×ßÛ5^Y6ºßÔZëìjxúÒvÞÖÙÚ{Õœ}¸[×;óíhñUÝ>šÖQÿÛÙØ\½ÞÔ°ììöž[ßÕÍÕœÚZÚøß9”úçrù[Ý_\OüY÷—ÿ¼puš]u)jóÝvÝ9¿‘_ûÙö_¹q³ú\¬díú\Ù½Y’Úþ[Y{¹÷þ˜\vì©6ü_Ò—ÑûQWÛwùž^¸~ñiíøv¾”ÓÛ–YRÚW]¶ºÕ]ùöñîºzr–ÙÚ]™^Ø“íóñµþøgšòñyÞZ¿øš_üúsýžµ¶õrr|÷*ûμßþÜÖØ›rÖÿóX[i·×ðð»ÞÒ~þ˜ûÿÙÖrÚöxó߯”uøÙ¾UQýõUµSºÞYýø_^õ‘Ôn™QÞÚ]ØW_¼|÷Ú}/Ñu¾Ú¯”~öxSõq¹×ë¹^z1\5rúÿù®÷[ó|5wùùñxX¾ñw\¶vþšøÿz’qöÚ[õyÛ.ØÑo¿¿ûßÿñ¾Z°zðîr¿q¹>ý{ìp¼[åÚXt´ÕóðÛy±üÞvô™|;ßS×_•ÕØÙ{Ù”ùÙÌßq”ÓÞ”•ýZÔ~Ø÷ÕÏ|Þט¸1X×s—ßY¹¸ùõ\ýyÓtnÙrï}ûÞ0ßò®ò¯¸n~úùõ{^­ÿÒû´|Z¿=r³¹øx_Ösøø÷³Ý’p›tûö{Z÷U˜ºu[÷kXŸÛÜWÚ^¹™[ûR×UPý»Z°’×Y—þù}TnºÖÕÙ·TV^,Þ—þºþ|øþóîym™±´×µêÞÚªx^ÿû|×®íòøì¸Ýùøþx®Òð·UÜÝö_¶5òß›¾s×ÐÞï}t¸ÙØÖw—XÚµXzú–YŸÌÿtyQÓ?ôÓÔUØ÷º{Ô»ÏzòóŒ÷|8¸Õ6q½qû{ómµšìúTtø]4ß¿òÜžgÞÜpïùÕýlw˜tÝW·*¿ŸÐkR}Õû—wÞ]ë\RZ7°,[}ú~üúzÝÜò°|·[œîóNmŸY9n¸yÖÿxÖ]XôúÚRþVØÔœ]žÒQ˜Õô[\›[´óÓý]ºÜPþTP_ï²ï›\|ò×™Õôl­5ú:ö·rü{ñ´{zsÝs´ôôoq:û?ÙÛÛùm]t1ß[­÷w¹÷[>=×VÚõéÝ×k\Ý»ØÓüÓ¾Ù>ÿ³}Xº³Øö~ÔÕÏ[ÜÚó|z¾”ýtt‘”ù^LÏrôü9­ttù:ÿ_t°øÕ1îç¸ö1p~×ëZßþZ<~ûúñð|¸óšøÒ—=Ü]ÿ—ZëÛŸù[7^¹Û•˜Ó¼p~þôì3ÞUÒóºQÕÝÔZ_þ›úÑ”¬ü×W»ÕPþxÍž6û7zúsWnÙr¶YÚžyò~z¸mxœþûn˜Í+îíìmvtó_x7ôù~8·õøW¾÷ùpüØþrÙ{ž™ðØ°w˜^ÕsïM;YϹŒ2W;Z|ÝÚžý~Þ>þ]ßßö\]ö{zÝøY·]Û}Ù²ÿ˜¶Üÿý{^ \ No newline at end of file
diff --git a/tests/gatt_test.py b/tests/gatt_test.py
index 5df6e08..0652197 100644
--- a/tests/gatt_test.py
+++ b/tests/gatt_test.py
@@ -22,11 +22,14 @@ import struct
import pytest
from bumble.controller import Controller
+from bumble.gatt_client import CharacteristicProxy
+from bumble.gatt_server import Server
from bumble.link import LocalLink
from bumble.device import Device, Peer
from bumble.host import Host
from bumble.gatt import (
GATT_BATTERY_LEVEL_CHARACTERISTIC,
+ GATT_CLIENT_CHARACTERISTIC_CONFIGURATION_DESCRIPTOR,
CharacteristicAdapter,
DelegatedCharacteristicAdapter,
PackedCharacteristicAdapter,
@@ -34,16 +37,18 @@ from bumble.gatt import (
UTF8CharacteristicAdapter,
Service,
Characteristic,
- CharacteristicValue
+ CharacteristicValue,
+ Descriptor,
)
from bumble.transport import AsyncPipeSink
from bumble.core import UUID
from bumble.att import (
+ Attribute,
ATT_EXCHANGE_MTU_REQUEST,
ATT_ATTRIBUTE_NOT_FOUND_ERROR,
ATT_PDU,
ATT_Error_Response,
- ATT_Read_By_Group_Type_Request
+ ATT_Read_By_Group_Type_Request,
)
@@ -53,37 +58,37 @@ def basic_check(x):
parsed = ATT_PDU.from_bytes(pdu)
x_str = str(x)
parsed_str = str(parsed)
- assert(x_str == parsed_str)
+ assert x_str == parsed_str
# -----------------------------------------------------------------------------
def test_UUID():
u = UUID.from_16_bits(0x7788)
- assert(str(u) == 'UUID-16:7788')
+ assert str(u) == 'UUID-16:7788'
u = UUID.from_32_bits(0x11223344)
- assert(str(u) == 'UUID-32:11223344')
+ assert str(u) == 'UUID-32:11223344'
u = UUID('61A3512C-09BE-4DDC-A6A6-0B03667AAFC6')
- assert(str(u) == '61A3512C-09BE-4DDC-A6A6-0B03667AAFC6')
+ assert str(u) == '61A3512C-09BE-4DDC-A6A6-0B03667AAFC6'
v = UUID(str(u))
- assert(str(v) == '61A3512C-09BE-4DDC-A6A6-0B03667AAFC6')
+ assert str(v) == '61A3512C-09BE-4DDC-A6A6-0B03667AAFC6'
w = UUID.from_bytes(v.to_bytes())
- assert(str(w) == '61A3512C-09BE-4DDC-A6A6-0B03667AAFC6')
+ assert str(w) == '61A3512C-09BE-4DDC-A6A6-0B03667AAFC6'
u1 = UUID.from_16_bits(0x1234)
- b1 = u1.to_bytes(force_128 = True)
+ b1 = u1.to_bytes(force_128=True)
u2 = UUID.from_bytes(b1)
- assert(u1 == u2)
+ assert u1 == u2
- u3 = UUID.from_16_bits(0x180a)
- assert(str(u3) == 'UUID-16:180A (Device Information)')
+ u3 = UUID.from_16_bits(0x180A)
+ assert str(u3) == 'UUID-16:180A (Device Information)'
# -----------------------------------------------------------------------------
def test_ATT_Error_Response():
pdu = ATT_Error_Response(
- request_opcode_in_error = ATT_EXCHANGE_MTU_REQUEST,
- attribute_handle_in_error = 0x0000,
- error_code = ATT_ATTRIBUTE_NOT_FOUND_ERROR
+ request_opcode_in_error=ATT_EXCHANGE_MTU_REQUEST,
+ attribute_handle_in_error=0x0000,
+ error_code=ATT_ATTRIBUTE_NOT_FOUND_ERROR,
)
basic_check(pdu)
@@ -91,36 +96,223 @@ def test_ATT_Error_Response():
# -----------------------------------------------------------------------------
def test_ATT_Read_By_Group_Type_Request():
pdu = ATT_Read_By_Group_Type_Request(
- starting_handle = 0x0001,
- ending_handle = 0xFFFF,
- attribute_group_type = UUID.from_16_bits(0x2800)
+ starting_handle=0x0001,
+ ending_handle=0xFFFF,
+ attribute_group_type=UUID.from_16_bits(0x2800),
)
basic_check(pdu)
# -----------------------------------------------------------------------------
+@pytest.mark.asyncio
+async def test_characteristic_encoding():
+ class Foo(Characteristic):
+ def encode_value(self, value):
+ return bytes([value])
+
+ def decode_value(self, value_bytes):
+ return value_bytes[0]
+
+ c = Foo(
+ GATT_BATTERY_LEVEL_CHARACTERISTIC,
+ Characteristic.Properties.READ,
+ Characteristic.READABLE,
+ 123,
+ )
+ x = c.read_value(None)
+ assert x == bytes([123])
+ c.write_value(None, bytes([122]))
+ assert c.value == 122
+
+ class FooProxy(CharacteristicProxy):
+ def __init__(self, characteristic):
+ super().__init__(
+ characteristic.client,
+ characteristic.handle,
+ characteristic.end_group_handle,
+ characteristic.uuid,
+ characteristic.properties,
+ )
+
+ def encode_value(self, value):
+ return bytes([value])
+
+ def decode_value(self, value_bytes):
+ return value_bytes[0]
+
+ [client, server] = LinkedDevices().devices[:2]
+
+ characteristic = Characteristic(
+ 'FDB159DB-036C-49E3-B3DB-6325AC750806',
+ Characteristic.Properties.READ
+ | Characteristic.Properties.WRITE
+ | Characteristic.Properties.NOTIFY,
+ Characteristic.READABLE | Characteristic.WRITEABLE,
+ bytes([123]),
+ )
+
+ service = Service('3A657F47-D34F-46B3-B1EC-698E29B6B829', [characteristic])
+ server.add_service(service)
+
+ await client.power_on()
+ await server.power_on()
+ connection = await client.connect(server.random_address)
+ peer = Peer(connection)
+
+ await peer.discover_services()
+ await peer.discover_characteristics()
+ c = peer.get_characteristics_by_uuid(characteristic.uuid)
+ assert len(c) == 1
+ c = c[0]
+ cp = FooProxy(c)
+
+ v = await cp.read_value()
+ assert v == 123
+ await cp.write_value(124)
+ await async_barrier()
+ assert characteristic.value == bytes([124])
+
+ v = await cp.read_value()
+ assert v == 124
+ await cp.write_value(125, with_response=True)
+ await async_barrier()
+ assert characteristic.value == bytes([125])
+
+ cd = DelegatedCharacteristicAdapter(c, encode=lambda x: bytes([x // 2]))
+ await cd.write_value(100, with_response=True)
+ await async_barrier()
+ assert characteristic.value == bytes([50])
+
+ last_change = None
+
+ def on_change(value):
+ nonlocal last_change
+ last_change = value
+
+ await c.subscribe(on_change)
+ await server.notify_subscribers(characteristic)
+ await async_barrier()
+ assert last_change == characteristic.value
+ last_change = None
+
+ await server.notify_subscribers(characteristic, value=bytes([125]))
+ await async_barrier()
+ assert last_change == bytes([125])
+ last_change = None
+
+ await c.unsubscribe(on_change)
+ await server.notify_subscribers(characteristic)
+ await async_barrier()
+ assert last_change is None
+
+ await cp.subscribe(on_change)
+ await server.notify_subscribers(characteristic)
+ await async_barrier()
+ assert last_change == characteristic.value[0]
+ last_change = None
+
+ await server.notify_subscribers(characteristic, value=bytes([126]))
+ await async_barrier()
+ assert last_change == 126
+ last_change = None
+
+ await cp.unsubscribe(on_change)
+ await server.notify_subscribers(characteristic)
+ await async_barrier()
+ assert last_change is None
+
+ cd = DelegatedCharacteristicAdapter(c, decode=lambda x: x[0])
+ await cd.subscribe(on_change)
+ await server.notify_subscribers(characteristic)
+ await async_barrier()
+ assert last_change == characteristic.value[0]
+ last_change = None
+
+ await cd.unsubscribe(on_change)
+ await server.notify_subscribers(characteristic)
+ await async_barrier()
+ assert last_change is None
+
+
+# -----------------------------------------------------------------------------
+@pytest.mark.asyncio
+async def test_attribute_getters():
+ [client, server] = LinkedDevices().devices[:2]
+
+ characteristic_uuid = UUID('FDB159DB-036C-49E3-B3DB-6325AC750806')
+ characteristic = Characteristic(
+ characteristic_uuid,
+ Characteristic.Properties.READ
+ | Characteristic.Properties.WRITE
+ | Characteristic.Properties.NOTIFY,
+ Characteristic.READABLE | Characteristic.WRITEABLE,
+ bytes([123]),
+ )
+
+ service_uuid = UUID('3A657F47-D34F-46B3-B1EC-698E29B6B829')
+ service = Service(service_uuid, [characteristic])
+ server.add_service(service)
+
+ service_attr = server.gatt_server.get_service_attribute(service_uuid)
+ assert service_attr
+
+ (
+ char_decl_attr,
+ char_value_attr,
+ ) = server.gatt_server.get_characteristic_attributes(
+ service_uuid, characteristic_uuid
+ )
+ assert char_decl_attr and char_value_attr
+
+ desc_attr = server.gatt_server.get_descriptor_attribute(
+ service_uuid,
+ characteristic_uuid,
+ GATT_CLIENT_CHARACTERISTIC_CONFIGURATION_DESCRIPTOR,
+ )
+ assert desc_attr
+
+ # assert all handles are in expected order
+ assert (
+ service_attr.handle
+ < char_decl_attr.handle
+ < char_value_attr.handle
+ < desc_attr.handle
+ == service_attr.end_group_handle
+ )
+ # assert characteristic declarations attribute is followed by characteristic value attribute
+ assert char_decl_attr.handle + 1 == char_value_attr.handle
+
+
+# -----------------------------------------------------------------------------
def test_CharacteristicAdapter():
# Check that the CharacteristicAdapter base class is transparent
v = bytes([1, 2, 3])
- c = Characteristic(GATT_BATTERY_LEVEL_CHARACTERISTIC, Characteristic.READ, Characteristic.READABLE, v)
+ c = Characteristic(
+ GATT_BATTERY_LEVEL_CHARACTERISTIC,
+ Characteristic.Properties.READ,
+ Characteristic.READABLE,
+ v,
+ )
a = CharacteristicAdapter(c)
value = a.read_value(None)
- assert(value == v)
+ assert value == v
v = bytes([3, 4, 5])
a.write_value(None, v)
- assert(c.value == v)
+ assert c.value == v
# Simple delegated adapter
- a = DelegatedCharacteristicAdapter(c, lambda x: bytes(reversed(x)), lambda x: bytes(reversed(x)))
+ a = DelegatedCharacteristicAdapter(
+ c, lambda x: bytes(reversed(x)), lambda x: bytes(reversed(x))
+ )
value = a.read_value(None)
- assert(value == bytes(reversed(v)))
+ assert value == bytes(reversed(v))
v = bytes([3, 4, 5])
a.write_value(None, v)
- assert(a.value == bytes(reversed(v)))
+ assert a.value == bytes(reversed(v))
# Packed adapter with single element format
v = 1234
@@ -129,10 +321,10 @@ def test_CharacteristicAdapter():
a = PackedCharacteristicAdapter(c, '>H')
value = a.read_value(None)
- assert(value == pv)
+ assert value == pv
c.value = None
a.write_value(None, pv)
- assert(a.value == v)
+ assert a.value == v
# Packed adapter with multi-element format
v1 = 1234
@@ -142,10 +334,10 @@ def test_CharacteristicAdapter():
a = PackedCharacteristicAdapter(c, '>HH')
value = a.read_value(None)
- assert(value == pv)
+ assert value == pv
c.value = None
a.write_value(None, pv)
- assert(a.value == (v1, v2))
+ assert a.value == (v1, v2)
# Mapped adapter
v1 = 1234
@@ -156,10 +348,10 @@ def test_CharacteristicAdapter():
a = MappedCharacteristicAdapter(c, '>HH', ('v1', 'v2'))
value = a.read_value(None)
- assert(value == pv)
+ assert value == pv
c.value = None
a.write_value(None, pv)
- assert(a.value == mapped)
+ assert a.value == mapped
# UTF-8 adapter
v = 'Hello π'
@@ -168,10 +360,10 @@ def test_CharacteristicAdapter():
a = UTF8CharacteristicAdapter(c)
value = a.read_value(None)
- assert(value == ev)
+ assert value == ev
c.value = None
a.write_value(None, ev)
- assert(a.value == v)
+ assert a.value == v
# -----------------------------------------------------------------------------
@@ -179,37 +371,44 @@ def test_CharacteristicValue():
b = bytes([1, 2, 3])
c = CharacteristicValue(read=lambda _: b)
x = c.read(None)
- assert(x == b)
+ assert x == b
result = []
- c = CharacteristicValue(write=lambda connection, value: result.append((connection, value)))
+ c = CharacteristicValue(
+ write=lambda connection, value: result.append((connection, value))
+ )
z = object()
c.write(z, b)
- assert(result == [(z, b)])
+ assert result == [(z, b)]
# -----------------------------------------------------------------------------
-class TwoDevices:
+class LinkedDevices:
def __init__(self):
- self.connections = [None, None]
+ self.connections = [None, None, None]
self.link = LocalLink()
self.controllers = [
- Controller('C1', link = self.link),
- Controller('C2', link = self.link)
+ Controller('C1', link=self.link),
+ Controller('C2', link=self.link),
+ Controller('C3', link=self.link),
]
self.devices = [
Device(
- address = 'F0:F1:F2:F3:F4:F5',
- host = Host(self.controllers[0], AsyncPipeSink(self.controllers[0]))
+ address='F0:F1:F2:F3:F4:F5',
+ host=Host(self.controllers[0], AsyncPipeSink(self.controllers[0])),
),
Device(
- address = 'F5:F4:F3:F2:F1:F0',
- host = Host(self.controllers[1], AsyncPipeSink(self.controllers[1]))
- )
+ address='F1:F2:F3:F4:F5:F6',
+ host=Host(self.controllers[1], AsyncPipeSink(self.controllers[1])),
+ ),
+ Device(
+ address='F2:F3:F4:F5:F6:F7',
+ host=Host(self.controllers[2], AsyncPipeSink(self.controllers[2])),
+ ),
]
- self.paired = [None, None]
+ self.paired = [None, None, None]
# -----------------------------------------------------------------------------
@@ -222,12 +421,12 @@ async def async_barrier():
# -----------------------------------------------------------------------------
@pytest.mark.asyncio
async def test_read_write():
- [client, server] = TwoDevices().devices
+ [client, server] = LinkedDevices().devices[:2]
characteristic1 = Characteristic(
'FDB159DB-036C-49E3-B3DB-6325AC750806',
- Characteristic.READ | Characteristic.WRITE,
- Characteristic.READABLE | Characteristic.WRITEABLE
+ Characteristic.Properties.READ | Characteristic.Properties.WRITE,
+ Characteristic.READABLE | Characteristic.WRITEABLE,
)
def on_characteristic1_write(connection, value):
@@ -243,17 +442,15 @@ async def test_read_write():
characteristic2 = Characteristic(
'66DE9057-C848-4ACA-B993-D675644EBB85',
- Characteristic.READ | Characteristic.WRITE,
+ Characteristic.Properties.READ | Characteristic.Properties.WRITE,
Characteristic.READABLE | Characteristic.WRITEABLE,
- CharacteristicValue(read=on_characteristic2_read, write=on_characteristic2_write)
+ CharacteristicValue(
+ read=on_characteristic2_read, write=on_characteristic2_write
+ ),
)
service1 = Service(
- '3A657F47-D34F-46B3-B1EC-698E29B6B829',
- [
- characteristic1,
- characteristic2
- ]
+ '3A657F47-D34F-46B3-B1EC-698E29B6B829', [characteristic1, characteristic2]
)
server.add_services([service1])
@@ -265,56 +462,55 @@ async def test_read_write():
await peer.discover_services()
await peer.discover_characteristics()
c = peer.get_characteristics_by_uuid(characteristic1.uuid)
- assert(len(c) == 1)
+ assert len(c) == 1
c1 = c[0]
c = peer.get_characteristics_by_uuid(characteristic2.uuid)
- assert(len(c) == 1)
+ assert len(c) == 1
c2 = c[0]
v1 = await peer.read_value(c1)
- assert(v1 == b'')
+ assert v1 == b''
b = bytes([1, 2, 3])
await peer.write_value(c1, b)
await async_barrier()
- assert(characteristic1.value == b)
+ assert characteristic1.value == b
v1 = await peer.read_value(c1)
- assert(v1 == b)
- assert(type(characteristic1._last_value) is tuple)
- assert(len(characteristic1._last_value) == 2)
- assert(str(characteristic1._last_value[0].peer_address) == str(client.random_address))
- assert(characteristic1._last_value[1] == b)
+ assert v1 == b
+ assert type(characteristic1._last_value is tuple)
+ assert len(characteristic1._last_value) == 2
+ assert str(characteristic1._last_value[0].peer_address) == str(
+ client.random_address
+ )
+ assert characteristic1._last_value[1] == b
bb = bytes([3, 4, 5, 6])
characteristic1.value = bb
v1 = await peer.read_value(c1)
- assert(v1 == bb)
+ assert v1 == bb
await peer.write_value(c2, b)
await async_barrier()
- assert(type(characteristic2._last_value) is tuple)
- assert(len(characteristic2._last_value) == 2)
- assert(str(characteristic2._last_value[0].peer_address) == str(client.random_address))
- assert(characteristic2._last_value[1] == b)
+ assert type(characteristic2._last_value is tuple)
+ assert len(characteristic2._last_value) == 2
+ assert str(characteristic2._last_value[0].peer_address) == str(
+ client.random_address
+ )
+ assert characteristic2._last_value[1] == b
# -----------------------------------------------------------------------------
@pytest.mark.asyncio
async def test_read_write2():
- [client, server] = TwoDevices().devices
+ [client, server] = LinkedDevices().devices[:2]
v = bytes([0x11, 0x22, 0x33, 0x44])
characteristic1 = Characteristic(
'FDB159DB-036C-49E3-B3DB-6325AC750806',
- Characteristic.READ | Characteristic.WRITE,
+ Characteristic.Properties.READ | Characteristic.Properties.WRITE,
Characteristic.READABLE | Characteristic.WRITEABLE,
- value=v
+ value=v,
)
- service1 = Service(
- '3A657F47-D34F-46B3-B1EC-698E29B6B829',
- [
- characteristic1
- ]
- )
+ service1 = Service('3A657F47-D34F-46B3-B1EC-698E29B6B829', [characteristic1])
server.add_services([service1])
await client.power_on()
@@ -324,81 +520,98 @@ async def test_read_write2():
await peer.discover_services()
c = peer.get_services_by_uuid(service1.uuid)
- assert(len(c) == 1)
+ assert len(c) == 1
s = c[0]
await s.discover_characteristics()
c = s.get_characteristics_by_uuid(characteristic1.uuid)
- assert(len(c) == 1)
+ assert len(c) == 1
c1 = c[0]
v1 = await c1.read_value()
- assert(v1 == v)
+ assert v1 == v
a1 = PackedCharacteristicAdapter(c1, '>I')
v1 = await a1.read_value()
- assert(v1 == struct.unpack('>I', v)[0])
+ assert v1 == struct.unpack('>I', v)[0]
b = bytes([0x55, 0x66, 0x77, 0x88])
await a1.write_value(struct.unpack('>I', b)[0])
await async_barrier()
- assert(characteristic1.value == b)
+ assert characteristic1.value == b
v1 = await a1.read_value()
- assert(v1 == struct.unpack('>I', b)[0])
+ assert v1 == struct.unpack('>I', b)[0]
# -----------------------------------------------------------------------------
@pytest.mark.asyncio
async def test_subscribe_notify():
- [client, server] = TwoDevices().devices
+ [client, server] = LinkedDevices().devices[:2]
characteristic1 = Characteristic(
'FDB159DB-036C-49E3-B3DB-6325AC750806',
- Characteristic.READ | Characteristic.NOTIFY,
+ Characteristic.Properties.READ | Characteristic.Properties.NOTIFY,
Characteristic.READABLE,
- bytes([1, 2, 3])
+ bytes([1, 2, 3]),
)
def on_characteristic1_subscription(connection, notify_enabled, indicate_enabled):
- characteristic1._last_subscription = (connection, notify_enabled, indicate_enabled)
+ characteristic1._last_subscription = (
+ connection,
+ notify_enabled,
+ indicate_enabled,
+ )
characteristic1.on('subscription', on_characteristic1_subscription)
characteristic2 = Characteristic(
'66DE9057-C848-4ACA-B993-D675644EBB85',
- Characteristic.READ | Characteristic.INDICATE,
+ Characteristic.Properties.READ | Characteristic.Properties.INDICATE,
Characteristic.READABLE,
- bytes([4, 5, 6])
+ bytes([4, 5, 6]),
)
def on_characteristic2_subscription(connection, notify_enabled, indicate_enabled):
- characteristic2._last_subscription = (connection, notify_enabled, indicate_enabled)
+ characteristic2._last_subscription = (
+ connection,
+ notify_enabled,
+ indicate_enabled,
+ )
characteristic2.on('subscription', on_characteristic2_subscription)
characteristic3 = Characteristic(
'AB5E639C-40C1-4238-B9CB-AF41F8B806E4',
- Characteristic.READ | Characteristic.NOTIFY | Characteristic.INDICATE,
+ Characteristic.Properties.READ
+ | Characteristic.Properties.NOTIFY
+ | Characteristic.Properties.INDICATE,
Characteristic.READABLE,
- bytes([7, 8, 9])
+ bytes([7, 8, 9]),
)
def on_characteristic3_subscription(connection, notify_enabled, indicate_enabled):
- characteristic3._last_subscription = (connection, notify_enabled, indicate_enabled)
+ characteristic3._last_subscription = (
+ connection,
+ notify_enabled,
+ indicate_enabled,
+ )
characteristic3.on('subscription', on_characteristic3_subscription)
service1 = Service(
'3A657F47-D34F-46B3-B1EC-698E29B6B829',
- [
- characteristic1,
- characteristic2,
- characteristic3
- ]
+ [characteristic1, characteristic2, characteristic3],
)
server.add_services([service1])
- def on_characteristic_subscription(connection, characteristic, notify_enabled, indicate_enabled):
- server._last_subscription = (connection, characteristic, notify_enabled, indicate_enabled)
+ def on_characteristic_subscription(
+ connection, characteristic, notify_enabled, indicate_enabled
+ ):
+ server._last_subscription = (
+ connection,
+ characteristic,
+ notify_enabled,
+ indicate_enabled,
+ )
server.on('characteristic_subscription', on_characteristic_subscription)
@@ -410,68 +623,258 @@ async def test_subscribe_notify():
await peer.discover_services()
await peer.discover_characteristics()
c = peer.get_characteristics_by_uuid(characteristic1.uuid)
- assert(len(c) == 1)
+ assert len(c) == 1
c1 = c[0]
c = peer.get_characteristics_by_uuid(characteristic2.uuid)
- assert(len(c) == 1)
+ assert len(c) == 1
c2 = c[0]
c = peer.get_characteristics_by_uuid(characteristic3.uuid)
- assert(len(c) == 1)
+ assert len(c) == 1
c3 = c[0]
+ c1._called = False
c1._last_update = None
- def on_c1_update(connection, value):
- c1._last_update = (connection, value)
+ def on_c1_update(value):
+ c1._called = True
+ c1._last_update = value
c1.on('update', on_c1_update)
await peer.subscribe(c1)
await async_barrier()
- assert(server._last_subscription[1] == characteristic1)
- assert(server._last_subscription[2])
- assert(not server._last_subscription[3])
- assert(characteristic1._last_subscription[1])
- assert(not characteristic1._last_subscription[2])
+ assert server._last_subscription[1] == characteristic1
+ assert server._last_subscription[2]
+ assert not server._last_subscription[3]
+ assert characteristic1._last_subscription[1]
+ assert not characteristic1._last_subscription[2]
await server.indicate_subscribers(characteristic1)
await async_barrier()
- assert(c1._last_update is None)
+ assert not c1._called
await server.notify_subscribers(characteristic1)
await async_barrier()
- assert(c1._last_update is not None)
- assert(c1._last_update[1] == characteristic1.value)
+ assert c1._called
+ assert c1._last_update == characteristic1.value
+
+ c1._called = False
+ c1._last_update = None
+ c1_value = characteristic1.value
+ await server.notify_subscribers(characteristic1, bytes([0, 1, 2]))
+ await async_barrier()
+ assert c1._called
+ assert c1._last_update == bytes([0, 1, 2])
+ assert characteristic1.value == c1_value
+
+ c1._called = False
+ await peer.unsubscribe(c1)
+ await server.notify_subscribers(characteristic1)
+ assert not c1._called
+ c2._called = False
c2._last_update = None
def on_c2_update(value):
- c2._last_update = (connection, value)
+ c2._called = True
+ c2._last_update = value
await peer.subscribe(c2, on_c2_update)
await async_barrier()
- await server.notify_subscriber(characteristic2._last_subscription[0], characteristic2)
+ await server.notify_subscriber(
+ characteristic2._last_subscription[0], characteristic2
+ )
+ await async_barrier()
+ assert not c2._called
+ await server.indicate_subscriber(
+ characteristic2._last_subscription[0], characteristic2
+ )
await async_barrier()
- assert(c2._last_update is None)
- await server.indicate_subscriber(characteristic2._last_subscription[0], characteristic2)
+ assert c2._called
+ assert c2._last_update == characteristic2.value
+
+ c2._called = False
+ await peer.unsubscribe(c2, on_c2_update)
+ await server.indicate_subscriber(
+ characteristic2._last_subscription[0], characteristic2
+ )
await async_barrier()
- assert(c2._last_update is not None)
- assert(c2._last_update[1] == characteristic2.value)
+ assert not c2._called
+ c3._called = False
+ c3._called_2 = False
+ c3._called_3 = False
c3._last_update = None
+ c3._last_update_2 = None
+ c3._last_update_3 = None
- def on_c3_update(connection, value):
- c3._last_update = (connection, value)
+ def on_c3_update(value):
+ c3._called = True
+ c3._last_update = value
+
+ def on_c3_update_2(value): # for notify
+ c3._called_2 = True
+ c3._last_update_2 = value
+
+ def on_c3_update_3(value): # for indicate
+ c3._called_3 = True
+ c3._last_update_3 = value
c3.on('update', on_c3_update)
- await peer.subscribe(c3)
+ await peer.subscribe(c3, on_c3_update_2)
+ await async_barrier()
+ await server.notify_subscriber(
+ characteristic3._last_subscription[0], characteristic3
+ )
await async_barrier()
- await server.notify_subscriber(characteristic3._last_subscription[0], characteristic3)
+ assert c3._called
+ assert c3._last_update == characteristic3.value
+ assert c3._called_2
+ assert c3._last_update_2 == characteristic3.value
+ assert not c3._called_3
+
+ c3._called = False
+ c3._called_2 = False
+ c3._called_3 = False
+ await peer.unsubscribe(c3)
+ await peer.subscribe(c3, on_c3_update_3, prefer_notify=False)
await async_barrier()
- assert(c3._last_update is not None)
- assert(c3._last_update[1] == characteristic3.value)
characteristic3.value = bytes([1, 2, 3])
- await server.indicate_subscriber(characteristic3._last_subscription[0], characteristic3)
+ await server.indicate_subscriber(
+ characteristic3._last_subscription[0], characteristic3
+ )
+ await async_barrier()
+ assert c3._called
+ assert c3._last_update == characteristic3.value
+ assert not c3._called_2
+ assert c3._called_3
+ assert c3._last_update_3 == characteristic3.value
+
+ c3._called = False
+ c3._called_2 = False
+ c3._called_3 = False
+ await peer.unsubscribe(c3)
+ await server.notify_subscriber(
+ characteristic3._last_subscription[0], characteristic3
+ )
+ await server.indicate_subscriber(
+ characteristic3._last_subscription[0], characteristic3
+ )
await async_barrier()
- assert(c3._last_update is not None)
- assert(c3._last_update[1] == characteristic3.value)
+ assert not c3._called
+ assert not c3._called_2
+ assert not c3._called_3
+
+
+# -----------------------------------------------------------------------------
+@pytest.mark.asyncio
+async def test_mtu_exchange():
+ [d1, d2, d3] = LinkedDevices().devices[:3]
+
+ d3.gatt_server.max_mtu = 100
+
+ d3_connections = []
+
+ @d3.on('connection')
+ def on_d3_connection(connection):
+ d3_connections.append(connection)
+
+ await d1.power_on()
+ await d2.power_on()
+ await d3.power_on()
+
+ d1_connection = await d1.connect(d3.random_address)
+ assert len(d3_connections) == 1
+ assert d3_connections[0] is not None
+
+ d2_connection = await d2.connect(d3.random_address)
+ assert len(d3_connections) == 2
+ assert d3_connections[1] is not None
+
+ d1_peer = Peer(d1_connection)
+ d2_peer = Peer(d2_connection)
+
+ d1_client_mtu = await d1_peer.request_mtu(220)
+ assert d1_client_mtu == 100
+ assert d1_connection.att_mtu == 100
+
+ d2_client_mtu = await d2_peer.request_mtu(50)
+ assert d2_client_mtu == 50
+ assert d2_connection.att_mtu == 50
+
+
+# -----------------------------------------------------------------------------
+def test_char_property_to_string():
+ # single
+ assert str(Characteristic.Properties(0x01)) == "Properties.BROADCAST"
+ assert str(Characteristic.Properties.BROADCAST) == "Properties.BROADCAST"
+
+ # double
+ assert str(Characteristic.Properties(0x03)) == "Properties.READ|BROADCAST"
+ assert (
+ str(Characteristic.Properties.BROADCAST | Characteristic.Properties.READ)
+ == "Properties.READ|BROADCAST"
+ )
+
+
+# -----------------------------------------------------------------------------
+def test_characteristic_property_from_string():
+ # single
+ assert (
+ Characteristic.Properties.from_string("BROADCAST")
+ == Characteristic.Properties.BROADCAST
+ )
+
+ # double
+ assert (
+ Characteristic.Properties.from_string("BROADCAST,READ")
+ == Characteristic.Properties.BROADCAST | Characteristic.Properties.READ
+ )
+ assert (
+ Characteristic.Properties.from_string("READ,BROADCAST")
+ == Characteristic.Properties.BROADCAST | Characteristic.Properties.READ
+ )
+
+
+# -----------------------------------------------------------------------------
+def test_characteristic_property_from_string_assert():
+ with pytest.raises(TypeError) as e_info:
+ Characteristic.Properties.from_string("BROADCAST,HELLO")
+
+ assert (
+ str(e_info.value)
+ == """Characteristic.Properties::from_string() error:
+Expected a string containing any of the keys, separated by commas: BROADCAST,READ,WRITE_WITHOUT_RESPONSE,WRITE,NOTIFY,INDICATE,AUTHENTICATED_SIGNED_WRITES,EXTENDED_PROPERTIES
+Got: BROADCAST,HELLO"""
+ )
+
+
+# -----------------------------------------------------------------------------
+@pytest.mark.asyncio
+async def test_server_string():
+ [_, server] = LinkedDevices().devices[:2]
+
+ characteristic = Characteristic(
+ 'FDB159DB-036C-49E3-B3DB-6325AC750806',
+ Characteristic.Properties.READ
+ | Characteristic.Properties.WRITE
+ | Characteristic.Properties.NOTIFY,
+ Characteristic.READABLE | Characteristic.WRITEABLE,
+ bytes([123]),
+ )
+
+ service = Service('3A657F47-D34F-46B3-B1EC-698E29B6B829', [characteristic])
+ server.add_service(service)
+
+ assert (
+ str(server.gatt_server)
+ == """Service(handle=0x0001, end=0x0005, uuid=UUID-16:1800 (Generic Access))
+CharacteristicDeclaration(handle=0x0002, value_handle=0x0003, uuid=UUID-16:2A00 (Device Name), Properties.READ)
+Characteristic(handle=0x0003, end=0x0003, uuid=UUID-16:2A00 (Device Name), Properties.READ)
+CharacteristicDeclaration(handle=0x0004, value_handle=0x0005, uuid=UUID-16:2A01 (Appearance), Properties.READ)
+Characteristic(handle=0x0005, end=0x0005, uuid=UUID-16:2A01 (Appearance), Properties.READ)
+Service(handle=0x0006, end=0x0009, uuid=3A657F47-D34F-46B3-B1EC-698E29B6B829)
+CharacteristicDeclaration(handle=0x0007, value_handle=0x0008, uuid=FDB159DB-036C-49E3-B3DB-6325AC750806, Properties.NOTIFY|WRITE|READ)
+Characteristic(handle=0x0008, end=0x0009, uuid=FDB159DB-036C-49E3-B3DB-6325AC750806, Properties.NOTIFY|WRITE|READ)
+Descriptor(handle=0x0009, type=UUID-16:2902 (Client Characteristic Configuration), value=0000)"""
+ )
# -----------------------------------------------------------------------------
@@ -479,10 +882,146 @@ async def async_main():
await test_read_write()
await test_read_write2()
await test_subscribe_notify()
+ await test_characteristic_encoding()
+ await test_mtu_exchange()
+
+
+# -----------------------------------------------------------------------------
+def test_attribute_string_to_permissions():
+ assert Attribute.string_to_permissions('READABLE') == 1
+ assert Attribute.string_to_permissions('WRITEABLE') == 2
+ assert Attribute.string_to_permissions('READABLE,WRITEABLE') == 3
+
+
+# -----------------------------------------------------------------------------
+def test_characteristic_permissions():
+ characteristic = Characteristic(
+ 'FDB159DB-036C-49E3-B3DB-6325AC750806',
+ Characteristic.Properties.READ
+ | Characteristic.Properties.WRITE
+ | Characteristic.Properties.NOTIFY,
+ 'READABLE,WRITEABLE',
+ )
+ assert characteristic.permissions == 3
+
+
+# -----------------------------------------------------------------------------
+def test_characteristic_has_properties():
+ characteristic = Characteristic(
+ 'FDB159DB-036C-49E3-B3DB-6325AC750806',
+ Characteristic.Properties.READ
+ | Characteristic.Properties.WRITE
+ | Characteristic.Properties.NOTIFY,
+ 'READABLE,WRITEABLE',
+ )
+ assert characteristic.has_properties(Characteristic.Properties.READ)
+ assert characteristic.has_properties(
+ Characteristic.Properties.READ | Characteristic.Properties.WRITE
+ )
+ assert not characteristic.has_properties(
+ Characteristic.Properties.READ
+ | Characteristic.Properties.WRITE
+ | Characteristic.Properties.INDICATE
+ )
+ assert not characteristic.has_properties(Characteristic.Properties.INDICATE)
+
+
+# -----------------------------------------------------------------------------
+def test_descriptor_permissions():
+ descriptor = Descriptor('2902', 'READABLE,WRITEABLE')
+ assert descriptor.permissions == 3
+
+
+# -----------------------------------------------------------------------------
+def test_get_attribute_group():
+ device = Device()
+
+ # add some services / characteristics to the gatt server
+ characteristic1 = Characteristic(
+ '1111',
+ Characteristic.READ | Characteristic.WRITE | Characteristic.NOTIFY,
+ Characteristic.READABLE | Characteristic.WRITEABLE,
+ bytes([123]),
+ )
+ characteristic2 = Characteristic(
+ '2222',
+ Characteristic.READ | Characteristic.WRITE | Characteristic.NOTIFY,
+ Characteristic.READABLE | Characteristic.WRITEABLE,
+ bytes([123]),
+ )
+ services = [Service('1212', [characteristic1]), Service('3233', [characteristic2])]
+ device.gatt_server.add_services(services)
+
+ # get the handles from gatt server
+ characteristic_attributes1 = device.gatt_server.get_characteristic_attributes(
+ UUID('1212'), UUID('1111')
+ )
+ assert characteristic_attributes1 is not None
+ characteristic_attributes2 = device.gatt_server.get_characteristic_attributes(
+ UUID('3233'), UUID('2222')
+ )
+ assert characteristic_attributes2 is not None
+ descriptor1 = device.gatt_server.get_descriptor_attribute(
+ UUID('1212'), UUID('1111'), UUID('2902')
+ )
+ assert descriptor1 is not None
+ descriptor2 = device.gatt_server.get_descriptor_attribute(
+ UUID('3233'), UUID('2222'), UUID('2902')
+ )
+ assert descriptor2 is not None
+
+ # confirm the handles map back to the service
+ assert (
+ UUID('1212')
+ == device.gatt_server.get_attribute_group(
+ characteristic_attributes1[0].handle, Service
+ ).uuid
+ )
+ assert (
+ UUID('1212')
+ == device.gatt_server.get_attribute_group(
+ characteristic_attributes1[1].handle, Service
+ ).uuid
+ )
+ assert (
+ UUID('1212')
+ == device.gatt_server.get_attribute_group(descriptor1.handle, Service).uuid
+ )
+ assert (
+ UUID('3233')
+ == device.gatt_server.get_attribute_group(
+ characteristic_attributes2[0].handle, Service
+ ).uuid
+ )
+ assert (
+ UUID('3233')
+ == device.gatt_server.get_attribute_group(
+ characteristic_attributes2[1].handle, Service
+ ).uuid
+ )
+ assert (
+ UUID('3233')
+ == device.gatt_server.get_attribute_group(descriptor2.handle, Service).uuid
+ )
+
+ # confirm the handles map back to the characteristic
+ assert (
+ UUID('1111')
+ == device.gatt_server.get_attribute_group(
+ descriptor1.handle, Characteristic
+ ).uuid
+ )
+ assert (
+ UUID('2222')
+ == device.gatt_server.get_attribute_group(
+ descriptor2.handle, Characteristic
+ ).uuid
+ )
+
# -----------------------------------------------------------------------------
if __name__ == '__main__':
- logging.basicConfig(level = os.environ.get('BUMBLE_LOGLEVEL', 'INFO').upper())
+ logging.basicConfig(level=os.environ.get('BUMBLE_LOGLEVEL', 'INFO').upper())
test_UUID()
test_ATT_Error_Response()
test_ATT_Read_By_Group_Type_Request()
diff --git a/tests/hci_test.py b/tests/hci_test.py
index c4da67e..af68e86 100644
--- a/tests/hci_test.py
+++ b/tests/hci_test.py
@@ -15,10 +15,56 @@
# -----------------------------------------------------------------------------
# Imports
# -----------------------------------------------------------------------------
-from bumble.hci import *
+
+from bumble.hci import (
+ HCI_DISCONNECT_COMMAND,
+ HCI_LE_1M_PHY_BIT,
+ HCI_LE_CODED_PHY_BIT,
+ HCI_LE_READ_BUFFER_SIZE_COMMAND,
+ HCI_RESET_COMMAND,
+ HCI_SUCCESS,
+ Address,
+ HCI_Command,
+ HCI_Command_Complete_Event,
+ HCI_Command_Status_Event,
+ HCI_CustomPacket,
+ HCI_Disconnect_Command,
+ HCI_Event,
+ HCI_LE_Add_Device_To_Filter_Accept_List_Command,
+ HCI_LE_Advertising_Report_Event,
+ HCI_LE_Channel_Selection_Algorithm_Event,
+ HCI_LE_Connection_Complete_Event,
+ HCI_LE_Connection_Update_Command,
+ HCI_LE_Connection_Update_Complete_Event,
+ HCI_LE_Create_Connection_Command,
+ HCI_LE_Extended_Create_Connection_Command,
+ HCI_LE_Read_Buffer_Size_Command,
+ HCI_LE_Read_Remote_Features_Command,
+ HCI_LE_Read_Remote_Features_Complete_Event,
+ HCI_LE_Remove_Device_From_Filter_Accept_List_Command,
+ HCI_LE_Set_Advertising_Data_Command,
+ HCI_LE_Set_Advertising_Parameters_Command,
+ HCI_LE_Set_Default_PHY_Command,
+ HCI_LE_Set_Event_Mask_Command,
+ HCI_LE_Set_Extended_Scan_Parameters_Command,
+ HCI_LE_Set_Random_Address_Command,
+ HCI_LE_Set_Scan_Enable_Command,
+ HCI_LE_Set_Scan_Parameters_Command,
+ HCI_Number_Of_Completed_Packets_Event,
+ HCI_Packet,
+ HCI_PIN_Code_Request_Reply_Command,
+ HCI_Read_Local_Supported_Commands_Command,
+ HCI_Read_Local_Supported_Features_Command,
+ HCI_Read_Local_Version_Information_Command,
+ HCI_Reset_Command,
+ HCI_Set_Event_Mask_Command,
+)
+
+
+# -----------------------------------------------------------------------------
+# pylint: disable=invalid-name
-# -----------------------------------------------------------------------------
def basic_check(x):
packet = x.to_bytes()
print(packet.hex())
@@ -27,8 +73,8 @@ def basic_check(x):
parsed_str = str(parsed)
print(x_str)
parsed_bytes = parsed.to_bytes()
- assert(x_str == parsed_str)
- assert(packet == parsed_bytes)
+ assert x_str == parsed_str
+ assert packet == parsed_bytes
# -----------------------------------------------------------------------------
@@ -44,29 +90,31 @@ def test_HCI_Event():
def test_HCI_LE_Connection_Complete_Event():
address = Address('00:11:22:33:44:55')
event = HCI_LE_Connection_Complete_Event(
- status = HCI_SUCCESS,
- connection_handle = 1,
- role = 1,
- peer_address_type = 1,
- peer_address = address,
- conn_interval = 3,
- conn_latency = 4,
- supervision_timeout = 5,
- master_clock_accuracy = 6
+ status=HCI_SUCCESS,
+ connection_handle=1,
+ role=1,
+ peer_address_type=1,
+ peer_address=address,
+ connection_interval=3,
+ peripheral_latency=4,
+ supervision_timeout=5,
+ central_clock_accuracy=6,
)
basic_check(event)
# -----------------------------------------------------------------------------
def test_HCI_LE_Advertising_Report_Event():
- address = Address('00:11:22:33:44:55')
- report = HCI_Object(
- HCI_LE_Advertising_Report_Event.REPORT_FIELDS,
- event_type = HCI_LE_Advertising_Report_Event.ADV_IND,
- address_type = Address.PUBLIC_DEVICE_ADDRESS,
- address = address,
- data = bytes.fromhex('0201061106ba5689a6fabfa2bd01467d6e00fbabad08160a181604659b03'),
- rssi = 100
+ address = Address('00:11:22:33:44:55/P')
+ report = HCI_LE_Advertising_Report_Event.Report(
+ HCI_LE_Advertising_Report_Event.Report.FIELDS,
+ event_type=HCI_LE_Advertising_Report_Event.ADV_IND,
+ address_type=Address.PUBLIC_DEVICE_ADDRESS,
+ address=address,
+ data=bytes.fromhex(
+ '0201061106ba5689a6fabfa2bd01467d6e00fbabad08160a181604659b03'
+ ),
+ rssi=100,
)
event = HCI_LE_Advertising_Report_Event([report])
basic_check(event)
@@ -75,9 +123,9 @@ def test_HCI_LE_Advertising_Report_Event():
# -----------------------------------------------------------------------------
def test_HCI_LE_Read_Remote_Features_Complete_Event():
event = HCI_LE_Read_Remote_Features_Complete_Event(
- status = HCI_SUCCESS,
- connection_handle = 0x007,
- le_features = bytes.fromhex('0011223344556677')
+ status=HCI_SUCCESS,
+ connection_handle=0x007,
+ le_features=bytes.fromhex('0011223344556677'),
)
basic_check(event)
@@ -85,11 +133,11 @@ def test_HCI_LE_Read_Remote_Features_Complete_Event():
# -----------------------------------------------------------------------------
def test_HCI_LE_Connection_Update_Complete_Event():
event = HCI_LE_Connection_Update_Complete_Event(
- status = HCI_SUCCESS,
- connection_handle = 0x007,
- conn_interval = 10,
- conn_latency = 3,
- supervision_timeout = 5
+ status=HCI_SUCCESS,
+ connection_handle=0x007,
+ connection_interval=10,
+ peripheral_latency=3,
+ supervision_timeout=5,
)
basic_check(event)
@@ -97,8 +145,7 @@ def test_HCI_LE_Connection_Update_Complete_Event():
# -----------------------------------------------------------------------------
def test_HCI_LE_Channel_Selection_Algorithm_Event():
event = HCI_LE_Channel_Selection_Algorithm_Event(
- connection_handle = 7,
- channel_selection_algorithm = 1
+ connection_handle=7, channel_selection_algorithm=1
)
basic_check(event)
@@ -107,60 +154,53 @@ def test_HCI_LE_Channel_Selection_Algorithm_Event():
def test_HCI_Command_Complete_Event():
# With a serializable object
event = HCI_Command_Complete_Event(
- num_hci_command_packets = 34,
- command_opcode = HCI_LE_READ_BUFFER_SIZE_COMMAND,
- return_parameters = HCI_LE_Read_Buffer_Size_Command.create_return_parameters(
- status = 0,
- hc_le_acl_data_packet_length = 1234,
- hc_total_num_le_acl_data_packets = 56
- )
+ num_hci_command_packets=34,
+ command_opcode=HCI_LE_READ_BUFFER_SIZE_COMMAND,
+ return_parameters=HCI_LE_Read_Buffer_Size_Command.create_return_parameters(
+ status=0,
+ hc_le_acl_data_packet_length=1234,
+ hc_total_num_le_acl_data_packets=56,
+ ),
)
basic_check(event)
# With an arbitrary byte array
event = HCI_Command_Complete_Event(
- num_hci_command_packets = 1,
- command_opcode = HCI_RESET_COMMAND,
- return_parameters = bytes([1, 2, 3, 4])
+ num_hci_command_packets=1,
+ command_opcode=HCI_RESET_COMMAND,
+ return_parameters=bytes([1, 2, 3, 4]),
)
basic_check(event)
# With a simple status as a 1-byte array
event = HCI_Command_Complete_Event(
- num_hci_command_packets = 1,
- command_opcode = HCI_RESET_COMMAND,
- return_parameters = bytes([7])
+ num_hci_command_packets=1,
+ command_opcode=HCI_RESET_COMMAND,
+ return_parameters=bytes([7]),
)
basic_check(event)
event = HCI_Packet.from_bytes(event.to_bytes())
- assert(event.return_parameters == 7)
+ assert event.return_parameters == 7
# With a simple status as an integer status
event = HCI_Command_Complete_Event(
- num_hci_command_packets = 1,
- command_opcode = HCI_RESET_COMMAND,
- return_parameters = 9
+ num_hci_command_packets=1, command_opcode=HCI_RESET_COMMAND, return_parameters=9
)
basic_check(event)
- assert(event.return_parameters == 9)
+ assert event.return_parameters == 9
# -----------------------------------------------------------------------------
def test_HCI_Command_Status_Event():
event = HCI_Command_Status_Event(
- status = 0,
- num_hci_command_packets = 37,
- command_opcode = HCI_DISCONNECT_COMMAND
+ status=0, num_hci_command_packets=37, command_opcode=HCI_DISCONNECT_COMMAND
)
basic_check(event)
# -----------------------------------------------------------------------------
def test_HCI_Number_Of_Completed_Packets_Event():
- event = HCI_Number_Of_Completed_Packets_Event([
- (1, 2),
- (3, 4)
- ])
+ event = HCI_Number_Of_Completed_Packets_Event([(1, 2), (3, 4)])
basic_check(event)
@@ -174,6 +214,23 @@ def test_HCI_Command():
# -----------------------------------------------------------------------------
+def test_HCI_PIN_Code_Request_Reply_Command():
+ pin_code = b'1234'
+ pin_code_length = len(pin_code)
+ # here to make the test pass, we need to
+ # pad pin_code, as HCI_Object.format_fields
+ # does not do it for us
+ padded_pin_code = pin_code + bytes(16 - pin_code_length)
+ command = HCI_PIN_Code_Request_Reply_Command(
+ bd_addr=Address(
+ '00:11:22:33:44:55', address_type=Address.PUBLIC_DEVICE_ADDRESS
+ ),
+ pin_code_length=pin_code_length,
+ pin_code=padded_pin_code,
+ )
+ basic_check(command)
+
+
def test_HCI_Reset_Command():
command = HCI_Reset_Command()
basic_check(command)
@@ -199,25 +256,20 @@ def test_HCI_Read_Local_Supported_Features_Command():
# -----------------------------------------------------------------------------
def test_HCI_Disconnect_Command():
- command = HCI_Disconnect_Command(
- connection_handle = 123,
- reason = 0x11
- )
+ command = HCI_Disconnect_Command(connection_handle=123, reason=0x11)
basic_check(command)
# -----------------------------------------------------------------------------
def test_HCI_Set_Event_Mask_Command():
- command = HCI_Set_Event_Mask_Command(
- event_mask = bytes.fromhex('0011223344556677')
- )
+ command = HCI_Set_Event_Mask_Command(event_mask=bytes.fromhex('0011223344556677'))
basic_check(command)
# -----------------------------------------------------------------------------
def test_HCI_LE_Set_Event_Mask_Command():
command = HCI_LE_Set_Event_Mask_Command(
- le_event_mask = bytes.fromhex('0011223344556677')
+ le_event_mask=bytes.fromhex('0011223344556677')
)
basic_check(command)
@@ -225,7 +277,7 @@ def test_HCI_LE_Set_Event_Mask_Command():
# -----------------------------------------------------------------------------
def test_HCI_LE_Set_Random_Address_Command():
command = HCI_LE_Set_Random_Address_Command(
- random_address = Address('00:11:22:33:44:55')
+ random_address=Address('00:11:22:33:44:55')
)
basic_check(command)
@@ -233,14 +285,14 @@ def test_HCI_LE_Set_Random_Address_Command():
# -----------------------------------------------------------------------------
def test_HCI_LE_Set_Advertising_Parameters_Command():
command = HCI_LE_Set_Advertising_Parameters_Command(
- advertising_interval_min = 20,
- advertising_interval_max = 30,
- advertising_type = HCI_LE_Set_Advertising_Parameters_Command.ADV_NONCONN_IND,
- own_address_type = Address.PUBLIC_DEVICE_ADDRESS,
- peer_address_type = Address.RANDOM_DEVICE_ADDRESS,
- peer_address = Address('00:11:22:33:44:55'),
- advertising_channel_map = 0x03,
- advertising_filter_policy = 1
+ advertising_interval_min=20,
+ advertising_interval_max=30,
+ advertising_type=HCI_LE_Set_Advertising_Parameters_Command.ADV_NONCONN_IND,
+ own_address_type=Address.PUBLIC_DEVICE_ADDRESS,
+ peer_address_type=Address.RANDOM_DEVICE_ADDRESS,
+ peer_address=Address('00:11:22:33:44:55'),
+ advertising_channel_map=0x03,
+ advertising_filter_policy=1,
)
basic_check(command)
@@ -248,7 +300,7 @@ def test_HCI_LE_Set_Advertising_Parameters_Command():
# -----------------------------------------------------------------------------
def test_HCI_LE_Set_Advertising_Data_Command():
command = HCI_LE_Set_Advertising_Data_Command(
- advertising_data = bytes.fromhex('AABBCC')
+ advertising_data=bytes.fromhex('AABBCC')
)
basic_check(command)
@@ -256,57 +308,72 @@ def test_HCI_LE_Set_Advertising_Data_Command():
# -----------------------------------------------------------------------------
def test_HCI_LE_Set_Scan_Parameters_Command():
command = HCI_LE_Set_Scan_Parameters_Command(
- le_scan_type = 1,
- le_scan_interval = 20,
- le_scan_window = 10,
- own_address_type = 1,
- scanning_filter_policy = 0
+ le_scan_type=1,
+ le_scan_interval=20,
+ le_scan_window=10,
+ own_address_type=1,
+ scanning_filter_policy=0,
)
basic_check(command)
# -----------------------------------------------------------------------------
def test_HCI_LE_Set_Scan_Enable_Command():
- command = HCI_LE_Set_Scan_Enable_Command(
- le_scan_enable = 1,
- filter_duplicates = 0
- )
+ command = HCI_LE_Set_Scan_Enable_Command(le_scan_enable=1, filter_duplicates=0)
basic_check(command)
# -----------------------------------------------------------------------------
def test_HCI_LE_Create_Connection_Command():
command = HCI_LE_Create_Connection_Command(
- le_scan_interval = 4,
- le_scan_window = 5,
- initiator_filter_policy = 1,
- peer_address_type = 1,
- peer_address = Address('00:11:22:33:44:55'),
- own_address_type = 2,
- conn_interval_min = 7,
- conn_interval_max = 8,
- conn_latency = 9,
- supervision_timeout = 10,
- minimum_ce_length = 11,
- maximum_ce_length = 12
+ le_scan_interval=4,
+ le_scan_window=5,
+ initiator_filter_policy=1,
+ peer_address_type=1,
+ peer_address=Address('00:11:22:33:44:55'),
+ own_address_type=2,
+ connection_interval_min=7,
+ connection_interval_max=8,
+ max_latency=9,
+ supervision_timeout=10,
+ min_ce_length=11,
+ max_ce_length=12,
)
basic_check(command)
# -----------------------------------------------------------------------------
-def test_HCI_LE_Add_Device_To_White_List_Command():
- command = HCI_LE_Add_Device_To_White_List_Command(
- address_type = 1,
- address = Address('00:11:22:33:44:55')
+def test_HCI_LE_Extended_Create_Connection_Command():
+ command = HCI_LE_Extended_Create_Connection_Command(
+ initiator_filter_policy=0,
+ own_address_type=0,
+ peer_address_type=1,
+ peer_address=Address('00:11:22:33:44:55'),
+ initiating_phys=3,
+ scan_intervals=(10, 11),
+ scan_windows=(12, 13),
+ connection_interval_mins=(14, 15),
+ connection_interval_maxs=(16, 17),
+ max_latencies=(18, 19),
+ supervision_timeouts=(20, 21),
+ min_ce_lengths=(100, 101),
+ max_ce_lengths=(102, 103),
)
basic_check(command)
# -----------------------------------------------------------------------------
-def test_HCI_LE_Remove_Device_From_White_List_Command():
- command = HCI_LE_Remove_Device_From_White_List_Command(
- address_type = 1,
- address = Address('00:11:22:33:44:55')
+def test_HCI_LE_Add_Device_To_Filter_Accept_List_Command():
+ command = HCI_LE_Add_Device_To_Filter_Accept_List_Command(
+ address_type=1, address=Address('00:11:22:33:44:55')
+ )
+ basic_check(command)
+
+
+# -----------------------------------------------------------------------------
+def test_HCI_LE_Remove_Device_From_Filter_Accept_List_Command():
+ command = HCI_LE_Remove_Device_From_Filter_Accept_List_Command(
+ address_type=1, address=Address('00:11:22:33:44:55')
)
basic_check(command)
@@ -314,31 +381,43 @@ def test_HCI_LE_Remove_Device_From_White_List_Command():
# -----------------------------------------------------------------------------
def test_HCI_LE_Connection_Update_Command():
command = HCI_LE_Connection_Update_Command(
- connection_handle = 0x0002,
- conn_interval_min = 10,
- conn_interval_max = 20,
- conn_latency = 7,
- supervision_timeout = 3,
- minimum_ce_length = 100,
- maximum_ce_length = 200
+ connection_handle=0x0002,
+ connection_interval_min=10,
+ connection_interval_max=20,
+ max_latency=7,
+ supervision_timeout=3,
+ min_ce_length=100,
+ max_ce_length=200,
)
basic_check(command)
# -----------------------------------------------------------------------------
def test_HCI_LE_Read_Remote_Features_Command():
- command = HCI_LE_Read_Remote_Features_Command(
- connection_handle = 0x0002
- )
+ command = HCI_LE_Read_Remote_Features_Command(connection_handle=0x0002)
basic_check(command)
# -----------------------------------------------------------------------------
def test_HCI_LE_Set_Default_PHY_Command():
- command = HCI_LE_Set_Default_PHY_Command(
- all_phys = 0,
- tx_phys = 1,
- rx_phys = 1
+ command = HCI_LE_Set_Default_PHY_Command(all_phys=0, tx_phys=1, rx_phys=1)
+ basic_check(command)
+
+
+# -----------------------------------------------------------------------------
+def test_HCI_LE_Set_Extended_Scan_Parameters_Command():
+ command = HCI_LE_Set_Extended_Scan_Parameters_Command(
+ own_address_type=Address.RANDOM_DEVICE_ADDRESS,
+ # pylint: disable-next=line-too-long
+ scanning_filter_policy=HCI_LE_Set_Extended_Scan_Parameters_Command.BASIC_FILTERED_POLICY,
+ scanning_phys=(1 << HCI_LE_1M_PHY_BIT | 1 << HCI_LE_CODED_PHY_BIT | 1 << 4),
+ scan_types=[
+ HCI_LE_Set_Extended_Scan_Parameters_Command.ACTIVE_SCANNING,
+ HCI_LE_Set_Extended_Scan_Parameters_Command.ACTIVE_SCANNING,
+ HCI_LE_Set_Extended_Scan_Parameters_Command.PASSIVE_SCANNING,
+ ],
+ scan_intervals=[1, 2, 3],
+ scan_windows=[4, 5, 6],
)
basic_check(command)
@@ -346,20 +425,20 @@ def test_HCI_LE_Set_Default_PHY_Command():
# -----------------------------------------------------------------------------
def test_address():
a = Address('C4:F2:17:1A:1D:BB')
- assert(not a.is_public)
- assert(a.is_random)
- assert(a.address_type == Address.RANDOM_DEVICE_ADDRESS)
- assert(not a.is_resolvable)
- assert(not a.is_resolved)
- assert(a.is_static)
+ assert not a.is_public
+ assert a.is_random
+ assert a.address_type == Address.RANDOM_DEVICE_ADDRESS
+ assert not a.is_resolvable
+ assert not a.is_resolved
+ assert a.is_static
# -----------------------------------------------------------------------------
def test_custom():
data = bytes([0x77, 0x02, 0x01, 0x03])
packet = HCI_CustomPacket(data)
- assert(packet.hci_packet_type == 0x77)
- assert(packet.payload == data)
+ assert packet.hci_packet_type == 0x77
+ assert packet.payload == data
# -----------------------------------------------------------------------------
@@ -379,6 +458,7 @@ def run_test_events():
def run_test_commands():
test_HCI_Command()
test_HCI_Reset_Command()
+ test_HCI_PIN_Code_Request_Reply_Command()
test_HCI_Read_Local_Version_Information_Command()
test_HCI_Read_Local_Supported_Commands_Command()
test_HCI_Read_Local_Supported_Features_Command()
@@ -391,11 +471,13 @@ def run_test_commands():
test_HCI_LE_Set_Scan_Parameters_Command()
test_HCI_LE_Set_Scan_Enable_Command()
test_HCI_LE_Create_Connection_Command()
- test_HCI_LE_Add_Device_To_White_List_Command()
- test_HCI_LE_Remove_Device_From_White_List_Command()
+ test_HCI_LE_Extended_Create_Connection_Command()
+ test_HCI_LE_Add_Device_To_Filter_Accept_List_Command()
+ test_HCI_LE_Remove_Device_From_Filter_Accept_List_Command()
test_HCI_LE_Connection_Update_Command()
test_HCI_LE_Read_Remote_Features_Command()
test_HCI_LE_Set_Default_PHY_Command()
+ test_HCI_LE_Set_Extended_Scan_Parameters_Command()
# -----------------------------------------------------------------------------
diff --git a/tests/import_test.py b/tests/import_test.py
index d6eafbd..e0b6e3c 100644
--- a/tests/import_test.py
+++ b/tests/import_test.py
@@ -38,7 +38,7 @@ def test_import():
sdp,
smp,
transport,
- utils
+ utils,
)
assert att
@@ -63,5 +63,67 @@ def test_import():
# -----------------------------------------------------------------------------
+def test_app_imports():
+ from apps.console import main
+
+ assert main
+
+ from apps.controller_info import main
+
+ assert main
+
+ from apps.controllers import main
+
+ assert main
+
+ from apps.gatt_dump import main
+
+ assert main
+
+ from apps.gg_bridge import main
+
+ assert main
+
+ from apps.hci_bridge import main
+
+ assert main
+
+ from apps.pair import main
+
+ assert main
+
+ from apps.scan import main
+
+ assert main
+
+ from apps.show import main
+
+ assert main
+
+ from apps.unbond import main
+
+ assert main
+
+ from apps.usb_probe import main
+
+ assert main
+
+
+# -----------------------------------------------------------------------------
+def test_profiles_imports():
+ from bumble.profiles import (
+ battery_service,
+ device_information_service,
+ heart_rate_service,
+ )
+
+ assert battery_service
+ assert device_information_service
+ assert heart_rate_service
+
+
+# -----------------------------------------------------------------------------
if __name__ == '__main__':
test_import()
+ test_app_imports()
+ test_profiles_imports()
diff --git a/tests/l2cap_test.py b/tests/l2cap_test.py
new file mode 100644
index 0000000..6f8e181
--- /dev/null
+++ b/tests/l2cap_test.py
@@ -0,0 +1,279 @@
+# Copyright 2021-2022 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# -----------------------------------------------------------------------------
+# Imports
+# -----------------------------------------------------------------------------
+import asyncio
+import logging
+import os
+import random
+import pytest
+
+from bumble.controller import Controller
+from bumble.link import LocalLink
+from bumble.device import Device
+from bumble.host import Host
+from bumble.transport import AsyncPipeSink
+from bumble.core import ProtocolError
+from bumble.l2cap import L2CAP_Connection_Request
+
+
+# -----------------------------------------------------------------------------
+# Logging
+# -----------------------------------------------------------------------------
+logger = logging.getLogger(__name__)
+
+
+# -----------------------------------------------------------------------------
+class TwoDevices:
+ def __init__(self):
+ self.connections = [None, None]
+
+ self.link = LocalLink()
+ self.controllers = [
+ Controller('C1', link=self.link),
+ Controller('C2', link=self.link),
+ ]
+ self.devices = [
+ Device(
+ address='F0:F1:F2:F3:F4:F5',
+ host=Host(self.controllers[0], AsyncPipeSink(self.controllers[0])),
+ ),
+ Device(
+ address='F5:F4:F3:F2:F1:F0',
+ host=Host(self.controllers[1], AsyncPipeSink(self.controllers[1])),
+ ),
+ ]
+
+ self.paired = [None, None]
+
+ def on_connection(self, which, connection):
+ self.connections[which] = connection
+
+ def on_paired(self, which, keys):
+ self.paired[which] = keys
+
+
+# -----------------------------------------------------------------------------
+async def setup_connection():
+ # Create two devices, each with a controller, attached to the same link
+ two_devices = TwoDevices()
+
+ # Attach listeners
+ two_devices.devices[0].on(
+ 'connection', lambda connection: two_devices.on_connection(0, connection)
+ )
+ two_devices.devices[1].on(
+ 'connection', lambda connection: two_devices.on_connection(1, connection)
+ )
+
+ # Start
+ await two_devices.devices[0].power_on()
+ await two_devices.devices[1].power_on()
+
+ # Connect the two devices
+ await two_devices.devices[0].connect(two_devices.devices[1].random_address)
+
+ # Check the post conditions
+ assert two_devices.connections[0] is not None
+ assert two_devices.connections[1] is not None
+
+ return two_devices
+
+
+# -----------------------------------------------------------------------------
+def test_helpers():
+ psm = L2CAP_Connection_Request.serialize_psm(0x01)
+ assert psm == bytes([0x01, 0x00])
+
+ psm = L2CAP_Connection_Request.serialize_psm(0x1023)
+ assert psm == bytes([0x23, 0x10])
+
+ psm = L2CAP_Connection_Request.serialize_psm(0x242311)
+ assert psm == bytes([0x11, 0x23, 0x24])
+
+ (offset, psm) = L2CAP_Connection_Request.parse_psm(
+ bytes([0x00, 0x01, 0x00, 0x44]), 1
+ )
+ assert offset == 3
+ assert psm == 0x01
+
+ (offset, psm) = L2CAP_Connection_Request.parse_psm(
+ bytes([0x00, 0x23, 0x10, 0x44]), 1
+ )
+ assert offset == 3
+ assert psm == 0x1023
+
+ (offset, psm) = L2CAP_Connection_Request.parse_psm(
+ bytes([0x00, 0x11, 0x23, 0x24, 0x44]), 1
+ )
+ assert offset == 4
+ assert psm == 0x242311
+
+ rq = L2CAP_Connection_Request(psm=0x01, source_cid=0x44)
+ brq = bytes(rq)
+ srq = L2CAP_Connection_Request.from_bytes(brq)
+ assert srq.psm == rq.psm
+ assert srq.source_cid == rq.source_cid
+
+
+# -----------------------------------------------------------------------------
+@pytest.mark.asyncio
+async def test_basic_connection():
+ devices = await setup_connection()
+ psm = 1234
+
+ # Check that if there's no one listening, we can't connect
+ with pytest.raises(ProtocolError):
+ l2cap_channel = await devices.connections[0].open_l2cap_channel(psm)
+
+ # Now add a listener
+ incoming_channel = None
+ received = []
+
+ def on_coc(channel):
+ nonlocal incoming_channel
+ incoming_channel = channel
+
+ def on_data(data):
+ received.append(data)
+
+ channel.sink = on_data
+
+ devices.devices[1].register_l2cap_channel_server(psm, on_coc)
+ l2cap_channel = await devices.connections[0].open_l2cap_channel(psm)
+
+ messages = (bytes([1, 2, 3]), bytes([4, 5, 6]), bytes(10000))
+ for message in messages:
+ l2cap_channel.write(message)
+ await asyncio.sleep(0)
+
+ await l2cap_channel.drain()
+
+ # Test closing
+ closed = [False, False]
+ closed_event = asyncio.Event()
+
+ def on_close(which, event):
+ closed[which] = True
+ if event:
+ event.set()
+
+ l2cap_channel.on('close', lambda: on_close(0, None))
+ incoming_channel.on('close', lambda: on_close(1, closed_event))
+ await l2cap_channel.disconnect()
+ assert closed == [True, True]
+ await closed_event.wait()
+
+ sent_bytes = b''.join(messages)
+ received_bytes = b''.join(received)
+ assert sent_bytes == received_bytes
+
+
+# -----------------------------------------------------------------------------
+async def transfer_payload(max_credits, mtu, mps):
+ devices = await setup_connection()
+
+ received = []
+
+ def on_coc(channel):
+ def on_data(data):
+ received.append(data)
+
+ channel.sink = on_data
+
+ psm = devices.devices[1].register_l2cap_channel_server(
+ psm=0, server=on_coc, max_credits=max_credits, mtu=mtu, mps=mps
+ )
+ l2cap_channel = await devices.connections[0].open_l2cap_channel(psm)
+
+ messages = [bytes([1, 2, 3, 4, 5, 6, 7]) * x for x in (3, 10, 100, 789)]
+ for message in messages:
+ l2cap_channel.write(message)
+ await asyncio.sleep(0)
+ if random.randint(0, 5) == 1:
+ await l2cap_channel.drain()
+
+ await l2cap_channel.drain()
+ await l2cap_channel.disconnect()
+
+ sent_bytes = b''.join(messages)
+ received_bytes = b''.join(received)
+ assert sent_bytes == received_bytes
+
+
+@pytest.mark.asyncio
+async def test_transfer():
+ for max_credits in (1, 10, 100, 10000):
+ for mtu in (50, 255, 256, 1000):
+ for mps in (50, 255, 256, 1000):
+ # print(max_credits, mtu, mps)
+ await transfer_payload(max_credits, mtu, mps)
+
+
+# -----------------------------------------------------------------------------
+@pytest.mark.asyncio
+async def test_bidirectional_transfer():
+ devices = await setup_connection()
+
+ client_received = []
+ server_received = []
+ server_channel = None
+
+ def on_server_coc(channel):
+ nonlocal server_channel
+ server_channel = channel
+
+ def on_server_data(data):
+ server_received.append(data)
+
+ channel.sink = on_server_data
+
+ def on_client_data(data):
+ client_received.append(data)
+
+ psm = devices.devices[1].register_l2cap_channel_server(psm=0, server=on_server_coc)
+ client_channel = await devices.connections[0].open_l2cap_channel(psm)
+ client_channel.sink = on_client_data
+
+ messages = [bytes([1, 2, 3, 4, 5, 6, 7]) * x for x in (3, 10, 100)]
+ for message in messages:
+ client_channel.write(message)
+ await client_channel.drain()
+ await asyncio.sleep(0)
+ server_channel.write(message)
+ await server_channel.drain()
+
+ await client_channel.disconnect()
+
+ message_bytes = b''.join(messages)
+ client_received_bytes = b''.join(client_received)
+ server_received_bytes = b''.join(server_received)
+ assert client_received_bytes == message_bytes
+ assert server_received_bytes == message_bytes
+
+
+# -----------------------------------------------------------------------------
+async def run():
+ test_helpers()
+ await test_basic_connection()
+ await test_transfer()
+ await test_bidirectional_transfer()
+
+
+# -----------------------------------------------------------------------------
+if __name__ == '__main__':
+ logging.basicConfig(level=os.environ.get('BUMBLE_LOGLEVEL', 'INFO').upper())
+ asyncio.run(run())
diff --git a/tests/pytest.ini b/tests/pytest.ini
index 6796337..13c0bbf 100644
--- a/tests/pytest.ini
+++ b/tests/pytest.ini
@@ -1,3 +1,3 @@
[pytest]
junit_logging = all
-asyncio_mode = auto \ No newline at end of file
+asyncio_mode = auto
diff --git a/tests/rfcomm_test.py b/tests/rfcomm_test.py
index 6f1c44f..9465462 100644
--- a/tests/rfcomm_test.py
+++ b/tests/rfcomm_test.py
@@ -30,10 +30,10 @@ def basic_frame_check(x):
parsed_bytes = bytes(parsed)
if len(serialized) < 500:
print('Parsed Bytes:', parsed_bytes.hex())
- assert(parsed_bytes == serialized)
+ assert parsed_bytes == serialized
x_str = str(x)
parsed_str = str(parsed)
- assert(x_str == parsed_str)
+ assert x_str == parsed_str
# -----------------------------------------------------------------------------
diff --git a/tests/sdp_test.py b/tests/sdp_test.py
index d7cf8be..f07b579 100644
--- a/tests/sdp_test.py
+++ b/tests/sdp_test.py
@@ -15,9 +15,12 @@
# -----------------------------------------------------------------------------
# Imports
# -----------------------------------------------------------------------------
-from bumble.sdp import *
from bumble.core import UUID
+from bumble.sdp import DataElement
+# -----------------------------------------------------------------------------
+# pylint: disable=invalid-name
+# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
def basic_check(x):
@@ -31,10 +34,10 @@ def basic_check(x):
parsed_bytes = bytes(parsed)
if len(serialized) < 500:
print('Parsed Bytes:', parsed_bytes.hex())
- assert(parsed_bytes == serialized)
+ assert parsed_bytes == serialized
x_str = str(x)
parsed_str = str(parsed)
- assert(x_str == parsed_str)
+ assert x_str == parsed_str
# -----------------------------------------------------------------------------
@@ -99,19 +102,25 @@ def test_data_elements():
e = DataElement(DataElement.SEQUENCE, [DataElement(DataElement.BOOLEAN, True)])
basic_check(e)
- e = DataElement(DataElement.SEQUENCE, [
- DataElement(DataElement.BOOLEAN, True),
- DataElement(DataElement.TEXT_STRING, 'hello')
- ])
+ e = DataElement(
+ DataElement.SEQUENCE,
+ [
+ DataElement(DataElement.BOOLEAN, True),
+ DataElement(DataElement.TEXT_STRING, 'hello'),
+ ],
+ )
basic_check(e)
e = DataElement(DataElement.ALTERNATIVE, [DataElement(DataElement.BOOLEAN, True)])
basic_check(e)
- e = DataElement(DataElement.ALTERNATIVE, [
- DataElement(DataElement.BOOLEAN, True),
- DataElement(DataElement.TEXT_STRING, 'hello')
- ])
+ e = DataElement(
+ DataElement.ALTERNATIVE,
+ [
+ DataElement(DataElement.BOOLEAN, True),
+ DataElement(DataElement.TEXT_STRING, 'hello'),
+ ],
+ )
basic_check(e)
e = DataElement(DataElement.URL, 'http://example.com')
@@ -133,10 +142,14 @@ def test_data_elements():
e = DataElement.boolean(True)
basic_check(e)
- e = DataElement.sequence([DataElement.signed_integer(0, 1), DataElement.text_string('hello')])
+ e = DataElement.sequence(
+ [DataElement.signed_integer(0, 1), DataElement.text_string('hello')]
+ )
basic_check(e)
- e = DataElement.alternative([DataElement.signed_integer(0, 1), DataElement.text_string('hello')])
+ e = DataElement.alternative(
+ [DataElement.signed_integer(0, 1), DataElement.text_string('hello')]
+ )
basic_check(e)
e = DataElement.url('http://foobar.com')
diff --git a/tests/self_test.py b/tests/self_test.py
index a1d2ddd..1a1a474 100644
--- a/tests/self_test.py
+++ b/tests/self_test.py
@@ -22,17 +22,16 @@ import os
import pytest
from bumble.controller import Controller
+from bumble.core import BT_BR_EDR_TRANSPORT, BT_PERIPHERAL_ROLE, BT_CENTRAL_ROLE
from bumble.link import LocalLink
from bumble.device import Device, Peer
from bumble.host import Host
from bumble.gatt import Service, Characteristic
from bumble.transport import AsyncPipeSink
+from bumble.pairing import PairingConfig, PairingDelegate
from bumble.smp import (
- PairingConfig,
- PairingDelegate,
SMP_PAIRING_NOT_SUPPORTED_ERROR,
SMP_CONFIRM_VALUE_FAILED_ERROR,
- SMP_ID_KEY_DISTRIBUTION_FLAG,
)
from bumble.core import ProtocolError
@@ -48,20 +47,21 @@ class TwoDevices:
def __init__(self):
self.connections = [None, None]
+ addresses = ['F0:F1:F2:F3:F4:F5', 'F5:F4:F3:F2:F1:F0']
self.link = LocalLink()
self.controllers = [
- Controller('C1', link = self.link),
- Controller('C2', link = self.link)
+ Controller('C1', link=self.link, public_address=addresses[0]),
+ Controller('C2', link=self.link, public_address=addresses[1]),
]
self.devices = [
Device(
- address = 'F0:F1:F2:F3:F4:F5',
- host = Host(self.controllers[0], AsyncPipeSink(self.controllers[0]))
+ address=addresses[0],
+ host=Host(self.controllers[0], AsyncPipeSink(self.controllers[0])),
),
Device(
- address = 'F5:F4:F3:F2:F1:F0',
- host = Host(self.controllers[1], AsyncPipeSink(self.controllers[1]))
- )
+ address=addresses[1],
+ host=Host(self.controllers[1], AsyncPipeSink(self.controllers[1])),
+ ),
]
self.paired = [None, None]
@@ -80,8 +80,12 @@ async def test_self_connection():
two_devices = TwoDevices()
# Attach listeners
- two_devices.devices[0].on('connection', lambda connection: two_devices.on_connection(0, connection))
- two_devices.devices[1].on('connection', lambda connection: two_devices.on_connection(1, connection))
+ two_devices.devices[0].on(
+ 'connection', lambda connection: two_devices.on_connection(0, connection)
+ )
+ two_devices.devices[1].on(
+ 'connection', lambda connection: two_devices.on_connection(1, connection)
+ )
# Start
await two_devices.devices[0].power_on()
@@ -91,8 +95,62 @@ async def test_self_connection():
await two_devices.devices[0].connect(two_devices.devices[1].random_address)
# Check the post conditions
- assert(two_devices.connections[0] is not None)
- assert(two_devices.connections[1] is not None)
+ assert two_devices.connections[0] is not None
+ assert two_devices.connections[1] is not None
+
+
+# -----------------------------------------------------------------------------
+@pytest.mark.asyncio
+@pytest.mark.parametrize(
+ 'responder_role,',
+ (BT_CENTRAL_ROLE, BT_PERIPHERAL_ROLE),
+)
+async def test_self_classic_connection(responder_role):
+ # Create two devices, each with a controller, attached to the same link
+ two_devices = TwoDevices()
+
+ # Attach listeners
+ two_devices.devices[0].on(
+ 'connection', lambda connection: two_devices.on_connection(0, connection)
+ )
+ two_devices.devices[1].on(
+ 'connection', lambda connection: two_devices.on_connection(1, connection)
+ )
+
+ # Enable Classic connections
+ two_devices.devices[0].classic_enabled = True
+ two_devices.devices[1].classic_enabled = True
+
+ # Start
+ await two_devices.devices[0].power_on()
+ await two_devices.devices[1].power_on()
+
+ # Connect the two devices
+ await asyncio.gather(
+ two_devices.devices[0].connect(
+ two_devices.devices[1].public_address, transport=BT_BR_EDR_TRANSPORT
+ ),
+ two_devices.devices[1].accept(
+ two_devices.devices[0].public_address, responder_role
+ ),
+ )
+
+ # Check the post conditions
+ assert two_devices.connections[0] is not None
+ assert two_devices.connections[1] is not None
+
+ # Check the role
+ assert two_devices.connections[0].role != responder_role
+ assert two_devices.connections[1].role == responder_role
+
+ # Role switch
+ await two_devices.connections[0].switch_role(responder_role)
+
+ # Check the role
+ assert two_devices.connections[0].role == responder_role
+ assert two_devices.connections[1].role != responder_role
+
+ await two_devices.connections[0].disconnect()
# -----------------------------------------------------------------------------
@@ -104,63 +162,117 @@ async def test_self_gatt():
# Add some GATT characteristics to device 1
c1 = Characteristic(
'3A143AD7-D4A7-436B-97D6-5B62C315E833',
- Characteristic.READ,
+ Characteristic.Properties.READ,
Characteristic.READABLE,
- bytes([1, 2, 3])
+ bytes([1, 2, 3]),
)
c2 = Characteristic(
'9557CCE2-DB37-46EB-94C4-50AE5B9CB0F8',
- Characteristic.READ | Characteristic.WRITE,
+ Characteristic.Properties.READ | Characteristic.Properties.WRITE,
Characteristic.READABLE | Characteristic.WRITEABLE,
- bytes([4, 5, 6])
+ bytes([4, 5, 6]),
)
c3 = Characteristic(
'84FC1A2E-C52D-4A2D-B8C3-8855BAB86638',
- Characteristic.READ | Characteristic.WRITE_WITHOUT_RESPONSE,
+ Characteristic.Properties.READ
+ | Characteristic.Properties.WRITE_WITHOUT_RESPONSE,
Characteristic.READABLE | Characteristic.WRITEABLE,
- bytes([7, 8, 9])
+ bytes([7, 8, 9]),
)
c4 = Characteristic(
'84FC1A2E-C52D-4A2D-B8C3-8855BAB86638',
- Characteristic.READ | Characteristic.NOTIFY | Characteristic.INDICATE,
+ Characteristic.Properties.READ
+ | Characteristic.Properties.NOTIFY
+ | Characteristic.Properties.INDICATE,
Characteristic.READABLE,
- bytes([1, 1, 1])
+ bytes([1, 1, 1]),
)
s1 = Service('8140E247-04F0-42C1-BC34-534C344DAFCA', [c1, c2, c3])
s2 = Service('97210A0F-1875-4D05-9E5D-326EB171257A', [c4])
- two_devices.devices[1].add_services([s1, s2])
+ s3 = Service('1853', [])
+ s4 = Service('3A12C182-14E2-4FE0-8C5B-65D7C569F9DB', [], included_services=[s2, s3])
+ two_devices.devices[1].add_services([s1, s2, s4])
# Start
await two_devices.devices[0].power_on()
await two_devices.devices[1].power_on()
# Connect the two devices
- connection = await two_devices.devices[0].connect(two_devices.devices[1].random_address)
+ connection = await two_devices.devices[0].connect(
+ two_devices.devices[1].random_address
+ )
peer = Peer(connection)
bogus_uuid = 'A0AA6007-0B48-4BBE-80AC-0DE9AAF541EA'
result = await peer.discover_services([bogus_uuid])
- assert(result == [])
+ assert result == []
services = peer.get_services_by_uuid(bogus_uuid)
- assert(len(services) == 0)
+ assert len(services) == 0
result = await peer.discover_service(s1.uuid)
- assert(len(result) == 1)
+ assert len(result) == 1
services = peer.get_services_by_uuid(s1.uuid)
- assert(len(services) == 1)
+ assert len(services) == 1
s = services[0]
- assert(services[0].uuid == s1.uuid)
+ assert services[0].uuid == s1.uuid
result = await peer.discover_characteristics([c1.uuid], s)
- assert(len(result) == 1)
+ assert len(result) == 1
characteristics = peer.get_characteristics_by_uuid(c1.uuid)
- assert(len(characteristics) == 1)
+ assert len(characteristics) == 1
c = characteristics[0]
- assert(c.uuid == c1.uuid)
+ assert c.uuid == c1.uuid
result = await peer.read_value(c)
- assert(result is not None)
- assert(result == c1.value)
+ assert result is not None
+ assert result == c1.value
+
+ result = await peer.discover_service(s4.uuid)
+ assert len(result) == 1
+ result = await peer.discover_included_services(result[0])
+ assert len(result) == 2
+ # Service UUID is only present when the UUID is 16-bit Bluetooth UUID
+ assert result[1].uuid.to_bytes() == s3.uuid.to_bytes()
+
+
+# -----------------------------------------------------------------------------
+@pytest.mark.asyncio
+async def test_self_gatt_long_read():
+ # Create two devices, each with a controller, attached to the same link
+ two_devices = TwoDevices()
+
+ # Add some GATT characteristics to device 1
+ characteristics = [
+ Characteristic(
+ f'3A143AD7-D4A7-436B-97D6-5B62C315{i:04X}',
+ Characteristic.Properties.READ,
+ Characteristic.READABLE,
+ bytes([x & 255 for x in range(i)]),
+ )
+ for i in range(0, 513)
+ ]
+
+ service = Service('8140E247-04F0-42C1-BC34-534C344DAFCA', characteristics)
+ two_devices.devices[1].add_service(service)
+
+ # Start
+ await two_devices.devices[0].power_on()
+ await two_devices.devices[1].power_on()
+
+ # Connect the two devices
+ connection = await two_devices.devices[0].connect(
+ two_devices.devices[1].random_address
+ )
+ peer = Peer(connection)
+
+ result = await peer.discover_service(service.uuid)
+ assert len(result) == 1
+ found_service = result[0]
+ found_characteristics = await found_service.discover_characteristics()
+ assert len(found_characteristics) == 513
+ for i, characteristic in enumerate(found_characteristics):
+ value = await characteristic.read_value()
+ assert value == characteristics[i].value
# -----------------------------------------------------------------------------
@@ -173,53 +285,85 @@ async def _test_self_smp_with_configs(pairing_config1, pairing_config2):
await two_devices.devices[1].power_on()
# Attach listeners
- two_devices.devices[0].on('connection', lambda connection: two_devices.on_connection(0, connection))
- two_devices.devices[1].on('connection', lambda connection: two_devices.on_connection(1, connection))
+ two_devices.devices[0].on(
+ 'connection', lambda connection: two_devices.on_connection(0, connection)
+ )
+ two_devices.devices[1].on(
+ 'connection', lambda connection: two_devices.on_connection(1, connection)
+ )
# Connect the two devices
- connection = await two_devices.devices[0].connect(two_devices.devices[1].random_address)
- assert(not connection.is_encrypted)
+ connection = await two_devices.devices[0].connect(
+ two_devices.devices[1].random_address
+ )
+ assert not connection.is_encrypted
# Attach connection listeners
- two_devices.connections[0].on('pairing', lambda keys: two_devices.on_paired(0, keys))
- two_devices.connections[1].on('pairing', lambda keys: two_devices.on_paired(1, keys))
+ two_devices.connections[0].on(
+ 'pairing', lambda keys: two_devices.on_paired(0, keys)
+ )
+ two_devices.connections[1].on(
+ 'pairing', lambda keys: two_devices.on_paired(1, keys)
+ )
# Set up the pairing configs
if pairing_config1:
- two_devices.devices[0].pairing_config_factory = lambda connection: pairing_config1
+ two_devices.devices[
+ 0
+ ].pairing_config_factory = lambda connection: pairing_config1
if pairing_config2:
- two_devices.devices[1].pairing_config_factory = lambda connection: pairing_config2
+ two_devices.devices[
+ 1
+ ].pairing_config_factory = lambda connection: pairing_config2
# Pair
await two_devices.devices[0].pair(connection)
- assert(connection.is_encrypted)
- assert(two_devices.paired[0] is not None)
- assert(two_devices.paired[1] is not None)
+ assert connection.is_encrypted
+ assert two_devices.paired[0] is not None
+ assert two_devices.paired[1] is not None
# -----------------------------------------------------------------------------
IO_CAP = [
- PairingDelegate.NO_OUTPUT_NO_INPUT,
- PairingDelegate.KEYBOARD_INPUT_ONLY,
- PairingDelegate.DISPLAY_OUTPUT_ONLY,
- PairingDelegate.DISPLAY_OUTPUT_AND_YES_NO_INPUT,
- PairingDelegate.DISPLAY_OUTPUT_AND_KEYBOARD_INPUT
+ PairingDelegate.IoCapability.NO_OUTPUT_NO_INPUT,
+ PairingDelegate.IoCapability.KEYBOARD_INPUT_ONLY,
+ PairingDelegate.IoCapability.DISPLAY_OUTPUT_ONLY,
+ PairingDelegate.IoCapability.DISPLAY_OUTPUT_AND_YES_NO_INPUT,
+ PairingDelegate.IoCapability.DISPLAY_OUTPUT_AND_KEYBOARD_INPUT,
]
SC = [False, True]
MITM = [False, True]
# Key distribution is a 4-bit bitmask
-# IdKey is necessary for current SMP structure
-KEY_DIST = [i for i in range(16) if (i & SMP_ID_KEY_DISTRIBUTION_FLAG)]
+KEY_DIST = range(16)
+
@pytest.mark.asyncio
-@pytest.mark.parametrize('io_cap, sc, mitm, key_dist',
- itertools.product(IO_CAP, SC, MITM, KEY_DIST)
+@pytest.mark.parametrize(
+ 'io_caps, sc, mitm, key_dist',
+ itertools.chain(
+ itertools.product([IO_CAP], SC, MITM, [15]),
+ itertools.product(
+ [[PairingDelegate.IoCapability.DISPLAY_OUTPUT_AND_KEYBOARD_INPUT]],
+ SC,
+ MITM,
+ KEY_DIST,
+ ),
+ ),
)
-async def test_self_smp(io_cap, sc, mitm, key_dist):
+async def test_self_smp(io_caps, sc, mitm, key_dist):
class Delegate(PairingDelegate):
- def __init__(self, name, io_capability, local_initiator_key_distribution, local_responder_key_distribution):
- super().__init__(io_capability, local_initiator_key_distribution,
- local_responder_key_distribution)
+ def __init__(
+ self,
+ name,
+ io_capability,
+ local_initiator_key_distribution,
+ local_responder_key_distribution,
+ ):
+ super().__init__(
+ io_capability,
+ local_initiator_key_distribution,
+ local_responder_key_distribution,
+ )
self.name = name
self.reset()
@@ -227,9 +371,10 @@ async def test_self_smp(io_cap, sc, mitm, key_dist):
self.peer_delegate = None
self.number = asyncio.get_running_loop().create_future()
+ # pylint: disable-next=unused-argument
async def compare_numbers(self, number, digits):
if self.peer_delegate is None:
- logger.warn(f'[{self.name}] no peer delegate')
+ logger.warning(f'[{self.name}] no peer delegate')
return False
await self.display_number(number, digits=6)
logger.debug(f'[{self.name}] waiting for peer number')
@@ -239,10 +384,13 @@ async def test_self_smp(io_cap, sc, mitm, key_dist):
async def get_number(self):
if self.peer_delegate is None:
- logger.warn(f'[{self.name}] no peer delegate')
+ logger.warning(f'[{self.name}] no peer delegate')
return 0
else:
- if self.peer_delegate.io_capability == PairingDelegate.KEYBOARD_INPUT_ONLY:
+ if (
+ self.peer_delegate.io_capability
+ == PairingDelegate.IoCapability.KEYBOARD_INPUT_ONLY
+ ):
peer_number = 6789
else:
logger.debug(f'[{self.name}] waiting for peer number')
@@ -259,12 +407,15 @@ async def test_self_smp(io_cap, sc, mitm, key_dist):
pairing_config_sets = [('Initiator', [None]), ('Responder', [None])]
for pairing_config_set in pairing_config_sets:
- delegate = Delegate(pairing_config_set[0], io_cap, key_dist, key_dist)
- pairing_config_set[1].append(PairingConfig(sc, mitm, True, delegate))
+ for io_cap in io_caps:
+ delegate = Delegate(pairing_config_set[0], io_cap, key_dist, key_dist)
+ pairing_config_set[1].append(PairingConfig(sc, mitm, True, delegate))
for pairing_config1 in pairing_config_sets[0][1]:
for pairing_config2 in pairing_config_sets[1][1]:
- logger.info(f'########## self_smp with {pairing_config1} and {pairing_config2}')
+ logger.info(
+ f'########## self_smp with {pairing_config1} and {pairing_config2}'
+ )
if pairing_config1:
pairing_config1.delegate.reset()
if pairing_config2:
@@ -274,7 +425,6 @@ async def test_self_smp(io_cap, sc, mitm, key_dist):
pairing_config2.delegate.peer_delegate = pairing_config1.delegate
await _test_self_smp_with_configs(pairing_config1, pairing_config2)
-
# -----------------------------------------------------------------------------
@@ -282,20 +432,20 @@ async def test_self_smp(io_cap, sc, mitm, key_dist):
async def test_self_smp_reject():
class RejectingDelegate(PairingDelegate):
def __init__(self):
- super().__init__(PairingDelegate.NO_OUTPUT_NO_INPUT)
+ super().__init__(PairingDelegate.IoCapability.NO_OUTPUT_NO_INPUT)
async def accept(self):
return False
- rejecting_pairing_config = PairingConfig(delegate = RejectingDelegate())
+ rejecting_pairing_config = PairingConfig(delegate=RejectingDelegate())
paired = False
try:
await _test_self_smp_with_configs(None, rejecting_pairing_config)
paired = True
except ProtocolError as error:
- assert(error.error_code == SMP_PAIRING_NOT_SUPPORTED_ERROR)
+ assert error.error_code == SMP_PAIRING_NOT_SUPPORTED_ERROR
- assert(not paired)
+ assert not paired
# -----------------------------------------------------------------------------
@@ -303,31 +453,37 @@ async def test_self_smp_reject():
async def test_self_smp_wrong_pin():
class WrongPinDelegate(PairingDelegate):
def __init__(self):
- super().__init__(PairingDelegate.DISPLAY_OUTPUT_AND_KEYBOARD_INPUT)
+ super().__init__(
+ PairingDelegate.IoCapability.DISPLAY_OUTPUT_AND_KEYBOARD_INPUT
+ )
async def compare_numbers(self, number, digits):
return False
- wrong_pin_pairing_config = PairingConfig(delegate = WrongPinDelegate())
+ wrong_pin_pairing_config = PairingConfig(mitm=True, delegate=WrongPinDelegate())
paired = False
try:
- await _test_self_smp_with_configs(wrong_pin_pairing_config, wrong_pin_pairing_config)
+ await _test_self_smp_with_configs(
+ wrong_pin_pairing_config, wrong_pin_pairing_config
+ )
paired = True
except ProtocolError as error:
- assert(error.error_code == SMP_CONFIRM_VALUE_FAILED_ERROR)
+ assert error.error_code == SMP_CONFIRM_VALUE_FAILED_ERROR
- assert(not paired)
+ assert not paired
# -----------------------------------------------------------------------------
async def run_test_self():
await test_self_connection()
await test_self_gatt()
+ await test_self_gatt_long_read()
await test_self_smp()
await test_self_smp_reject()
await test_self_smp_wrong_pin()
+
# -----------------------------------------------------------------------------
if __name__ == '__main__':
- logging.basicConfig(level = os.environ.get('BUMBLE_LOGLEVEL', 'INFO').upper())
+ logging.basicConfig(level=os.environ.get('BUMBLE_LOGLEVEL', 'INFO').upper())
asyncio.run(run_test_self())
diff --git a/tests/smp_test.py b/tests/smp_test.py
index 9120c47..bdfa021 100644
--- a/tests/smp_test.py
+++ b/tests/smp_test.py
@@ -15,12 +15,16 @@
# -----------------------------------------------------------------------------
# Imports
# -----------------------------------------------------------------------------
-from bumble.crypto import *
+from bumble.crypto import EccKey, aes_cmac, ah, c1, f4, f5, f6, g2, h6, h7, s1
# -----------------------------------------------------------------------------
-def reversed_hex(hex):
- return bytes(reversed(bytes.fromhex(hex)))
+# pylint: disable=invalid-name
+# -----------------------------------------------------------------------------
+
+# -----------------------------------------------------------------------------
+def reversed_hex(hex_str):
+ return bytes(reversed(bytes.fromhex(hex_str)))
# -----------------------------------------------------------------------------
@@ -29,39 +33,41 @@ def test_ecc():
x = key.x
y = key.y
- assert(len(x) == 32)
- assert(len(y) == 32)
+ assert len(x) == 32
+ assert len(y) == 32
# Test DH with test vectors from the spec
- private_A = '3f49f6d4 a3c55f38 74c9b3e3 d2103f50 4aff607b eb40b799 5899b8a6 cd3c1abd'
- private_B = '55188b3d 32f6bb9a 900afcfb eed4e72a 59cb9ac2 f19d7cfb 6b4fdd49 f47fc5fd'
- public_A_x = '20b003d2 f297be2c 5e2c83a7 e9f9a5b9 eff49111 acf4fddb cc030148 0e359de6'
- public_A_y = 'dc809c49 652aeb6d 63329abf 5a52155c 766345c2 8fed3024 741c8ed0 1589d28b'
- public_B_x = '1ea1f0f0 1faf1d96 09592284 f19e4c00 47b58afd 8615a69f 559077b2 2faaa190'
- public_B_y = '4c55f33e 429dad37 7356703a 9ab85160 472d1130 e28e3676 5f89aff9 15b1214a'
- dhkey = 'ec0234a3 57c8ad05 341010a6 0a397d9b 99796b13 b4f866f1 868d34f3 73bfa698'
+ private_A = (
+ '3f49f6d4 a3c55f38 74c9b3e3 d2103f50 4aff607b eb40b799 5899b8a6 cd3c1abd'
+ )
+ private_B = (
+ '55188b3d 32f6bb9a 900afcfb eed4e72a 59cb9ac2 f19d7cfb 6b4fdd49 f47fc5fd'
+ )
+ public_A_x = (
+ '20b003d2 f297be2c 5e2c83a7 e9f9a5b9 eff49111 acf4fddb cc030148 0e359de6'
+ )
+ public_A_y = (
+ 'dc809c49 652aeb6d 63329abf 5a52155c 766345c2 8fed3024 741c8ed0 1589d28b'
+ )
+ public_B_x = (
+ '1ea1f0f0 1faf1d96 09592284 f19e4c00 47b58afd 8615a69f 559077b2 2faaa190'
+ )
+ public_B_y = (
+ '4c55f33e 429dad37 7356703a 9ab85160 472d1130 e28e3676 5f89aff9 15b1214a'
+ )
+ dhkey = 'ec0234a3 57c8ad05 341010a6 0a397d9b 99796b13 b4f866f1 868d34f3 73bfa698'
key_a = EccKey.from_private_key_bytes(
- bytes.fromhex(private_A),
- bytes.fromhex(public_A_x),
- bytes.fromhex(public_A_y)
- )
- shared_key = key_a.dh(
- bytes.fromhex(public_B_x),
- bytes.fromhex(public_B_y)
+ bytes.fromhex(private_A), bytes.fromhex(public_A_x), bytes.fromhex(public_A_y)
)
- assert(shared_key == bytes.fromhex(dhkey))
+ shared_key = key_a.dh(bytes.fromhex(public_B_x), bytes.fromhex(public_B_y))
+ assert shared_key == bytes.fromhex(dhkey)
key_b = EccKey.from_private_key_bytes(
- bytes.fromhex(private_B),
- bytes.fromhex(public_B_x),
- bytes.fromhex(public_B_y)
+ bytes.fromhex(private_B), bytes.fromhex(public_B_x), bytes.fromhex(public_B_y)
)
- shared_key = key_b.dh(
- bytes.fromhex(public_A_x),
- bytes.fromhex(public_A_y)
- )
- assert(shared_key == bytes.fromhex(dhkey))
+ shared_key = key_b.dh(bytes.fromhex(public_A_x), bytes.fromhex(public_A_y))
+ assert shared_key == bytes.fromhex(dhkey)
# -----------------------------------------------------------------------------
@@ -75,7 +81,7 @@ def test_c1():
rat = 0
ra = reversed_hex('B1B2B3B4B5B6')
result = c1(k, r, preq, pres, iat, rat, ia, ra)
- assert(result == reversed_hex('1e1e3fef878988ead2a74dc5bef13b86'))
+ assert result == reversed_hex('1e1e3fef878988ead2a74dc5bef13b86')
# -----------------------------------------------------------------------------
@@ -84,7 +90,7 @@ def test_s1():
r1 = reversed_hex('000F0E0D0C0B0A091122334455667788')
r2 = reversed_hex('010203040506070899AABBCCDDEEFF00')
result = s1(k, r1, r2)
- assert(result == reversed_hex('9a1fe1f0e8b0f49b5b4216ae796da062'))
+ assert result == reversed_hex('9a1fe1f0e8b0f49b5b4216ae796da062')
# -----------------------------------------------------------------------------
@@ -92,59 +98,77 @@ def test_aes_cmac():
m = b''
k = bytes.fromhex('2b7e1516 28aed2a6 abf71588 09cf4f3c')
cmac = aes_cmac(m, k)
- assert(cmac == bytes.fromhex('bb1d6929 e9593728 7fa37d12 9b756746'))
+ assert cmac == bytes.fromhex('bb1d6929 e9593728 7fa37d12 9b756746')
m = bytes.fromhex('6bc1bee2 2e409f96 e93d7e11 7393172a')
cmac = aes_cmac(m, k)
- assert(cmac == bytes.fromhex('070a16b4 6b4d4144 f79bdd9d d04a287c'))
+ assert cmac == bytes.fromhex('070a16b4 6b4d4144 f79bdd9d d04a287c')
m = bytes.fromhex(
- '6bc1bee2 2e409f96 e93d7e11 7393172a' +
- 'ae2d8a57 1e03ac9c 9eb76fac 45af8e51' +
- '30c81c46 a35ce411'
+ '6bc1bee2 2e409f96 e93d7e11 7393172a'
+ + 'ae2d8a57 1e03ac9c 9eb76fac 45af8e51'
+ + '30c81c46 a35ce411'
)
cmac = aes_cmac(m, k)
- assert(cmac == bytes.fromhex('dfa66747 de9ae630 30ca3261 1497c827'))
+ assert cmac == bytes.fromhex('dfa66747 de9ae630 30ca3261 1497c827')
m = bytes.fromhex(
- '6bc1bee2 2e409f96 e93d7e11 7393172a' +
- 'ae2d8a57 1e03ac9c 9eb76fac 45af8e51' +
- '30c81c46 a35ce411 e5fbc119 1a0a52ef' +
- 'f69f2445 df4f9b17 ad2b417b e66c3710'
+ '6bc1bee2 2e409f96 e93d7e11 7393172a'
+ + 'ae2d8a57 1e03ac9c 9eb76fac 45af8e51'
+ + '30c81c46 a35ce411 e5fbc119 1a0a52ef'
+ + 'f69f2445 df4f9b17 ad2b417b e66c3710'
)
cmac = aes_cmac(m, k)
- assert(cmac == bytes.fromhex('51f0bebf 7e3b9d92 fc497417 79363cfe'))
+ assert cmac == bytes.fromhex('51f0bebf 7e3b9d92 fc497417 79363cfe')
# -----------------------------------------------------------------------------
def test_f4():
- u = bytes(reversed(bytes.fromhex(
- '20b003d2 f297be2c 5e2c83a7 e9f9a5b9' +
- 'eff49111 acf4fddb cc030148 0e359de6'
- )))
- v = bytes(reversed(bytes.fromhex(
- '55188b3d 32f6bb9a 900afcfb eed4e72a' +
- '59cb9ac2 f19d7cfb 6b4fdd49 f47fc5fd'
- )))
+ u = bytes(
+ reversed(
+ bytes.fromhex(
+ '20b003d2 f297be2c 5e2c83a7 e9f9a5b9'
+ + 'eff49111 acf4fddb cc030148 0e359de6'
+ )
+ )
+ )
+ v = bytes(
+ reversed(
+ bytes.fromhex(
+ '55188b3d 32f6bb9a 900afcfb eed4e72a'
+ + '59cb9ac2 f19d7cfb 6b4fdd49 f47fc5fd'
+ )
+ )
+ )
x = bytes(reversed(bytes.fromhex('d5cb8454 d177733e ffffb2ec 712baeab')))
z = bytes([0])
value = f4(u, v, x, z)
- assert(bytes(reversed(value)) == bytes.fromhex('f2c916f1 07a9bd1c f1eda1be a974872d'))
+ assert bytes(reversed(value)) == bytes.fromhex(
+ 'f2c916f1 07a9bd1c f1eda1be a974872d'
+ )
# -----------------------------------------------------------------------------
def test_f5():
- w = bytes(reversed(bytes.fromhex(
- 'ec0234a3 57c8ad05 341010a6 0a397d9b' +
- '99796b13 b4f866f1 868d34f3 73bfa698'
- )))
+ w = bytes(
+ reversed(
+ bytes.fromhex(
+ 'ec0234a3 57c8ad05 341010a6 0a397d9b'
+ + '99796b13 b4f866f1 868d34f3 73bfa698'
+ )
+ )
+ )
n1 = bytes(reversed(bytes.fromhex('d5cb8454 d177733e ffffb2ec 712baeab')))
n2 = bytes(reversed(bytes.fromhex('a6e8e7cc 25a75f6e 216583f7 ff3dc4cf')))
a1 = bytes(reversed(bytes.fromhex('00561237 37bfce')))
a2 = bytes(reversed(bytes.fromhex('00a71370 2dcfc1')))
value = f5(w, n1, n2, a1, a2)
- assert(bytes(reversed(value[0])) == bytes.fromhex('2965f176 a1084a02 fd3f6a20 ce636e20'))
- assert(bytes(reversed(value[1])) == bytes.fromhex('69867911 69d7cd23 980522b5 94750a38'))
+ assert bytes(reversed(value[0])) == bytes.fromhex(
+ '2965f176 a1084a02 fd3f6a20 ce636e20'
+ )
+ assert bytes(reversed(value[1])) == bytes.fromhex(
+ '69867911 69d7cd23 980522b5 94750a38'
+ )
# -----------------------------------------------------------------------------
@@ -157,37 +181,47 @@ def test_f6():
a1 = bytes(reversed(bytes.fromhex('00561237 37bfce')))
a2 = bytes(reversed(bytes.fromhex('00a71370 2dcfc1')))
value = f6(mac_key, n1, n2, r, io_cap, a1, a2)
- assert(bytes(reversed(value)) == bytes.fromhex('e3c47398 9cd0e8c5 d26c0b09 da958f61'))
+ assert bytes(reversed(value)) == bytes.fromhex(
+ 'e3c47398 9cd0e8c5 d26c0b09 da958f61'
+ )
# -----------------------------------------------------------------------------
def test_g2():
- u = bytes(reversed(bytes.fromhex(
- '20b003d2 f297be2c 5e2c83a7 e9f9a5b9' +
- 'eff49111 acf4fddb cc030148 0e359de6'
- )))
- v = bytes(reversed(bytes.fromhex(
- '55188b3d 32f6bb9a 900afcfb eed4e72a' +
- '59cb9ac2 f19d7cfb 6b4fdd49 f47fc5fd'
- )))
+ u = bytes(
+ reversed(
+ bytes.fromhex(
+ '20b003d2 f297be2c 5e2c83a7 e9f9a5b9'
+ + 'eff49111 acf4fddb cc030148 0e359de6'
+ )
+ )
+ )
+ v = bytes(
+ reversed(
+ bytes.fromhex(
+ '55188b3d 32f6bb9a 900afcfb eed4e72a'
+ + '59cb9ac2 f19d7cfb 6b4fdd49 f47fc5fd'
+ )
+ )
+ )
x = bytes(reversed(bytes.fromhex('d5cb8454 d177733e ffffb2ec 712baeab')))
y = bytes(reversed(bytes.fromhex('a6e8e7cc 25a75f6e 216583f7 ff3dc4cf')))
value = g2(u, v, x, y)
- assert(value == 0x2f9ed5ba)
+ assert value == 0x2F9ED5BA
# -----------------------------------------------------------------------------
def test_h6():
KEY = bytes.fromhex('ec0234a3 57c8ad05 341010a6 0a397d9b')
KEY_ID = bytes.fromhex('6c656272')
- assert(h6(KEY, KEY_ID) == bytes.fromhex('2d9ae102 e76dc91c e8d3a9e2 80b16399'))
+ assert h6(KEY, KEY_ID) == bytes.fromhex('2d9ae102 e76dc91c e8d3a9e2 80b16399')
# -----------------------------------------------------------------------------
def test_h7():
KEY = bytes.fromhex('ec0234a3 57c8ad05 341010a6 0a397d9b')
SALT = bytes.fromhex('00000000 00000000 00000000 746D7031')
- assert(h7(SALT, KEY) == bytes.fromhex('fb173597 c6a3c0ec d2998c2a 75a57011'))
+ assert h7(SALT, KEY) == bytes.fromhex('fb173597 c6a3c0ec d2998c2a 75a57011')
# -----------------------------------------------------------------------------
@@ -196,7 +230,7 @@ def test_ah():
prand = bytes(reversed(bytes.fromhex('708194')))
value = ah(irk, prand)
expected = bytes(reversed(bytes.fromhex('0dfbaa')))
- assert(value == expected)
+ assert value == expected
# -----------------------------------------------------------------------------
diff --git a/tests/transport_test.py b/tests/transport_test.py
index 3005345..cd3c5f2 100644
--- a/tests/transport_test.py
+++ b/tests/transport_test.py
@@ -37,7 +37,9 @@ def test_parser():
parser2 = PacketParser(sink2)
for parser in [parser1, parser2]:
- with open(os.path.join(os.path.dirname(__file__), 'hci_data_001.bin'), 'rb') as input:
+ with open(
+ os.path.join(os.path.dirname(__file__), 'hci_data_001.bin'), 'rb'
+ ) as input:
while True:
n = random.randint(1, 9)
data = input.read(n)
@@ -45,7 +47,7 @@ def test_parser():
break
parser.feed_data(data)
- assert(sink1.packets == sink2.packets)
+ assert sink1.packets == sink2.packets
# -----------------------------------------------------------------------------
@@ -60,15 +62,16 @@ def test_parser_extensions():
except ValueError:
exception_thrown = True
- assert(exception_thrown)
+ assert exception_thrown
# Now add a custom info
parser.extended_packet_info[0x77] = (1, 1, 'B')
parser.reset()
parser.feed_data(bytes([0x77, 0x00, 0x02, 0x01, 0x02]))
- assert(len(sink.packets) == 1)
+ assert len(sink.packets) == 1
# -----------------------------------------------------------------------------
-test_parser()
-test_parser_extensions() \ No newline at end of file
+if __name__ == '__main__':
+ test_parser()
+ test_parser_extensions()
diff --git a/web/index.html b/web/index.html
index c8c77e0..4374db0 100644
--- a/web/index.html
+++ b/web/index.html
@@ -128,4 +128,4 @@
}
</script>
</body>
-</html> \ No newline at end of file
+</html>
diff --git a/web/scanner.py b/web/scanner.py
index 9ab9f47..59eda67 100644
--- a/web/scanner.py
+++ b/web/scanner.py
@@ -16,14 +16,16 @@
# Imports
# -----------------------------------------------------------------------------
from bumble.device import Device
-from bumble.transport import PacketParser
+from bumble.transport.common import PacketParser
# -----------------------------------------------------------------------------
class ScannerListener(Device.Listener):
- def on_advertisement(self, address, ad_data, rssi, connectable):
- address_type_string = ('P', 'R', 'PI', 'RI')[address.address_type]
- print(f'>>> {address} [{address_type_string}]: RSSI={rssi}, {ad_data}')
+ def on_advertisement(self, advertisement):
+ address_type_string = ('P', 'R', 'PI', 'RI')[advertisement.address.address_type]
+ print(
+ f'>>> {advertisement.address} [{address_type_string}]: RSSI={advertisement.rssi}, {advertisement.ad_data}'
+ )
class HciSource: