From 17a58fec211f7e7614434202316f019df1b09597 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Mon, 23 Jul 2018 14:44:59 -0400 Subject: [PATCH 001/332] Add models dir --- atst/models/__init__.py | 0 atst/models/request.py | 32 ++++++++++++++++++++++++++++++++ atst/models/status_event.py | 17 +++++++++++++++++ atst/models/types.py | 10 ++++++++++ 4 files changed, 59 insertions(+) create mode 100644 atst/models/__init__.py create mode 100644 atst/models/request.py create mode 100644 atst/models/status_event.py create mode 100644 atst/models/types.py diff --git a/atst/models/__init__.py b/atst/models/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/atst/models/request.py b/atst/models/request.py new file mode 100644 index 00000000..5762e857 --- /dev/null +++ b/atst/models/request.py @@ -0,0 +1,32 @@ +from sqlalchemy import Column, func +from sqlalchemy.types import DateTime +from sqlalchemy.dialects.postgresql import JSONB, UUID +from sqlalchemy.orm import relationship + +from requests_queue.models import Base +from requests_queue.models.types import Id + + +class Request(Base): + __tablename__ = 'requests' + + id = Id() + creator = Column(UUID(as_uuid=True)) + time_created = Column(DateTime(timezone=True), server_default=func.now()) + body = Column(JSONB) + status_events = relationship('StatusEvent', + backref='request', + order_by='StatusEvent.sequence') + + @property + def status(self): + return self.status_events[-1].new_status + + @property + def action_required_by(self): + return { + "incomplete": "mission_owner", + "pending_submission": "mission_owner", + "submitted": "ccpo", + "approved": "mission_owner", + }.get(self.status) diff --git a/atst/models/status_event.py b/atst/models/status_event.py new file mode 100644 index 00000000..c5c5c715 --- /dev/null +++ b/atst/models/status_event.py @@ -0,0 +1,17 @@ +from sqlalchemy import Column, func, ForeignKey +from sqlalchemy.types import DateTime, String, BigInteger +from sqlalchemy.schema import Sequence +from sqlalchemy.dialects.postgresql import UUID + +from requests_queue.models import Base +from requests_queue.models.types import Id + + +class StatusEvent(Base): + __tablename__ = 'status_events' + + id = Id() + new_status = Column(String()) + time_created = Column(DateTime(timezone=True), server_default=func.now()) + request_id = Column(UUID(as_uuid=True), ForeignKey('requests.id', ondelete='CASCADE')) + sequence = Column(BigInteger, Sequence('status_events_sequence_seq'), nullable=False) diff --git a/atst/models/types.py b/atst/models/types.py new file mode 100644 index 00000000..b2e1c6d7 --- /dev/null +++ b/atst/models/types.py @@ -0,0 +1,10 @@ +import sqlalchemy +from sqlalchemy import Column +from sqlalchemy.dialects.postgresql import UUID + + +def Id(): + return Column( + UUID(as_uuid=True), + primary_key=True, + server_default=sqlalchemy.text("uuid_generate_v4()")) From 543250377ca5a81661c6b5d7474018988f7ac6ec Mon Sep 17 00:00:00 2001 From: richard-dds Date: Mon, 23 Jul 2018 14:45:08 -0400 Subject: [PATCH 002/332] Merge pipfiles --- Pipfile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Pipfile b/Pipfile index eb946fb9..81cadd0d 100644 --- a/Pipfile +++ b/Pipfile @@ -10,6 +10,9 @@ Unipath = "==1.1" wtforms-tornado = "*" pendulum = "*" redis = "*" +sqlalchemy = "*" +alembic = "*" +"psycopg2-binary" = "*" [dev-packages] bandit = "*" @@ -20,6 +23,7 @@ ipdb = "*" pylint = "*" black = "*" pytest-watch = "*" +factory-boy = "*" [requires] python_version = "3.6" From 024051ae07987848ebe40a77e8c336352a591581 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Mon, 23 Jul 2018 14:58:26 -0400 Subject: [PATCH 003/332] Models and migrations for requests --- Pipfile.lock | 180 ++++++++++++------ alembic.ini | 74 +++++++ alembic/README | 1 + alembic/env.py | 85 +++++++++ alembic/script.py.mako | 24 +++ alembic/versions/b5b17d465166_requests.py | 44 +++++ .../ff1c9c02fa61_enable_uuid_extension.py | 26 +++ atst/database.py | 8 + atst/models/__init__.py | 6 + atst/models/request.py | 4 +- ...tatus_event.py => request_status_event.py} | 10 +- config/base.ini | 1 + 12 files changed, 401 insertions(+), 62 deletions(-) create mode 100644 alembic.ini create mode 100644 alembic/README create mode 100644 alembic/env.py create mode 100644 alembic/script.py.mako create mode 100644 alembic/versions/b5b17d465166_requests.py create mode 100644 alembic/versions/ff1c9c02fa61_enable_uuid_extension.py create mode 100644 atst/database.py rename atst/models/{status_event.py => request_status_event.py} (63%) diff --git a/Pipfile.lock b/Pipfile.lock index 2fadae1e..d87dfa97 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "3bea02ccdb0e3877f2595d7fb405408114ec8947e0484d5b4aaf14a4c8ff78b2" + "sha256": "7cd87f2c2c42bc776a6aa6f72fcbb8b30d4e703e50b6480ce1c8ace6ae6dd0a4" }, "pipfile-spec": 6, "requires": { @@ -16,6 +16,26 @@ ] }, "default": { + "alembic": { + "hashes": [ + "sha256:52d73b1d750f1414fa90c25a08da47b87de1e4ad883935718a8f36396e19e78e", + "sha256:eb7db9b4510562ec37c91d00b00d95fde076c1030d3f661aea882eec532b3565" + ], + "index": "pypi", + "version": "==1.0.0" + }, + "mako": { + "hashes": [ + "sha256:4e02fde57bd4abb5ec400181e4c314f56ac3e49ba4fb8b0d50bba18cb27d25ae" + ], + "version": "==1.0.7" + }, + "markupsafe": { + "hashes": [ + "sha256:a6be69091dac236ea9c6bc7d012beab42010fa914c459791d627dad4910eb665" + ], + "version": "==1.0" + }, "pendulum": { "hashes": [ "sha256:0643d45824e6789b88187728337dfa6075a0233f6976c2abefba00d064156309", @@ -32,6 +52,42 @@ "index": "pypi", "version": "==2.0.2" }, + "psycopg2-binary": { + "hashes": [ + "sha256:04afb59bbbd2eab3148e6816beddc74348078b8c02a1113ea7f7822f5be4afe3", + "sha256:098b18f4d8857a8f9b206d1dc54db56c2255d5d26458917e7bcad61ebfe4338f", + "sha256:0bf855d4a7083e20ead961fda4923887094eaeace0ab2d76eb4aa300f4bbf5bd", + "sha256:197dda3ffd02057820be83fe4d84529ea70bf39a9a4daee1d20ffc74eb3d042e", + "sha256:278ef63afb4b3d842b4609f2c05ffbfb76795cf6a184deeb8707cd5ed3c981a5", + "sha256:3cbf8c4fc8f22f0817220891cf405831559f4d4c12c4f73913730a2ea6c47a47", + "sha256:4305aed922c4d9d6163ab3a41d80b5a1cfab54917467da8168552c42cad84d32", + "sha256:47ee296f704fb8b2a616dec691cdcfd5fa0f11943955e88faa98cbd1dc3b3e3d", + "sha256:4a0e38cb30457e70580903367161173d4a7d1381eb2f2cfe4e69b7806623f484", + "sha256:4d6c294c6638a71cafb82a37f182f24321f1163b08b5d5ca076e11fe838a3086", + "sha256:4f3233c366500730f839f92833194fd8f9a5c4529c8cd8040aa162c3740de8e5", + "sha256:5221f5a3f4ca2ddf0d58e8b8a32ca50948be9a43351fda797eb4e72d7a7aa34d", + "sha256:5c6ca0b507540a11eaf9e77dee4f07c131c2ec80ca0cffa146671bf690bc1c02", + "sha256:789bd89d71d704db2b3d5e67d6d518b158985d791d3b2dec5ab85457cfc9677b", + "sha256:7b94d29239efeaa6a967f3b5971bd0518d2a24edd1511edbf4a2c8b815220d07", + "sha256:89bc65ef3301c74cf32db25334421ea6adbe8f65601ea45dcaaf095abed910bb", + "sha256:89d6d3a549f405c20c9ae4dc94d7ed2de2fa77427a470674490a622070732e62", + "sha256:97521704ac7127d7d8ba22877da3c7bf4a40366587d238ec679ff38e33177498", + "sha256:a395b62d5f44ff6f633231abe568e2203b8fabf9797cd6386aa92497df912d9a", + "sha256:a6d32c37f714c3f34158f3fa659f3a8f2658d5f53c4297d45579b9677cc4d852", + "sha256:a89ee5c26f72f2d0d74b991ce49e42ddeb4ac0dc2d8c06a0f2770a1ab48f4fe0", + "sha256:b4c8b0ef3608e59317bfc501df84a61e48b5445d45f24d0391a24802de5f2d84", + "sha256:b5fcf07140219a1f71e18486b8dc28e2e1b76a441c19374805c617aa6d9a9d55", + "sha256:b86f527f00956ecebad6ab3bb30e3a75fedf1160a8716978dd8ce7adddedd86f", + "sha256:be4c4aa22ba22f70de36c98b06480e2f1697972d49eb20d525f400d204a6d272", + "sha256:c2ac7aa1a144d4e0e613ac7286dae85671e99fe7a1353954d4905629c36b811c", + "sha256:de26ef4787b5e778e8223913a3e50368b44e7480f83c76df1f51d23bd21cea16", + "sha256:e70ebcfc5372dc7b699c0110454fc4263967f30c55454397e5769eb72c0eb0ce", + "sha256:eadbd32b6bc48b67b0457fccc94c86f7ccc8178ab839f684eb285bb592dc143e", + "sha256:ecbc6dfff6db06b8b72ae8a2f25ff20fbdcb83cb543811a08f7cb555042aa729" + ], + "index": "pypi", + "version": "==2.7.5" + }, "python-dateutil": { "hashes": [ "sha256:1adb80e7a782c12e52ef9a8182bebeb73f1d7e24e374397af06fb4956c8dc5c0", @@ -39,12 +95,18 @@ ], "version": "==2.7.3" }, + "python-editor": { + "hashes": [ + "sha256:a3c066acee22a1c94f63938341d4fb374e3fdd69366ed6603d7b24bed1efc565" + ], + "version": "==1.0.3" + }, "pytzdata": { "hashes": [ "sha256:1d936da41ee06216d89fdc7ead1ee9a5da2811a8787515a976b646e110c3f622", "sha256:e4ef42e82b0b493c5849eed98b5ab49d6767caf982127e9a33167f1153b36cc5" ], - "markers": "python_version != '3.3.*' and python_version >= '2.7' and python_version != '3.2.*' and python_version != '3.1.*' and python_version != '3.0.*'", + "markers": "python_version != '3.1.*' and python_version != '3.2.*' and python_version != '3.0.*' and python_version != '3.3.*' and python_version >= '2.7'", "version": "==2018.5" }, "redis": { @@ -62,6 +124,13 @@ ], "version": "==1.11.0" }, + "sqlalchemy": { + "hashes": [ + "sha256:72325e67fb85f6e9ad304c603d83626d1df684fdf0c7ab1f0352e71feeab69d8" + ], + "index": "pypi", + "version": "==1.2.10" + }, "tornado": { "hashes": [ "sha256:1b83d5c10550f2653380b4c77331d6f8850f287c4f67d7ce1e1c639d9222fbc7", @@ -128,10 +197,10 @@ }, "astroid": { "hashes": [ - "sha256:a8d8c7fe34e34e868426b9bafce852c355a3951eef60bc831b2ed541558f8d37", - "sha256:e722228b5259ce8c7cbf75f3b0ee8b483cfbd4df01167474a84087d1aeade22c" + "sha256:0a0c484279a5f08c9bcedd6fa9b42e378866a7dcc695206b92d59dc9f2d9760d", + "sha256:218e36cf8d98a42f16214e8670819ce307fa707d1dcf7f9af84c7aede1febc7f" ], - "version": "==2.0.0.dev4" + "version": "==2.0.1" }, "atomicwrites": { "hashes": [ @@ -197,19 +266,35 @@ ], "version": "==0.6.2" }, + "factory-boy": { + "hashes": [ + "sha256:6f25cc4761ac109efd503f096e2ad99421b1159f01a29dbb917359dcd68e08ca", + "sha256:d552cb872b310ae78bd7429bf318e42e1e903b1a109e899a523293dfa762ea4f" + ], + "index": "pypi", + "version": "==2.11.1" + }, + "faker": { + "hashes": [ + "sha256:0e9a1227a3a0f3297a485715e72ee6eb77081b17b629367042b586e38c03c867", + "sha256:b4840807a94a3bad0217d6ed3f9b65a1cc6e1db1c99e1184673056ae2c0a4c4d" + ], + "markers": "python_version != '3.2.*' and python_version != '3.0.*' and python_version >= '2.7' and python_version != '3.1.*'", + "version": "==0.8.17" + }, "gitdb2": { "hashes": [ - "sha256:b60e29d4533e5e25bb50b7678bbc187c8f6bcff1344b4f293b2ba55c85795f09", - "sha256:cf9a4b68e8c4da8d42e48728c944ff7af2d8c9db303ac1ab32eac37aa4194b0e" + "sha256:87783b7f4a8f6b71c7fe81d32179b3c8781c1a7d6fa0c69bff2f315b00aff4f8", + "sha256:bb4c85b8a58531c51373c89f92163b92f30f81369605a67cd52d1fc21246c044" ], - "version": "==2.0.3" + "version": "==2.0.4" }, "gitpython": { "hashes": [ - "sha256:1ec4c44846cf76a1e55769560673a97731849c9d05401e035e607495f10db959", - "sha256:b60b045cf64a321e5b620debb49890099fa6c7be6dfb7fb249027e5d34227301" + "sha256:563221e5a44369c6b79172f455584c9ebbb122a13368cc82cb4b5addff788f82", + "sha256:8237dc5bfd6f1366abeee5624111b9d6879393d84745a507de0fda86043b65a8" ], - "version": "==2.1.10" + "version": "==2.1.11" }, "ipdb": { "hashes": [ @@ -239,7 +324,7 @@ "sha256:b9c40e9750f3d77e6e4d441d8b0266cf555e7cdabdcff33c4fd06366ca761ef8", "sha256:ec9ef8f4a9bc6f71eec99e1806bfa2de401650d996c59330782b89a5555c1497" ], - "markers": "python_version != '3.3.*' and python_version >= '2.7' and python_version != '3.2.*' and python_version != '3.1.*' and python_version != '3.0.*'", + "markers": "python_version >= '2.7' and python_version != '3.1.*' and python_version != '3.3.*' and python_version != '3.0.*' and python_version != '3.2.*'", "version": "==4.3.4" }, "jedi": { @@ -313,10 +398,10 @@ }, "pbr": { "hashes": [ - "sha256:4f2b11d95917af76e936811be8361b2b19616e5ef3b55956a429ec7864378e0c", - "sha256:e0f23b61ec42473723b2fec2f33fb12558ff221ee551962f01dd4de9053c2055" + "sha256:754e766b4f4bad3aa68cfd532456298da1aa39375da8748392dbae90860d5f18", + "sha256:c6bddbad814f23c7faaf88d8a186e9965243cc6206a23361b73023648e645794" ], - "version": "==4.1.0" + "version": "==4.1.1" }, "pexpect": { "hashes": [ @@ -339,7 +424,7 @@ "sha256:d345c8fe681115900d6da8d048ba67c25df42973bda370783cd58826442dcd7c", "sha256:e160a7fcf25762bb60efc7e171d4497ff1d8d2d75a3d0df7a21b76821ecbf5c5" ], - "markers": "python_version != '3.3.*' and python_version >= '2.7' and python_version != '3.2.*' and python_version != '3.1.*' and python_version != '3.0.*'", + "markers": "python_version >= '2.7' and python_version != '3.1.*' and python_version != '3.3.*' and python_version != '3.0.*' and python_version != '3.2.*'", "version": "==0.6.0" }, "prompt-toolkit": { @@ -362,7 +447,7 @@ "sha256:3fd59af7435864e1a243790d322d763925431213b6b8529c6ca71081ace3bbf7", "sha256:e31fb2767eb657cbde86c454f02e99cb846d3cd9d61b318525140214fdc0e98e" ], - "markers": "python_version != '3.3.*' and python_version >= '2.7' and python_version != '3.2.*' and python_version != '3.1.*' and python_version != '3.0.*'", + "markers": "python_version >= '2.7' and python_version != '3.1.*' and python_version != '3.3.*' and python_version != '3.0.*' and python_version != '3.2.*'", "version": "==1.5.4" }, "pygments": { @@ -374,11 +459,11 @@ }, "pylint": { "hashes": [ - "sha256:285c9ae7255acb584057fe31051a37498985e632b99fc0ec93b7eb38a1b137f9", - "sha256:dd5c0fc4e6a4cb9483a4367699099a7dfc8a13de9ecac4cb16855ffac68d49de" + "sha256:2c90a24bee8fae22ac98061c896e61f45c5b73c2e0511a4bf53f99ba56e90434", + "sha256:454532779425098969b8f54ab0f056000b883909f69d05905ea114df886e3251" ], "index": "pypi", - "version": "==2.0.0.dev2" + "version": "==2.0.1" }, "pytest": { "hashes": [ @@ -403,6 +488,13 @@ "index": "pypi", "version": "==4.2.0" }, + "python-dateutil": { + "hashes": [ + "sha256:1adb80e7a782c12e52ef9a8182bebeb73f1d7e24e374397af06fb4956c8dc5c0", + "sha256:e27001de32f627c22380a688bcc43ce83504a7bc5da472209b4c70f02829f0b8" + ], + "version": "==2.7.3" + }, "pyyaml": { "hashes": [ "sha256:254bf6fda2b7c651837acb2c718e213df29d531eebf00edb54743d10bcb694eb", @@ -428,17 +520,24 @@ }, "smmap2": { "hashes": [ - "sha256:b78ee0f1f5772d69ff50b1cbdb01b8c6647a8354f02f23b488cf4b2cfc923956", - "sha256:c7530db63f15f09f8251094b22091298e82bf6c699a6b8344aaaef3f2e1276c3" + "sha256:0dd53d991af487f9b22774fa89451358da3607c02b9b886a54736c6a313ece0b", + "sha256:dc216005e529d57007ace27048eb336dcecb7fc413cfb3b2f402bb25972b69c6" ], - "version": "==2.0.3" + "version": "==2.0.4" }, "stevedore": { "hashes": [ - "sha256:e3d96b2c4e882ec0c1ff95eaebf7b575a779fd0ccb4c741b9832bed410d58b3d", - "sha256:f1c7518e7b160336040fee272174f1f7b29a46febb3632502a8f2055f973d60b" + "sha256:1e153545aca7a6a49d8337acca4f41c212fbfa60bf864ecd056df0cafb9627e8", + "sha256:c7eac1c0d95824c88b655273da5c17cdde6482b2739f47c30bf851dcc9d3c2c0" ], - "version": "==1.28.0" + "version": "==1.29.0" + }, + "text-unidecode": { + "hashes": [ + "sha256:5a1375bb2ba7968740508ae38d92e1f889a0832913cb1c447d5e2046061a396d", + "sha256:801e38bd550b943563660a91de8d4b6fa5df60a542be9093f7abf819f86050cc" + ], + "version": "==1.2" }, "toml": { "hashes": [ @@ -464,35 +563,6 @@ ], "version": "==4.3.2" }, - "typed-ast": { - "hashes": [ - "sha256:0948004fa228ae071054f5208840a1e88747a357ec1101c17217bfe99b299d58", - "sha256:10703d3cec8dcd9eef5a630a04056bbc898abc19bac5691612acba7d1325b66d", - "sha256:1f6c4bd0bdc0f14246fd41262df7dfc018d65bb05f6e16390b7ea26ca454a291", - "sha256:25d8feefe27eb0303b73545416b13d108c6067b846b543738a25ff304824ed9a", - "sha256:29464a177d56e4e055b5f7b629935af7f49c196be47528cc94e0a7bf83fbc2b9", - "sha256:2e214b72168ea0275efd6c884b114ab42e316de3ffa125b267e732ed2abda892", - "sha256:3e0d5e48e3a23e9a4d1a9f698e32a542a4a288c871d33ed8df1b092a40f3a0f9", - "sha256:519425deca5c2b2bdac49f77b2c5625781abbaf9a809d727d3a5596b30bb4ded", - "sha256:57fe287f0cdd9ceaf69e7b71a2e94a24b5d268b35df251a88fef5cc241bf73aa", - "sha256:668d0cec391d9aed1c6a388b0d5b97cd22e6073eaa5fbaa6d2946603b4871efe", - "sha256:68ba70684990f59497680ff90d18e756a47bf4863c604098f10de9716b2c0bdd", - "sha256:6de012d2b166fe7a4cdf505eee3aaa12192f7ba365beeefaca4ec10e31241a85", - "sha256:79b91ebe5a28d349b6d0d323023350133e927b4de5b651a8aa2db69c761420c6", - "sha256:8550177fa5d4c1f09b5e5f524411c44633c80ec69b24e0e98906dd761941ca46", - "sha256:898f818399cafcdb93cbbe15fc83a33d05f18e29fb498ddc09b0214cdfc7cd51", - "sha256:94b091dc0f19291adcb279a108f5d38de2430411068b219f41b343c03b28fb1f", - "sha256:a26863198902cda15ab4503991e8cf1ca874219e0118cbf07c126bce7c4db129", - "sha256:a8034021801bc0440f2e027c354b4eafd95891b573e12ff0418dec385c76785c", - "sha256:bc978ac17468fe868ee589c795d06777f75496b1ed576d308002c8a5756fb9ea", - "sha256:c05b41bc1deade9f90ddc5d988fe506208019ebba9f2578c622516fd201f5863", - "sha256:c9b060bd1e5a26ab6e8267fd46fc9e02b54eb15fffb16d112d4c7b1c12987559", - "sha256:edb04bdd45bfd76c8292c4d9654568efaedf76fe78eb246dde69bdb13b2dad87", - "sha256:f19f2a4f547505fe9072e15f6f4ae714af51b5a681a97f187971f50c283193b6" - ], - "markers": "python_version < '3.7' and implementation_name == 'cpython'", - "version": "==1.1.0" - }, "watchdog": { "hashes": [ "sha256:7e65882adb7746039b6f3876ee174952f8eaaa34491ba34333ddf1fe35de4162" diff --git a/alembic.ini b/alembic.ini new file mode 100644 index 00000000..08ce3124 --- /dev/null +++ b/alembic.ini @@ -0,0 +1,74 @@ +# A generic, single database configuration. + +[alembic] +# path to migration scripts +script_location = alembic + +# template used to generate migration files +# file_template = %%(rev)s_%%(slug)s + +# timezone to use when rendering the date +# within the migration file as well as the filename. +# string value is passed to dateutil.tz.gettz() +# leave blank for localtime +# timezone = + +# max length of characters to apply to the +# "slug" field +#truncate_slug_length = 40 + +# set to 'true' to run the environment during +# the 'revision' command, regardless of autogenerate +# revision_environment = false + +# set to 'true' to allow .pyc and .pyo files without +# a source .py file to be detected as revisions in the +# versions/ directory +# sourceless = false + +# version location specification; this defaults +# to alembic/versions. When using multiple version +# directories, initial revisions must be specified with --version-path +# version_locations = %(here)s/bar %(here)s/bat alembic/versions + +# the output encoding used when revision files +# are written from script.py.mako +# output_encoding = utf-8 + +sqlalchemy.url = driver://user:pass@localhost/dbname + + +# Logging configuration +[loggers] +keys = root,sqlalchemy,alembic + +[handlers] +keys = console + +[formatters] +keys = generic + +[logger_root] +level = WARN +handlers = console +qualname = + +[logger_sqlalchemy] +level = WARN +handlers = +qualname = sqlalchemy.engine + +[logger_alembic] +level = INFO +handlers = +qualname = alembic + +[handler_console] +class = StreamHandler +args = (sys.stderr,) +level = NOTSET +formatter = generic + +[formatter_generic] +format = %(levelname)-5.5s [%(name)s] %(message)s +datefmt = %H:%M:%S diff --git a/alembic/README b/alembic/README new file mode 100644 index 00000000..98e4f9c4 --- /dev/null +++ b/alembic/README @@ -0,0 +1 @@ +Generic single-database configuration. \ No newline at end of file diff --git a/alembic/env.py b/alembic/env.py new file mode 100644 index 00000000..6a9d9749 --- /dev/null +++ b/alembic/env.py @@ -0,0 +1,85 @@ +from __future__ import with_statement +from alembic import context +from sqlalchemy import engine_from_config, pool +from logging.config import fileConfig + +# this is the Alembic Config object, which provides +# access to the values within the .ini file in use. +config = context.config + +# Interpret the config file for Python logging. +# This line sets up loggers basically. +fileConfig(config.config_file_name) + +# add your model's MetaData object here +# for 'autogenerate' support +# from myapp import mymodel +# target_metadata = mymodel.Base.metadata +target_metadata = None + +# other values from the config, defined by the needs of env.py, +# can be acquired: +# my_important_option = config.get_main_option("my_important_option") +# ... etc. + +import sys +from unipath import Path + +parent_dir = Path(__file__).parent.parent +sys.path.append(parent_dir) + +from atst.app import make_config +app_config = make_config() +config.set_main_option('sqlalchemy.url', app_config['default']['DATABASE_URI']) + +from atst.database import make_db +from atst.models import * +db = make_db(app_config) +target_metadata = Base.metadata + + +def run_migrations_offline(): + """Run migrations in 'offline' mode. + + This configures the context with just a URL + and not an Engine, though an Engine is acceptable + here as well. By skipping the Engine creation + we don't even need a DBAPI to be available. + + Calls to context.execute() here emit the given string to the + script output. + + """ + url = config.get_main_option("sqlalchemy.url") + context.configure( + url=url, target_metadata=target_metadata, literal_binds=True) + + with context.begin_transaction(): + context.run_migrations() + + +def run_migrations_online(): + """Run migrations in 'online' mode. + + In this scenario we need to create an Engine + and associate a connection with the context. + + """ + connectable = engine_from_config( + config.get_section(config.config_ini_section), + prefix='sqlalchemy.', + poolclass=pool.NullPool) + + with connectable.connect() as connection: + context.configure( + connection=connection, + target_metadata=target_metadata + ) + + with context.begin_transaction(): + context.run_migrations() + +if context.is_offline_mode(): + run_migrations_offline() +else: + run_migrations_online() diff --git a/alembic/script.py.mako b/alembic/script.py.mako new file mode 100644 index 00000000..2c015630 --- /dev/null +++ b/alembic/script.py.mako @@ -0,0 +1,24 @@ +"""${message} + +Revision ID: ${up_revision} +Revises: ${down_revision | comma,n} +Create Date: ${create_date} + +""" +from alembic import op +import sqlalchemy as sa +${imports if imports else ""} + +# revision identifiers, used by Alembic. +revision = ${repr(up_revision)} +down_revision = ${repr(down_revision)} +branch_labels = ${repr(branch_labels)} +depends_on = ${repr(depends_on)} + + +def upgrade(): + ${upgrades if upgrades else "pass"} + + +def downgrade(): + ${downgrades if downgrades else "pass"} diff --git a/alembic/versions/b5b17d465166_requests.py b/alembic/versions/b5b17d465166_requests.py new file mode 100644 index 00000000..dd701f9c --- /dev/null +++ b/alembic/versions/b5b17d465166_requests.py @@ -0,0 +1,44 @@ +"""requests + +Revision ID: b5b17d465166 +Revises: ff1c9c02fa61 +Create Date: 2018-07-23 14:58:05.044456 + +""" +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision = 'b5b17d465166' +down_revision = 'ff1c9c02fa61' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('requests', + sa.Column('id', postgresql.UUID(as_uuid=True), server_default=sa.text('uuid_generate_v4()'), nullable=False), + sa.Column('creator', postgresql.UUID(as_uuid=True), nullable=True), + sa.Column('time_created', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=True), + sa.Column('body', postgresql.JSONB(astext_type=sa.Text()), nullable=True), + sa.PrimaryKeyConstraint('id') + ) + op.create_table('request_status_events', + sa.Column('id', postgresql.UUID(as_uuid=True), server_default=sa.text('uuid_generate_v4()'), nullable=False), + sa.Column('new_status', sa.String(), nullable=True), + sa.Column('time_created', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=True), + sa.Column('request_id', postgresql.UUID(as_uuid=True), nullable=True), + sa.Column('sequence', sa.BigInteger(), nullable=False), + sa.ForeignKeyConstraint(['request_id'], ['requests.id'], ondelete='CASCADE'), + sa.PrimaryKeyConstraint('id') + ) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('request_status_events') + op.drop_table('requests') + # ### end Alembic commands ### diff --git a/alembic/versions/ff1c9c02fa61_enable_uuid_extension.py b/alembic/versions/ff1c9c02fa61_enable_uuid_extension.py new file mode 100644 index 00000000..a6f6206a --- /dev/null +++ b/alembic/versions/ff1c9c02fa61_enable_uuid_extension.py @@ -0,0 +1,26 @@ +"""enable uuid extension + +Revision ID: ff1c9c02fa61 +Revises: +Create Date: 2018-07-23 14:54:05.422286 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'ff1c9c02fa61' +down_revision = None +branch_labels = None +depends_on = None + + +def upgrade(): + connection = op.get_bind() + connection.execute('CREATE EXTENSION IF NOT EXISTS "uuid-ossp"') + + +def downgrade(): + connection = op.get_bind() + connection.execute('DROP EXTENSION IF EXISTS "uuid-ossp"') diff --git a/atst/database.py b/atst/database.py new file mode 100644 index 00000000..6191f62e --- /dev/null +++ b/atst/database.py @@ -0,0 +1,8 @@ +from sqlalchemy import create_engine +from sqlalchemy.orm import sessionmaker, scoped_session + + +def make_db(config): + engine = create_engine(config['default']['DATABASE_URI']) + session = scoped_session(sessionmaker(bind=engine)) + return session diff --git a/atst/models/__init__.py b/atst/models/__init__.py index e69de29b..ef5d9457 100644 --- a/atst/models/__init__.py +++ b/atst/models/__init__.py @@ -0,0 +1,6 @@ +from sqlalchemy.ext.declarative import declarative_base + +Base = declarative_base() + +from .request import Request +from .request_status_event import RequestStatusEvent diff --git a/atst/models/request.py b/atst/models/request.py index 5762e857..baaa92b3 100644 --- a/atst/models/request.py +++ b/atst/models/request.py @@ -3,8 +3,8 @@ from sqlalchemy.types import DateTime from sqlalchemy.dialects.postgresql import JSONB, UUID from sqlalchemy.orm import relationship -from requests_queue.models import Base -from requests_queue.models.types import Id +from atst.models import Base +from atst.models.types import Id class Request(Base): diff --git a/atst/models/status_event.py b/atst/models/request_status_event.py similarity index 63% rename from atst/models/status_event.py rename to atst/models/request_status_event.py index c5c5c715..d7c363cd 100644 --- a/atst/models/status_event.py +++ b/atst/models/request_status_event.py @@ -3,15 +3,15 @@ from sqlalchemy.types import DateTime, String, BigInteger from sqlalchemy.schema import Sequence from sqlalchemy.dialects.postgresql import UUID -from requests_queue.models import Base -from requests_queue.models.types import Id +from atst.models import Base +from atst.models.types import Id -class StatusEvent(Base): - __tablename__ = 'status_events' +class RequestStatusEvent(Base): + __tablename__ = 'request_status_events' id = Id() new_status = Column(String()) time_created = Column(DateTime(timezone=True), server_default=func.now()) request_id = Column(UUID(as_uuid=True), ForeignKey('requests.id', ondelete='CASCADE')) - sequence = Column(BigInteger, Sequence('status_events_sequence_seq'), nullable=False) + sequence = Column(BigInteger, Sequence('request_status_events_sequence_seq'), nullable=False) diff --git a/config/base.ini b/config/base.ini index 431eacf7..8b6e68a2 100644 --- a/config/base.ini +++ b/config/base.ini @@ -11,3 +11,4 @@ CAC_URL = https://localhost:8001 REQUESTS_QUEUE_BASE_URL = http://localhost:8003 REDIS_URI = redis://localhost:6379 SESSION_TTL_SECONDS = 600 +DATABASE_URI = postgres://postgres:postgres@localhost/atat From 8d477003db9a8f5c6b3ebf1fafd255759c747109 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Mon, 23 Jul 2018 15:23:09 -0400 Subject: [PATCH 004/332] Requests page working --- alembic/versions/b5b17d465166_requests.py | 3 + atst/app.py | 4 +- atst/domain/__init__.py | 0 atst/domain/exceptions.py | 16 +++ atst/domain/requests.py | 130 ++++++++++++++++++++++ atst/handlers/request.py | 20 ++-- atst/models/request.py | 4 +- 7 files changed, 164 insertions(+), 13 deletions(-) create mode 100644 atst/domain/__init__.py create mode 100644 atst/domain/exceptions.py create mode 100644 atst/domain/requests.py diff --git a/alembic/versions/b5b17d465166_requests.py b/alembic/versions/b5b17d465166_requests.py index dd701f9c..b8d47c06 100644 --- a/alembic/versions/b5b17d465166_requests.py +++ b/alembic/versions/b5b17d465166_requests.py @@ -36,6 +36,9 @@ def upgrade(): ) # ### end Alembic commands ### + db = op.get_bind() + db.execute("CREATE SEQUENCE request_status_events_sequence_seq OWNED BY request_status_events.sequence;") + def downgrade(): # ### commands auto generated by Alembic - please adjust! ### diff --git a/atst/app.py b/atst/app.py index 8b812018..29b02bed 100644 --- a/atst/app.py +++ b/atst/app.py @@ -20,6 +20,7 @@ from atst.api_client import ApiClient from atst.sessions import RedisSessions from atst import ui_modules from atst import ui_methods +from atst.database import make_db ENV = os.getenv("TORNADO_ENV", "dev") @@ -55,7 +56,7 @@ def make_app(config, deps, **kwargs): url( r"/requests", Request, - {"page": "requests", "requests_client": deps["requests_client"]}, + {"page": "requests", "db_session": deps["db_session"]}, name="requests", ), url( @@ -159,6 +160,7 @@ def make_deps(config): ) return { + "db_session": make_db(config), "authz_client": ApiClient( config["default"]["AUTHZ_BASE_URL"], api_version="v1", diff --git a/atst/domain/__init__.py b/atst/domain/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/atst/domain/exceptions.py b/atst/domain/exceptions.py new file mode 100644 index 00000000..802997d4 --- /dev/null +++ b/atst/domain/exceptions.py @@ -0,0 +1,16 @@ +class NotFoundError(Exception): + def __init__(self, resource_name): + self.resource_name = resource_name + + @property + def message(self): + return "No {} could be found.".format(self.resource_name) + + +class AlreadyExistsError(Exception): + def __init__(self, resource_name): + self.resource_name = resource_name + + @property + def message(self): + return "{} already exists".format(self.resource_name) diff --git a/atst/domain/requests.py b/atst/domain/requests.py new file mode 100644 index 00000000..09acb0af --- /dev/null +++ b/atst/domain/requests.py @@ -0,0 +1,130 @@ +import tornado.gen +from sqlalchemy import exists, and_ +from sqlalchemy.orm.exc import NoResultFound +from sqlalchemy.orm.attributes import flag_modified + +from atst.models import Request, RequestStatusEvent +from .exceptions import NotFoundError + + +def deep_merge(source, destination: dict): + """ + Merge source dict into destination dict recursively. + """ + + def _deep_merge(a, b): + for key, value in a.items(): + if isinstance(value, dict): + node = b.setdefault(key, {}) + _deep_merge(value, node) + else: + b[key] = value + + return b + + return _deep_merge(source, dict(destination)) + + +class Requests(object): + AUTO_APPROVE_THRESHOLD = 1000000 + + def __init__(self, db_session): + self.db_session = db_session + + def create(self, creator_id, body): + request = Request(creator=creator_id, body=body) + + status_event = RequestStatusEvent(new_status="incomplete") + request.status_events.append(status_event) + + self.db_session.add(request) + self.db_session.commit() + + return request + + def exists(self, request_id, creator_id): + return self.db_session.query( + exists().where( + and_(Request.id == request_id, Request.creator == creator_id) + ) + ).scalar() + + def get(self, request_id): + try: + request = self.db_session.query(Request).filter_by(id=request_id).one() + except NoResultFound: + raise NotFoundError("request") + + return request + + def get_many(self, creator_id=None): + filters = [] + if creator_id: + filters.append(Request.creator == creator_id) + + requests = ( + self.db_session.query(Request) + .filter(*filters) + .order_by(Request.time_created.desc()) + .all() + ) + return requests + + @tornado.gen.coroutine + def submit(self, request): + request.status_events.append(StatusEvent(new_status="submitted")) + + if Requests.should_auto_approve(request): + request.status_events.append(StatusEvent(new_status="approved")) + + self.db_session.add(request) + self.db_session.commit() + + return request + + @tornado.gen.coroutine + def update(self, request_id, request_delta): + try: + # Query for request matching id, acquiring a row-level write lock. + # https://www.postgresql.org/docs/10/static/sql-select.html#SQL-FOR-UPDATE-SHARE + request = ( + self.db_session.query(Request) + .filter_by(id=request_id) + .with_for_update(of=Request) + .one() + ) + except NoResultFound: + return + + request.body = deep_merge(request_delta, request.body) + + if Requests.should_allow_submission(request): + request.status_events.append(StatusEvent(new_status="pending_submission")) + + # Without this, sqlalchemy won't notice the change to request.body, + # since it doesn't track dictionary mutations by default. + flag_modified(request, "body") + + self.db_session.add(request) + self.db_session.commit() + + @classmethod + def should_auto_approve(cls, request): + try: + dollar_value = request.body["details_of_use"]["dollar_value"] + except KeyError: + return False + + return dollar_value < cls.AUTO_APPROVE_THRESHOLD + + @classmethod + def should_allow_submission(cls, request): + all_request_sections = [ + "details_of_use", + "information_about_you", + "primary_poc", + ] + existing_request_sections = request.body.keys() + return request.status == "incomplete" and all( + section in existing_request_sections for section in all_request_sections + ) diff --git a/atst/handlers/request.py b/atst/handlers/request.py index d9bec160..1373280a 100644 --- a/atst/handlers/request.py +++ b/atst/handlers/request.py @@ -2,16 +2,17 @@ import tornado import pendulum from atst.handler import BaseHandler +from atst.domain.requests import Requests def map_request(user, request): - time_created = pendulum.parse(request["time_created"]) + time_created = pendulum.instance(request.time_created) is_new = time_created.add(days=1) > pendulum.now() return { - "order_id": request["id"], + "order_id": request.id, "is_new": is_new, - "status": request["status"], + "status": request.status, "app_count": 1, "date": time_created.format("M/DD/YYYY"), "full_name": "{} {}".format(user["first_name"], user["last_name"]), @@ -19,9 +20,9 @@ def map_request(user, request): class Request(BaseHandler): - def initialize(self, page, requests_client): + def initialize(self, page, db_session): self.page = page - self.requests_client = requests_client + self.requests = Requests(db_session) @tornado.web.authenticated @tornado.gen.coroutine @@ -33,11 +34,10 @@ class Request(BaseHandler): @tornado.gen.coroutine def fetch_requests(self, user): + requests = [] if "review_and_approve_jedi_workspace_request" in user["atat_permissions"]: - response = yield self.requests_client.get("/requests") + requests = self.requests.get_many() else: - response = yield self.requests_client.get( - "/requests?creator_id={}".format(user["id"]) - ) + requests = self.requests.get_many(creator_id=user["id"]) - return response.json["requests"] + return requests diff --git a/atst/models/request.py b/atst/models/request.py index baaa92b3..42bec6ed 100644 --- a/atst/models/request.py +++ b/atst/models/request.py @@ -14,9 +14,9 @@ class Request(Base): creator = Column(UUID(as_uuid=True)) time_created = Column(DateTime(timezone=True), server_default=func.now()) body = Column(JSONB) - status_events = relationship('StatusEvent', + status_events = relationship('RequestStatusEvent', backref='request', - order_by='StatusEvent.sequence') + order_by='RequestStatusEvent.sequence') @property def status(self): From 42cdf17ab656945200766e6cbd7c9df56344d019 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Mon, 23 Jul 2018 15:58:57 -0400 Subject: [PATCH 005/332] Fix request_new --- atst/app.py | 6 +-- atst/domain/requests.py | 6 +-- atst/handlers/request_new.py | 83 ++++++++++++++++-------------------- 3 files changed, 42 insertions(+), 53 deletions(-) diff --git a/atst/app.py b/atst/app.py index 29b02bed..023e49fa 100644 --- a/atst/app.py +++ b/atst/app.py @@ -64,7 +64,7 @@ def make_app(config, deps, **kwargs): RequestNew, { "page": "requests_new", - "requests_client": deps["requests_client"], + "db_session": deps["db_session"], "fundz_client": deps["fundz_client"], }, name="request_new", @@ -74,7 +74,7 @@ def make_app(config, deps, **kwargs): RequestNew, { "page": "requests_new", - "requests_client": deps["requests_client"], + "db_session": deps["db_session"], "fundz_client": deps["fundz_client"], }, name="request_form_new", @@ -84,7 +84,7 @@ def make_app(config, deps, **kwargs): RequestNew, { "page": "requests_new", - "requests_client": deps["requests_client"], + "db_session": deps["db_session"], "fundz_client": deps["fundz_client"], }, name="request_form_update", diff --git a/atst/domain/requests.py b/atst/domain/requests.py index 09acb0af..aa37b932 100644 --- a/atst/domain/requests.py +++ b/atst/domain/requests.py @@ -72,10 +72,10 @@ class Requests(object): @tornado.gen.coroutine def submit(self, request): - request.status_events.append(StatusEvent(new_status="submitted")) + request.status_events.append(RequestStatusEvent(new_status="submitted")) if Requests.should_auto_approve(request): - request.status_events.append(StatusEvent(new_status="approved")) + request.status_events.append(RequestStatusEvent(new_status="approved")) self.db_session.add(request) self.db_session.commit() @@ -99,7 +99,7 @@ class Requests(object): request.body = deep_merge(request_delta, request.body) if Requests.should_allow_submission(request): - request.status_events.append(StatusEvent(new_status="pending_submission")) + request.status_events.append(RequestStatusEvent(new_status="pending_submission")) # Without this, sqlalchemy won't notice the change to request.body, # since it doesn't track dictionary mutations by default. diff --git a/atst/handlers/request_new.py b/atst/handlers/request_new.py index d71c307e..49454874 100644 --- a/atst/handlers/request_new.py +++ b/atst/handlers/request_new.py @@ -9,17 +9,16 @@ from atst.forms.review import ReviewForm class RequestNew(BaseHandler): - def initialize(self, page, requests_client, fundz_client): + def initialize(self, page, db_session, fundz_client): self.page = page - self.requests_client = requests_client + self.requests_repo = Requests(db_session) self.fundz_client = fundz_client - @tornado.gen.coroutine def get_existing_request(self, request_id): if request_id is None: - return {} - request = yield self.requests_client.get("/requests/{}".format(request_id)) - return request.json + return None + request = self.requests_repo.get(request_id) + return request @tornado.web.authenticated @tornado.gen.coroutine @@ -28,9 +27,9 @@ class RequestNew(BaseHandler): screen = int(screen) post_data = self.request.arguments current_user = self.get_current_user() - existing_request = yield self.get_existing_request(request_id) + existing_request = self.get_existing_request(request_id) jedi_flow = JEDIRequestFlow( - self.requests_client, + self.requests_repo, self.fundz_client, screen, post_data=post_data, @@ -50,24 +49,21 @@ class RequestNew(BaseHandler): ) if jedi_flow.validate(): - response = yield jedi_flow.create_or_update_request() - if response.ok: - valid = yield jedi_flow.validate_warnings() - if valid: - if jedi_flow.next_screen > len(jedi_flow.screens): - where = "/requests" - else: - where = self.application.default_router.reverse_url( - "request_form_update", jedi_flow.next_screen, jedi_flow.request_id - ) - self.redirect(where) + request = jedi_flow.create_or_update_request() + valid = yield jedi_flow.validate_warnings() + if valid: + if jedi_flow.next_screen > len(jedi_flow.screens): + where = "/requests" else: - self.render( - "requests/screen-%d.html.to" % int(screen), - **rerender_args + where = self.application.default_router.reverse_url( + "request_form_update", jedi_flow.next_screen, jedi_flow.request_id ) + self.redirect(where) else: - self.set_status(response.code) + self.render( + "requests/screen-%d.html.to" % int(screen), + **rerender_args + ) else: self.render( "requests/screen-%d.html.to" % int(screen), @@ -81,15 +77,10 @@ class RequestNew(BaseHandler): request = None if request_id: - response = yield self.requests_client.get( - "/requests/{}".format(request_id), - raise_error=False, - ) - if response.ok: - request = response.json + request = self.requests_repo.get(request_id) jedi_flow = JEDIRequestFlow( - self.requests_client, self.fundz_client, screen, request, request_id=request_id + self.requests_repo, self.fundz_client, screen, request, request_id=request_id ) self.render( @@ -108,7 +99,7 @@ class RequestNew(BaseHandler): class JEDIRequestFlow(object): def __init__( self, - requests_client, + requests_repo, fundz_client, current_step, request=None, @@ -117,7 +108,7 @@ class JEDIRequestFlow(object): current_user=None, existing_request=None, ): - self.requests_client = requests_client + self.requests_repo = requests_repo self.fundz_client = fundz_client self.current_step = current_step @@ -145,8 +136,13 @@ class JEDIRequestFlow(object): @tornado.gen.coroutine def validate_warnings(self): + existing_request_data = ( + self.existing_request + and self.existing_request.body.get(self.form_section) + ) or None + valid = yield self.form.perform_extra_validation( - self.existing_request.get('body', {}).get(self.form_section), + existing_request_data, self.fundz_client, ) return valid @@ -171,15 +167,15 @@ class JEDIRequestFlow(object): if self.request: if self.form_section == "review_submit": - data = self.request["body"] + data = self.request.body else: - data = self.request["body"].get(self.form_section, {}) + data = self.request.body.get(self.form_section, {}) return defaultdict(lambda: defaultdict(lambda: 'Input required'), data) @property def can_submit(self): - return self.request and self.request["status"] != "incomplete" + return self.request and self.request.status != "incomplete" @property def next_screen(self): @@ -222,19 +218,12 @@ class JEDIRequestFlow(object): }, ] - @tornado.gen.coroutine def create_or_update_request(self): request_data = { - "creator_id": self.current_user["id"], - "request": {self.form_section: self.form.data}, + self.form_section: self.form.data } if self.request_id: - response = yield self.requests_client.patch( - "/requests/{}".format(self.request_id), json=request_data - ) + self.requests_repo.update(self.request_id, request_data) else: - response = yield self.requests_client.post("/requests", json=request_data) - self.request = response.json - self.request_id = self.request["id"] - - return response + request = self.requests_repo.create(self.current_user["id"], request_data) + self.request_id = request.id From 818d180285849e8461f57b80da8842b14e5f2ebd Mon Sep 17 00:00:00 2001 From: richard-dds Date: Mon, 23 Jul 2018 16:04:06 -0400 Subject: [PATCH 006/332] Update requests_submit --- atst/app.py | 2 +- atst/handlers/request_submit.py | 22 ++++++---------------- 2 files changed, 7 insertions(+), 17 deletions(-) diff --git a/atst/app.py b/atst/app.py index 023e49fa..7be27a6b 100644 --- a/atst/app.py +++ b/atst/app.py @@ -92,7 +92,7 @@ def make_app(config, deps, **kwargs): url( r"/requests/submit/(\S+)", RequestsSubmit, - {"requests_client": deps["requests_client"]}, + {"db_session": deps["db_session"]}, name="requests_submit", ), # Dummy request/approval screen diff --git a/atst/handlers/request_submit.py b/atst/handlers/request_submit.py index f4d19b3d..ff27803b 100644 --- a/atst/handlers/request_submit.py +++ b/atst/handlers/request_submit.py @@ -1,29 +1,19 @@ import tornado from atst.handler import BaseHandler +from atst.domain.requests import Requests class RequestsSubmit(BaseHandler): - def initialize(self, requests_client): - self.requests_client = requests_client + def initialize(self, db_session): + self.requests_repo = Requests(db_session) @tornado.web.authenticated @tornado.gen.coroutine def post(self, request_id): - yield self.requests_client.post( - "/requests/{}/submit".format(request_id), - allow_nonstandard_methods=True - ) - approved = yield self._check_approved(request_id) - if approved: + request = self.requests_repo.get(request_id) + request = yield self.requests_repo.submit(request) + if request.status == "approved": self.redirect("/requests?modal=True") else: self.redirect("/requests") - - @tornado.gen.coroutine - def _check_approved(self, request_id): - response = yield self.requests_client.get( - "/requests/{}".format(request_id) - ) - status = response.json.get("status") - return status == "approved" From 4291b614c913f0248c3e9a784de74cc0d7bd692d Mon Sep 17 00:00:00 2001 From: richard-dds Date: Mon, 23 Jul 2018 16:19:12 -0400 Subject: [PATCH 007/332] Add request domain tests and factories --- tests/conftest.py | 25 +++++++++++++++- tests/domain/__init__.py | 0 tests/domain/test_requests.py | 55 +++++++++++++++++++++++++++++++++++ tests/factories.py | 11 +++++++ 4 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 tests/domain/__init__.py create mode 100644 tests/domain/test_requests.py create mode 100644 tests/factories.py diff --git a/tests/conftest.py b/tests/conftest.py index c650b5f1..baafaeda 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,18 +1,21 @@ import pytest +from sqlalchemy.orm import sessionmaker, scoped_session from atst.app import make_app, make_deps, make_config +from atst.database import make_db from tests.mocks import MockApiClient, MockFundzClient, MockRequestsClient, MockAuthzClient from atst.sessions import DictSessions @pytest.fixture -def app(): +def app(db): TEST_DEPS = { "authz_client": MockAuthzClient("authz"), "requests_client": MockRequestsClient("requests"), "authnid_client": MockApiClient("authnid"), "fundz_client": MockFundzClient("fundz"), "sessions": DictSessions(), + "db_session": db } config = make_config() @@ -21,6 +24,26 @@ def app(): return make_app(config, deps) + +@pytest.fixture(scope='function') +def db(): + + # Override db with a new SQLAlchemy session so that we can rollback + # each test's transaction. + # Inspiration: https://docs.sqlalchemy.org/en/latest/orm/session_transaction.html#session-external-transaction + config = make_config() + database = make_db(config) + connection = database.get_bind().connect() + transaction = connection.begin() + db = scoped_session(sessionmaker(bind=connection)) + + yield db + + db.close() + transaction.rollback() + connection.close() + + class DummyForm(dict): pass diff --git a/tests/domain/__init__.py b/tests/domain/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/domain/test_requests.py b/tests/domain/test_requests.py new file mode 100644 index 00000000..f45d5be2 --- /dev/null +++ b/tests/domain/test_requests.py @@ -0,0 +1,55 @@ +import pytest +from uuid import uuid4 + +from atst.domain.exceptions import NotFoundError +from atst.domain.requests import Requests + +from tests.factories import RequestFactory + + +@pytest.fixture() +def requests(db): + return Requests(db) + +@pytest.fixture(scope="function") +def new_request(db): + created_request = RequestFactory.create() + db.add(created_request) + db.commit() + + return created_request + + +def test_can_get_request(requests, new_request): + request = requests.get(new_request.id) + + assert request.id == new_request.id + + +def test_nonexistent_request_raises(requests): + with pytest.raises(NotFoundError): + requests.get(uuid4()) + + +@pytest.mark.gen_test +def test_auto_approve_less_than_1m(requests, new_request): + new_request.body = {"details_of_use": {"dollar_value": 999999}} + request = yield requests.submit(new_request) + + assert request.status == 'approved' + + +@pytest.mark.gen_test +def test_dont_auto_approve_if_dollar_value_is_1m_or_above(requests, new_request): + new_request.body = {"details_of_use": {"dollar_value": 1000000}} + request = yield requests.submit(new_request) + + assert request.status == 'submitted' + + +@pytest.mark.gen_test +def test_dont_auto_approve_if_no_dollar_value_specified(requests, new_request): + new_request.body = {"details_of_use": {}} + request = yield requests.submit(new_request) + + assert request.status == 'submitted' diff --git a/tests/factories.py b/tests/factories.py new file mode 100644 index 00000000..b07b36fa --- /dev/null +++ b/tests/factories.py @@ -0,0 +1,11 @@ +import factory +from uuid import uuid4 + +from atst.models import Request, RequestStatusEvent + + +class RequestFactory(factory.Factory): + class Meta: + model = Request + + id = factory.Sequence(lambda x: uuid4()) From 12507109ac10ba9ce80a3d5b2ed390b53c77b34a Mon Sep 17 00:00:00 2001 From: richard-dds Date: Mon, 23 Jul 2018 16:44:39 -0400 Subject: [PATCH 008/332] update tests, remove MockRequestsClient --- tests/conftest.py | 3 +-- tests/handlers/test_request_new.py | 9 +++++++++ tests/mocks.py | 23 ----------------------- 3 files changed, 10 insertions(+), 25 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index baafaeda..a0ed8550 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -3,7 +3,7 @@ from sqlalchemy.orm import sessionmaker, scoped_session from atst.app import make_app, make_deps, make_config from atst.database import make_db -from tests.mocks import MockApiClient, MockFundzClient, MockRequestsClient, MockAuthzClient +from tests.mocks import MockApiClient, MockFundzClient, MockAuthzClient from atst.sessions import DictSessions @@ -11,7 +11,6 @@ from atst.sessions import DictSessions def app(db): TEST_DEPS = { "authz_client": MockAuthzClient("authz"), - "requests_client": MockRequestsClient("requests"), "authnid_client": MockApiClient("authnid"), "fundz_client": MockFundzClient("fundz"), "sessions": DictSessions(), diff --git a/tests/handlers/test_request_new.py b/tests/handlers/test_request_new.py index dfa57cab..8409fc13 100644 --- a/tests/handlers/test_request_new.py +++ b/tests/handlers/test_request_new.py @@ -3,8 +3,17 @@ import pytest import tornado import urllib from tests.mocks import MOCK_USER +from tests.factories import RequestFactory ERROR_CLASS = "alert--error" +MOCK_REQUEST = RequestFactory.create( + creator=MOCK_USER["id"], + body={ + "financial_verification": { + "pe_id": "0203752A", + }, + } +) @pytest.mark.gen_test def test_submit_invalid_request_form(monkeypatch, http_client, base_url): diff --git a/tests/mocks.py b/tests/mocks.py index a7290a03..105824f7 100644 --- a/tests/mocks.py +++ b/tests/mocks.py @@ -51,31 +51,8 @@ class MockApiClient(ApiClient): return response -MOCK_REQUEST = { - "id": "66b8ef71-86d3-48ef-abc2-51bfa1732b6b", - "creator": "49903ae7-da4a-49bf-a6dc-9dff5d004238", - "body": { - "financial_verification": { - "pe_id": "0203752A", - }, - }, - "status": "incomplete" -} - -class MockRequestsClient(MockApiClient): - - @tornado.gen.coroutine - def get(self, path, **kwargs): - return self._get_response("GET", path, 200, json=MOCK_REQUEST) - - @tornado.gen.coroutine - def post(self, path, **kwargs): - return self._get_response("POST", path, 202, json=MOCK_REQUEST) - - MOCK_VALID_PE_ID = "8675309U" - class MockFundzClient(MockApiClient): @tornado.gen.coroutine From 84c228ec2e5d6a985b6e3b63259fd1410f11043b Mon Sep 17 00:00:00 2001 From: dandds Date: Fri, 27 Jul 2018 14:57:59 -0400 Subject: [PATCH 009/332] update submodule --- script/include | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/include b/script/include index 7417942f..8597f54c 160000 --- a/script/include +++ b/script/include @@ -1 +1 @@ -Subproject commit 7417942f1614d6a7ad94e94d1621dca9b422dec2 +Subproject commit 8597f54c69dc1eb04c53a2fc487ebd7f8c8e648f From 7f5f02985b2ba3f35f0bd613155c667934eefa8a Mon Sep 17 00:00:00 2001 From: dandds Date: Fri, 27 Jul 2018 15:15:44 -0400 Subject: [PATCH 010/332] update and fix some tests from rebase --- atst/handlers/request_new.py | 1 + script/update | 7 +++-- tests/handlers/test_financial_verification.py | 2 +- tests/handlers/test_request_new.py | 1 - tests/handlers/test_request_submit.py | 30 ++++++++++++------- tests/mocks.py | 9 ++++++ 6 files changed, 35 insertions(+), 15 deletions(-) diff --git a/atst/handlers/request_new.py b/atst/handlers/request_new.py index 49454874..e43e6ab3 100644 --- a/atst/handlers/request_new.py +++ b/atst/handlers/request_new.py @@ -6,6 +6,7 @@ from atst.forms.request import RequestForm from atst.forms.org import OrgForm from atst.forms.poc import POCForm from atst.forms.review import ReviewForm +from atst.domain.requests import Requests class RequestNew(BaseHandler): diff --git a/script/update b/script/update index 8cb772c1..1baef9a8 100755 --- a/script/update +++ b/script/update @@ -4,5 +4,8 @@ source "$(dirname "${0}")"/../script/include/global_header.inc.sh -# Run the bootstrap script -source ./script/bootstrap +# Enable DB migration +MIGRATE_DB="true" + +# Run the shared update script +source ./script/include/run_update diff --git a/tests/handlers/test_financial_verification.py b/tests/handlers/test_financial_verification.py index 6e60bb4e..234c8d57 100644 --- a/tests/handlers/test_financial_verification.py +++ b/tests/handlers/test_financial_verification.py @@ -40,7 +40,7 @@ class TestPENumberInForm: @tornado.gen.coroutine def submit_data(self, http_client, base_url, data): response = yield http_client.fetch( - base_url + "/requests/verify/{}".format(MOCK_REQUEST["id"]), + base_url + "/requests/verify/{}".format(MOCK_REQUEST.id), method="POST", headers={"Content-Type": "application/x-www-form-urlencoded"}, body=urllib.parse.urlencode(data), diff --git a/tests/handlers/test_request_new.py b/tests/handlers/test_request_new.py index 8409fc13..3373c867 100644 --- a/tests/handlers/test_request_new.py +++ b/tests/handlers/test_request_new.py @@ -3,7 +3,6 @@ import pytest import tornado import urllib from tests.mocks import MOCK_USER -from tests.factories import RequestFactory ERROR_CLASS = "alert--error" MOCK_REQUEST = RequestFactory.create( diff --git a/tests/handlers/test_request_submit.py b/tests/handlers/test_request_submit.py index 0f60c1a1..635ff157 100644 --- a/tests/handlers/test_request_submit.py +++ b/tests/handlers/test_request_submit.py @@ -1,19 +1,26 @@ import pytest +import tornado from tests.mocks import MOCK_USER +from tests.factories import RequestFactory + + +@tornado.gen.coroutine +def _mock_func(*args, **kwargs): + return RequestFactory.create() -ERROR_CLASS = "usa-input-error-message" -APPROVED_MOCK_REQUEST = { - "status": "approved" -} @pytest.mark.gen_test def test_submit_reviewed_request(monkeypatch, http_client, base_url): monkeypatch.setattr( - "atst.handlers.request_submit.RequestsSubmit.get_current_user", lambda s: MOCK_USER + "atst.handlers.request_submit.RequestsSubmit.get_current_user", + lambda s: MOCK_USER, ) monkeypatch.setattr( "atst.handlers.request_submit.RequestsSubmit.check_xsrf_cookie", lambda s: True ) + monkeypatch.setattr("atst.domain.requests.Requests.get", _mock_func) + monkeypatch.setattr("atst.domain.requests.Requests.submit", _mock_func) + monkeypatch.setattr("atst.models.request.Request.status", "pending") # this just needs to send a known invalid form value response = yield http_client.fetch( base_url + "/requests/submit/1", @@ -21,7 +28,7 @@ def test_submit_reviewed_request(monkeypatch, http_client, base_url): headers={"Content-Type": "application/x-www-form-urlencoded"}, body="", raise_error=False, - follow_redirects=False + follow_redirects=False, ) assert response.headers["Location"] == "/requests" @@ -29,14 +36,15 @@ def test_submit_reviewed_request(monkeypatch, http_client, base_url): @pytest.mark.gen_test def test_submit_autoapproved_reviewed_request(monkeypatch, http_client, base_url): monkeypatch.setattr( - "atst.handlers.request_submit.RequestsSubmit.get_current_user", lambda s: MOCK_USER + "atst.handlers.request_submit.RequestsSubmit.get_current_user", + lambda s: MOCK_USER, ) monkeypatch.setattr( "atst.handlers.request_submit.RequestsSubmit.check_xsrf_cookie", lambda s: True ) - monkeypatch.setattr( - "tests.mocks.MOCK_REQUEST", APPROVED_MOCK_REQUEST - ) + monkeypatch.setattr("atst.domain.requests.Requests.get", _mock_func) + monkeypatch.setattr("atst.domain.requests.Requests.submit", _mock_func) + monkeypatch.setattr("atst.models.request.Request.status", "approved") # this just needs to send a known invalid form value response = yield http_client.fetch( base_url + "/requests/submit/1", @@ -44,6 +52,6 @@ def test_submit_autoapproved_reviewed_request(monkeypatch, http_client, base_url headers={"Content-Type": "application/x-www-form-urlencoded"}, body="", raise_error=False, - follow_redirects=False + follow_redirects=False, ) assert response.headers["Location"] == "/requests?modal=True" diff --git a/tests/mocks.py b/tests/mocks.py index 105824f7..96c22e4a 100644 --- a/tests/mocks.py +++ b/tests/mocks.py @@ -2,6 +2,7 @@ import tornado.gen from tornado.httpclient import HTTPRequest, HTTPResponse from atst.api_client import ApiClient +from tests.factories import RequestFactory MOCK_USER = { @@ -10,6 +11,14 @@ MOCK_USER = { "first_name": "Fake", "last_name": "User", } +MOCK_REQUEST = RequestFactory.create( + creator=MOCK_USER["id"], + body={ + "financial_verification": { + "pe_id": "0203752A", + }, + } +) class MockApiClient(ApiClient): From 78c55099bcb5081c5d0d466e74015fa28949cb71 Mon Sep 17 00:00:00 2001 From: dandds Date: Fri, 27 Jul 2018 15:27:50 -0400 Subject: [PATCH 011/332] update financial verification to use requests repo --- atst/app.py | 2 +- .../request_financial_verification.py | 49 ++++++++----------- tests/handlers/test_financial_verification.py | 3 +- 3 files changed, 23 insertions(+), 31 deletions(-) diff --git a/atst/app.py b/atst/app.py index 7be27a6b..1a785fe6 100644 --- a/atst/app.py +++ b/atst/app.py @@ -107,7 +107,7 @@ def make_app(config, deps, **kwargs): RequestFinancialVerification, { "page": "financial_verification", - "requests_client": deps["requests_client"], + "db_session": deps["db_session"], "fundz_client": deps["fundz_client"], }, name="financial_verification", diff --git a/atst/handlers/request_financial_verification.py b/atst/handlers/request_financial_verification.py index 4c81f9d7..a063692c 100644 --- a/atst/handlers/request_financial_verification.py +++ b/atst/handlers/request_financial_verification.py @@ -2,26 +2,23 @@ import tornado from atst.handler import BaseHandler from atst.forms.financial import FinancialForm +from atst.domain.requests import Requests class RequestFinancialVerification(BaseHandler): - def initialize(self, page, requests_client, fundz_client): + def initialize(self, page, db_session, fundz_client): self.page = page - self.requests_client = requests_client + self.requests_repo = Requests(db_session) self.fundz_client = fundz_client - @tornado.gen.coroutine def get_existing_request(self, request_id): - if request_id is None: - return {} - request = yield self.requests_client.get("/requests/{}".format(request_id)) - return request.json + return self.requests_repo.get(request_id) @tornado.web.authenticated @tornado.gen.coroutine def get(self, request_id=None): - existing_request = yield self.get_existing_request(request_id) - form = FinancialForm(data=existing_request['body'].get('financial_verification')) + existing_request = self.get_existing_request(request_id) + form = FinancialForm(data=existing_request.body.get('financial_verification')) self.render( "requests/financial_verification.html.to", page=self.page, @@ -35,39 +32,33 @@ class RequestFinancialVerification(BaseHandler): "creator_id": self.current_user["id"], "request": {"financial_verification": form_data}, } - response = yield self.requests_client.patch( - "/requests/{}".format(request_id), json=request_data - ) - return response + return self.requests_repo.update(request_id, request_data) @tornado.web.authenticated @tornado.gen.coroutine def post(self, request_id=None): self.check_xsrf_cookie() post_data = self.request.arguments - existing_request = yield self.get_existing_request(request_id) + existing_request = self.get_existing_request(request_id) form = FinancialForm(post_data) rerender_args = dict(request_id=request_id, f=form) if form.validate(): - response = yield self.update_request(request_id, form.data) - if response.ok: - valid = yield form.perform_extra_validation( - existing_request.get('body', {}).get('financial_verification'), - self.fundz_client + yield self.update_request(request_id, form.data) + valid = yield form.perform_extra_validation( + existing_request.body.get('financial_verification'), + self.fundz_client + ) + if valid: + self.redirect( + self.application.default_router.reverse_url("financial_verification_submitted") ) - if valid: - self.redirect( - self.application.default_router.reverse_url("financial_verification_submitted") - ) - else: - self.render( - "requests/financial_verification.html.to", - **rerender_args - ) else: - self.set_status(response.code) + self.render( + "requests/financial_verification.html.to", + **rerender_args + ) else: self.render( "requests/financial_verification.html.to", diff --git a/tests/handlers/test_financial_verification.py b/tests/handlers/test_financial_verification.py index 234c8d57..57b8851d 100644 --- a/tests/handlers/test_financial_verification.py +++ b/tests/handlers/test_financial_verification.py @@ -36,6 +36,7 @@ class TestPENumberInForm: "atst.handlers.request_financial_verification.RequestFinancialVerification.check_xsrf_cookie", lambda s: True ) monkeypatch.setattr("atst.forms.request.RequestForm.validate", lambda s: True) + monkeypatch.setattr("atst.domain.requests.Requests.get", lambda s, i: MOCK_REQUEST) @tornado.gen.coroutine def submit_data(self, http_client, base_url, data): @@ -64,7 +65,7 @@ class TestPENumberInForm: self._set_monkeypatches(monkeypatch) data = dict(self.required_data) - data['pe_id'] = MOCK_REQUEST['body']['financial_verification']['pe_id'] + data['pe_id'] = MOCK_REQUEST.body['financial_verification']['pe_id'] response = yield self.submit_data(http_client, base_url, data) From 4b2047df0a36ae445a2d3bac8222b5a9af28a3e7 Mon Sep 17 00:00:00 2001 From: dandds Date: Mon, 30 Jul 2018 10:15:48 -0400 Subject: [PATCH 012/332] add new config pattern for database URI and overrides --- atst/app.py | 55 ++++++++++++++++++++++++++++++++++++------------- config/base.ini | 6 +++++- 2 files changed, 46 insertions(+), 15 deletions(-) diff --git a/atst/app.py b/atst/app.py index 1a785fe6..00162535 100644 --- a/atst/app.py +++ b/atst/app.py @@ -24,6 +24,7 @@ from atst.database import make_db ENV = os.getenv("TORNADO_ENV", "dev") + def make_app(config, deps, **kwargs): routes = [ @@ -31,16 +32,15 @@ def make_app(config, deps, **kwargs): url( r"/login-redirect", LoginRedirect, - {"sessions": deps["sessions"], "authnid_client": deps["authnid_client"], "authz_client": deps["authz_client"]}, + { + "sessions": deps["sessions"], + "authnid_client": deps["authnid_client"], + "authz_client": deps["authz_client"], + }, name="login_redirect", ), url(r"/home", Main, {"page": "home"}, name="home"), - url( - r"/styleguide", - Main, - {"page": "styleguide"}, - name="styleguide", - ), + url(r"/styleguide", Main, {"page": "styleguide"}, name="styleguide"), url( r"/workspaces/blank", Main, @@ -100,7 +100,7 @@ def make_app(config, deps, **kwargs): r"/request/approval", Main, {"page": "request_approval"}, - name="request_approval" + name="request_approval", ), url( r"/requests/verify/(\S+)", @@ -121,7 +121,9 @@ def make_app(config, deps, **kwargs): url(r"/users", Main, {"page": "users"}, name="users"), url(r"/reports", Main, {"page": "reports"}, name="reports"), url(r"/calculator", Main, {"page": "calculator"}, name="calculator"), - url(r"/workspaces/(\S+)/members", WorkspaceMembers, {}, name="workspace_members"), + url( + r"/workspaces/(\S+)/members", WorkspaceMembers, {}, name="workspace_members" + ), url(r"/workspaces/(\S+)/projects", Workspace, {}, name="workspace_projects"), url(r"/workspaces/123456/projects/789/edit", Main, {"page": "project_edit"}, name="project_edit"), ] @@ -131,7 +133,11 @@ def make_app(config, deps, **kwargs): url( r"/login-dev", Dev, - {"action": "login", "sessions": deps["sessions"], "authz_client": deps["authz_client"]}, + { + "action": "login", + "sessions": deps["sessions"], + "authz_client": deps["authz_client"], + }, name="dev-login", ) ] @@ -145,7 +151,7 @@ def make_app(config, deps, **kwargs): debug=config["default"].getboolean("DEBUG"), ui_modules=ui_modules, ui_methods=ui_methods, - **kwargs, + **kwargs ) app.config = config app.sessions = deps["sessions"] @@ -172,8 +178,7 @@ def make_deps(config): validate_cert=validate_cert, ), "fundz_client": ApiClient( - config["default"]["FUNDZ_BASE_URL"], - validate_cert=validate_cert, + config["default"]["FUNDZ_BASE_URL"], validate_cert=validate_cert ), "requests_client": ApiClient( config["default"]["REQUESTS_QUEUE_BASE_URL"], @@ -191,8 +196,30 @@ def make_config(): ENV_CONFIG_FILENAME = os.path.join( os.path.dirname(__file__), "../config/", "{}.ini".format(ENV.lower()) ) + OVERRIDE_CONFIG_FILENAME = os.getenv("OVERRIDE_CONFIG_FULLPATH") + config = ConfigParser() + config_files = [BASE_CONFIG_FILENAME, ENV_CONFIG_FILENAME] + if OVERRIDE_CONFIG_FILENAME: + config_files.append(OVERRIDE_CONFIG_FILENAME) + # ENV_CONFIG will override values in BASE_CONFIG. - config.read([BASE_CONFIG_FILENAME, ENV_CONFIG_FILENAME]) + config.read(config_files) + + # Assemble DATABASE_URI value + database_uri = ( + "postgres://" + + config.get("default", "DATABASE_USERNAME") + + ":" + + config.get("default", "DATABASE_PASSWORD") + + "@" + + config.get("default", "DATABASE_HOST") + + ":" + + config.get("default", "DATABASE_PORT") + + "/" + + config.get("default", "DATABASE_NAME") + ) + config.set("default", "DATABASE_URI", database_uri) + return config diff --git a/config/base.ini b/config/base.ini index 8b6e68a2..92f40d5a 100644 --- a/config/base.ini +++ b/config/base.ini @@ -11,4 +11,8 @@ CAC_URL = https://localhost:8001 REQUESTS_QUEUE_BASE_URL = http://localhost:8003 REDIS_URI = redis://localhost:6379 SESSION_TTL_SECONDS = 600 -DATABASE_URI = postgres://postgres:postgres@localhost/atat +DATABASE_HOST = localhost +DATABASE_PORT = 5432 +DATABASE_USERNAME = postgres +DATABASE_PASSWORD = postgres +DATABASE_NAME = atat From 85c8a1166d918b5fe74ae65cbc3ba1b92da2870a Mon Sep 17 00:00:00 2001 From: Devon Mackay Date: Mon, 30 Jul 2018 15:50:50 -0400 Subject: [PATCH 013/332] Change db vars to standard postgres equivalents --- atst/app.py | 10 +++++----- config/base.ini | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/atst/app.py b/atst/app.py index 00162535..9ac6f55f 100644 --- a/atst/app.py +++ b/atst/app.py @@ -210,15 +210,15 @@ def make_config(): # Assemble DATABASE_URI value database_uri = ( "postgres://" - + config.get("default", "DATABASE_USERNAME") + + config.get("default", "PGUSER") + ":" - + config.get("default", "DATABASE_PASSWORD") + + config.get("default", "PGPASSWORD") + "@" - + config.get("default", "DATABASE_HOST") + + config.get("default", "PGHOST") + ":" - + config.get("default", "DATABASE_PORT") + + config.get("default", "PGPORT") + "/" - + config.get("default", "DATABASE_NAME") + + config.get("default", "PGDATABASE") ) config.set("default", "DATABASE_URI", database_uri) diff --git a/config/base.ini b/config/base.ini index 92f40d5a..6e6af123 100644 --- a/config/base.ini +++ b/config/base.ini @@ -11,8 +11,8 @@ CAC_URL = https://localhost:8001 REQUESTS_QUEUE_BASE_URL = http://localhost:8003 REDIS_URI = redis://localhost:6379 SESSION_TTL_SECONDS = 600 -DATABASE_HOST = localhost -DATABASE_PORT = 5432 -DATABASE_USERNAME = postgres -DATABASE_PASSWORD = postgres -DATABASE_NAME = atat +PGHOST = localhost +PGPORT = 5432 +PGUSER = postgres +PGPASSWORD = postgres +PGDATABASE = atat From 239a0e98212216f0117919159dfd60030d7f606e Mon Sep 17 00:00:00 2001 From: Devon Mackay Date: Mon, 30 Jul 2018 15:51:36 -0400 Subject: [PATCH 014/332] Add wrapper script for settign DB ENV vars --- script/get_db_settings.sh | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100755 script/get_db_settings.sh diff --git a/script/get_db_settings.sh b/script/get_db_settings.sh new file mode 100755 index 00000000..7b30fd7b --- /dev/null +++ b/script/get_db_settings.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +# script/get_db_settings: Fetch postgresql settings and set them as ENV vars + +source "$(dirname "${0}")"/../script/include/global_header.inc.sh + +# Run the shared get_db_settings script +source ./script/include/run_get_sb_settings.sh From aa1c73262b720dbcc158a3df432f15f85b1b9853 Mon Sep 17 00:00:00 2001 From: Devon Mackay Date: Mon, 30 Jul 2018 15:51:55 -0400 Subject: [PATCH 015/332] Switch to scriptz feature branch --- script/include | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/include b/script/include index 8597f54c..cb8cbe46 160000 --- a/script/include +++ b/script/include @@ -1 +1 @@ -Subproject commit 8597f54c69dc1eb04c53a2fc487ebd7f8c8e648f +Subproject commit cb8cbe46d0e8171fcd497e4d22ab719692347562 From ea014d3b8b636d2ab490bb5d153c524b5f513d2a Mon Sep 17 00:00:00 2001 From: Devon Mackay Date: Mon, 30 Jul 2018 18:22:08 -0400 Subject: [PATCH 016/332] Add postgres hostname used during CI --- config/ci.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/config/ci.ini b/config/ci.ini index e69de29b..0469ae77 100644 --- a/config/ci.ini +++ b/config/ci.ini @@ -0,0 +1,2 @@ +[default] +PGHOST = travishost From 79204383aca8af01e24812b0292310696c156d32 Mon Sep 17 00:00:00 2001 From: Devon Mackay Date: Mon, 30 Jul 2018 18:22:42 -0400 Subject: [PATCH 017/332] Add postgres to ATST build - Add postgres 9.6 service - Add Travis host IP entry to docker container --- .travis.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 02dab0db..0b452ab2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,11 @@ sudo: required language: python python: "3.6" -services: docker +services: + - docker + - postgres +addons: + postgresql: "9.6" git: submodules: false env: @@ -16,8 +20,9 @@ before_install: - git submodule update --init --recursive before_script: + - travis_host_ip="$(/sbin/ip route|awk '/default/ { print $3 }')" - docker login -u $ATAT_DOCKER_REGISTRY_USERNAME -p $ATAT_DOCKER_REGISTRY_PASSWORD $ATAT_DOCKER_REGISTRY_URL - - docker build --tag "${TESTER_IMAGE_NAME}" . -f deploy/docker/tester/Dockerfile + - docker build --tag "${TESTER_IMAGE_NAME}" --add-host "travishost:${travis_host_ip}" . -f deploy/docker/tester/Dockerfile script: - docker run "${TESTER_IMAGE_NAME}" From 413f5329bb8ce67362b78a257c2309f4c0abaf68 Mon Sep 17 00:00:00 2001 From: Devon Mackay Date: Mon, 30 Jul 2018 18:26:53 -0400 Subject: [PATCH 018/332] Add DB info and setup --- script/setup | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/script/setup b/script/setup index 925ced94..5cd11461 100755 --- a/script/setup +++ b/script/setup @@ -8,5 +8,11 @@ source "$(dirname "${0}")"/../script/include/global_header.inc.sh # Turn on sass compiler installation INSTALL_SASS="true" +# Set database name +DATABASE_NAME="atat" + +# Enable database resetting +RESET_DB="true" + # Run the shared setup script source ./script/include/run_setup From 1d0d57735da3ddb80de9686f1d05198822a8e1ac Mon Sep 17 00:00:00 2001 From: Devon Mackay Date: Mon, 30 Jul 2018 18:31:18 -0400 Subject: [PATCH 019/332] Rename script --- script/{get_db_settings.sh => get_db_settings} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename script/{get_db_settings.sh => get_db_settings} (100%) diff --git a/script/get_db_settings.sh b/script/get_db_settings similarity index 100% rename from script/get_db_settings.sh rename to script/get_db_settings From 0d30d08718d45903edc12e4008a7f5c95aed41d7 Mon Sep 17 00:00:00 2001 From: Devon Mackay Date: Mon, 30 Jul 2018 18:41:01 -0400 Subject: [PATCH 020/332] Fix type --- script/get_db_settings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/get_db_settings b/script/get_db_settings index 7b30fd7b..c96970a8 100755 --- a/script/get_db_settings +++ b/script/get_db_settings @@ -5,4 +5,4 @@ source "$(dirname "${0}")"/../script/include/global_header.inc.sh # Run the shared get_db_settings script -source ./script/include/run_get_sb_settings.sh +source ./script/include/run_get_db_settings.sh From c1dc9149533ddbc9f30b26a14d6cb95321cdbdeb Mon Sep 17 00:00:00 2001 From: Devon Mackay Date: Mon, 30 Jul 2018 19:50:33 -0400 Subject: [PATCH 021/332] Remove blank line --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 6089986f..455d5baa 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,3 @@ - # ATST [![Build Status](https://travis-ci.org/dod-ccpo/atst.svg?branch=master)](https://travis-ci.org/dod-ccpo/atst) From 09b8b8ab4c8ec6d0acd3ac7d4eebc0d220007cca Mon Sep 17 00:00:00 2001 From: Devon Mackay Date: Mon, 30 Jul 2018 20:02:41 -0400 Subject: [PATCH 022/332] Debug travis ip and psql connect issues --- .travis.yml | 3 +++ script/get_db_settings | 3 +++ script/setup | 3 +++ 3 files changed, 9 insertions(+) diff --git a/.travis.yml b/.travis.yml index 0b452ab2..37b0fa76 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,6 +18,9 @@ before_install: - sed -i 's/git@github.com:/https:\/\/github.com\//' .gitmodules # Manually initialize submodules - git submodule update --init --recursive + - /sbin/ip route|awk '/default/ { print $3 }' + - /sbin/ip addr + - ./foo before_script: - travis_host_ip="$(/sbin/ip route|awk '/default/ { print $3 }')" diff --git a/script/get_db_settings b/script/get_db_settings index c96970a8..2c60ec3c 100755 --- a/script/get_db_settings +++ b/script/get_db_settings @@ -6,3 +6,6 @@ source "$(dirname "${0}")"/../script/include/global_header.inc.sh # Run the shared get_db_settings script source ./script/include/run_get_db_settings.sh + +echo "Postgres settings: " +echo $PGHOST diff --git a/script/setup b/script/setup index 5cd11461..c64ff07a 100755 --- a/script/setup +++ b/script/setup @@ -14,5 +14,8 @@ DATABASE_NAME="atat" # Enable database resetting RESET_DB="true" +echo "Hosts file:" +cat /etc/hosts + # Run the shared setup script source ./script/include/run_setup From 9e937eca8ba740c8c441603f03350e2e2cc7a2ff Mon Sep 17 00:00:00 2001 From: Devon Mackay Date: Mon, 30 Jul 2018 20:05:50 -0400 Subject: [PATCH 023/332] Debug travis ip and psql connect issues --- .travis.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 37b0fa76..311e93ce 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,15 +14,15 @@ env: - PROD_IMAGE_NAME=atst-prod before_install: - # Use sed to replace the SSH URL with the public URL - - sed -i 's/git@github.com:/https:\/\/github.com\//' .gitmodules - # Manually initialize submodules - - git submodule update --init --recursive - - /sbin/ip route|awk '/default/ { print $3 }' - - /sbin/ip addr - - ./foo + # Use sed to replace the SSH URL with the public URL + - sed -i 's/git@github.com:/https:\/\/github.com\//' .gitmodules + # Manually initialize submodules + - git submodule update --init --recursive + - /sbin/ip route|awk '/default/ { print $3 }' + - /sbin/ip addr before_script: + - netstat -anlp | grep LISTEN | grep tcp - travis_host_ip="$(/sbin/ip route|awk '/default/ { print $3 }')" - docker login -u $ATAT_DOCKER_REGISTRY_USERNAME -p $ATAT_DOCKER_REGISTRY_PASSWORD $ATAT_DOCKER_REGISTRY_URL - docker build --tag "${TESTER_IMAGE_NAME}" --add-host "travishost:${travis_host_ip}" . -f deploy/docker/tester/Dockerfile From e4fd71437ee454c42eaa8e350ba6780ac0c2afa2 Mon Sep 17 00:00:00 2001 From: Devon Mackay Date: Mon, 30 Jul 2018 20:19:36 -0400 Subject: [PATCH 024/332] Ensure get_db is sourced so the vars carry over --- script/get_db_settings | 5 ++++- script/include | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/script/get_db_settings b/script/get_db_settings index 2c60ec3c..701c2844 100755 --- a/script/get_db_settings +++ b/script/get_db_settings @@ -7,5 +7,8 @@ source "$(dirname "${0}")"/../script/include/global_header.inc.sh # Run the shared get_db_settings script source ./script/include/run_get_db_settings.sh +echo echo "Postgres settings: " -echo $PGHOST +echo "PGHOST: $PGHOST" +echo "PGDATABASE: $PGDATABASE" +echo diff --git a/script/include b/script/include index cb8cbe46..5c19aef7 160000 --- a/script/include +++ b/script/include @@ -1 +1 @@ -Subproject commit cb8cbe46d0e8171fcd497e4d22ab719692347562 +Subproject commit 5c19aef7482aa0035f2d85e4c30ee21dfd7969c9 From 129db2968bc4b223179e120861dd79f1e058e783 Mon Sep 17 00:00:00 2001 From: Devon Mackay Date: Mon, 30 Jul 2018 20:25:01 -0400 Subject: [PATCH 025/332] Ensure app env is ci when testing --- deploy/docker/tester/Dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/deploy/docker/tester/Dockerfile b/deploy/docker/tester/Dockerfile index c490c6ec..bfec5729 100644 --- a/deploy/docker/tester/Dockerfile +++ b/deploy/docker/tester/Dockerfile @@ -8,7 +8,9 @@ ARG APP_DIR=/opt/atat/atst ARG CIBUILD=true ENV APP_DIR "${APP_DIR}" +ENV FLASK_ENV ci ENV SKIP_PIPENV true +ENV TORNADO_ENV ci # Use dumb-init for proper signal handling ENTRYPOINT ["/usr/bin/dumb-init", "--"] From dd69506e72c414564ca8f64bc717bda02f41c414 Mon Sep 17 00:00:00 2001 From: Devon Mackay Date: Mon, 30 Jul 2018 20:35:00 -0400 Subject: [PATCH 026/332] Add app name to PG settings --- config/base.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/config/base.ini b/config/base.ini index 6e6af123..6f63d78f 100644 --- a/config/base.ini +++ b/config/base.ini @@ -11,6 +11,7 @@ CAC_URL = https://localhost:8001 REQUESTS_QUEUE_BASE_URL = http://localhost:8003 REDIS_URI = redis://localhost:6379 SESSION_TTL_SECONDS = 600 +PGAPPNAME = atst PGHOST = localhost PGPORT = 5432 PGUSER = postgres From 40359e8e2d7e067b12306e5bedd4f557f9a2edd8 Mon Sep 17 00:00:00 2001 From: Devon Mackay Date: Tue, 31 Jul 2018 06:26:25 -0400 Subject: [PATCH 027/332] Switch to postgres in a container --- .travis.yml | 10 ++++------ config/ci.ini | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 311e93ce..3d76a657 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,9 +3,6 @@ language: python python: "3.6" services: - docker - - postgres -addons: - postgresql: "9.6" git: submodules: false env: @@ -22,10 +19,11 @@ before_install: - /sbin/ip addr before_script: - - netstat -anlp | grep LISTEN | grep tcp - - travis_host_ip="$(/sbin/ip route|awk '/default/ { print $3 }')" + - docker run -d --name postgres96 postgres:9.6-alpine + - docker run --link postgres96:postgres96 waisbrot/wait + - postgres_ip="$(docker inspect -f "{{ .NetworkSettings.IPAddress }}" postgres96)" - docker login -u $ATAT_DOCKER_REGISTRY_USERNAME -p $ATAT_DOCKER_REGISTRY_PASSWORD $ATAT_DOCKER_REGISTRY_URL - - docker build --tag "${TESTER_IMAGE_NAME}" --add-host "travishost:${travis_host_ip}" . -f deploy/docker/tester/Dockerfile + - docker build --tag "${TESTER_IMAGE_NAME}" --add-host "postgreshost:${postgres_ip}" . -f deploy/docker/tester/Dockerfile script: - docker run "${TESTER_IMAGE_NAME}" diff --git a/config/ci.ini b/config/ci.ini index 0469ae77..3796c0a7 100644 --- a/config/ci.ini +++ b/config/ci.ini @@ -1,2 +1,2 @@ [default] -PGHOST = travishost +PGHOST = postgreshost From 8f22921622938e50c76f6b3afc9f8056910db125 Mon Sep 17 00:00:00 2001 From: Devon Mackay Date: Tue, 31 Jul 2018 06:37:26 -0400 Subject: [PATCH 028/332] Add postgres host to running container --- .travis.yml | 4 ++-- script/cibuild | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3d76a657..479a8955 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,12 +21,12 @@ before_install: before_script: - docker run -d --name postgres96 postgres:9.6-alpine - docker run --link postgres96:postgres96 waisbrot/wait - - postgres_ip="$(docker inspect -f "{{ .NetworkSettings.IPAddress }}" postgres96)" + - export postgres_ip="$(docker inspect -f "{{ .NetworkSettings.IPAddress }}" postgres96)" - docker login -u $ATAT_DOCKER_REGISTRY_USERNAME -p $ATAT_DOCKER_REGISTRY_PASSWORD $ATAT_DOCKER_REGISTRY_URL - docker build --tag "${TESTER_IMAGE_NAME}" --add-host "postgreshost:${postgres_ip}" . -f deploy/docker/tester/Dockerfile script: - - docker run "${TESTER_IMAGE_NAME}" + - docker run --add-host "postgreshost:${postgres_ip}" "${TESTER_IMAGE_NAME}" before_deploy: - docker build --tag "${PROD_IMAGE_NAME}" . -f deploy/docker/prod/Dockerfile diff --git a/script/cibuild b/script/cibuild index e9d01564..387f61b8 100755 --- a/script/cibuild +++ b/script/cibuild @@ -4,5 +4,10 @@ source "$(dirname "${0}")"/../script/include/global_header.inc.sh +echo +echo "DEBUG: Hosts file:" +cat /etc/hosts +echo + # Run lint/style checks and unit tests source ./script/test From da40d22add96a76bc65f5365ea4ab5640d9a92d3 Mon Sep 17 00:00:00 2001 From: Devon Mackay Date: Tue, 31 Jul 2018 07:03:49 -0400 Subject: [PATCH 029/332] Remove debugging related items --- .travis.yml | 2 -- script/cibuild | 5 ----- script/get_db_settings | 6 ------ script/setup | 3 --- 4 files changed, 16 deletions(-) diff --git a/.travis.yml b/.travis.yml index 479a8955..49883310 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,8 +15,6 @@ before_install: - sed -i 's/git@github.com:/https:\/\/github.com\//' .gitmodules # Manually initialize submodules - git submodule update --init --recursive - - /sbin/ip route|awk '/default/ { print $3 }' - - /sbin/ip addr before_script: - docker run -d --name postgres96 postgres:9.6-alpine diff --git a/script/cibuild b/script/cibuild index 387f61b8..e9d01564 100755 --- a/script/cibuild +++ b/script/cibuild @@ -4,10 +4,5 @@ source "$(dirname "${0}")"/../script/include/global_header.inc.sh -echo -echo "DEBUG: Hosts file:" -cat /etc/hosts -echo - # Run lint/style checks and unit tests source ./script/test diff --git a/script/get_db_settings b/script/get_db_settings index 701c2844..c96970a8 100755 --- a/script/get_db_settings +++ b/script/get_db_settings @@ -6,9 +6,3 @@ source "$(dirname "${0}")"/../script/include/global_header.inc.sh # Run the shared get_db_settings script source ./script/include/run_get_db_settings.sh - -echo -echo "Postgres settings: " -echo "PGHOST: $PGHOST" -echo "PGDATABASE: $PGDATABASE" -echo diff --git a/script/setup b/script/setup index c64ff07a..5cd11461 100755 --- a/script/setup +++ b/script/setup @@ -14,8 +14,5 @@ DATABASE_NAME="atat" # Enable database resetting RESET_DB="true" -echo "Hosts file:" -cat /etc/hosts - # Run the shared setup script source ./script/include/run_setup From 96ed26ed9fbb972197f37c0ba86ae048a9e4c2b4 Mon Sep 17 00:00:00 2001 From: Devon Mackay Date: Tue, 31 Jul 2018 08:47:57 -0400 Subject: [PATCH 030/332] Update to most recent scriptz --- script/include | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/include b/script/include index 5c19aef7..90a453b2 160000 --- a/script/include +++ b/script/include @@ -1 +1 @@ -Subproject commit 5c19aef7482aa0035f2d85e4c30ee21dfd7969c9 +Subproject commit 90a453b2ac4272961b3ed5f7d77d60816a09e092 From eeb45b61edd4f92ae98417a401b6eeab2d2a9eed Mon Sep 17 00:00:00 2001 From: dandds Date: Tue, 31 Jul 2018 08:49:00 -0400 Subject: [PATCH 031/332] fix lint errors --- atst/domain/workspaces.py | 3 --- atst/handlers/request_new.py | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/atst/domain/workspaces.py b/atst/domain/workspaces.py index ca848425..b4cc85b8 100644 --- a/atst/domain/workspaces.py +++ b/atst/domain/workspaces.py @@ -1,6 +1,3 @@ -import tornado.gen - - class Projects(object): def __init__(self): diff --git a/atst/handlers/request_new.py b/atst/handlers/request_new.py index e43e6ab3..67c24585 100644 --- a/atst/handlers/request_new.py +++ b/atst/handlers/request_new.py @@ -50,7 +50,7 @@ class RequestNew(BaseHandler): ) if jedi_flow.validate(): - request = jedi_flow.create_or_update_request() + jedi_flow.create_or_update_request() valid = yield jedi_flow.validate_warnings() if valid: if jedi_flow.next_screen > len(jedi_flow.screens): From dc2a1f572d02f4734880295fdc07a3be5ad901df Mon Sep 17 00:00:00 2001 From: dandds Date: Tue, 31 Jul 2018 09:35:17 -0400 Subject: [PATCH 032/332] remove references to requests-queue url and client --- atst/app.py | 5 ----- config/base.ini | 1 - 2 files changed, 6 deletions(-) diff --git a/atst/app.py b/atst/app.py index 9ac6f55f..4a76fbda 100644 --- a/atst/app.py +++ b/atst/app.py @@ -180,11 +180,6 @@ def make_deps(config): "fundz_client": ApiClient( config["default"]["FUNDZ_BASE_URL"], validate_cert=validate_cert ), - "requests_client": ApiClient( - config["default"]["REQUESTS_QUEUE_BASE_URL"], - api_version="v1", - validate_cert=validate_cert, - ), "sessions": RedisSessions( redis_client, config["default"]["SESSION_TTL_SECONDS"] ), diff --git a/config/base.ini b/config/base.ini index 6f63d78f..78d56c36 100644 --- a/config/base.ini +++ b/config/base.ini @@ -8,7 +8,6 @@ FUNDZ_BASE_URL= http://localhost:8004 COOKIE_SECRET = some-secret-please-replace SECRET = change_me_into_something_secret CAC_URL = https://localhost:8001 -REQUESTS_QUEUE_BASE_URL = http://localhost:8003 REDIS_URI = redis://localhost:6379 SESSION_TTL_SECONDS = 600 PGAPPNAME = atst From 8c75a5239db50f3a80ac95e808c5d83718394e43 Mon Sep 17 00:00:00 2001 From: dandds Date: Mon, 30 Jul 2018 11:36:03 -0400 Subject: [PATCH 033/332] import authz models --- .../versions/4ede1e3e50d1_add_authz_models.py | 62 +++++++++++++++++++ atst/models/__init__.py | 4 ++ atst/models/permissions.py | 40 ++++++++++++ atst/models/role.py | 14 +++++ atst/models/user.py | 21 +++++++ atst/models/workspace_role.py | 24 +++++++ 6 files changed, 165 insertions(+) create mode 100644 alembic/versions/4ede1e3e50d1_add_authz_models.py create mode 100644 atst/models/permissions.py create mode 100644 atst/models/role.py create mode 100644 atst/models/user.py create mode 100644 atst/models/workspace_role.py diff --git a/alembic/versions/4ede1e3e50d1_add_authz_models.py b/alembic/versions/4ede1e3e50d1_add_authz_models.py new file mode 100644 index 00000000..d782b676 --- /dev/null +++ b/alembic/versions/4ede1e3e50d1_add_authz_models.py @@ -0,0 +1,62 @@ +"""add_authz_models + +Revision ID: 4ede1e3e50d1 +Revises: b5b17d465166 +Create Date: 2018-07-30 11:34:12.016857 + +""" +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision = '4ede1e3e50d1' +down_revision = 'b5b17d465166' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('roles', + sa.Column('id', postgresql.UUID(as_uuid=True), server_default=sa.text('uuid_generate_v4()'), nullable=False), + sa.Column('name', sa.String(), nullable=True), + sa.Column('description', sa.String(), nullable=True), + sa.Column('permissions', postgresql.ARRAY(sa.String()), server_default='{}', nullable=True), + sa.PrimaryKeyConstraint('id') + ) + op.create_index(op.f('ix_roles_name'), 'roles', ['name'], unique=True) + op.create_index(op.f('ix_roles_permissions'), 'roles', ['permissions'], unique=False) + op.create_table('users', + sa.Column('id', postgresql.UUID(as_uuid=True), server_default=sa.text('uuid_generate_v4()'), nullable=False), + sa.Column('username', sa.String(), nullable=True), + sa.Column('atat_role_id', postgresql.UUID(as_uuid=True), nullable=True), + sa.ForeignKeyConstraint(['atat_role_id'], ['roles.id'], ), + sa.PrimaryKeyConstraint('id') + ) + op.create_table('workspace_role', + sa.Column('id', postgresql.UUID(as_uuid=True), server_default=sa.text('uuid_generate_v4()'), nullable=False), + sa.Column('workspace_id', postgresql.UUID(as_uuid=True), nullable=True), + sa.Column('role_id', postgresql.UUID(as_uuid=True), nullable=True), + sa.Column('user_id', postgresql.UUID(as_uuid=True), nullable=True), + sa.ForeignKeyConstraint(['role_id'], ['roles.id'], ), + sa.ForeignKeyConstraint(['user_id'], ['users.id'], ), + sa.PrimaryKeyConstraint('id') + ) + op.create_index(op.f('ix_workspace_role_user_id'), 'workspace_role', ['user_id'], unique=False) + op.create_index(op.f('ix_workspace_role_workspace_id'), 'workspace_role', ['workspace_id'], unique=False) + op.create_index('workspace_role_user_workspace', 'workspace_role', ['user_id', 'workspace_id'], unique=True) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_index('workspace_role_user_workspace', table_name='workspace_role') + op.drop_index(op.f('ix_workspace_role_workspace_id'), table_name='workspace_role') + op.drop_index(op.f('ix_workspace_role_user_id'), table_name='workspace_role') + op.drop_table('workspace_role') + op.drop_table('users') + op.drop_index(op.f('ix_roles_permissions'), table_name='roles') + op.drop_index(op.f('ix_roles_name'), table_name='roles') + op.drop_table('roles') + # ### end Alembic commands ### diff --git a/atst/models/__init__.py b/atst/models/__init__.py index ef5d9457..fef82003 100644 --- a/atst/models/__init__.py +++ b/atst/models/__init__.py @@ -4,3 +4,7 @@ Base = declarative_base() from .request import Request from .request_status_event import RequestStatusEvent +from .permissions import Permissions +from .role import Role +from .user import User +from .workspace_role import WorkspaceRole diff --git a/atst/models/permissions.py b/atst/models/permissions.py new file mode 100644 index 00000000..9536348f --- /dev/null +++ b/atst/models/permissions.py @@ -0,0 +1,40 @@ +class Permissions(object): + REQUEST_JEDI_WORKSPACE = "request_jedi_workspace" + VIEW_ORIGINAL_JEDI_REQEUST = "view_original_jedi_request" + REVIEW_AND_APPROVE_JEDI_WORKSPACE_REQUEST = ( + "review_and_approve_jedi_workspace_request" + ) + MODIFY_ATAT_ROLE_PERMISSIONS = "modify_atat_role_permissions" + CREATE_CSP_ROLE = "create_csp_role" + DELETE_CSP_ROLE = "delete_csp_role" + DEACTIVE_CSP_ROLE = "deactivate_csp_role" + MODIFY_CSP_ROLE_PERMISSIONS = "modify_csp_role_permissions" + + VIEW_USAGE_REPORT = "view_usage_report" + VIEW_USAGE_DOLLARS = "view_usage_dollars" + ADD_AND_ASSIGN_CSP_ROLES = "add_and_assign_csp_roles" + REMOVE_CSP_ROLES = "remove_csp_roles" + REQUEST_NEW_CSP_ROLE = "request_new_csp_role" + ASSIGN_AND_UNASSIGN_ATAT_ROLE = "assign_and_unassign_atat_role" + + VIEW_ASSIGNED_ATAT_ROLE_CONFIGURATIONS = "view_assigned_atat_role_configurations" + VIEW_ASSIGNED_CSP_ROLE_CONFIGURATIONS = "view_assigned_csp_role_configurations" + + DEACTIVATE_WORKSPACE = "deactivate_workspace" + VIEW_ATAT_PERMISSIONS = "view_atat_permissions" + TRANSFER_OWNERSHIP_OF_WORKSPACE = "transfer_ownership_of_workspace" + + ADD_APPLICATION_IN_WORKSPACE = "add_application_in_workspace" + DELETE_APPLICATION_IN_WORKSPACE = "delete_application_in_workspace" + DEACTIVATE_APPLICATION_IN_WORKSPACE = "deactivate_application_in_workspace" + VIEW_APPLICATION_IN_WORKSPACE = "view_application_in_workspace" + RENAME_APPLICATION_IN_WORKSPACE = "rename_application_in_workspace" + + ADD_ENVIRONMENT_IN_APPLICATION = "add_environment_in_application" + DELETE_ENVIRONMENT_IN_APPLICATION = "delete_environment_in_application" + DEACTIVATE_ENVIRONMENT_IN_APPLICATION = "deactivate_environment_in_application" + VIEW_ENVIRONMENT_IN_APPLICATION = "view_environment_in_application" + RENAME_ENVIRONMENT_IN_APPLICATION = "rename_environment_in_application" + + ADD_TAG_TO_WORKSPACE = "add_tag_to_workspace" + REMOVE_TAG_FROM_WORKSPACE = "remove_tag_from_workspace" diff --git a/atst/models/role.py b/atst/models/role.py new file mode 100644 index 00000000..1205dedd --- /dev/null +++ b/atst/models/role.py @@ -0,0 +1,14 @@ +from sqlalchemy import String, Column +from sqlalchemy.dialects.postgresql import ARRAY + +from atst.models import Base +from .types import Id + + +class Role(Base): + __tablename__ = "roles" + + id = Id() + name = Column(String, index=True, unique=True) + description = Column(String) + permissions = Column(ARRAY(String), index=True, server_default="{}") diff --git a/atst/models/user.py b/atst/models/user.py new file mode 100644 index 00000000..f3954f26 --- /dev/null +++ b/atst/models/user.py @@ -0,0 +1,21 @@ +from sqlalchemy import String, ForeignKey, Column +from sqlalchemy.orm import relationship +from sqlalchemy.dialects.postgresql import UUID + +from atst.models import Base +from .types import Id + + +class User(Base): + __tablename__ = "users" + + id = Id() + username = Column(String) + atat_role_id = Column(UUID(as_uuid=True), ForeignKey("roles.id")) + + atat_role = relationship("Role") + workspace_roles = relationship("WorkspaceRole", backref="user") + + @property + def atat_permissions(self): + return self.atat_role.permissions diff --git a/atst/models/workspace_role.py b/atst/models/workspace_role.py new file mode 100644 index 00000000..86970e0b --- /dev/null +++ b/atst/models/workspace_role.py @@ -0,0 +1,24 @@ +from sqlalchemy import Index, ForeignKey, Column +from sqlalchemy.dialects.postgresql import UUID +from sqlalchemy.orm import relationship + +from atst.models import Base +from .types import Id + + +class WorkspaceRole(Base): + __tablename__ = "workspace_role" + + id = Id() + workspace_id = Column(UUID(as_uuid=True), index=True) + role_id = Column(UUID(as_uuid=True), ForeignKey("roles.id")) + user_id = Column(UUID(as_uuid=True), ForeignKey("users.id"), index=True) + role = relationship("Role") + + +Index( + "workspace_role_user_workspace", + WorkspaceRole.user_id, + WorkspaceRole.workspace_id, + unique=True, +) From 06c2c205a1cb394b5f73d08e48dd959c46a9e447 Mon Sep 17 00:00:00 2001 From: dandds Date: Mon, 30 Jul 2018 11:44:56 -0400 Subject: [PATCH 034/332] import authz domain module --- atst/domain/roles.py | 19 ++++++++++ atst/domain/users.py | 58 ++++++++++++++++++++++++++++++ atst/domain/workspace_users.py | 64 ++++++++++++++++++++++++++++++++++ atst/models/workspace_user.py | 14 ++++++++ 4 files changed, 155 insertions(+) create mode 100644 atst/domain/roles.py create mode 100644 atst/domain/users.py create mode 100644 atst/domain/workspace_users.py create mode 100644 atst/models/workspace_user.py diff --git a/atst/domain/roles.py b/atst/domain/roles.py new file mode 100644 index 00000000..1b5f66c0 --- /dev/null +++ b/atst/domain/roles.py @@ -0,0 +1,19 @@ +from sqlalchemy.orm.exc import NoResultFound + +from atst.models import Role +from .exceptions import NotFoundError + + +class Roles(object): + @classmethod + def get(cls, role_name): + try: + role = Role.query.filter_by(name=role_name).one() + except NoResultFound: + raise NotFoundError("role") + + return role + + @classmethod + def get_all(cls): + return Role.query.all() diff --git a/atst/domain/users.py b/atst/domain/users.py new file mode 100644 index 00000000..ace13eb5 --- /dev/null +++ b/atst/domain/users.py @@ -0,0 +1,58 @@ +from sqlalchemy.orm.exc import NoResultFound +from sqlalchemy.exc import IntegrityError + +from atst.models import User + +from .roles import Roles +from .exceptions import NotFoundError, AlreadyExistsError + + +class Users(object): + + def __init__(self, db_session): + self.db_session = db_session + + + def get(self, user_id): + try: + user = User.query.filter_by(id=user_id).one() + except NoResultFound: + raise NotFoundError("user") + + return user + + def create(self, user_id, atat_role_name): + atat_role = Roles.get(atat_role_name) + + try: + user = User(id=user_id, atat_role=atat_role) + self.db_session.add(user) + self.db_session.commit() + except IntegrityError: + raise AlreadyExistsError("user") + + return user + + def get_or_create(self, user_id, *args, **kwargs): + created = False + + try: + user = Users.get(user_id) + except NotFoundError: + user = Users.create(user_id, *args, **kwargs) + self.db_session.add(user) + self.db_session.commit() + created = True + + return user, created + + def update(self, user_id, atat_role_name): + + user = Users.get(user_id) + atat_role = Roles.get(atat_role_name) + user.atat_role = atat_role + + self.db_session.add(user) + self.db_session.commit() + + return user diff --git a/atst/domain/workspace_users.py b/atst/domain/workspace_users.py new file mode 100644 index 00000000..9ff139cd --- /dev/null +++ b/atst/domain/workspace_users.py @@ -0,0 +1,64 @@ +from sqlalchemy.orm.exc import NoResultFound +from sqlalchemy.dialects.postgresql import insert + +from atst.models import User, WorkspaceRole, Role +from .exceptions import NotFoundError + +class WorkspaceUsers(object): + + def __init__(self, db_session): + self.db_session = db_session + + def get(self, workspace_id, user_id): + try: + user = User.query.filter_by(id=user_id).one() + except NoResultFound: + raise NotFoundError("user") + + try: + workspace_role = ( + WorkspaceRole.query.join(User) + .filter(User.id == user_id, WorkspaceRole.workspace_id == workspace_id) + .one() + ) + except NoResultFound: + workspace_role = None + + return WorkspaceUser(user, workspace_role) + + def add_many(self, workspace_id, workspace_user_dicts): + workspace_users = [] + + for user_dict in workspace_user_dicts: + try: + user = User.query.filter_by(id=user_dict["id"]).one() + except NoResultFound: + default_role = Role.query.filter_by(name="developer").one_or_none() + user = User(id=user_dict["id"], atat_role=default_role) + + try: + role = Role.query.filter_by(name=user_dict["workspace_role"]).one() + except NoResultFound: + raise NotFoundError("role") + + try: + existing_workspace_role = WorkspaceRole.query.filter( + WorkspaceRole.user == user, + WorkspaceRole.workspace_id == workspace_id, + ).one() + new_workspace_role = existing_workspace_role + new_workspace_role.role = role + except NoResultFound: + new_workspace_role = WorkspaceRole( + user=user, role_id=role.id, workspace_id=workspace_id + ) + + user.workspace_roles.append(new_workspace_role) + workspace_user = WorkspaceUser(user, new_workspace_role) + workspace_users.append(workspace_user) + + self.db_session.add(user) + + self.db_session.commit() + + return workspace_users diff --git a/atst/models/workspace_user.py b/atst/models/workspace_user.py new file mode 100644 index 00000000..6faba2d6 --- /dev/null +++ b/atst/models/workspace_user.py @@ -0,0 +1,14 @@ +class WorkspaceUser(object): + def __init__(self, user, workspace_role): + self.user = user + self.workspace_role = workspace_role + + def permissions(self): + atat_permissions = set(self.user.atat_role.permissions) + workspace_permissions = ( + [] if self.workspace_role is None else self.workspace_role.role.permissions + ) + return set(workspace_permissions).union(atat_permissions) + + def workspace_id(self): + return self.workspace_role.workspace_id From 4baa5fdd8ce21d9772bd4b7903e546fbedb789de Mon Sep 17 00:00:00 2001 From: dandds Date: Mon, 30 Jul 2018 14:03:42 -0400 Subject: [PATCH 035/332] add role and perms migrations for authorization --- .../4ea5917e7781_add_default_atat_role.py | 39 ++++ .../96a9f3537996_add_roles_and_permissions.py | 183 ++++++++++++++++++ 2 files changed, 222 insertions(+) create mode 100644 alembic/versions/4ea5917e7781_add_default_atat_role.py create mode 100644 alembic/versions/96a9f3537996_add_roles_and_permissions.py diff --git a/alembic/versions/4ea5917e7781_add_default_atat_role.py b/alembic/versions/4ea5917e7781_add_default_atat_role.py new file mode 100644 index 00000000..78b6ef55 --- /dev/null +++ b/alembic/versions/4ea5917e7781_add_default_atat_role.py @@ -0,0 +1,39 @@ +"""add_default_atat_role + +Revision ID: 4ea5917e7781 +Revises: 96a9f3537996 +Create Date: 2018-07-30 13:51:29.576931 + +""" +from alembic import op +import sqlalchemy as sa +from sqlalchemy.orm.session import Session + + +# revision identifiers, used by Alembic. +revision = '4ea5917e7781' +down_revision = '96a9f3537996' +branch_labels = None +depends_on = None + +from atst.models.role import Role +from atst.models.permissions import Permissions + + +def upgrade(): + session = Session(bind=op.get_bind()) + mission_owner_role = Role( + name='default', + description='', + permissions=[ + Permissions.REQUEST_JEDI_WORKSPACE, + ] + ) + session.add(mission_owner_role) + session.commit() + + +def downgrade(): + db = op.get_bind() + db.execute("DELETE FROM roles WHERE name = 'default'") + diff --git a/alembic/versions/96a9f3537996_add_roles_and_permissions.py b/alembic/versions/96a9f3537996_add_roles_and_permissions.py new file mode 100644 index 00000000..4380208a --- /dev/null +++ b/alembic/versions/96a9f3537996_add_roles_and_permissions.py @@ -0,0 +1,183 @@ +"""add_roles_and_permissions + +Revision ID: 96a9f3537996 +Revises: 4ede1e3e50d1 +Create Date: 2018-07-30 13:48:31.325234 + +""" +import os +import sys +from alembic import op +import sqlalchemy as sa + +from sqlalchemy.orm.session import Session + +from atst.models.role import Role +from atst.models.permissions import Permissions + +# revision identifiers, used by Alembic. +revision = '96a9f3537996' +down_revision = '4ede1e3e50d1' +branch_labels = None +depends_on = None + + +def upgrade(): + session = Session(bind=op.get_bind()) + roles = [ + Role( + name='ccpo', + description='', + permissions=[ + Permissions.VIEW_ORIGINAL_JEDI_REQEUST, + Permissions.REVIEW_AND_APPROVE_JEDI_WORKSPACE_REQUEST, + Permissions.MODIFY_ATAT_ROLE_PERMISSIONS, + Permissions.CREATE_CSP_ROLE, + Permissions.DELETE_CSP_ROLE, + Permissions.DEACTIVE_CSP_ROLE, + Permissions.MODIFY_CSP_ROLE_PERMISSIONS, + + Permissions.VIEW_USAGE_REPORT, + Permissions.VIEW_USAGE_DOLLARS, + Permissions.ADD_AND_ASSIGN_CSP_ROLES, + Permissions.REMOVE_CSP_ROLES, + Permissions.REQUEST_NEW_CSP_ROLE, + Permissions.ASSIGN_AND_UNASSIGN_ATAT_ROLE, + + Permissions.VIEW_ASSIGNED_ATAT_ROLE_CONFIGURATIONS, + Permissions.VIEW_ASSIGNED_CSP_ROLE_CONFIGURATIONS, + + Permissions.DEACTIVATE_WORKSPACE, + Permissions.VIEW_ATAT_PERMISSIONS, + Permissions.TRANSFER_OWNERSHIP_OF_WORKSPACE, + + Permissions.ADD_APPLICATION_IN_WORKSPACE, + Permissions.DELETE_APPLICATION_IN_WORKSPACE, + Permissions.DEACTIVATE_APPLICATION_IN_WORKSPACE, + Permissions.VIEW_APPLICATION_IN_WORKSPACE, + Permissions.RENAME_APPLICATION_IN_WORKSPACE, + + Permissions.ADD_ENVIRONMENT_IN_APPLICATION, + Permissions.DELETE_ENVIRONMENT_IN_APPLICATION, + Permissions.DEACTIVATE_ENVIRONMENT_IN_APPLICATION, + Permissions.VIEW_ENVIRONMENT_IN_APPLICATION, + Permissions.RENAME_ENVIRONMENT_IN_APPLICATION, + + Permissions.ADD_TAG_TO_WORKSPACE, + Permissions.REMOVE_TAG_FROM_WORKSPACE + ] + ), + Role( + name='owner', + description='', + permissions=[ + Permissions.REQUEST_JEDI_WORKSPACE, + Permissions.VIEW_ORIGINAL_JEDI_REQEUST, + + Permissions.VIEW_USAGE_REPORT, + Permissions.VIEW_USAGE_DOLLARS, + Permissions.ADD_AND_ASSIGN_CSP_ROLES, + Permissions.REMOVE_CSP_ROLES, + Permissions.REQUEST_NEW_CSP_ROLE, + Permissions.ASSIGN_AND_UNASSIGN_ATAT_ROLE, + + Permissions.VIEW_ASSIGNED_ATAT_ROLE_CONFIGURATIONS, + Permissions.VIEW_ASSIGNED_CSP_ROLE_CONFIGURATIONS, + + Permissions.DEACTIVATE_WORKSPACE, + Permissions.VIEW_ATAT_PERMISSIONS, + + Permissions.ADD_APPLICATION_IN_WORKSPACE, + Permissions.DELETE_APPLICATION_IN_WORKSPACE, + Permissions.DEACTIVATE_APPLICATION_IN_WORKSPACE, + Permissions.VIEW_APPLICATION_IN_WORKSPACE, + Permissions.RENAME_APPLICATION_IN_WORKSPACE, + + Permissions.ADD_ENVIRONMENT_IN_APPLICATION, + Permissions.DELETE_ENVIRONMENT_IN_APPLICATION, + Permissions.DEACTIVATE_ENVIRONMENT_IN_APPLICATION, + Permissions.VIEW_ENVIRONMENT_IN_APPLICATION, + Permissions.RENAME_ENVIRONMENT_IN_APPLICATION, + ] + ), + Role( + name='admin', + description='', + permissions=[ + Permissions.VIEW_USAGE_REPORT, + Permissions.ADD_AND_ASSIGN_CSP_ROLES, + Permissions.REMOVE_CSP_ROLES, + Permissions.REQUEST_NEW_CSP_ROLE, + Permissions.ASSIGN_AND_UNASSIGN_ATAT_ROLE, + + Permissions.VIEW_ASSIGNED_ATAT_ROLE_CONFIGURATIONS, + Permissions.VIEW_ASSIGNED_CSP_ROLE_CONFIGURATIONS, + + Permissions.ADD_APPLICATION_IN_WORKSPACE, + Permissions.DELETE_APPLICATION_IN_WORKSPACE, + Permissions.DEACTIVATE_APPLICATION_IN_WORKSPACE, + Permissions.VIEW_APPLICATION_IN_WORKSPACE, + Permissions.RENAME_APPLICATION_IN_WORKSPACE, + + Permissions.ADD_ENVIRONMENT_IN_APPLICATION, + Permissions.DELETE_ENVIRONMENT_IN_APPLICATION, + Permissions.DEACTIVATE_ENVIRONMENT_IN_APPLICATION, + Permissions.VIEW_ENVIRONMENT_IN_APPLICATION, + Permissions.RENAME_ENVIRONMENT_IN_APPLICATION, + ] + ), + Role( + name='developer', + description='', + permissions=[ + Permissions.VIEW_USAGE_REPORT, + Permissions.VIEW_USAGE_DOLLARS, + Permissions.VIEW_APPLICATION_IN_WORKSPACE, + Permissions.VIEW_ENVIRONMENT_IN_APPLICATION + ] + ), + Role( + name='billing_auditor', + description='', + permissions=[ + Permissions.VIEW_USAGE_REPORT, + Permissions.VIEW_USAGE_DOLLARS, + + Permissions.VIEW_APPLICATION_IN_WORKSPACE, + + Permissions.VIEW_ENVIRONMENT_IN_APPLICATION, + ] + ), + Role( + name='security_auditor', + description='', + permissions=[ + Permissions.VIEW_ASSIGNED_ATAT_ROLE_CONFIGURATIONS, + Permissions.VIEW_ASSIGNED_CSP_ROLE_CONFIGURATIONS, + + Permissions.VIEW_ATAT_PERMISSIONS, + + Permissions.VIEW_APPLICATION_IN_WORKSPACE, + + Permissions.VIEW_ENVIRONMENT_IN_APPLICATION, + ] + ), + ] + + session.add_all(roles) + session.commit() + + +def downgrade(): + db = op.get_bind() + db.execute(""" + DELETE FROM roles + WHERE name IN ( + 'ccpo', + 'owner', + 'admin', + 'developer', + 'billing_auditor', + 'security_auditor' + ); + """) From 202f88bae59c05644f8abeca22ff5a04d9fb222f Mon Sep 17 00:00:00 2001 From: dandds Date: Mon, 30 Jul 2018 14:04:05 -0400 Subject: [PATCH 036/332] update handlers to user Users repo for managing authorization --- atst/app.py | 11 +++-------- atst/domain/roles.py | 13 +++++++------ atst/domain/users.py | 18 ++++++++---------- atst/handler.py | 21 +++++++-------------- atst/handlers/dev.py | 12 +++++------- atst/handlers/login_redirect.py | 4 ++-- atst/handlers/request.py | 1 + atst/handlers/request_submit.py | 1 + atst/handlers/workspaces.py | 4 ++-- tests/conftest.py | 1 - 10 files changed, 36 insertions(+), 50 deletions(-) diff --git a/atst/app.py b/atst/app.py index 4a76fbda..5ef0e18f 100644 --- a/atst/app.py +++ b/atst/app.py @@ -35,7 +35,7 @@ def make_app(config, deps, **kwargs): { "sessions": deps["sessions"], "authnid_client": deps["authnid_client"], - "authz_client": deps["authz_client"], + "db_session": deps["db_session"], }, name="login_redirect", ), @@ -50,7 +50,7 @@ def make_app(config, deps, **kwargs): url( r"/workspaces", Workspaces, - {"page": "workspaces", "authz_client": deps["authz_client"]}, + {"page": "workspaces", "db_session": deps["db_session"]}, name="workspaces", ), url( @@ -136,7 +136,7 @@ def make_app(config, deps, **kwargs): { "action": "login", "sessions": deps["sessions"], - "authz_client": deps["authz_client"], + "db_session": deps["db_session"], }, name="dev-login", ) @@ -167,11 +167,6 @@ def make_deps(config): return { "db_session": make_db(config), - "authz_client": ApiClient( - config["default"]["AUTHZ_BASE_URL"], - api_version="v1", - validate_cert=validate_cert, - ), "authnid_client": ApiClient( config["default"]["AUTHNID_BASE_URL"], api_version="v1", diff --git a/atst/domain/roles.py b/atst/domain/roles.py index 1b5f66c0..87a36961 100644 --- a/atst/domain/roles.py +++ b/atst/domain/roles.py @@ -5,15 +5,16 @@ from .exceptions import NotFoundError class Roles(object): - @classmethod - def get(cls, role_name): + def __init__(self, db_session): + self.db_session = db_session + + def get(self, role_name): try: - role = Role.query.filter_by(name=role_name).one() + role = self.db_session.query(Role).filter_by(name=role_name).one() except NoResultFound: raise NotFoundError("role") return role - @classmethod - def get_all(cls): - return Role.query.all() + def get_all(self): + return self.db_session.query(Role).all() diff --git a/atst/domain/users.py b/atst/domain/users.py index ace13eb5..94e99056 100644 --- a/atst/domain/users.py +++ b/atst/domain/users.py @@ -11,18 +11,19 @@ class Users(object): def __init__(self, db_session): self.db_session = db_session + self.roles_repo = Roles(db_session) def get(self, user_id): try: - user = User.query.filter_by(id=user_id).one() + user = self.db_session.query(User).filter_by(id=user_id).one() except NoResultFound: raise NotFoundError("user") return user def create(self, user_id, atat_role_name): - atat_role = Roles.get(atat_role_name) + atat_role = self.roles_repo.get(atat_role_name) try: user = User(id=user_id, atat_role=atat_role) @@ -34,22 +35,19 @@ class Users(object): return user def get_or_create(self, user_id, *args, **kwargs): - created = False - try: - user = Users.get(user_id) + user = self.get(user_id) except NotFoundError: - user = Users.create(user_id, *args, **kwargs) + user = self.create(user_id, *args, **kwargs) self.db_session.add(user) self.db_session.commit() - created = True - return user, created + return user def update(self, user_id, atat_role_name): - user = Users.get(user_id) - atat_role = Roles.get(atat_role_name) + user = self.get(user_id) + atat_role = self.roles_repo.get(atat_role_name) user.atat_role = atat_role self.db_session.add(user) diff --git a/atst/handler.py b/atst/handler.py index 3766aa95..bcbcf879 100644 --- a/atst/handler.py +++ b/atst/handler.py @@ -1,6 +1,7 @@ import tornado.web from atst.assets import environment from atst.sessions import SessionNotFoundError +from atst.domain.users import Users helpers = {"assets": environment} @@ -15,26 +16,18 @@ class BaseHandler(tornado.web.RequestHandler): @tornado.gen.coroutine def login(self, user): - user_permissions = yield self._get_user_permissions(user["id"]) - user["atat_permissions"] = user_permissions["atat_permissions"] - user["atat_role"] = user_permissions["atat_role"] + db_user = yield self._get_user_permissions(user["id"]) + user["atat_permissions"] = db_user.atat_permissions + user["atat_role"] = db_user.atat_role.name session_id = self.sessions.start_session(user) self.set_secure_cookie("atat", session_id) return self.redirect("/home") @tornado.gen.coroutine def _get_user_permissions(self, user_id): - response = yield self.authz_client.get( - "/users/{}".format(user_id), raise_error=False - ) - if response.code == 404: - response = yield self.authz_client.post( - "/users", json={"id": user_id, "atat_role": "developer"} - ) - return response.json - - else: - return response.json + user_repo = Users(self.db_session) + user = user_repo.get_or_create(user_id, atat_role_name="developer") + return user def get_current_user(self): cookie = self.get_secure_cookie("atat") diff --git a/atst/handlers/dev.py b/atst/handlers/dev.py index 878aca11..4394936b 100644 --- a/atst/handlers/dev.py +++ b/atst/handlers/dev.py @@ -1,6 +1,7 @@ import tornado.gen from atst.handler import BaseHandler +from atst.domain.users import Users _DEV_USERS = { "sam": { @@ -9,7 +10,6 @@ _DEV_USERS = { "last_name": "Seeceepio", "atat_role": "ccpo" }, - "amanda": { "id": "cce17030-4109-4719-b958-ed109dbb87c8", "first_name": "Amanda", @@ -44,10 +44,11 @@ _DEV_USERS = { class Dev(BaseHandler): - def initialize(self, action, sessions, authz_client): + def initialize(self, action, sessions, db_session): + self.db_session = db_session self.action = action self.sessions = sessions - self.authz_client = authz_client + self.users_repo = Users(db_session) @tornado.gen.coroutine def get(self): @@ -58,7 +59,4 @@ class Dev(BaseHandler): @tornado.gen.coroutine def _set_user_permissions(self, user_id, role): - response = yield self.authz_client.post( - "/users", json={"id": user_id, "atat_role": role} - ) - return response.json + return self.users_repo.get_or_create(user_id, atat_role_name=role) diff --git a/atst/handlers/login_redirect.py b/atst/handlers/login_redirect.py index 59fb8751..7746e934 100644 --- a/atst/handlers/login_redirect.py +++ b/atst/handlers/login_redirect.py @@ -3,10 +3,10 @@ from atst.handler import BaseHandler class LoginRedirect(BaseHandler): - def initialize(self, authnid_client, sessions, authz_client): + def initialize(self, authnid_client, sessions, db_session): + self.db_session = db_session self.authnid_client = authnid_client self.sessions = sessions - self.authz_client = authz_client @tornado.gen.coroutine def get(self): diff --git a/atst/handlers/request.py b/atst/handlers/request.py index 1373280a..6918526e 100644 --- a/atst/handlers/request.py +++ b/atst/handlers/request.py @@ -22,6 +22,7 @@ def map_request(user, request): class Request(BaseHandler): def initialize(self, page, db_session): self.page = page + self.db_session = db_session self.requests = Requests(db_session) @tornado.web.authenticated diff --git a/atst/handlers/request_submit.py b/atst/handlers/request_submit.py index ff27803b..116e996a 100644 --- a/atst/handlers/request_submit.py +++ b/atst/handlers/request_submit.py @@ -6,6 +6,7 @@ from atst.domain.requests import Requests class RequestsSubmit(BaseHandler): def initialize(self, db_session): + self.db_session = db_session self.requests_repo = Requests(db_session) @tornado.web.authenticated diff --git a/atst/handlers/workspaces.py b/atst/handlers/workspaces.py index c7e06451..b6fa1dbe 100644 --- a/atst/handlers/workspaces.py +++ b/atst/handlers/workspaces.py @@ -12,9 +12,9 @@ mock_workspaces = [ class Workspaces(BaseHandler): - def initialize(self, page, authz_client): + def initialize(self, page, db_session): self.page = page - self.authz_client = authz_client + self.db_session = db_session @tornado.gen.coroutine @tornado.web.authenticated diff --git a/tests/conftest.py b/tests/conftest.py index a0ed8550..555e1f79 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -10,7 +10,6 @@ from atst.sessions import DictSessions @pytest.fixture def app(db): TEST_DEPS = { - "authz_client": MockAuthzClient("authz"), "authnid_client": MockApiClient("authnid"), "fundz_client": MockFundzClient("fundz"), "sessions": DictSessions(), From e270350925cec91122f6a85b046282fbd60e110c Mon Sep 17 00:00:00 2001 From: dandds Date: Mon, 30 Jul 2018 14:19:38 -0400 Subject: [PATCH 037/332] add WorkspaceUser tests from authz --- atst/domain/workspace_users.py | 18 ++++++++---- tests/domain/test_workspace_users.py | 43 ++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 6 deletions(-) create mode 100644 tests/domain/test_workspace_users.py diff --git a/atst/domain/workspace_users.py b/atst/domain/workspace_users.py index 9ff139cd..857be057 100644 --- a/atst/domain/workspace_users.py +++ b/atst/domain/workspace_users.py @@ -1,17 +1,23 @@ from sqlalchemy.orm.exc import NoResultFound from sqlalchemy.dialects.postgresql import insert -from atst.models import User, WorkspaceRole, Role +from atst.models.workspace_role import WorkspaceRole +from atst.models.workspace_user import WorkspaceUser +from atst.models.user import User +from .roles import Roles +from .users import Users from .exceptions import NotFoundError class WorkspaceUsers(object): def __init__(self, db_session): self.db_session = db_session + self.roles_repo = Roles(db_session) + self.users_repo = Users(db_session) def get(self, workspace_id, user_id): try: - user = User.query.filter_by(id=user_id).one() + user = self.users_repo.get(user_id) except NoResultFound: raise NotFoundError("user") @@ -31,18 +37,18 @@ class WorkspaceUsers(object): for user_dict in workspace_user_dicts: try: - user = User.query.filter_by(id=user_dict["id"]).one() + user = self.users_repo.get(user_dict["id"]) except NoResultFound: - default_role = Role.query.filter_by(name="developer").one_or_none() + default_role = self.roles_repo.get("developer") user = User(id=user_dict["id"], atat_role=default_role) try: - role = Role.query.filter_by(name=user_dict["workspace_role"]).one() + role = self.roles_repo.get(user_dict["workspace_role"]) except NoResultFound: raise NotFoundError("role") try: - existing_workspace_role = WorkspaceRole.query.filter( + existing_workspace_role = self.db_session.query(WorkspaceRole).filter( WorkspaceRole.user == user, WorkspaceRole.workspace_id == workspace_id, ).one() diff --git a/tests/domain/test_workspace_users.py b/tests/domain/test_workspace_users.py new file mode 100644 index 00000000..e86662f3 --- /dev/null +++ b/tests/domain/test_workspace_users.py @@ -0,0 +1,43 @@ +import pytest +from uuid import uuid4 + +from atst.domain.workspace_users import WorkspaceUsers +from atst.domain.users import Users + + +@pytest.fixture() +def users_repo(db): + return Users(db) + +@pytest.fixture() +def workspace_users_repo(db): + return WorkspaceUsers(db) + +def test_can_create_new_workspace_user(users_repo, workspace_users_repo): + workspace_id = uuid4() + user = users_repo.create(uuid4(), "developer") + + workspace_user_dicts = [ + {"id": user.id, "workspace_role": "owner"} + ] + + workspace_users = workspace_users_repo.add_many(workspace_id, workspace_user_dicts) + + assert workspace_users[0].user.id == user.id + assert workspace_users[0].user.atat_role.name == "developer" + assert workspace_users[0].workspace_role.role.name == "owner" + + +def test_can_update_existing_workspace_user(users_repo, workspace_users_repo): + workspace_id = uuid4() + user = users_repo.create(uuid4(), "developer") + + workspace_users_repo.add_many(workspace_id, [ + {"id": user.id, "workspace_role": "owner"} + ]) + workspace_users = workspace_users_repo.add_many(workspace_id, [ + {"id": user.id, "workspace_role": "developer"} + ]) + + assert workspace_users[0].user.id == user.id + assert workspace_users[0].workspace_role.role.name == "developer" From 08243a199a8c0c7dd796eff6c61d1ade6a28b35d Mon Sep 17 00:00:00 2001 From: richard-dds Date: Mon, 30 Jul 2018 15:31:14 -0400 Subject: [PATCH 038/332] Add domain tests for all of authz --- tests/domain/test_roles.py | 23 ++++++++++++ tests/domain/test_users.py | 72 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 tests/domain/test_roles.py create mode 100644 tests/domain/test_users.py diff --git a/tests/domain/test_roles.py b/tests/domain/test_roles.py new file mode 100644 index 00000000..1280292f --- /dev/null +++ b/tests/domain/test_roles.py @@ -0,0 +1,23 @@ +import pytest +from atst.domain.roles import Roles +from atst.domain.exceptions import NotFoundError + + +@pytest.fixture() +def roles_repo(db): + return Roles(db) + + +def test_get_all_roles(roles_repo): + roles = roles_repo.get_all() + assert roles + + +def test_get_existing_role(roles_repo): + role = roles_repo.get("developer") + assert role.name == "developer" + + +def test_get_nonexistent_role(roles_repo): + with pytest.raises(NotFoundError): + roles_repo.get("nonexistent") diff --git a/tests/domain/test_users.py b/tests/domain/test_users.py new file mode 100644 index 00000000..921463f8 --- /dev/null +++ b/tests/domain/test_users.py @@ -0,0 +1,72 @@ +import pytest +from uuid import uuid4, UUID + +from atst.domain.users import Users +from atst.domain.exceptions import NotFoundError, AlreadyExistsError + +@pytest.fixture() +def users_repo(db) -> Users: + return Users(db) + + +@pytest.fixture(scope="function") +def user_id(): + return uuid4() + + +def test_create_user(users_repo, user_id): + user = users_repo.create(user_id, "developer") + assert user.id == user_id + + +def test_create_user_with_nonexistent_role(users_repo, user_id): + with pytest.raises(NotFoundError): + users_repo.create(user_id, "nonexistent") + + +def test_create_already_existing_user(users_repo, user_id): + users_repo.create(user_id, "developer") + with pytest.raises(AlreadyExistsError): + users_repo.create(user_id, "developer") + + +def test_get_or_create_nonexistent_user(users_repo, user_id): + user = users_repo.get_or_create(user_id, atat_role_name="developer") + assert user.id == user_id + + +def test_get_or_create_existing_user(users_repo, user_id): + users_repo.get_or_create(user_id, atat_role_name="developer") + user = users_repo.get_or_create(user_id, atat_role_name="developer") + assert user + + +def test_get_user(users_repo, user_id): + users_repo.create(user_id, "developer") + user = users_repo.get(user_id) + assert user.id == user_id + + +def test_get_nonexistent_user(users_repo, user_id): + users_repo.create(user_id, "developer") + with pytest.raises(NotFoundError): + users_repo.get(uuid4()) + + +def test_update_user(users_repo, user_id): + users_repo.create(user_id, "developer") + updated_user = users_repo.update(user_id, "ccpo") + + assert updated_user.atat_role.name == "ccpo" + + +def test_update_nonexistent_user(users_repo, user_id): + users_repo.create(user_id, "developer") + with pytest.raises(NotFoundError): + users_repo.update(uuid4(), "ccpo") + + +def test_update_existing_user_with_nonexistent_role(users_repo, user_id): + users_repo.create(user_id, "developer") + with pytest.raises(NotFoundError): + users_repo.update(user_id, "nonexistent") From efdf0b04ba561c4c4f40053970647aee99609697 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Mon, 30 Jul 2018 15:33:19 -0400 Subject: [PATCH 039/332] Formatting --- atst/domain/users.py | 2 -- atst/domain/workspace_users.py | 14 +++++++++----- atst/domain/workspaces.py | 2 -- tests/domain/test_users.py | 1 + tests/domain/test_workspace_users.py | 18 +++++++++--------- 5 files changed, 19 insertions(+), 18 deletions(-) diff --git a/atst/domain/users.py b/atst/domain/users.py index 94e99056..76385228 100644 --- a/atst/domain/users.py +++ b/atst/domain/users.py @@ -8,12 +8,10 @@ from .exceptions import NotFoundError, AlreadyExistsError class Users(object): - def __init__(self, db_session): self.db_session = db_session self.roles_repo = Roles(db_session) - def get(self, user_id): try: user = self.db_session.query(User).filter_by(id=user_id).one() diff --git a/atst/domain/workspace_users.py b/atst/domain/workspace_users.py index 857be057..e4d93c19 100644 --- a/atst/domain/workspace_users.py +++ b/atst/domain/workspace_users.py @@ -8,8 +8,8 @@ from .roles import Roles from .users import Users from .exceptions import NotFoundError -class WorkspaceUsers(object): +class WorkspaceUsers(object): def __init__(self, db_session): self.db_session = db_session self.roles_repo = Roles(db_session) @@ -48,10 +48,14 @@ class WorkspaceUsers(object): raise NotFoundError("role") try: - existing_workspace_role = self.db_session.query(WorkspaceRole).filter( - WorkspaceRole.user == user, - WorkspaceRole.workspace_id == workspace_id, - ).one() + existing_workspace_role = ( + self.db_session.query(WorkspaceRole) + .filter( + WorkspaceRole.user == user, + WorkspaceRole.workspace_id == workspace_id, + ) + .one() + ) new_workspace_role = existing_workspace_role new_workspace_role.role = role except NoResultFound: diff --git a/atst/domain/workspaces.py b/atst/domain/workspaces.py index b4cc85b8..6ec0b856 100644 --- a/atst/domain/workspaces.py +++ b/atst/domain/workspaces.py @@ -1,5 +1,4 @@ class Projects(object): - def __init__(self): pass @@ -47,7 +46,6 @@ class Projects(object): class Members(object): - def __init__(self): pass diff --git a/tests/domain/test_users.py b/tests/domain/test_users.py index 921463f8..a76a9ae8 100644 --- a/tests/domain/test_users.py +++ b/tests/domain/test_users.py @@ -4,6 +4,7 @@ from uuid import uuid4, UUID from atst.domain.users import Users from atst.domain.exceptions import NotFoundError, AlreadyExistsError + @pytest.fixture() def users_repo(db) -> Users: return Users(db) diff --git a/tests/domain/test_workspace_users.py b/tests/domain/test_workspace_users.py index e86662f3..f76bdf3e 100644 --- a/tests/domain/test_workspace_users.py +++ b/tests/domain/test_workspace_users.py @@ -9,17 +9,17 @@ from atst.domain.users import Users def users_repo(db): return Users(db) + @pytest.fixture() def workspace_users_repo(db): return WorkspaceUsers(db) + def test_can_create_new_workspace_user(users_repo, workspace_users_repo): workspace_id = uuid4() user = users_repo.create(uuid4(), "developer") - workspace_user_dicts = [ - {"id": user.id, "workspace_role": "owner"} - ] + workspace_user_dicts = [{"id": user.id, "workspace_role": "owner"}] workspace_users = workspace_users_repo.add_many(workspace_id, workspace_user_dicts) @@ -32,12 +32,12 @@ def test_can_update_existing_workspace_user(users_repo, workspace_users_repo): workspace_id = uuid4() user = users_repo.create(uuid4(), "developer") - workspace_users_repo.add_many(workspace_id, [ - {"id": user.id, "workspace_role": "owner"} - ]) - workspace_users = workspace_users_repo.add_many(workspace_id, [ - {"id": user.id, "workspace_role": "developer"} - ]) + workspace_users_repo.add_many( + workspace_id, [{"id": user.id, "workspace_role": "owner"}] + ) + workspace_users = workspace_users_repo.add_many( + workspace_id, [{"id": user.id, "workspace_role": "developer"}] + ) assert workspace_users[0].user.id == user.id assert workspace_users[0].workspace_role.role.name == "developer" From d207b259cf4465e6710afbc38b82774eb8121737 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Mon, 30 Jul 2018 15:37:31 -0400 Subject: [PATCH 040/332] Fix linting errors --- atst/domain/workspace_users.py | 1 - tests/conftest.py | 2 +- tests/domain/test_users.py | 2 +- tests/factories.py | 2 +- tests/mocks.py | 49 ---------------------------------- 5 files changed, 3 insertions(+), 53 deletions(-) diff --git a/atst/domain/workspace_users.py b/atst/domain/workspace_users.py index e4d93c19..ef51b78d 100644 --- a/atst/domain/workspace_users.py +++ b/atst/domain/workspace_users.py @@ -1,5 +1,4 @@ from sqlalchemy.orm.exc import NoResultFound -from sqlalchemy.dialects.postgresql import insert from atst.models.workspace_role import WorkspaceRole from atst.models.workspace_user import WorkspaceUser diff --git a/tests/conftest.py b/tests/conftest.py index 555e1f79..04510f1b 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -3,7 +3,7 @@ from sqlalchemy.orm import sessionmaker, scoped_session from atst.app import make_app, make_deps, make_config from atst.database import make_db -from tests.mocks import MockApiClient, MockFundzClient, MockAuthzClient +from tests.mocks import MockApiClient, MockFundzClient from atst.sessions import DictSessions diff --git a/tests/domain/test_users.py b/tests/domain/test_users.py index a76a9ae8..f136e3bd 100644 --- a/tests/domain/test_users.py +++ b/tests/domain/test_users.py @@ -1,5 +1,5 @@ import pytest -from uuid import uuid4, UUID +from uuid import uuid4 from atst.domain.users import Users from atst.domain.exceptions import NotFoundError, AlreadyExistsError diff --git a/tests/factories.py b/tests/factories.py index b07b36fa..1c870308 100644 --- a/tests/factories.py +++ b/tests/factories.py @@ -1,7 +1,7 @@ import factory from uuid import uuid4 -from atst.models import Request, RequestStatusEvent +from atst.models import Request class RequestFactory(factory.Factory): diff --git a/tests/mocks.py b/tests/mocks.py index 96c22e4a..3a277b0f 100644 --- a/tests/mocks.py +++ b/tests/mocks.py @@ -70,52 +70,3 @@ class MockFundzClient(MockApiClient): return self._get_response("GET", path, 200) else: return self._get_response("GET", path, 404) - - -class MockAuthzClient(MockApiClient): - _json = { - "atat_permissions": [ - "view_original_jedi_request", - "review_and_approve_jedi_workspace_request", - "modify_atat_role_permissions", - "create_csp_role", - "delete_csp_role", - "deactivate_csp_role", - "modify_csp_role_permissions", - "view_usage_report", - "view_usage_dollars", - "add_and_assign_csp_roles", - "remove_csp_roles", - "request_new_csp_role", - "assign_and_unassign_atat_role", - "view_assigned_atat_role_configurations", - "view_assigned_csp_role_configurations", - "deactivate_workspace", - "view_atat_permissions", - "transfer_ownership_of_workspace", - "add_application_in_workspace", - "delete_application_in_workspace", - "deactivate_application_in_workspace", - "view_application_in_workspace", - "rename_application_in_workspace", - "add_environment_in_application", - "delete_environment_in_application", - "deactivate_environment_in_application", - "view_environment_in_application", - "rename_environment_in_application", - "add_tag_to_workspace", - "remove_tag_from_workspace", - ], - "atat_role": "ccpo", - "id": "164497f6-c1ea-4f42-a5ef-101da278c012", - "username": None, - "workspace_roles": [], - } - - @tornado.gen.coroutine - def post(self, path, **kwargs): - return self._get_response("POST", path, 200, json=self._json) - - @tornado.gen.coroutine - def get(self, path, **kwargs): - return self._get_response("POST", path, 200, json=self._json) From 206b7f7b2be368879d2da61e3b3193d908b5713d Mon Sep 17 00:00:00 2001 From: richard-dds Date: Mon, 30 Jul 2018 15:40:37 -0400 Subject: [PATCH 041/332] Remove unnecessary type hint --- tests/domain/test_users.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/domain/test_users.py b/tests/domain/test_users.py index f136e3bd..9a2245b9 100644 --- a/tests/domain/test_users.py +++ b/tests/domain/test_users.py @@ -6,7 +6,7 @@ from atst.domain.exceptions import NotFoundError, AlreadyExistsError @pytest.fixture() -def users_repo(db) -> Users: +def users_repo(db): return Users(db) From d3a51ccc29115555de22faa7834604e929fc46a7 Mon Sep 17 00:00:00 2001 From: dandds Date: Tue, 31 Jul 2018 10:50:22 -0400 Subject: [PATCH 042/332] remove authz url reference in config --- config/base.ini | 1 - 1 file changed, 1 deletion(-) diff --git a/config/base.ini b/config/base.ini index 78d56c36..285eb11f 100644 --- a/config/base.ini +++ b/config/base.ini @@ -2,7 +2,6 @@ PORT=8000 ENVIRONMENT = dev DEBUG = true -AUTHZ_BASE_URL = http://localhost:8002 AUTHNID_BASE_URL= https://localhost:8001 FUNDZ_BASE_URL= http://localhost:8004 COOKIE_SECRET = some-secret-please-replace From 56690ed63126d9df5623da3c761918b8ad13c444 Mon Sep 17 00:00:00 2001 From: dandds Date: Mon, 30 Jul 2018 14:46:37 -0400 Subject: [PATCH 043/332] import fundz models --- .../versions/55ba973d08b9_add_fundz_models.py | 38 +++++++++++++++++++ atst/models/__init__.py | 2 + atst/models/pe_number.py | 13 +++++++ atst/models/task_order.py | 9 +++++ 4 files changed, 62 insertions(+) create mode 100644 alembic/versions/55ba973d08b9_add_fundz_models.py create mode 100644 atst/models/pe_number.py create mode 100644 atst/models/task_order.py diff --git a/alembic/versions/55ba973d08b9_add_fundz_models.py b/alembic/versions/55ba973d08b9_add_fundz_models.py new file mode 100644 index 00000000..097532f4 --- /dev/null +++ b/alembic/versions/55ba973d08b9_add_fundz_models.py @@ -0,0 +1,38 @@ +"""add_fundz_models + +Revision ID: 55ba973d08b9 +Revises: 4ea5917e7781 +Create Date: 2018-07-30 14:43:34.099799 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '55ba973d08b9' +down_revision = '4ea5917e7781' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('pe_number', + sa.Column('number', sa.String(), nullable=False), + sa.Column('description', sa.String(), nullable=True), + sa.PrimaryKeyConstraint('number') + ) + op.create_table('task_order', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('number', sa.String(), nullable=True), + sa.PrimaryKeyConstraint('id') + ) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('task_order') + op.drop_table('pe_number') + # ### end Alembic commands ### diff --git a/atst/models/__init__.py b/atst/models/__init__.py index fef82003..1d6daae1 100644 --- a/atst/models/__init__.py +++ b/atst/models/__init__.py @@ -8,3 +8,5 @@ from .permissions import Permissions from .role import Role from .user import User from .workspace_role import WorkspaceRole +from .pe_number import PENumber +from .task_order import TaskOrder diff --git a/atst/models/pe_number.py b/atst/models/pe_number.py new file mode 100644 index 00000000..61a0755e --- /dev/null +++ b/atst/models/pe_number.py @@ -0,0 +1,13 @@ +from sqlalchemy import String, Column + +from atst.models import Base + +class PENumber(Base): + __tablename__ = "pe_number" + + number = Column(String, primary_key=True) + description = Column(String) + + def __repr__(self): + return "".format( + self.number, self.description) diff --git a/atst/models/task_order.py b/atst/models/task_order.py new file mode 100644 index 00000000..7a7879a7 --- /dev/null +++ b/atst/models/task_order.py @@ -0,0 +1,9 @@ +from sqlalchemy import Column, Integer, String + +from atst.models import Base + +class TaskOrder(Base): + __tablename__ = "task_order" + + id = Column(Integer, primary_key=True) + number = Column(String) From fc535ea715c32d79cab4ea64dcf0fdba0cd35342 Mon Sep 17 00:00:00 2001 From: dandds Date: Mon, 30 Jul 2018 15:50:33 -0400 Subject: [PATCH 044/332] domain repos for PE numbers and task orders --- atst/domain/pe_numbers.py | 15 ++++++++++++++ atst/domain/task_orders.py | 18 +++++++++++++++++ tests/domain/test_pe_numbers.py | 34 ++++++++++++++++++++++++++++++++ tests/domain/test_task_orders.py | 34 ++++++++++++++++++++++++++++++++ tests/factories.py | 12 ++++++++++- 5 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 atst/domain/pe_numbers.py create mode 100644 atst/domain/task_orders.py create mode 100644 tests/domain/test_pe_numbers.py create mode 100644 tests/domain/test_task_orders.py diff --git a/atst/domain/pe_numbers.py b/atst/domain/pe_numbers.py new file mode 100644 index 00000000..07d79585 --- /dev/null +++ b/atst/domain/pe_numbers.py @@ -0,0 +1,15 @@ +from atst.models.pe_number import PENumber +from .exceptions import NotFoundError + + +class PENumbers(object): + + def __init__(self, db_session): + self.db_session = db_session + + def get(self, number): + pe_number = self.db_session.query(PENumber).get(number) + if not pe_number: + raise NotFoundError("pe_number") + + return pe_number diff --git a/atst/domain/task_orders.py b/atst/domain/task_orders.py new file mode 100644 index 00000000..cbc4cc4e --- /dev/null +++ b/atst/domain/task_orders.py @@ -0,0 +1,18 @@ +from sqlalchemy.orm.exc import NoResultFound + +from atst.models.task_order import TaskOrder +from .exceptions import NotFoundError + + +class TaskOrders(object): + + def __init__(self, db_session): + self.db_session = db_session + + def get(self, order_number): + try: + task_order = self.db_session.query(TaskOrder).filter_by(number=order_number).one() + except NoResultFound: + raise NotFoundError("task_order") + + return task_order diff --git a/tests/domain/test_pe_numbers.py b/tests/domain/test_pe_numbers.py new file mode 100644 index 00000000..ba9025be --- /dev/null +++ b/tests/domain/test_pe_numbers.py @@ -0,0 +1,34 @@ +import pytest + +from atst.domain.exceptions import NotFoundError +from atst.domain.pe_numbers import PENumbers + +from tests.factories import PENumberFactory + + +@pytest.fixture() +def pe_numbers(db): + return PENumbers(db) + +@pytest.fixture(scope="function") +def new_pe_number(db): + def make_pe_number(**kwargs): + pen = PENumberFactory.create(**kwargs) + db.add(pen) + db.commit() + + return pen + + return make_pe_number + + +def test_can_get_pe_number(pe_numbers, new_pe_number): + new_pen = new_pe_number(number="0101969F", description="Combat Support - Offensive") + pen = pe_numbers.get(new_pen.number) + + assert pen.number == new_pen.number + + +def test_nonexistent_pe_number_raises(pe_numbers): + with pytest.raises(NotFoundError): + pe_numbers.get("some fake number") diff --git a/tests/domain/test_task_orders.py b/tests/domain/test_task_orders.py new file mode 100644 index 00000000..9b7c0882 --- /dev/null +++ b/tests/domain/test_task_orders.py @@ -0,0 +1,34 @@ +import pytest + +from atst.domain.exceptions import NotFoundError +from atst.domain.task_orders import TaskOrders + +from tests.factories import TaskOrderFactory + + +@pytest.fixture() +def task_orders(db): + return TaskOrders(db) + +@pytest.fixture(scope="function") +def new_task_order(db): + def make_task_order(**kwargs): + to = TaskOrderFactory.create(**kwargs) + db.add(to) + db.commit() + + return to + + return make_task_order + + +def test_can_get_task_order(task_orders, new_task_order): + new_to = new_task_order(number="0101969F") + to = task_orders.get(new_to.number) + + assert to.id == to.id + + +def test_nonexistent_task_order_raises(task_orders): + with pytest.raises(NotFoundError): + task_orders.get("some fake number") diff --git a/tests/factories.py b/tests/factories.py index 1c870308..582ce461 100644 --- a/tests/factories.py +++ b/tests/factories.py @@ -1,7 +1,9 @@ import factory from uuid import uuid4 -from atst.models import Request +from atst.models import Request, RequestStatusEvent +from atst.models.pe_number import PENumber +from atst.models.task_order import TaskOrder class RequestFactory(factory.Factory): @@ -9,3 +11,11 @@ class RequestFactory(factory.Factory): model = Request id = factory.Sequence(lambda x: uuid4()) + +class PENumberFactory(factory.Factory): + class Meta: + model = PENumber + +class TaskOrderFactory(factory.Factory): + class Meta: + model = TaskOrder From cb30ee99cae0af9cde6e71ad1af57be4b0f58299 Mon Sep 17 00:00:00 2001 From: dandds Date: Mon, 30 Jul 2018 16:25:15 -0400 Subject: [PATCH 045/332] remove fundz_client in favor of pe numbers repo --- atst/app.py | 7 ------- atst/forms/financial.py | 16 ++++++++-------- atst/handlers/request_financial_verification.py | 7 ++++--- atst/handlers/request_new.py | 15 ++++++++------- tests/conftest.py | 1 - tests/handlers/test_financial_verification.py | 10 +++++++--- 6 files changed, 27 insertions(+), 29 deletions(-) diff --git a/atst/app.py b/atst/app.py index 5ef0e18f..dab66e8d 100644 --- a/atst/app.py +++ b/atst/app.py @@ -65,7 +65,6 @@ def make_app(config, deps, **kwargs): { "page": "requests_new", "db_session": deps["db_session"], - "fundz_client": deps["fundz_client"], }, name="request_new", ), @@ -75,7 +74,6 @@ def make_app(config, deps, **kwargs): { "page": "requests_new", "db_session": deps["db_session"], - "fundz_client": deps["fundz_client"], }, name="request_form_new", ), @@ -85,7 +83,6 @@ def make_app(config, deps, **kwargs): { "page": "requests_new", "db_session": deps["db_session"], - "fundz_client": deps["fundz_client"], }, name="request_form_update", ), @@ -108,7 +105,6 @@ def make_app(config, deps, **kwargs): { "page": "financial_verification", "db_session": deps["db_session"], - "fundz_client": deps["fundz_client"], }, name="financial_verification", ), @@ -172,9 +168,6 @@ def make_deps(config): api_version="v1", validate_cert=validate_cert, ), - "fundz_client": ApiClient( - config["default"]["FUNDZ_BASE_URL"], validate_cert=validate_cert - ), "sessions": RedisSessions( redis_client, config["default"]["SESSION_TTL_SECONDS"] ), diff --git a/atst/forms/financial.py b/atst/forms/financial.py index 9c2a669c..52b4ef28 100644 --- a/atst/forms/financial.py +++ b/atst/forms/financial.py @@ -6,6 +6,8 @@ from wtforms.fields import StringField, SelectField from wtforms.form import Form from wtforms.validators import Required, Email +from atst.domain.exceptions import NotFoundError + from .fields import NewlineListField from .forms import ValidatedForm @@ -35,12 +37,10 @@ def suggest_pe_id(pe_id): @tornado.gen.coroutine -def validate_pe_id(field, existing_request, fundz_client): - response = yield fundz_client.get( - "/pe-number/{}".format(field.data), - raise_error=False, - ) - if not response.ok: +def validate_pe_id(field, existing_request, pe_numbers_repo): + try: + pe_number = pe_numbers_repo.get(field.data) + except NotFoundError: suggestion = suggest_pe_id(field.data) error_str = ( "We couldn't find that PE number. {}" @@ -56,10 +56,10 @@ def validate_pe_id(field, existing_request, fundz_client): class FinancialForm(ValidatedForm): @tornado.gen.coroutine - def perform_extra_validation(self, existing_request, fundz_client): + def perform_extra_validation(self, existing_request, pe_numbers_repo): valid = True if not existing_request or existing_request.get('pe_id') != self.pe_id.data: - valid = yield validate_pe_id(self.pe_id, existing_request, fundz_client) + valid = yield validate_pe_id(self.pe_id, existing_request, pe_numbers_repo) raise Return(valid) task_order_id = StringField( diff --git a/atst/handlers/request_financial_verification.py b/atst/handlers/request_financial_verification.py index a063692c..e93f999c 100644 --- a/atst/handlers/request_financial_verification.py +++ b/atst/handlers/request_financial_verification.py @@ -3,13 +3,14 @@ import tornado from atst.handler import BaseHandler from atst.forms.financial import FinancialForm from atst.domain.requests import Requests +from atst.domain.pe_numbers import PENumbers class RequestFinancialVerification(BaseHandler): - def initialize(self, page, db_session, fundz_client): + def initialize(self, page, db_session): self.page = page self.requests_repo = Requests(db_session) - self.fundz_client = fundz_client + self.pe_numbers_repo = PENumbers(db_session) def get_existing_request(self, request_id): return self.requests_repo.get(request_id) @@ -48,7 +49,7 @@ class RequestFinancialVerification(BaseHandler): yield self.update_request(request_id, form.data) valid = yield form.perform_extra_validation( existing_request.body.get('financial_verification'), - self.fundz_client + self.pe_numbers_repo ) if valid: self.redirect( diff --git a/atst/handlers/request_new.py b/atst/handlers/request_new.py index 67c24585..1d33daa0 100644 --- a/atst/handlers/request_new.py +++ b/atst/handlers/request_new.py @@ -7,13 +7,14 @@ from atst.forms.org import OrgForm from atst.forms.poc import POCForm from atst.forms.review import ReviewForm from atst.domain.requests import Requests +from atst.domain.pe_numbers import PENumbers class RequestNew(BaseHandler): - def initialize(self, page, db_session, fundz_client): + def initialize(self, page, db_session): self.page = page self.requests_repo = Requests(db_session) - self.fundz_client = fundz_client + self.pe_numbers_repo = PENumbers(db_session) def get_existing_request(self, request_id): if request_id is None: @@ -31,7 +32,7 @@ class RequestNew(BaseHandler): existing_request = self.get_existing_request(request_id) jedi_flow = JEDIRequestFlow( self.requests_repo, - self.fundz_client, + self.pe_numbers_repo, screen, post_data=post_data, request_id=request_id, @@ -81,7 +82,7 @@ class RequestNew(BaseHandler): request = self.requests_repo.get(request_id) jedi_flow = JEDIRequestFlow( - self.requests_repo, self.fundz_client, screen, request, request_id=request_id + self.requests_repo, self.pe_numbers_repo, screen, request, request_id=request_id ) self.render( @@ -101,7 +102,7 @@ class JEDIRequestFlow(object): def __init__( self, requests_repo, - fundz_client, + pe_numbers_repo, current_step, request=None, post_data=None, @@ -110,7 +111,7 @@ class JEDIRequestFlow(object): existing_request=None, ): self.requests_repo = requests_repo - self.fundz_client = fundz_client + self.pe_numbers_repo = pe_numbers_repo self.current_step = current_step self.request = request @@ -144,7 +145,7 @@ class JEDIRequestFlow(object): valid = yield self.form.perform_extra_validation( existing_request_data, - self.fundz_client, + self.pe_numbers_repo, ) return valid diff --git a/tests/conftest.py b/tests/conftest.py index 04510f1b..92da1bce 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -11,7 +11,6 @@ from atst.sessions import DictSessions def app(db): TEST_DEPS = { "authnid_client": MockApiClient("authnid"), - "fundz_client": MockFundzClient("fundz"), "sessions": DictSessions(), "db_session": db } diff --git a/tests/handlers/test_financial_verification.py b/tests/handlers/test_financial_verification.py index 57b8851d..d84f76bd 100644 --- a/tests/handlers/test_financial_verification.py +++ b/tests/handlers/test_financial_verification.py @@ -2,7 +2,8 @@ import re import pytest import tornado import urllib -from tests.mocks import MOCK_REQUEST, MOCK_USER, MOCK_VALID_PE_ID +from tests.mocks import MOCK_REQUEST, MOCK_USER +from tests.factories import PENumberFactory class TestPENumberInForm: @@ -73,11 +74,14 @@ class TestPENumberInForm: assert response.headers.get("Location") == "/requests/financial_verification_submitted" @pytest.mark.gen_test - def test_submit_request_form_with_new_valid_pe_id(self, monkeypatch, http_client, base_url): + def test_submit_request_form_with_new_valid_pe_id(self, db, monkeypatch, http_client, base_url): self._set_monkeypatches(monkeypatch) + pe = PENumberFactory.create(number="8675309U", description="sample PE number") + db.add(pe) + db.commit() data = dict(self.required_data) - data['pe_id'] = MOCK_VALID_PE_ID + data['pe_id'] = pe.number response = yield self.submit_data(http_client, base_url, data) From 0fca4753c5902ca70dc25a8112684ccac67b0310 Mon Sep 17 00:00:00 2001 From: dandds Date: Tue, 31 Jul 2018 09:21:33 -0400 Subject: [PATCH 046/332] add script for ingesting PE numbers and necessary script config for database --- config/base.ini | 1 + script/ingest_pe_numbers.py | 40 +++++++++++++++++++++++++++++++++++++ script/setup | 3 +++ script/update | 3 +++ 4 files changed, 47 insertions(+) create mode 100644 script/ingest_pe_numbers.py diff --git a/config/base.ini b/config/base.ini index 285eb11f..8b3a6881 100644 --- a/config/base.ini +++ b/config/base.ini @@ -7,6 +7,7 @@ FUNDZ_BASE_URL= http://localhost:8004 COOKIE_SECRET = some-secret-please-replace SECRET = change_me_into_something_secret CAC_URL = https://localhost:8001 +PE_NUMBER_CSV_URL = http://c95e1ebb198426ee57b8-174bb05a294821bedbf46b6384fe9b1f.r31.cf5.rackcdn.com/penumbers.csv REDIS_URI = redis://localhost:6379 SESSION_TTL_SECONDS = 600 PGAPPNAME = atst diff --git a/script/ingest_pe_numbers.py b/script/ingest_pe_numbers.py new file mode 100644 index 00000000..1df5b132 --- /dev/null +++ b/script/ingest_pe_numbers.py @@ -0,0 +1,40 @@ +from urllib.request import urlopen +import csv + +from sqlalchemy.dialects.postgresql import insert + +# Add root project dir to the python path +import os +import sys +parent_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) +sys.path.append(parent_dir) + +from atst.app import make_deps, make_config +from atst.models import PENumber + + +def get_pe_numbers(url): + response = urlopen(url) + t = response.read().decode("utf-8") + return list(csv.reader(t.split("\r\n"))) + + +def insert_pe_numbers(db, list_of_pe_numbers): + stmt = insert(PENumber).values(list_of_pe_numbers) + do_update = stmt.on_conflict_do_update( + index_elements=["number"], + set_=dict(description=stmt.excluded.description) + ) + db.execute(do_update) + db.commit() + + +if __name__ == "__main__": + config = make_config() + deps = make_deps(config) + db = deps["db_session"] + url = config["default"]['PE_NUMBER_CSV_URL'] + print("Fetching PE numbers from {}".format(url)) + pe_numbers = get_pe_numbers(url) + print("Inserting {} PE numbers".format(len(pe_numbers))) + insert_pe_numbers(db, pe_numbers) diff --git a/script/setup b/script/setup index 5cd11461..bf83b19a 100755 --- a/script/setup +++ b/script/setup @@ -16,3 +16,6 @@ RESET_DB="true" # Run the shared setup script source ./script/include/run_setup + +# Fetch and import the PE numbers +run_command "python script/ingest_pe_numbers.py" diff --git a/script/update b/script/update index 1baef9a8..46d5d549 100755 --- a/script/update +++ b/script/update @@ -9,3 +9,6 @@ MIGRATE_DB="true" # Run the shared update script source ./script/include/run_update + +# Fetch and import/update the PE numbers +run_command "python script/ingest_pe_numbers.py" From 65239b788232dd311c2f6031dfe722b1d5174c92 Mon Sep 17 00:00:00 2001 From: dandds Date: Tue, 31 Jul 2018 11:19:29 -0400 Subject: [PATCH 047/332] fix pe number test to add non-existent pe number --- tests/domain/test_pe_numbers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/domain/test_pe_numbers.py b/tests/domain/test_pe_numbers.py index ba9025be..332ae688 100644 --- a/tests/domain/test_pe_numbers.py +++ b/tests/domain/test_pe_numbers.py @@ -23,7 +23,7 @@ def new_pe_number(db): def test_can_get_pe_number(pe_numbers, new_pe_number): - new_pen = new_pe_number(number="0101969F", description="Combat Support - Offensive") + new_pen = new_pe_number(number="0701367F", description="Combat Support - Offensive") pen = pe_numbers.get(new_pen.number) assert pen.number == new_pen.number From ba4ea97d4bf84d1eefe2f965252548232cd47879 Mon Sep 17 00:00:00 2001 From: dandds Date: Tue, 31 Jul 2018 11:21:48 -0400 Subject: [PATCH 048/332] remove reference to fundz in config and api mocks --- config/base.ini | 1 - tests/conftest.py | 2 +- tests/mocks.py | 9 --------- 3 files changed, 1 insertion(+), 11 deletions(-) diff --git a/config/base.ini b/config/base.ini index 8b3a6881..e8be9197 100644 --- a/config/base.ini +++ b/config/base.ini @@ -3,7 +3,6 @@ PORT=8000 ENVIRONMENT = dev DEBUG = true AUTHNID_BASE_URL= https://localhost:8001 -FUNDZ_BASE_URL= http://localhost:8004 COOKIE_SECRET = some-secret-please-replace SECRET = change_me_into_something_secret CAC_URL = https://localhost:8001 diff --git a/tests/conftest.py b/tests/conftest.py index 92da1bce..0921f2bf 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -3,7 +3,7 @@ from sqlalchemy.orm import sessionmaker, scoped_session from atst.app import make_app, make_deps, make_config from atst.database import make_db -from tests.mocks import MockApiClient, MockFundzClient +from tests.mocks import MockApiClient from atst.sessions import DictSessions diff --git a/tests/mocks.py b/tests/mocks.py index 3a277b0f..c8903099 100644 --- a/tests/mocks.py +++ b/tests/mocks.py @@ -61,12 +61,3 @@ class MockApiClient(ApiClient): MOCK_VALID_PE_ID = "8675309U" - -class MockFundzClient(MockApiClient): - - @tornado.gen.coroutine - def get(self, path, **kwargs): - if path.endswith(MOCK_VALID_PE_ID): - return self._get_response("GET", path, 200) - else: - return self._get_response("GET", path, 404) From 55bd55a0b5f738745d76ddc51041cfae9a45ea88 Mon Sep 17 00:00:00 2001 From: dandds Date: Tue, 31 Jul 2018 11:43:09 -0400 Subject: [PATCH 049/332] move logic for creating many PE Numbers to the domain repo --- atst/domain/pe_numbers.py | 11 +++++++++++ script/ingest_pe_numbers.py | 23 +++++++---------------- tests/domain/test_pe_numbers.py | 7 +++++++ 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/atst/domain/pe_numbers.py b/atst/domain/pe_numbers.py index 07d79585..a80e10ef 100644 --- a/atst/domain/pe_numbers.py +++ b/atst/domain/pe_numbers.py @@ -1,3 +1,5 @@ +from sqlalchemy.dialects.postgresql import insert + from atst.models.pe_number import PENumber from .exceptions import NotFoundError @@ -13,3 +15,12 @@ class PENumbers(object): raise NotFoundError("pe_number") return pe_number + + def create_many(self, list_of_pe_numbers): + stmt = insert(PENumber).values(list_of_pe_numbers) + do_update = stmt.on_conflict_do_update( + index_elements=["number"], + set_=dict(description=stmt.excluded.description) + ) + self.db_session.execute(do_update) + self.db_session.commit() diff --git a/script/ingest_pe_numbers.py b/script/ingest_pe_numbers.py index 1df5b132..e3bbecb0 100644 --- a/script/ingest_pe_numbers.py +++ b/script/ingest_pe_numbers.py @@ -1,8 +1,6 @@ from urllib.request import urlopen import csv -from sqlalchemy.dialects.postgresql import insert - # Add root project dir to the python path import os import sys @@ -10,7 +8,7 @@ parent_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) sys.path.append(parent_dir) from atst.app import make_deps, make_config -from atst.models import PENumber +from atst.domain.pe_numbers import PENumbers def get_pe_numbers(url): @@ -18,23 +16,16 @@ def get_pe_numbers(url): t = response.read().decode("utf-8") return list(csv.reader(t.split("\r\n"))) - -def insert_pe_numbers(db, list_of_pe_numbers): - stmt = insert(PENumber).values(list_of_pe_numbers) - do_update = stmt.on_conflict_do_update( - index_elements=["number"], - set_=dict(description=stmt.excluded.description) - ) - db.execute(do_update) - db.commit() - +def make_pe_number_repo(config): + deps = make_deps(config) + db = deps["db_session"] + return PENumbers(db) if __name__ == "__main__": config = make_config() - deps = make_deps(config) - db = deps["db_session"] url = config["default"]['PE_NUMBER_CSV_URL'] print("Fetching PE numbers from {}".format(url)) pe_numbers = get_pe_numbers(url) print("Inserting {} PE numbers".format(len(pe_numbers))) - insert_pe_numbers(db, pe_numbers) + pe_numbers_repo = make_pe_number_repo(config) + pe_numbers_repo.create_many(pe_numbers) diff --git a/tests/domain/test_pe_numbers.py b/tests/domain/test_pe_numbers.py index 332ae688..028aa712 100644 --- a/tests/domain/test_pe_numbers.py +++ b/tests/domain/test_pe_numbers.py @@ -32,3 +32,10 @@ def test_can_get_pe_number(pe_numbers, new_pe_number): def test_nonexistent_pe_number_raises(pe_numbers): with pytest.raises(NotFoundError): pe_numbers.get("some fake number") + +def test_create_many(pe_numbers): + pen_list = [['123456', 'Land Speeder'], ['7891011', 'Lightsaber']] + pe_numbers.create_many(pen_list) + + assert pe_numbers.get(pen_list[0][0]) + assert pe_numbers.get(pen_list[1][0]) From b5c174526641b0409acf5370474154be57827f25 Mon Sep 17 00:00:00 2001 From: dandds Date: Wed, 1 Aug 2018 09:06:48 -0400 Subject: [PATCH 050/332] fix missing import from rebase --- tests/handlers/test_request_new.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/handlers/test_request_new.py b/tests/handlers/test_request_new.py index 3373c867..8409fc13 100644 --- a/tests/handlers/test_request_new.py +++ b/tests/handlers/test_request_new.py @@ -3,6 +3,7 @@ import pytest import tornado import urllib from tests.mocks import MOCK_USER +from tests.factories import RequestFactory ERROR_CLASS = "alert--error" MOCK_REQUEST = RequestFactory.create( From bf279b7eeee9696c4aff886c5ea72c4dde74f096 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Tue, 24 Jul 2018 16:48:15 -0400 Subject: [PATCH 051/332] Create mock eda client --- atst/eda_client.py | 356 +++++++++++++++++++++++++++++++++++++++ tests/test_eda_client.py | 17 ++ 2 files changed, 373 insertions(+) create mode 100644 atst/eda_client.py create mode 100644 tests/test_eda_client.py diff --git a/atst/eda_client.py b/atst/eda_client.py new file mode 100644 index 00000000..09acd859 --- /dev/null +++ b/atst/eda_client.py @@ -0,0 +1,356 @@ +class EDAClientBase(object): + def list_contracts( + self, + contract_number=None, + delivery_order=None, + cage_code=None, + duns_number=None, + ): + """ + Get a list of all contracts matching the given filters. + """ + raise NotImplementedError() + + def get_contract(self, contract_number, status): + """ + Get details for a contract. + """ + raise NotImplementedError() + + +class MockEDAClient(EDAClientBase): + def __init__(self, *args, **kwargs): + pass + + def list_contracts( + self, + contract_number=None, + delivery_order=None, + cage_code=None, + duns_number=None, + ): + return [ + { + "aco_mod": "01", + "admin_dodaac": None, + "cage_code": "1U305", + "contract_no": "DCA10096D0052", + "delivery_order": "0084", + "duns_number": None, + "issue_date": "20000228", + "issue_dodaac": None, + "location": "https://docsrv1.nit.disa.mil:443/eda/enforcer/C0414345.PDF?ver=1.4&loc=Y29udHJhY3RzL29nZGVuL3ZlbmRvci8xOTk4LzA5LzE0L0MwNDE0MzQ1LlBERg==&sourceurl=aHR0cHM6Ly9lZGE0Lm5pdC5kaXNhLm1pbC9wbHMvdXNlci9uZXdfYXBwLkdldF9Eb2M_cFRhYmxlX0lEPTImcFJlY29yZF9LZXk9OEE2ODExNjM2RUY5NkU2M0UwMzQwMDYwQjBCMjgyNkM=&uid=6CFC2B2322E86FD5E054002264936E3C&qid=19344159&signed=G&qdate=20180529194407GMT&token=6xQICrrrfIMciEJSpXmfsAYrToM=", + "pay_dodaac": None, + "pco_mod": "02", + }, + { + "aco_mod": "01", + "admin_dodaac": None, + "cage_code": "1U305", + "contract_no": "DCA10096D0052", + "delivery_order": "0084", + "duns_number": None, + "issue_date": "20000228", + "issue_dodaac": None, + "location": "https://docsrv1.nit.disa.mil:443/eda/enforcer/C0414345.PDF?ver=1.4&loc=Y29udHJhY3RzL29nZGVuL3ZlbmRvci8xOTk4LzA5LzE0L0MwNDE0MzQ1LlBERg==&sourceurl=aHR0cHM6Ly9lZGE0Lm5pdC5kaXNhLm1pbC9wbHMvdXNlci9uZXdfYXBwLkdldF9Eb2M_cFRhYmxlX0lEPTImcFJlY29yZF9LZXk9OEE2ODExNjM2RUY5NkU2M0UwMzQwMDYwQjBCMjgyNkM=&uid=6CFC2B2322E86FD5E054002264936E3C&qid=19344159&signed=G&qdate=20180529194407GMT&token=6xQICrrrfIMciEJSpXmfsAYrToM=", + "pay_dodaac": None, + "pco_mod": "02", + }, + { + "aco_mod": "01", + "admin_dodaac": None, + "cage_code": "1U305", + "contract_no": "DCA10096D0052", + "delivery_order": "0084", + "duns_number": None, + "issue_date": "20000228", + "issue_dodaac": None, + "location": "https://docsrv1.nit.disa.mil:443/eda/enforcer/C0414345.PDF?ver=1.4&loc=Y29udHJhY3RzL29nZGVuL3ZlbmRvci8xOTk4LzA5LzE0L0MwNDE0MzQ1LlBERg==&sourceurl=aHR0cHM6Ly9lZGE0Lm5pdC5kaXNhLm1pbC9wbHMvdXNlci9uZXdfYXBwLkdldF9Eb2M_cFRhYmxlX0lEPTImcFJlY29yZF9LZXk9OEE2ODExNjM2RUY5NkU2M0UwMzQwMDYwQjBCMjgyNkM=&uid=6CFC2B2322E86FD5E054002264936E3C&qid=19344159&signed=G&qdate=20180529194407GMT&token=6xQICrrrfIMciEJSpXmfsAYrToM=", + "pay_dodaac": None, + "pco_mod": "02", + }, + ] + + def get_contract(self, contract_number, status): + if contract_number == "DCA10096D0052" and status == "y": + return { + "aco_mod": "01", + "admin_dodaac": None, + "cage_code": "1U305", + "contract_no": "DCA10096D0052", + "delivery_order": "0084", + "duns_number": None, + "issue_date": "20000228", + "issue_dodaac": None, + "location": "https://docsrv1.nit.disa.mil:443/eda/enforcer/C0414345.PDF?ver=1.4&loc=Y29udHJhY3RzL29nZGVuL3ZlbmRvci8xOTk4LzA5LzE0L0MwNDE0MzQ1LlBERg==&sourceurl=aHR0cHM6Ly9lZGE0Lm5pdC5kaXNhLm1pbC9wbHMvdXNlci9uZXdfYXBwLkdldF9Eb2M_cFRhYmxlX0lEPTImcFJlY29yZF9LZXk9OEE2ODExNjM2RUY5NkU2M0UwMzQwMDYwQjBCMjgyNkM=&uid=6CFC2B2322E86FD5E054002264936E3C&qid=19344159&signed=G&qdate=20180529194407GMT&token=6xQICrrrfIMciEJSpXmfsAYrToM=", + "pay_dodaac": None, + "pco_mod": "02", + "amount": 2000000 + } + else: + return None + + +class EDAClient(EDAClientBase): + def __init__(self, base_url, user_name, user_role): + pass + + def list_contracts( + self, + contract_number=None, + delivery_order=None, + cage_code=None, + duns_number=None, + ): + # TODO: Fetch the contracts CSV and transform them into dictionaries. + # https://docs.python.org/3/library/csv.html#csv.DictReader + raise NotImplementedError() + + def get_contract(self, contract_number, status): + # TODO: Fetch the contract XML and transform it into a dictionary. + # https://docs.python.org/3.7/library/xml.etree.elementtree.html + raise NotImplementedError() + + + +CONTRACT_XML = """ + +2.5 +DD 1155 + +3244871 + +00000431 +704331 + + + + + +Department of Defense +Delivery Order +70433119F2644 +Represented Contract + + +Department of Defense +Basic Ordering Agreement +W81K0419G0001 +Ordering Instrument + + +false +Original +false + +Firm Fixed Price + + + + +http://farsite.hill.af.mil/reghtml/regs/far2afmcfars/fardfars/far/52_220.htm#P810_149596 + + +FAR +52.222-50 +Combating Trafficking in Persons. +2015-05 + + + [ lots of text ] + + +
I
+
+ +FAR +52.245-1 +Government Property. +2012-04 + + + [ lots of text ] + + +
I
+
+
+ +2016-02-04 + +2016-01-25 + +DALE WOLFE + +Telephone +520-533-9132 + + + + + +Contractor +
+ +0Z7K0 +808152482 + + +CACI TECHNOLOGIES, INC + + +6933 Gateway Ct +Manassas VA, 20109 + + + +
+
+ +Contract Issuing Office +
+ +704331 + + +FEMA DISTRIBUTION CENTER + + +3870 S. SIDE INDUSTRIAL CTR +ATLANTA GA, 30354 + + + +
+ +GENE BARBER + +Telephone +(202) 646-2727 + + +
+ +Contract Administrative Office +
+ +704331 + + +FEMA DISTRIBUTION CENTER + + +3870 S. SIDE INDUSTRIAL CTR +ATLANTA GA, 30354 + + + +
+
+ +Paying Office +
+ +HQ0131 + + +DEFENSE FINANCE AND ACCOUNTING SVC + + +P.O. BOX 369016 +COLUMBUS OH, 43236 + + + +
+
+ +Ship To +
+ +S0302A + + +DCMA PHOENIX + + +40 NORTH CENTRAL AVE, STE 400 +TWO RENAISSANCE SQUARE +PHOENIX AZ, 85004 + + + +
+
+ + +Header Only - Total Contract Value +192000.00 + + + + +Delivery Requested By + +2016-01-16 + + + + + +Defense Priorities Allocation System (DPAS) Priority Rating + +DO-A7 +
A
+
+ + +Contractor +Origin (after Loading) + + +
+ + + + + +CLIN +0001 + + + + +false + +Cost No Fee + + +Real Property +Radio Dishes +3 +false +Estimated +Each +64000.00 + +Manufacturer's Part Number +5L33M7730291DX081 + + + + + +Estimated Cost +192000.00 + + +Not to Exceed Amount (Funding) +200000.00 + + + + +
+
+""" diff --git a/tests/test_eda_client.py b/tests/test_eda_client.py new file mode 100644 index 00000000..eb1e92d8 --- /dev/null +++ b/tests/test_eda_client.py @@ -0,0 +1,17 @@ +from atst.eda_client import MockEDAClient + + +client = MockEDAClient() + +def test_list_contracts(): + results = client.list_contracts() + assert len(results) == 3 + +def test_get_contract(): + result = client.get_contract("DCA10096D0052", "y") + assert result["contract_no"] == "DCA10096D0052" + assert result["amount"] == 2000000 + +def test_contract_not_found(): + result = client.get_contract("abc", "y") + assert result is None From 6ee71113c7e8845ec5a867da2988afce263012a7 Mon Sep 17 00:00:00 2001 From: Andrew Croce Date: Tue, 31 Jul 2018 10:00:27 -0400 Subject: [PATCH 052/332] Clean up workspace list layout --- templates/workspaces.html.to | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/templates/workspaces.html.to b/templates/workspaces.html.to index 6e7e7931..21bbad7d 100644 --- a/templates/workspaces.html.to +++ b/templates/workspaces.html.to @@ -5,22 +5,23 @@ - - - + + + {% for w in workspaces %} - + - {% end %} From 34c570ab184ce659ab88d65f090f6a9e82ce506b Mon Sep 17 00:00:00 2001 From: Andrew Croce Date: Mon, 30 Jul 2018 16:09:55 -0400 Subject: [PATCH 053/332] EmptyState UI module --- atst/ui_modules.py | 9 ++++++ scss/components/_empty_state.scss | 36 ++++++++++++++++-------- templates/components/empty_state.html.to | 9 ++++++ 3 files changed, 42 insertions(+), 12 deletions(-) create mode 100644 templates/components/empty_state.html.to diff --git a/atst/ui_modules.py b/atst/ui_modules.py index 748ca980..96bdab07 100644 --- a/atst/ui_modules.py +++ b/atst/ui_modules.py @@ -46,3 +46,12 @@ class SidenavItem(UIModule): active=active, icon=icon, subnav=subnav) + +class EmptyState(UIModule): + def render(self, message, actionLabel, actionHref, icon=None): + return self.render_string( + "components/empty_state.html.to", + message=message, + actionLabel=actionLabel, + actionHref=actionHref, + icon=icon) diff --git a/scss/components/_empty_state.scss b/scss/components/_empty_state.scss index d11f5083..be8675ad 100644 --- a/scss/components/_empty_state.scss +++ b/scss/components/_empty_state.scss @@ -1,15 +1,27 @@ .empty-state { text-align: center; - padding-top: 10rem; - - p { - font-family: $font-sans; - font-weight: 300; - line-height: 10rem; - font-size: 44px; - line-height: 5rem; - margin: 0 auto; - padding-bottom: 2rem; - max-width: 40%; + padding: 6rem ($gap * 2) 0; + display: flex; + flex-direction: column; + align-items: center; + + @include media($medium-screen) { + padding: 8rem ($gap * 4) 0; } -} \ No newline at end of file + + .icon { + @include icon-size(50); + @include icon-color($color-gray-light); + } + + p { + @include h2; + line-height: 1.2; + max-width: 15em; + color: $color-gray; + + @include media($large-screen) { + @include h1; + } + } +} diff --git a/templates/components/empty_state.html.to b/templates/components/empty_state.html.to new file mode 100644 index 00000000..30246ddb --- /dev/null +++ b/templates/components/empty_state.html.to @@ -0,0 +1,9 @@ +
+

{{ message }}

+ + {% if icon %} + {% module Icon(icon) %} + {% end %} + + {{ actionLabel }} +
From 6973443f36937aa1251574d33f4246cf3ed6d2f3 Mon Sep 17 00:00:00 2001 From: Andrew Croce Date: Mon, 30 Jul 2018 16:10:28 -0400 Subject: [PATCH 054/332] Add conditional empty state modules to Requests, Workspace Members, and Workspace Projects --- templates/requests.html.to | 124 +++++++++++++++------------ templates/workspace_members.html.to | 118 +++++++++++-------------- templates/workspace_projects.html.to | 65 ++++++++------ 3 files changed, 163 insertions(+), 144 deletions(-) diff --git a/templates/requests.html.to b/templates/requests.html.to index 66dbcd9d..1cdd2433 100644 --- a/templates/requests.html.to +++ b/templates/requests.html.to @@ -1,5 +1,9 @@ {% extends "base.html.to" %} +{% block template_vars %} + {% set requestsEmpty = False %} +{% end %} + {% block modal %} {% if modalOpen() %} {% apply modal %} @@ -31,67 +35,79 @@ {% block content %} +{% if requestsEmpty %} -{% module Alert('Pending Financial Verification', - message="

Your next step is to create a Task Order (T.O.) associated with JEDI Cloud. Please consult a Contracting Officer (KO) or Contracting Officer Representative (COR) to help with this step.

" -) %} + {% module EmptyState( + 'There are currently no active requests for you to see.', + actionLabel='Create a new JEDI Cloud Request', + actionHref='/requests/new', + icon='document' + )%} -
+{% else %} - -
- - - -
+ {% module Alert('Pending Financial Verification', + message="

Your next step is to create a Task Order (T.O.) associated with JEDI Cloud. Please consult a Contracting Officer (KO) or Contracting Officer Representative (COR) to help with this step.

" + ) %} -
- - -
- +
-
-
Workspace NameWorkspace InfoActionsWorkspace NameTask OrderUsers
- {{ w['name'] }}
- Task Order: #{{ w['task_order']['number'] }} +
+ {{ w['name'] }}
- {{ w['user_count'] }}
Users + #{{ w['task_order']['number'] }} +
+ {{ w['user_count'] }}Users
- - - - - - - - - - - - {% for r in requests %} - - + +
+ + + +
+ +
+ + +
+ + +
+
Order IDRequest DateRequesterTotal AppsStatusActions
- {{ r['order_id'] }} - {% if r['is_new'] %}New -
+ + + + + + + + + + + + {% for r in requests %} + + + {% end %} + + + + + + {% end %} - - - - - - - {% end %} - -
Order IDRequest DateRequesterTotal AppsStatusActions
+ {{ r['order_id'] }} + {% if r['is_new'] %}New + {{ r['date'] }}{{ r['full_name'] }}{{ r['app_count'] }}{{ r['status'] }} + Download + Approval +
{{ r['date'] }}{{ r['full_name'] }}{{ r['app_count'] }}{{ r['status'] }} - Download - Approval -
+ + + - + +{% end %} {% end %} diff --git a/templates/workspace_members.html.to b/templates/workspace_members.html.to index a27a0b0b..53e70385 100644 --- a/templates/workspace_members.html.to +++ b/templates/workspace_members.html.to @@ -1,92 +1,78 @@ {% extends "base_workspace.html.to" %} +{% block template_vars %} + {% set membersEmpty = False %} +{% end %} + {% block workspace_content %} +{% if membersEmpty %} - +{% else %} -{#
-
-
- + + + +
+ + + + + + + + + + + {% for m in members %} + + + + + + + {% end %} + +
Name Status FlagStatusWorkspace Role
{{ m['first_name'] }} {{ m['last_name'] }}{% if m['num_projects'] == '0' %} No Project Access {% end %}{{ m['status'] }}{{ m['workspace_role'] }}
-
#} - - -
- - - - - - - - - - - {% for m in members %} - - - - - - - {% end %} - -
Name Status FlagStatusWorkspace Role
{{ m['first_name'] }} {{ m['last_name'] }}{% if m['num_projects'] == '0' %} No Project Access {% end %}{{ m['status'] }}{{ m['workspace_role'] }}
-
+{% end %} {% end %} diff --git a/templates/workspace_projects.html.to b/templates/workspace_projects.html.to index e4008c3c..620b8396 100644 --- a/templates/workspace_projects.html.to +++ b/templates/workspace_projects.html.to @@ -1,32 +1,49 @@ {% extends "base_workspace.html.to" %} +{% block template_vars %} + {% set projectsEmpty = False %} +{% end %} + {% block workspace_content %} -{% for project in projects %} -
-
-

{{ project['name'] }} ({{ len(project['environments'])}} environments)

- - {% module Icon('edit') %} - edit - -
- -
{% end %} {% end %} From 6db9db3f7decbabadf8ae4706061107ad845de26 Mon Sep 17 00:00:00 2001 From: Andrew Croce Date: Tue, 31 Jul 2018 12:07:25 -0400 Subject: [PATCH 055/332] remove dummy "empty" vars, just check if the arrays are empty --- templates/requests.html.to | 6 +----- templates/workspace_members.html.to | 6 +----- templates/workspace_projects.html.to | 6 +----- 3 files changed, 3 insertions(+), 15 deletions(-) diff --git a/templates/requests.html.to b/templates/requests.html.to index 1cdd2433..bd0c9e8c 100644 --- a/templates/requests.html.to +++ b/templates/requests.html.to @@ -1,9 +1,5 @@ {% extends "base.html.to" %} -{% block template_vars %} - {% set requestsEmpty = False %} -{% end %} - {% block modal %} {% if modalOpen() %} {% apply modal %} @@ -35,7 +31,7 @@ {% block content %} -{% if requestsEmpty %} +{% if not requests %} {% module EmptyState( 'There are currently no active requests for you to see.', diff --git a/templates/workspace_members.html.to b/templates/workspace_members.html.to index 53e70385..074628da 100644 --- a/templates/workspace_members.html.to +++ b/templates/workspace_members.html.to @@ -1,12 +1,8 @@ {% extends "base_workspace.html.to" %} -{% block template_vars %} - {% set membersEmpty = False %} -{% end %} - {% block workspace_content %} -{% if membersEmpty %} +{% if not members %} {% module EmptyState( 'There are currently no members in this Workspace.', diff --git a/templates/workspace_projects.html.to b/templates/workspace_projects.html.to index 620b8396..34b0933b 100644 --- a/templates/workspace_projects.html.to +++ b/templates/workspace_projects.html.to @@ -1,12 +1,8 @@ {% extends "base_workspace.html.to" %} -{% block template_vars %} - {% set projectsEmpty = False %} -{% end %} - {% block workspace_content %} -{% if projectsEmpty %} +{% if not projects %} {% module EmptyState( 'There are currently no projects set up for this Workspace.', From b14c490082de8aa7c7fb5eb7f4db86c7f7ae5b04 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Tue, 31 Jul 2018 14:44:09 -0400 Subject: [PATCH 056/332] Remove unnecessary XML --- atst/eda_client.py | 244 --------------------------------------------- 1 file changed, 244 deletions(-) diff --git a/atst/eda_client.py b/atst/eda_client.py index 09acd859..cebaad27 100644 --- a/atst/eda_client.py +++ b/atst/eda_client.py @@ -110,247 +110,3 @@ class EDAClient(EDAClientBase): # TODO: Fetch the contract XML and transform it into a dictionary. # https://docs.python.org/3.7/library/xml.etree.elementtree.html raise NotImplementedError() - - - -CONTRACT_XML = """ - -2.5 -DD 1155 - -3244871 - -00000431 -704331 - - - - - -Department of Defense -Delivery Order -70433119F2644 -Represented Contract - - -Department of Defense -Basic Ordering Agreement -W81K0419G0001 -Ordering Instrument - - -false -Original -false - -Firm Fixed Price - - - - -http://farsite.hill.af.mil/reghtml/regs/far2afmcfars/fardfars/far/52_220.htm#P810_149596 - - -FAR -52.222-50 -Combating Trafficking in Persons. -2015-05 - - - [ lots of text ] - - -
I
-
- -FAR -52.245-1 -Government Property. -2012-04 - - - [ lots of text ] - - -
I
-
-
- -2016-02-04 - -2016-01-25 - -DALE WOLFE - -Telephone -520-533-9132 - - - - - -Contractor -
- -0Z7K0 -808152482 - - -CACI TECHNOLOGIES, INC - - -6933 Gateway Ct -Manassas VA, 20109 - - - -
-
- -Contract Issuing Office -
- -704331 - - -FEMA DISTRIBUTION CENTER - - -3870 S. SIDE INDUSTRIAL CTR -ATLANTA GA, 30354 - - - -
- -GENE BARBER - -Telephone -(202) 646-2727 - - -
- -Contract Administrative Office -
- -704331 - - -FEMA DISTRIBUTION CENTER - - -3870 S. SIDE INDUSTRIAL CTR -ATLANTA GA, 30354 - - - -
-
- -Paying Office -
- -HQ0131 - - -DEFENSE FINANCE AND ACCOUNTING SVC - - -P.O. BOX 369016 -COLUMBUS OH, 43236 - - - -
-
- -Ship To -
- -S0302A - - -DCMA PHOENIX - - -40 NORTH CENTRAL AVE, STE 400 -TWO RENAISSANCE SQUARE -PHOENIX AZ, 85004 - - - -
-
- - -Header Only - Total Contract Value -192000.00 - - - - -Delivery Requested By - -2016-01-16 - - - - - -Defense Priorities Allocation System (DPAS) Priority Rating - -DO-A7 -
A
-
- - -Contractor -Origin (after Loading) - - -
- - - - - -CLIN -0001 - - - - -false - -Cost No Fee - - -Real Property -Radio Dishes -3 -false -Estimated -Each -64000.00 - -Manufacturer's Part Number -5L33M7730291DX081 - - - - - -Estimated Cost -192000.00 - - -Not to Exceed Amount (Funding) -200000.00 - - - - -
-
-""" From 106b87b96e7de6dcb3d75d53e6f31f9bb5b17e8e Mon Sep 17 00:00:00 2001 From: richard-dds Date: Tue, 31 Jul 2018 15:16:04 -0400 Subject: [PATCH 057/332] Allow for multiple date formats --- atst/forms/fields.py | 12 +++++++++++- tests/forms/test_fields.py | 25 +++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 tests/forms/test_fields.py diff --git a/atst/forms/fields.py b/atst/forms/fields.py index 3e9de703..6f733bd1 100644 --- a/atst/forms/fields.py +++ b/atst/forms/fields.py @@ -7,7 +7,17 @@ import pendulum class DateField(DateField): def _value(self): if self.data: - return pendulum.parse(self.data).date() + date_formats = [ + "YYYY-MM-DD", + "MM/DD/YYYY" + ] + for _format in date_formats: + try: + return pendulum.from_format(self.data, _format).date() + except (ValueError, pendulum.parsing.exceptions.ParserError): + pass + + raise ValueError("Unable to parse string {}".format(self.data)) else: return None diff --git a/tests/forms/test_fields.py b/tests/forms/test_fields.py new file mode 100644 index 00000000..ceece7c5 --- /dev/null +++ b/tests/forms/test_fields.py @@ -0,0 +1,25 @@ +import pytest +from wtforms import Form +import pendulum + +from atst.forms.fields import DateField + + +class MyForm(Form): + date = DateField() + + +def test_date_ie_format(): + form = MyForm(data={"date": "12/24/2018"}) + assert form.date._value() == pendulum.date(2018, 12, 24) + + +def test_date_sane_format(): + form = MyForm(data={"date": "2018-12-24"}) + assert form.date._value() == pendulum.date(2018, 12, 24) + + +def test_date_insane_format(): + form = MyForm(data={"date": "hello"}) + with pytest.raises(ValueError): + form.date._value() From 1db88a8191aae786792e8b6ce7ab1dc3e4ff562f Mon Sep 17 00:00:00 2001 From: Luis Cielak Date: Mon, 30 Jul 2018 17:26:07 -0400 Subject: [PATCH 058/332] Add member placeholder info --- atst/app.py | 1 + templates/member_edit.html.to | 85 +++++++++++++++++++ .../navigation/workspace_navigation.html.to | 15 +++- templates/workspace_members.html.to | 2 +- 4 files changed, 101 insertions(+), 2 deletions(-) create mode 100644 templates/member_edit.html.to diff --git a/atst/app.py b/atst/app.py index dab66e8d..a94a93ec 100644 --- a/atst/app.py +++ b/atst/app.py @@ -122,6 +122,7 @@ def make_app(config, deps, **kwargs): ), url(r"/workspaces/(\S+)/projects", Workspace, {}, name="workspace_projects"), url(r"/workspaces/123456/projects/789/edit", Main, {"page": "project_edit"}, name="project_edit"), + url(r"/workspaces/123456/members/789/edit", Main, {"page": "member_edit"}, name="member_edit"), ] if not ENV == "production": diff --git a/templates/member_edit.html.to b/templates/member_edit.html.to new file mode 100644 index 00000000..d454152c --- /dev/null +++ b/templates/member_edit.html.to @@ -0,0 +1,85 @@ +{% extends "base_workspace.html.to" %} + +{% block template_vars %} +{% set is_new_member = False %} +{% set member_name = "Danny Knight" %} +{% set member_email = "knight@mil.gov" %} +{% set member_workspace_role = "Billing Auditor" %} +{% set member_id = "789" %} +{% end %} + +{% block workspace_content %} + +{% module Alert( + "UI Mock", + message="

Please note, this screen is a non-functional UI mockup.

", + level="info" + ) %} + + +
+
+

+ {% if is_new_member %} + Add new member + {% else %} + {{ member_name }} + {% end %} +

+
Workspace Role {{member_workspace_role}}
+
+
+ + +
+
+
+ +
+
+
+ +
+
+

Code.mil

+ revoke all access +
+
    +
  • + + Development + +
    + no accessset role +
    +
  • +
  • + + Production + +
    + Billingset role +
    +
  • + +
+
+ + + + {% end %} + diff --git a/templates/navigation/workspace_navigation.html.to b/templates/navigation/workspace_navigation.html.to index 21b48bb5..65a9525b 100644 --- a/templates/navigation/workspace_navigation.html.to +++ b/templates/navigation/workspace_navigation.html.to @@ -17,7 +17,20 @@ {% module SidenavItem( "Members", href=reverse_url('workspace_members', '123456'), - active=matchesPath('\/workspaces\/[A-Za-z0-9]*\/members') + active=matchesPath('\/workspaces\/[A-Za-z0-9]*\/members'), + subnav=[ + { + "label": "Add New Member", + "href": "", + "active": matchesPath('/workspaces/members/new'), + "icon": "plus" + }, + { + "label": "Editing Member", + "href": "", + "active": matchesPath('/workspaces/123456/members/789/edit') + } + ] )%} {% module SidenavItem( diff --git a/templates/workspace_members.html.to b/templates/workspace_members.html.to index 074628da..0f538b05 100644 --- a/templates/workspace_members.html.to +++ b/templates/workspace_members.html.to @@ -58,7 +58,7 @@ {% for m in members %} - {{ m['first_name'] }} {{ m['last_name'] }} + {{ m['first_name'] }} {{ m['last_name'] }} {% if m['num_projects'] == '0' %} No Project Access {% end %} {{ m['status'] }} {{ m['workspace_role'] }} From b4b99de7defd84c63304c1ff5a88321f3f0b71ef Mon Sep 17 00:00:00 2001 From: Luis Cielak Date: Tue, 31 Jul 2018 10:29:22 -0400 Subject: [PATCH 059/332] Style block list links --- scss/elements/_block_lists.scss | 19 +++++++-- scss/elements/_icon_link.scss | 4 ++ templates/member_edit.html.to | 4 +- templates/workspace_projects.html.to | 61 +++++++++++----------------- 4 files changed, 45 insertions(+), 43 deletions(-) diff --git a/scss/elements/_block_lists.scss b/scss/elements/_block_lists.scss index e7caed75..ac15f80d 100644 --- a/scss/elements/_block_lists.scss +++ b/scss/elements/_block_lists.scss @@ -54,14 +54,25 @@ .block-list { @include block-list; + + .icon-link { + margin: -$gap 0; + } + + .icon-link { + &:first-child { + margin-left: -$gap; + } + + &:last-child { + margin-right: -$gap; + } + + } } .block-list__header { @include block-list-header; - - .block-list__header__link { - @include icon-link; - } } .block-list__title { diff --git a/scss/elements/_icon_link.scss b/scss/elements/_icon_link.scss index 95e372ec..00daae3f 100644 --- a/scss/elements/_icon_link.scss +++ b/scss/elements/_icon_link.scss @@ -59,4 +59,8 @@ &.icon-link--large { @include icon-link-large; } + + &.icon-link--danger { + @include icon-link-color($color-red, $color-red-lightest); + } } diff --git a/templates/member_edit.html.to b/templates/member_edit.html.to index d454152c..e6f36673 100644 --- a/templates/member_edit.html.to +++ b/templates/member_edit.html.to @@ -48,7 +48,7 @@

Code.mil

- revoke all access + revoke all access
  • @@ -56,7 +56,7 @@ Development
    - no accessset role + no access set role
  • diff --git a/templates/workspace_projects.html.to b/templates/workspace_projects.html.to index 34b0933b..a9f1a8aa 100644 --- a/templates/workspace_projects.html.to +++ b/templates/workspace_projects.html.to @@ -2,44 +2,31 @@ {% block workspace_content %} -{% if not projects %} - - {% module EmptyState( - 'There are currently no projects set up for this Workspace.', - actionLabel='Create a new Project', - actionHref='/project/new', - icon='cloud' - )%} - -{% else %} - - {% for project in projects %} -
    -
    -

    {{ project['name'] }} ({{ len(project['environments'])}} environments)

    - - {% module Icon('edit') %} - edit - -
    - -
    - {% end %} +{% for project in projects %} +
    +
    +

    {{ project['name'] }} ({{ len(project['environments'])}} environments)

    + + {% module Icon('edit') %} + edit + +
    + +
    {% end %} {% end %} From 88c073e1b234c823ea93cc3e5d98d22eda0df6dc Mon Sep 17 00:00:00 2001 From: Luis Cielak Date: Tue, 31 Jul 2018 10:42:14 -0400 Subject: [PATCH 060/332] Add placeholder project item --- templates/member_edit.html.to | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/templates/member_edit.html.to b/templates/member_edit.html.to index e6f36673..ebd3416a 100644 --- a/templates/member_edit.html.to +++ b/templates/member_edit.html.to @@ -48,7 +48,7 @@

    Code.mil

    - revoke all access + revoke all access
  • -
+
+
+

Digital Dojo

+ no access +
+
+ +
  • + + Sandbox + +
    + no accessset role +
    +
  • Production From ccb38dc2c6809a7a485ab8caaab43db27b4be8f9 Mon Sep 17 00:00:00 2001 From: Luis Cielak Date: Tue, 31 Jul 2018 13:49:06 -0400 Subject: [PATCH 063/332] Add fields to header --- templates/member_edit.html.to | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/templates/member_edit.html.to b/templates/member_edit.html.to index 44b9be53..89031d6b 100644 --- a/templates/member_edit.html.to +++ b/templates/member_edit.html.to @@ -18,17 +18,19 @@
    -

    - {% if is_new_member %} - Add new member - {% else %} - {{ member_name }} - {% end %} -

    +

    {{ member_name }}

    Workspace Role {{member_workspace_role}}
    - DOD ID: {{ member_id }} -
    Email: {{ member_email }}
    - edit account details +
    + +
    DOD ID:
    +
    {{ member_id }}
    +
    + +
    Email:
    +
    {{ member_email }}
    +
    +
    + edit account details
    From c5848995507ca3425a015c2ba0694ca52247c456 Mon Sep 17 00:00:00 2001 From: Luis Cielak Date: Tue, 31 Jul 2018 14:17:14 -0400 Subject: [PATCH 064/332] Update search bar --- templates/member_edit.html.to | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/templates/member_edit.html.to b/templates/member_edit.html.to index 89031d6b..f7082b73 100644 --- a/templates/member_edit.html.to +++ b/templates/member_edit.html.to @@ -29,29 +29,24 @@
    Email:
    {{ member_email }}
    + edit account details - edit account details
  • - -
    -
    -
    - -
    +
    +
    -

    Code.mil

    +

    ▾ Code.mil

    revoke all access
      @@ -84,7 +79,7 @@
      -

      Digital Dojo

      +

      ▸ Digital Dojo

      no access
      From cfbf2efdf6956145d1805e2cf3be67c461267fbc Mon Sep 17 00:00:00 2001 From: Luis Cielak Date: Tue, 31 Jul 2018 14:27:33 -0400 Subject: [PATCH 065/332] Remove dl markup --- templates/member_edit.html.to | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/templates/member_edit.html.to b/templates/member_edit.html.to index f7082b73..f9125323 100644 --- a/templates/member_edit.html.to +++ b/templates/member_edit.html.to @@ -20,17 +20,12 @@

      {{ member_name }}

      Workspace Role {{member_workspace_role}}
      -
      - -
      DOD ID:
      -
      {{ member_id }}
      -
      - -
      Email:
      -
      {{ member_email }}
      -
      - edit account details -
      + + DOD ID: + {{ member_id }} + Email: + {{ member_email }} + edit account details
    From 727680c31f16e33ee267d17434fc8f076590d022 Mon Sep 17 00:00:00 2001 From: Luis Cielak Date: Tue, 31 Jul 2018 14:44:56 -0400 Subject: [PATCH 066/332] Replace ascii traingles with svgs --- static/icons/arrow-down.svg | 1 + static/icons/arrow-right.svg | 1 + templates/member_edit.html.to | 4 ++-- templates/styleguide.html.to | 2 ++ 4 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 static/icons/arrow-down.svg create mode 100644 static/icons/arrow-right.svg diff --git a/static/icons/arrow-down.svg b/static/icons/arrow-down.svg new file mode 100644 index 00000000..ec8fe0b9 --- /dev/null +++ b/static/icons/arrow-down.svg @@ -0,0 +1 @@ + diff --git a/static/icons/arrow-right.svg b/static/icons/arrow-right.svg new file mode 100644 index 00000000..524470fd --- /dev/null +++ b/static/icons/arrow-right.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/templates/member_edit.html.to b/templates/member_edit.html.to index f9125323..3b744ad6 100644 --- a/templates/member_edit.html.to +++ b/templates/member_edit.html.to @@ -41,7 +41,7 @@
    -

    ▾ Code.mil

    +

    {% module Icon('arrow-down') %} Code.mil

    revoke all access
      @@ -74,7 +74,7 @@
      -

      ▸ Digital Dojo

      +

      {% module Icon('arrow-right') %} Digital Dojo

      no access
      diff --git a/templates/styleguide.html.to b/templates/styleguide.html.to index e90aefc9..1db19496 100644 --- a/templates/styleguide.html.to +++ b/templates/styleguide.html.to @@ -301,6 +301,8 @@ {% module Icon('link') %} 'link'    {% module Icon('ok') %} 'ok'    {% module Icon('checkmark') %} 'checkmark'    + {% module Icon('arrow-right') %} 'arrow-right'    + {% module Icon('arrow-down') %} 'arrow-down'   
    From cdd442c266bf0e26ce480b5b08705c9360456e3c Mon Sep 17 00:00:00 2001 From: Luis Cielak Date: Tue, 31 Jul 2018 16:04:17 -0400 Subject: [PATCH 067/332] Update member header layout --- scss/atat.scss | 1 + scss/sections/_member_edit.scss | 37 +++++++++++++++++++++++++++++++++ templates/member_edit.html.to | 27 +++++++++++++++--------- 3 files changed, 55 insertions(+), 10 deletions(-) create mode 100644 scss/sections/_member_edit.scss diff --git a/scss/atat.scss b/scss/atat.scss index f9e7f6aa..b4ae7797 100644 --- a/scss/atat.scss +++ b/scss/atat.scss @@ -33,3 +33,4 @@ @import 'sections/request_approval'; @import 'sections/projects_list'; @import 'sections/project_edit'; +@import 'sections/member_edit'; diff --git a/scss/sections/_member_edit.scss b/scss/sections/_member_edit.scss new file mode 100644 index 00000000..c868137a --- /dev/null +++ b/scss/sections/_member_edit.scss @@ -0,0 +1,37 @@ +.member-card { + @include grid-row; + padding: $gap*2; + justify-content: space-between; + + dl { + margin: 0; + + > div { + margin-bottom: $gap; + } + } + + dt { + font-weight: normal; + color: $color-gray; + } + + dd { + display: inline; + } + + .member-card__header { + display: flex; + flex-direction: column; + justify-content: space-between; + } + + .member-card__heading { + margin: 0; + @include h2; + } + + .member-card__details { + text-align: right; + } +} \ No newline at end of file diff --git a/templates/member_edit.html.to b/templates/member_edit.html.to index 3b744ad6..140e8a26 100644 --- a/templates/member_edit.html.to +++ b/templates/member_edit.html.to @@ -16,16 +16,23 @@ level="info" ) %} -
    -
    -

    {{ member_name }}

    -
    Workspace Role {{member_workspace_role}}
    - - DOD ID: - {{ member_id }} - Email: - {{ member_email }} - edit account details +
    +
    +

    {{ member_name }}

    +
    Workspace Role
    {{member_workspace_role}}
    +
    +
    +
    +
    +
    DOD ID:
    +
    {{ member_id }}
    +
    +
    +
    Email:
    +
    {{ member_email }}
    +
    +
    + edit account details
    From 1a6d42f385b3cbaa360c5aebe881e47c12c11463 Mon Sep 17 00:00:00 2001 From: Luis Cielak Date: Tue, 31 Jul 2018 16:16:43 -0400 Subject: [PATCH 068/332] Style lables and adjust list --- scss/elements/_block_lists.scss | 3 ++- scss/elements/_typography.scss | 8 ++------ scss/sections/_member_edit.scss | 4 ++++ templates/member_edit.html.to | 10 +++++----- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/scss/elements/_block_lists.scss b/scss/elements/_block_lists.scss index ac15f80d..6cb24d11 100644 --- a/scss/elements/_block_lists.scss +++ b/scss/elements/_block_lists.scss @@ -59,7 +59,8 @@ margin: -$gap 0; } - .icon-link { + .icon-link, + .label { &:first-child { margin-left: -$gap; } diff --git a/scss/elements/_typography.scss b/scss/elements/_typography.scss index 10f0846a..fcdc97d9 100644 --- a/scss/elements/_typography.scss +++ b/scss/elements/_typography.scss @@ -4,7 +4,7 @@ * @source https://github.com/uswds/uswds/blob/develop/src/stylesheets/elements/_typography.scss */ -* { + * { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } @@ -56,8 +56,4 @@ dl { > div { margin-bottom: $gap * 2; } -} - -.subtitle { - color: $color-gray; -} +} \ No newline at end of file diff --git a/scss/sections/_member_edit.scss b/scss/sections/_member_edit.scss index c868137a..aef2e042 100644 --- a/scss/sections/_member_edit.scss +++ b/scss/sections/_member_edit.scss @@ -33,5 +33,9 @@ .member-card__details { text-align: right; + + .icon-link { + margin: 0 -$gap; + } } } \ No newline at end of file diff --git a/templates/member_edit.html.to b/templates/member_edit.html.to index 140e8a26..24893bf2 100644 --- a/templates/member_edit.html.to +++ b/templates/member_edit.html.to @@ -19,7 +19,7 @@

    {{ member_name }}

    -
    Workspace Role
    {{member_workspace_role}}
    +
    Workspace Role
    {{member_workspace_role}}
    @@ -57,7 +57,7 @@ Development
    - no access set role + no access set role
  • @@ -65,7 +65,7 @@ Sandbox
    - no accessset role + no accessset role
  • @@ -73,7 +73,7 @@ Production
    - Billingset role + Billingset role
  • @@ -82,7 +82,7 @@

    {% module Icon('arrow-right') %} Digital Dojo

    - no access + no access
    From 6a5d3d57cf556c064b6a003cd628ae779ead2804 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Wed, 1 Aug 2018 10:51:14 -0400 Subject: [PATCH 069/332] Flask setup --- Pipfile | 13 +- Pipfile.lock | 196 ++++++++++++++++++++------- app.py | 12 +- atst/app.py | 290 ++++++++++++++++++++-------------------- atst/assets.py | 11 +- atst/database.py | 9 +- atst/handler.py | 3 +- atst/routes/__init__.py | 7 + 8 files changed, 318 insertions(+), 223 deletions(-) create mode 100644 atst/routes/__init__.py diff --git a/Pipfile b/Pipfile index 81cadd0d..4110ccbf 100644 --- a/Pipfile +++ b/Pipfile @@ -4,20 +4,23 @@ verify_ssl = true name = "pypi" [packages] -tornado = "==5.0.2" -webassets = "==0.12.1" -Unipath = "==1.1" +tornado = "*" +webassets = "*" +Unipath = "*" wtforms-tornado = "*" pendulum = "*" redis = "*" sqlalchemy = "*" alembic = "*" "psycopg2-binary" = "*" +flask = "*" +flask-sqlalchemy = "*" +flask-assets = "*" [dev-packages] bandit = "*" -pytest = "==3.6.0" -pytest-tornado = "==0.5.0" +pytest = "*" +pytest-tornado = "*" ipython = "*" ipdb = "*" pylint = "*" diff --git a/Pipfile.lock b/Pipfile.lock index d87dfa97..d6e5cf64 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "7cd87f2c2c42bc776a6aa6f72fcbb8b30d4e703e50b6480ce1c8ace6ae6dd0a4" + "sha256": "2ee6dd90ff3784e7b1781c680d690ac59118b4e3d72e8da3adf9e93d6e512bc7" }, "pipfile-spec": 6, "requires": { @@ -24,6 +24,49 @@ "index": "pypi", "version": "==1.0.0" }, + "click": { + "hashes": [ + "sha256:29f99fc6125fbc931b758dc053b3114e55c77a6e4c6c3a2674a2dc986016381d", + "sha256:f15516df478d5a56180fbf80e68f206010e6d160fc39fa508b65e035fd75130b" + ], + "version": "==6.7" + }, + "flask": { + "hashes": [ + "sha256:2271c0070dbcb5275fad4a82e29f23ab92682dc45f9dfbc22c02ba9b9322ce48", + "sha256:a080b744b7e345ccfcbc77954861cb05b3c63786e93f2b3875e0913d44b43f05" + ], + "index": "pypi", + "version": "==1.0.2" + }, + "flask-assets": { + "hashes": [ + "sha256:6031527b89fb3509d1581d932affa5a79dd348cfffb58d0aef99a43461d47847" + ], + "index": "pypi", + "version": "==0.12" + }, + "flask-sqlalchemy": { + "hashes": [ + "sha256:3bc0fac969dd8c0ace01b32060f0c729565293302f0c4269beed154b46bec50b", + "sha256:5971b9852b5888655f11db634e87725a9031e170f37c0ce7851cf83497f56e53" + ], + "index": "pypi", + "version": "==2.3.2" + }, + "itsdangerous": { + "hashes": [ + "sha256:cbb3fcf8d3e33df861709ecaf89d9e6629cff0a217bc2848f1b41cd30d360519" + ], + "version": "==0.24" + }, + "jinja2": { + "hashes": [ + "sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd", + "sha256:f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4" + ], + "version": "==2.10" + }, "mako": { "hashes": [ "sha256:4e02fde57bd4abb5ec400181e4c314f56ac3e49ba4fb8b0d50bba18cb27d25ae" @@ -38,19 +81,22 @@ }, "pendulum": { "hashes": [ - "sha256:0643d45824e6789b88187728337dfa6075a0233f6976c2abefba00d064156309", - "sha256:3cc271195d8054bec06f54ff7d56ea6c2e2b5ad5dd6b532d787b34d2cabe6a65", - "sha256:544e44d8a92954e5ef4db4fa8b662d3282f2ac7b7c2cbf4227dc193ba78b9e1e", - "sha256:846478ab5f7480b3d850a09e44fe03830d448633c84f0b1066615ff6c34293aa", - "sha256:8bb523f759daeecfc0649369f198cbeb27a6608347354f4f847d21d579003db6", - "sha256:a449142063100f1b3c1119453c7569667c9ba79897305a1c50ca83a8c790f1e4", - "sha256:b7ff156b3d7cccbdeeb63465578d9a4e6f57d463f6ff6d4474254208d08f8353", - "sha256:d8822a592bbc16576c44ec4625bff9187ed9b649d47714e4905a55adc5b25339", - "sha256:dd45c7b349faab69714df9835cdf8bf8bce50bf6fc471419d3b23ba33e1915a5", - "sha256:fac088b637b5db5a047a0e89194d8c3c9e9e9ce1665089240003bb7c05b92536" + "sha256:0ec5371949e147753661e1e98721273170638034dfceb578f29d69d93d3d474b", + "sha256:10ccdc8c6d004ba97883dd0f57503963ddf6cb83e849a16c4675ba18da657564", + "sha256:37bb54bcbb9d7fccd725f3fda69702e51ab3de9971b4c1c986505fbb3bc58bed", + "sha256:51803352e40778f914ff7af3494788b404260b415d9a9d607a8cf73e5e120994", + "sha256:5de295ca85761d9adf4020e6f3bed6eb933846ccf23b74e04b071f6d677f11a4", + "sha256:73f850265adcf0986fcc0af83ae9c8c5a7ca3c4a2525184110478a8bfd1a77b3", + "sha256:8fe289356322f6b0f4510082b4c412a1496a64054a37ae86b24411868a1901c6", + "sha256:c0401482dfa9fbd7005f2dfbf54ec61fd2c8130df37651ac2a3722d1f049ae4e", + "sha256:c358ee65ddb99c2b1bf301458e43ed09ff6d40465bcc9928265246912fad4d0f", + "sha256:d07962450e808556b3e6209a5830e2bbf8c7747129580c3b5b09e641f72617ab", + "sha256:dc05e6186c9c3b9969326aded9cba7a796744918581b25457f5148a5e3475d55", + "sha256:ee9466eea403e8e308c284d3055e285b97905a5ffb1566df0ef200b4f39c0f15", + "sha256:f7fa6220251a636112721e8158b9dd59018d818ec121047900934d80864eca62" ], "index": "pypi", - "version": "==2.0.2" + "version": "==2.0.3" }, "psycopg2-binary": { "hashes": [ @@ -106,7 +152,7 @@ "sha256:1d936da41ee06216d89fdc7ead1ee9a5da2811a8787515a976b646e110c3f622", "sha256:e4ef42e82b0b493c5849eed98b5ab49d6767caf982127e9a33167f1153b36cc5" ], - "markers": "python_version != '3.1.*' and python_version != '3.2.*' and python_version != '3.0.*' and python_version != '3.3.*' and python_version >= '2.7'", + "markers": "python_version != '3.0.*' and python_version != '3.1.*' and python_version != '3.2.*' and python_version >= '2.7' and python_version != '3.3.*'", "version": "==2018.5" }, "redis": { @@ -133,14 +179,16 @@ }, "tornado": { "hashes": [ - "sha256:1b83d5c10550f2653380b4c77331d6f8850f287c4f67d7ce1e1c639d9222fbc7", - "sha256:408d129e9d13d3c55aa73f8084aa97d5f90ed84132e38d6932e63a67d5bec563", - "sha256:88ce0282cce70df9045e515f578c78f1ebc35dcabe1d70f800c3583ebda7f5f5", - "sha256:ba9fbb249ac5390bff8a1d6aa4b844fd400701069bda7d2e380dfe2217895101", - "sha256:c050089173c2e9272244bccfb6a8615fb9e53b79420a5551acfa76094ecc3111" + "sha256:1c0816fc32b7d31b98781bd8ebc7a9726d7dce67407dc353a2e66e697e138448", + "sha256:4f66a2172cb947387193ca4c2c3e19131f1c70fa8be470ddbbd9317fd0801582", + "sha256:5327ba1a6c694e0149e7d9126426b3704b1d9d520852a3e4aa9fc8fe989e4046", + "sha256:6a7e8657618268bb007646b9eae7661d0b57f13efc94faa33cd2588eae5912c9", + "sha256:a9b14804783a1d77c0bd6c66f7a9b1196cbddfbdf8bceb64683c5ae60bd1ec6f", + "sha256:c58757e37c4a3172949c99099d4d5106e4d7b63aa0617f9bb24bfbff712c7866", + "sha256:d8984742ce86c0855cccecd5c6f54a9f7532c983947cff06f3a0e2115b47f85c" ], "index": "pypi", - "version": "==5.0.2" + "version": "==5.1" }, "unipath": { "hashes": [ @@ -157,6 +205,13 @@ "index": "pypi", "version": "==0.12.1" }, + "werkzeug": { + "hashes": [ + "sha256:c3fd7a7d41976d9f44db327260e263132466836cef6f91512889ed60ad26557c", + "sha256:d5da73735293558eb1651ee2fddc4d0dedcfa06538b8813a2e20011583c9e49b" + ], + "version": "==0.14.1" + }, "wtforms": { "hashes": [ "sha256:0cdbac3e7f6878086c334aa25dc5a33869a3954e9d1e015130d65a69309b3b61", @@ -197,10 +252,10 @@ }, "astroid": { "hashes": [ - "sha256:0a0c484279a5f08c9bcedd6fa9b42e378866a7dcc695206b92d59dc9f2d9760d", - "sha256:218e36cf8d98a42f16214e8670819ce307fa707d1dcf7f9af84c7aede1febc7f" + "sha256:a48b57ede295c3188ef5c84273bc2a8eadc46e4cbb001eae0d49fb5d1fabbb19", + "sha256:d066cdeec5faeb51a4be5010da612680653d844b57afd86a5c8315f2f801b4cc" ], - "version": "==2.0.1" + "version": "==2.0.2" }, "atomicwrites": { "hashes": [ @@ -279,7 +334,7 @@ "sha256:0e9a1227a3a0f3297a485715e72ee6eb77081b17b629367042b586e38c03c867", "sha256:b4840807a94a3bad0217d6ed3f9b65a1cc6e1db1c99e1184673056ae2c0a4c4d" ], - "markers": "python_version != '3.2.*' and python_version != '3.0.*' and python_version >= '2.7' and python_version != '3.1.*'", + "markers": "python_version != '3.1.*' and python_version != '3.2.*' and python_version >= '2.7' and python_version != '3.0.*'", "version": "==0.8.17" }, "gitdb2": { @@ -305,11 +360,11 @@ }, "ipython": { "hashes": [ - "sha256:a0c96853549b246991046f32d19db7140f5b1a644cc31f0dc1edc86713b7676f", - "sha256:eca537aa61592aca2fef4adea12af8e42f5c335004dfa80c78caf80e8b525e5c" + "sha256:007dcd929c14631f83daff35df0147ea51d1af420da303fd078343878bd5fb62", + "sha256:b0f2ef9eada4a68ef63ee10b6dde4f35c840035c50fd24265f8052c98947d5a4" ], "index": "pypi", - "version": "==6.4.0" + "version": "==6.5.0" }, "ipython-genutils": { "hashes": [ @@ -324,7 +379,7 @@ "sha256:b9c40e9750f3d77e6e4d441d8b0266cf555e7cdabdcff33c4fd06366ca761ef8", "sha256:ec9ef8f4a9bc6f71eec99e1806bfa2de401650d996c59330782b89a5555c1497" ], - "markers": "python_version >= '2.7' and python_version != '3.1.*' and python_version != '3.3.*' and python_version != '3.0.*' and python_version != '3.2.*'", + "markers": "python_version != '3.3.*' and python_version >= '2.7' and python_version != '3.1.*' and python_version != '3.0.*' and python_version != '3.2.*'", "version": "==4.3.4" }, "jedi": { @@ -377,11 +432,11 @@ }, "more-itertools": { "hashes": [ - "sha256:2b6b9893337bfd9166bee6a62c2b0c9fe7735dcf85948b387ec8cba30e85d8e8", - "sha256:6703844a52d3588f951883005efcf555e49566a48afd4db4e965d69b883980d3", - "sha256:a18d870ef2ffca2b8463c0070ad17b5978056f403fb64e3f15fe62a52db21cc0" + "sha256:c187a73da93e7a8acc0001572aebc7e3c69daf7bf6881a2cea10650bd4420092", + "sha256:c476b5d3a34e12d40130bc2f935028b5f636df8f372dc2c1c01dc19681b2039e", + "sha256:fcbfeaea0be121980e15bc97b3817b5202ca73d0eae185b4550cbfce2a3ebb3d" ], - "version": "==4.2.0" + "version": "==4.3.0" }, "parso": { "hashes": [ @@ -398,10 +453,10 @@ }, "pbr": { "hashes": [ - "sha256:754e766b4f4bad3aa68cfd532456298da1aa39375da8748392dbae90860d5f18", - "sha256:c6bddbad814f23c7faaf88d8a186e9965243cc6206a23361b73023648e645794" + "sha256:1b8be50d938c9bb75d0eaf7eda111eec1bf6dc88a62a6412e33bf077457e0f45", + "sha256:b486975c0cafb6beeb50ca0e17ba047647f229087bd74e37f4a7e2cac17d2caa" ], - "version": "==4.1.1" + "version": "==4.2.0" }, "pexpect": { "hashes": [ @@ -420,12 +475,11 @@ }, "pluggy": { "hashes": [ - "sha256:7f8ae7f5bdf75671a718d2daf0a64b7885f74510bcd98b1a0bb420eb9a9d0cff", - "sha256:d345c8fe681115900d6da8d048ba67c25df42973bda370783cd58826442dcd7c", - "sha256:e160a7fcf25762bb60efc7e171d4497ff1d8d2d75a3d0df7a21b76821ecbf5c5" + "sha256:6e3836e39f4d36ae72840833db137f7b7d35105079aee6ec4a62d9f80d594dd1", + "sha256:95eb8364a4708392bae89035f45341871286a333f749c3141c20573d2b3876e1" ], - "markers": "python_version >= '2.7' and python_version != '3.1.*' and python_version != '3.3.*' and python_version != '3.0.*' and python_version != '3.2.*'", - "version": "==0.6.0" + "markers": "python_version != '3.3.*' and python_version >= '2.7' and python_version != '3.1.*' and python_version != '3.0.*' and python_version != '3.2.*'", + "version": "==0.7.1" }, "prompt-toolkit": { "hashes": [ @@ -447,7 +501,7 @@ "sha256:3fd59af7435864e1a243790d322d763925431213b6b8529c6ca71081ace3bbf7", "sha256:e31fb2767eb657cbde86c454f02e99cb846d3cd9d61b318525140214fdc0e98e" ], - "markers": "python_version >= '2.7' and python_version != '3.1.*' and python_version != '3.3.*' and python_version != '3.0.*' and python_version != '3.2.*'", + "markers": "python_version != '3.3.*' and python_version >= '2.7' and python_version != '3.1.*' and python_version != '3.0.*' and python_version != '3.2.*'", "version": "==1.5.4" }, "pygments": { @@ -459,19 +513,19 @@ }, "pylint": { "hashes": [ - "sha256:2c90a24bee8fae22ac98061c896e61f45c5b73c2e0511a4bf53f99ba56e90434", - "sha256:454532779425098969b8f54ab0f056000b883909f69d05905ea114df886e3251" + "sha256:0edfec21270725c5aa8e8d8d06ef5666f766e0e748ed2f1ab23624727303b935", + "sha256:4cadcaa4f1fb19123d4baa758d9fbe6286c5b3aa513af6ea42a2d51d405db205" ], "index": "pypi", - "version": "==2.0.1" + "version": "==2.1.0" }, "pytest": { "hashes": [ - "sha256:39555d023af3200d004d09e51b4dd9fdd828baa863cded3fd6ba2f29f757ae2d", - "sha256:c76e93f3145a44812955e8d46cdd302d8a45fbfc7bf22be24fe231f9d8d8853a" + "sha256:8214ab8446104a1d0c17fbd218ec6aac743236c6ffbe23abc038e40213c60b88", + "sha256:e2b2c6e1560b8f9dc8dd600b0923183fbd68ba3d9bdecde04467be6dd296a384" ], "index": "pypi", - "version": "==3.6.0" + "version": "==3.7.0" }, "pytest-tornado": { "hashes": [ @@ -547,14 +601,16 @@ }, "tornado": { "hashes": [ - "sha256:1b83d5c10550f2653380b4c77331d6f8850f287c4f67d7ce1e1c639d9222fbc7", - "sha256:408d129e9d13d3c55aa73f8084aa97d5f90ed84132e38d6932e63a67d5bec563", - "sha256:88ce0282cce70df9045e515f578c78f1ebc35dcabe1d70f800c3583ebda7f5f5", - "sha256:ba9fbb249ac5390bff8a1d6aa4b844fd400701069bda7d2e380dfe2217895101", - "sha256:c050089173c2e9272244bccfb6a8615fb9e53b79420a5551acfa76094ecc3111" + "sha256:1c0816fc32b7d31b98781bd8ebc7a9726d7dce67407dc353a2e66e697e138448", + "sha256:4f66a2172cb947387193ca4c2c3e19131f1c70fa8be470ddbbd9317fd0801582", + "sha256:5327ba1a6c694e0149e7d9126426b3704b1d9d520852a3e4aa9fc8fe989e4046", + "sha256:6a7e8657618268bb007646b9eae7661d0b57f13efc94faa33cd2588eae5912c9", + "sha256:a9b14804783a1d77c0bd6c66f7a9b1196cbddfbdf8bceb64683c5ae60bd1ec6f", + "sha256:c58757e37c4a3172949c99099d4d5106e4d7b63aa0617f9bb24bfbff712c7866", + "sha256:d8984742ce86c0855cccecd5c6f54a9f7532c983947cff06f3a0e2115b47f85c" ], "index": "pypi", - "version": "==5.0.2" + "version": "==5.1" }, "traitlets": { "hashes": [ @@ -563,6 +619,42 @@ ], "version": "==4.3.2" }, + "typed-ast": { + "hashes": [ + "sha256:0948004fa228ae071054f5208840a1e88747a357ec1101c17217bfe99b299d58", + "sha256:10703d3cec8dcd9eef5a630a04056bbc898abc19bac5691612acba7d1325b66d", + "sha256:1f6c4bd0bdc0f14246fd41262df7dfc018d65bb05f6e16390b7ea26ca454a291", + "sha256:25d8feefe27eb0303b73545416b13d108c6067b846b543738a25ff304824ed9a", + "sha256:29464a177d56e4e055b5f7b629935af7f49c196be47528cc94e0a7bf83fbc2b9", + "sha256:2e214b72168ea0275efd6c884b114ab42e316de3ffa125b267e732ed2abda892", + "sha256:3e0d5e48e3a23e9a4d1a9f698e32a542a4a288c871d33ed8df1b092a40f3a0f9", + "sha256:519425deca5c2b2bdac49f77b2c5625781abbaf9a809d727d3a5596b30bb4ded", + "sha256:57fe287f0cdd9ceaf69e7b71a2e94a24b5d268b35df251a88fef5cc241bf73aa", + "sha256:668d0cec391d9aed1c6a388b0d5b97cd22e6073eaa5fbaa6d2946603b4871efe", + "sha256:68ba70684990f59497680ff90d18e756a47bf4863c604098f10de9716b2c0bdd", + "sha256:6de012d2b166fe7a4cdf505eee3aaa12192f7ba365beeefaca4ec10e31241a85", + "sha256:79b91ebe5a28d349b6d0d323023350133e927b4de5b651a8aa2db69c761420c6", + "sha256:8550177fa5d4c1f09b5e5f524411c44633c80ec69b24e0e98906dd761941ca46", + "sha256:898f818399cafcdb93cbbe15fc83a33d05f18e29fb498ddc09b0214cdfc7cd51", + "sha256:94b091dc0f19291adcb279a108f5d38de2430411068b219f41b343c03b28fb1f", + "sha256:a26863198902cda15ab4503991e8cf1ca874219e0118cbf07c126bce7c4db129", + "sha256:a8034021801bc0440f2e027c354b4eafd95891b573e12ff0418dec385c76785c", + "sha256:bc978ac17468fe868ee589c795d06777f75496b1ed576d308002c8a5756fb9ea", + "sha256:c05b41bc1deade9f90ddc5d988fe506208019ebba9f2578c622516fd201f5863", + "sha256:c9b060bd1e5a26ab6e8267fd46fc9e02b54eb15fffb16d112d4c7b1c12987559", + "sha256:edb04bdd45bfd76c8292c4d9654568efaedf76fe78eb246dde69bdb13b2dad87", + "sha256:f19f2a4f547505fe9072e15f6f4ae714af51b5a681a97f187971f50c283193b6" + ], + "version": "==1.1.0" + }, + "typing": { + "hashes": [ + "sha256:3a887b021a77b292e151afb75323dea88a7bc1b3dfa92176cff8e44c8b68bddf", + "sha256:b2c689d54e1144bbcfd191b0832980a21c2dbcf7b5ff7a66248a60c90e951eb8", + "sha256:d400a9344254803a2368533e4533a4200d21eb7b6b729c173bc38201a74db3f2" + ], + "version": "==3.6.4" + }, "watchdog": { "hashes": [ "sha256:7e65882adb7746039b6f3876ee174952f8eaaa34491ba34333ddf1fe35de4162" diff --git a/app.py b/app.py index b6d66f53..6d786f34 100755 --- a/app.py +++ b/app.py @@ -1,15 +1,11 @@ #!/usr/bin/env python -import tornado.ioloop - -from atst.app import make_app, make_deps, make_config +from atst.app import make_app, make_config config = make_config() -deps = make_deps(config) -app = make_app(config, deps) +app = make_app(config) if __name__ == "__main__": - port = int(config["default"]["PORT"]) - app.listen(port) + port = int(config["PORT"]) + app.run(port=port) print("Listening on http://localhost:%i" % port) - tornado.ioloop.IOLoop.current().start() diff --git a/atst/app.py b/atst/app.py index a94a93ec..5128117f 100644 --- a/atst/app.py +++ b/atst/app.py @@ -1,160 +1,166 @@ import os from configparser import ConfigParser -import tornado.web -from tornado.web import url from redis import StrictRedis +from flask import Flask +from unipath import Path -from atst.handlers.main import Main -from atst.handlers.root import Root -from atst.handlers.login_redirect import LoginRedirect -from atst.handlers.workspaces import Workspaces -from atst.handlers.workspace import Workspace -from atst.handlers.workspace_members import WorkspaceMembers -from atst.handlers.request import Request -from atst.handlers.request_financial_verification import RequestFinancialVerification -from atst.handlers.request_new import RequestNew -from atst.handlers.request_submit import RequestsSubmit -from atst.handlers.dev import Dev -from atst.home import home from atst.api_client import ApiClient from atst.sessions import RedisSessions -from atst import ui_modules -from atst import ui_methods -from atst.database import make_db +from atst.database import db +from atst.assets import assets +from atst.routes import bp ENV = os.getenv("TORNADO_ENV", "dev") -def make_app(config, deps, **kwargs): +def make_app(config): - routes = [ - url(r"/", Root, {"page": "root"}, name="root"), - url( - r"/login-redirect", - LoginRedirect, - { - "sessions": deps["sessions"], - "authnid_client": deps["authnid_client"], - "db_session": deps["db_session"], - }, - name="login_redirect", - ), - url(r"/home", Main, {"page": "home"}, name="home"), - url(r"/styleguide", Main, {"page": "styleguide"}, name="styleguide"), - url( - r"/workspaces/blank", - Main, - {"page": "workspaces_blank"}, - name="workspaces_blank", - ), - url( - r"/workspaces", - Workspaces, - {"page": "workspaces", "db_session": deps["db_session"]}, - name="workspaces", - ), - url( - r"/requests", - Request, - {"page": "requests", "db_session": deps["db_session"]}, - name="requests", - ), - url( - r"/requests/new", - RequestNew, - { - "page": "requests_new", - "db_session": deps["db_session"], - }, - name="request_new", - ), - url( - r"/requests/new/([0-9])", - RequestNew, - { - "page": "requests_new", - "db_session": deps["db_session"], - }, - name="request_form_new", - ), - url( - r"/requests/new/([0-9])/(\S+)", - RequestNew, - { - "page": "requests_new", - "db_session": deps["db_session"], - }, - name="request_form_update", - ), - url( - r"/requests/submit/(\S+)", - RequestsSubmit, - {"db_session": deps["db_session"]}, - name="requests_submit", - ), - # Dummy request/approval screen - url( - r"/request/approval", - Main, - {"page": "request_approval"}, - name="request_approval", - ), - url( - r"/requests/verify/(\S+)", - RequestFinancialVerification, - { - "page": "financial_verification", - "db_session": deps["db_session"], - }, - name="financial_verification", - ), - url( - r"/requests/financial_verification_submitted", - Main, - {"page": "requests/financial_verification_submitted"}, - name="financial_verification_submitted", - ), - url(r"/users", Main, {"page": "users"}, name="users"), - url(r"/reports", Main, {"page": "reports"}, name="reports"), - url(r"/calculator", Main, {"page": "calculator"}, name="calculator"), - url( - r"/workspaces/(\S+)/members", WorkspaceMembers, {}, name="workspace_members" - ), - url(r"/workspaces/(\S+)/projects", Workspace, {}, name="workspace_projects"), - url(r"/workspaces/123456/projects/789/edit", Main, {"page": "project_edit"}, name="project_edit"), - url(r"/workspaces/123456/members/789/edit", Main, {"page": "member_edit"}, name="member_edit"), - ] + parent_dir = Path().parent - if not ENV == "production": - routes += [ - url( - r"/login-dev", - Dev, - { - "action": "login", - "sessions": deps["sessions"], - "db_session": deps["db_session"], - }, - name="dev-login", - ) - ] - - app = tornado.web.Application( - routes, - login_url="/", - template_path=home.child("templates"), - static_path=home.child("static"), - cookie_secret=config["default"]["COOKIE_SECRET"], - debug=config["default"].getboolean("DEBUG"), - ui_modules=ui_modules, - ui_methods=ui_methods, - **kwargs + app = Flask( + __name__, + template_folder=parent_dir.child("templates").absolute(), + static_folder=parent_dir.child("static").absolute() ) - app.config = config - app.sessions = deps["sessions"] + app.config.update(config) + + db.init_app(app) + assets.init_app(app) + + app.register_blueprint(bp) + return app +# def make_app(config, deps, **kwargs): +# routes = [ +# url(r"/", Root, {"page": "root"}, name="root"), +# url( +# r"/login-redirect", +# LoginRedirect, +# { +# "sessions": deps["sessions"], +# "authnid_client": deps["authnid_client"], +# "db_session": deps["db_session"], +# }, +# name="login_redirect", +# ), +# url(r"/home", Main, {"page": "home"}, name="home"), +# url(r"/styleguide", Main, {"page": "styleguide"}, name="styleguide"), +# url( +# r"/workspaces/blank", +# Main, +# {"page": "workspaces_blank"}, +# name="workspaces_blank", +# ), +# url( +# r"/workspaces", +# Workspaces, +# {"page": "workspaces", "db_session": deps["db_session"]}, +# name="workspaces", +# ), +# url( +# r"/requests", +# Request, +# {"page": "requests", "db_session": deps["db_session"]}, +# name="requests", +# ), +# url( +# r"/requests/new", +# RequestNew, +# { +# "page": "requests_new", +# "db_session": deps["db_session"], +# }, +# name="request_new", +# ), +# url( +# r"/requests/new/([0-9])", +# RequestNew, +# { +# "page": "requests_new", +# "db_session": deps["db_session"], +# }, +# name="request_form_new", +# ), +# url( +# r"/requests/new/([0-9])/(\S+)", +# RequestNew, +# { +# "page": "requests_new", +# "db_session": deps["db_session"], +# }, +# name="request_form_update", +# ), +# url( +# r"/requests/submit/(\S+)", +# RequestsSubmit, +# {"db_session": deps["db_session"]}, +# name="requests_submit", +# ), +# # Dummy request/approval screen +# url( +# r"/request/approval", +# Main, +# {"page": "request_approval"}, +# name="request_approval", +# ), +# url( +# r"/requests/verify/(\S+)", +# RequestFinancialVerification, +# { +# "page": "financial_verification", +# "db_session": deps["db_session"], +# }, +# name="financial_verification", +# ), +# url( +# r"/requests/financial_verification_submitted", +# Main, +# {"page": "requests/financial_verification_submitted"}, +# name="financial_verification_submitted", +# ), +# url(r"/users", Main, {"page": "users"}, name="users"), +# url(r"/reports", Main, {"page": "reports"}, name="reports"), +# url(r"/calculator", Main, {"page": "calculator"}, name="calculator"), +# url( +# r"/workspaces/(\S+)/members", WorkspaceMembers, {}, name="workspace_members" +# ), +# url(r"/workspaces/(\S+)/projects", Workspace, {}, name="workspace_projects"), +# url(r"/workspaces/123456/projects/789/edit", Main, {"page": "project_edit"}, name="project_edit"), +# url(r"/workspaces/123456/members/789/edit", Main, {"page": "member_edit"}, name="member_edit"), +# ] + +# if not ENV == "production": +# routes += [ +# url( +# r"/login-dev", +# Dev, +# { +# "action": "login", +# "sessions": deps["sessions"], +# "db_session": deps["db_session"], +# }, +# name="dev-login", +# ) +# ] + +# app = tornado.web.Application( +# routes, +# login_url="/", +# template_path=home.child("templates"), +# static_path=home.child("static"), +# cookie_secret=config["default"]["COOKIE_SECRET"], +# debug=config["default"].getboolean("DEBUG"), +# ui_modules=ui_modules, +# ui_methods=ui_methods, +# **kwargs +# ) +# app.config = config +# app.sessions = deps["sessions"] +# return app + + def make_deps(config): # we do not want to do SSL verify services in test and development validate_cert = ENV == "production" @@ -206,4 +212,4 @@ def make_config(): ) config.set("default", "DATABASE_URI", database_uri) - return config + return config["default"] diff --git a/atst/assets.py b/atst/assets.py index 7f723f75..bed898ac 100644 --- a/atst/assets.py +++ b/atst/assets.py @@ -1,16 +1,13 @@ -from webassets import Environment, Bundle +from flask_assets import Environment, Bundle from atst.home import home -environment = Environment( - directory=home.child("scss"), - url="/static" -) +assets = Environment() css = Bundle( - "atat.scss", + "../scss/atat.scss", filters="scss", output="../static/assets/out.%(version)s.css", depends=("**/*.scss"), ) -environment.register("css", css) +assets.register("css", css) diff --git a/atst/database.py b/atst/database.py index 6191f62e..f0b13d6f 100644 --- a/atst/database.py +++ b/atst/database.py @@ -1,8 +1,3 @@ -from sqlalchemy import create_engine -from sqlalchemy.orm import sessionmaker, scoped_session +from flask_sqlalchemy import SQLAlchemy - -def make_db(config): - engine = create_engine(config['default']['DATABASE_URI']) - session = scoped_session(sessionmaker(bind=engine)) - return session +db = SQLAlchemy() diff --git a/atst/handler.py b/atst/handler.py index bcbcf879..bc931a8d 100644 --- a/atst/handler.py +++ b/atst/handler.py @@ -1,9 +1,8 @@ import tornado.web -from atst.assets import environment from atst.sessions import SessionNotFoundError from atst.domain.users import Users -helpers = {"assets": environment} +helpers = {"assets": None} class BaseHandler(tornado.web.RequestHandler): diff --git a/atst/routes/__init__.py b/atst/routes/__init__.py new file mode 100644 index 00000000..c6b03baf --- /dev/null +++ b/atst/routes/__init__.py @@ -0,0 +1,7 @@ +from flask import Blueprint, render_template + +bp = Blueprint("atst", __name__) + +@bp.route("/") +def home(): + return render_template("home.html") From 29c68151de9eb65253bbda163cbfe020bbfb91cc Mon Sep 17 00:00:00 2001 From: richard-dds Date: Wed, 1 Aug 2018 11:22:21 -0400 Subject: [PATCH 070/332] Convert ui methods into Flask globals --- atst/app.py | 31 +++++++++++++++++++++++++-- atst/routes/__init__.py | 2 +- templates/{base.html.to => base.html} | 22 +++++++++---------- templates/{home.html.to => home.html} | 4 ++-- 4 files changed, 42 insertions(+), 17 deletions(-) rename templates/{base.html.to => base.html} (60%) rename templates/{home.html.to => home.html} (68%) diff --git a/atst/app.py b/atst/app.py index 5128117f..f4cfe183 100644 --- a/atst/app.py +++ b/atst/app.py @@ -1,7 +1,8 @@ import os +import re from configparser import ConfigParser from redis import StrictRedis -from flask import Flask +from flask import Flask, request, g from unipath import Path from atst.api_client import ApiClient @@ -24,6 +25,8 @@ def make_app(config): ) app.config.update(config) + make_flask_callbacks(app) + db.init_app(app) assets.init_app(app) @@ -32,6 +35,21 @@ def make_app(config): return app +def make_flask_callbacks(app): + @app.before_request + def set_globals(): + g.navigationContext = 'workspace' if re.match('\/workspaces\/[A-Za-z0-9]*', request.url) else 'global' + g.dev = os.getenv("TORNADO_ENV", "dev") == "dev" + g.matchesPath = lambda href: re.match('^'+href, request.url) + g.modalOpen = request.args.get("modal", False) + + # TODO: Make me a macro + def modal(self, body): + return self.render_string( + "components/modal.html.to", + body=body) + + # def make_app(config, deps, **kwargs): # routes = [ # url(r"/", Root, {"page": "root"}, name="root"), @@ -180,6 +198,15 @@ def make_deps(config): ), } +def map_config(config): + return { + "ENV": config["default"]["ENVIRONMENT"], + "DEBUG": config["default"]["DEBUG"], + "PORT": int(config["default"]["PORT"]), + "SQLALCHEMY_DATABASE_URI": config["default"]["DATABASE_URI"], + "SQLALCHEMY_TRACK_MODIFICATIONS": False, + **config["default"] + } def make_config(): BASE_CONFIG_FILENAME = os.path.join(os.path.dirname(__file__), "../config/base.ini") @@ -212,4 +239,4 @@ def make_config(): ) config.set("default", "DATABASE_URI", database_uri) - return config["default"] + return map_config(config) diff --git a/atst/routes/__init__.py b/atst/routes/__init__.py index c6b03baf..93fde8e2 100644 --- a/atst/routes/__init__.py +++ b/atst/routes/__init__.py @@ -1,4 +1,4 @@ -from flask import Blueprint, render_template +from flask import Blueprint, render_template, g bp = Blueprint("atst", __name__) diff --git a/templates/base.html.to b/templates/base.html similarity index 60% rename from templates/base.html.to rename to templates/base.html index 3f0d5995..58c804cb 100644 --- a/templates/base.html.to +++ b/templates/base.html @@ -1,21 +1,21 @@ {# TODO: set this context elsewhere #} {# set context='workspace' #} -{% set context=navigationContext() %} +{% set context=g.navigationContext %} - {% block title %}JEDI{% end %} - {% for url in assets['css'].urls() %} - - {% end %} + {% block title %}JEDI{% endblock %} + {% assets "css" %} + + {% endassets %} - + - {% block template_vars %}{% end %} + {% block template_vars %}{% endblock %} {% include 'navigation/topbar.html.to' %} @@ -23,18 +23,16 @@ {% include 'navigation/global_navigation.html.to' %}
    - {% block sidenav %}{% end %} + {% block sidenav %}{% endblock %} {% block content %} these are not the droids you are looking for - {% end %} + {% endblock %}
    {% include 'footer.html.to' %} - {% block modal %}{% end %} + {% block modal %}{% endblock %} - - diff --git a/templates/home.html.to b/templates/home.html similarity index 68% rename from templates/home.html.to rename to templates/home.html index eb789f28..0df70037 100644 --- a/templates/home.html.to +++ b/templates/home.html @@ -1,4 +1,4 @@ -{% extends "base.html.to" %} +{% extends "base.html" %} {% block content %} @@ -8,7 +8,7 @@ -{% end %} +{% endblock %} From 0976aed77869b906fbad79c6a77d6a84f2039d11 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Wed, 1 Aug 2018 11:40:07 -0400 Subject: [PATCH 071/332] home.html is rendering - Converted Icon and SidenavItem into macros - Setting a mock user on g.current_user --- atst/app.py | 6 ++++ templates/components.html | 32 +++++++++++++++++++ .../navigation/global_navigation.html.to | 25 ++++++++------- templates/navigation/topbar.html.to | 9 +++--- 4 files changed, 56 insertions(+), 16 deletions(-) create mode 100644 templates/components.html diff --git a/atst/app.py b/atst/app.py index f4cfe183..23ad724b 100644 --- a/atst/app.py +++ b/atst/app.py @@ -42,6 +42,12 @@ def make_flask_callbacks(app): g.dev = os.getenv("TORNADO_ENV", "dev") == "dev" g.matchesPath = lambda href: re.match('^'+href, request.url) g.modalOpen = request.args.get("modal", False) + g.current_user = { + "id": "cce17030-4109-4719-b958-ed109dbb87c8", + "first_name": "Amanda", + "last_name": "Adamson", + "atat_role": "default" + } # TODO: Make me a macro def modal(self, body): diff --git a/templates/components.html b/templates/components.html new file mode 100644 index 00000000..06d487ea --- /dev/null +++ b/templates/components.html @@ -0,0 +1,32 @@ +{% macro Icon(name, classes="") -%} + {% autoescape false %} + + {% endautoescape %} +{%- endmacro %} + +{% macro SidenavItem(label, href, active=False, icon=None, subnav=None) -%} +
  • + + {% if icon %} + {{ Icon(icon, classes="sidenav__link-icon") }} + {% endif %} + + {{label}} + + + {% if subnav and active %} + + {% endif %} +
  • +{%- endmacro %} diff --git a/templates/navigation/global_navigation.html.to b/templates/navigation/global_navigation.html.to index 60991d47..594bf574 100644 --- a/templates/navigation/global_navigation.html.to +++ b/templates/navigation/global_navigation.html.to @@ -1,24 +1,25 @@ +{% from "components.html" import SidenavItem %} diff --git a/templates/navigation/topbar.html.to b/templates/navigation/topbar.html.to index 9af26690..10fc0c6d 100644 --- a/templates/navigation/topbar.html.to +++ b/templates/navigation/topbar.html.to @@ -1,18 +1,19 @@ +{% from "components.html" import Icon %}
    From 3a53fc122d4b832a3c67e75c77190efaae8ea58c Mon Sep 17 00:00:00 2001 From: dandds Date: Wed, 1 Aug 2018 13:15:07 -0400 Subject: [PATCH 072/332] switch workspace routes and templates to Flask and Jinja --- atst/app.py | 2 ++ atst/routes/workspaces.py | 31 ++++++++++++++++++ ..._workspace.html.to => base_workspace.html} | 6 ++-- templates/components.html | 12 +++++++ .../navigation/workspace_navigation.html.to | 32 ++++++++++--------- ...members.html.to => workspace_members.html} | 16 ++++++---- ...ojects.html.to => workspace_projects.html} | 16 ++++++---- .../{workspaces.html.to => workspaces.html} | 6 ++-- 8 files changed, 86 insertions(+), 35 deletions(-) create mode 100644 atst/routes/workspaces.py rename templates/{base_workspace.html.to => base_workspace.html} (70%) rename templates/{workspace_members.html.to => workspace_members.html} (92%) rename templates/{workspace_projects.html.to => workspace_projects.html} (72%) rename templates/{workspaces.html.to => workspaces.html} (91%) diff --git a/atst/app.py b/atst/app.py index 23ad724b..087277fc 100644 --- a/atst/app.py +++ b/atst/app.py @@ -10,6 +10,7 @@ from atst.sessions import RedisSessions from atst.database import db from atst.assets import assets from atst.routes import bp +from atst.routes.workspaces import bp as workspace_routes ENV = os.getenv("TORNADO_ENV", "dev") @@ -31,6 +32,7 @@ def make_app(config): assets.init_app(app) app.register_blueprint(bp) + app.register_blueprint(workspace_routes) return app diff --git a/atst/routes/workspaces.py b/atst/routes/workspaces.py new file mode 100644 index 00000000..1f3b47f2 --- /dev/null +++ b/atst/routes/workspaces.py @@ -0,0 +1,31 @@ +from flask import Blueprint, render_template + +from atst.domain.workspaces import Projects, Members +from atst.database import db + +bp = Blueprint("workspaces", __name__) + +mock_workspaces = [ + { + "name": "Unclassified IaaS and PaaS for Defense Digital Service (DDS)", + "id": "5966187a-eff9-44c3-aa15-4de7a65ac7ff", + "task_order": {"number": 123456}, + "user_count": 23, + } +] + +@bp.route("/workspaces") +def workspaces(): + return render_template("workspaces.html", page=5, workspaces=mock_workspaces) + +@bp.route("/workspaces//projects") +def workspace_projects(workspace_id): + projects_repo = Projects() + projects = projects_repo.get_many(workspace_id) + return render_template("workspace_projects.html", workspace_id=workspace_id, projects=projects) + +@bp.route("/workspaces//members") +def workspace_members(workspace_id): + members_repo = Members() + members = members_repo.get_many(workspace_id) + return render_template("workspace_members.html", workspace_id=workspace_id, members=members) diff --git a/templates/base_workspace.html.to b/templates/base_workspace.html similarity index 70% rename from templates/base_workspace.html.to rename to templates/base_workspace.html index 7803ace8..0ccad5ba 100644 --- a/templates/base_workspace.html.to +++ b/templates/base_workspace.html @@ -1,4 +1,4 @@ -{% extends "base.html.to" %} +{% extends "base.html" %} {% block content %} @@ -8,8 +8,8 @@
    - {% block workspace_content %}{% end %} + {% block workspace_content %}{% endblock %}
    -{% end %} +{% endblock %} diff --git a/templates/components.html b/templates/components.html index 06d487ea..0bc83991 100644 --- a/templates/components.html +++ b/templates/components.html @@ -30,3 +30,15 @@ {% endif %} {%- endmacro %} + +{% macro EmptyState(self, message, actionLabel, actionHref, icon=None) -%} +
    +

    {{ message }}

    + + {% if icon %} + {{ Icon(icon) }} + {% endif %} + + {{ actionLabel }} +
    +{%- endmacro %} diff --git a/templates/navigation/workspace_navigation.html.to b/templates/navigation/workspace_navigation.html.to index 65a9525b..d516c1b0 100644 --- a/templates/navigation/workspace_navigation.html.to +++ b/templates/navigation/workspace_navigation.html.to @@ -1,42 +1,44 @@ +{% from "components.html" import SidenavItem %} + diff --git a/templates/workspace_members.html.to b/templates/workspace_members.html similarity index 92% rename from templates/workspace_members.html.to rename to templates/workspace_members.html index 0f538b05..989d1d0e 100644 --- a/templates/workspace_members.html.to +++ b/templates/workspace_members.html @@ -1,15 +1,17 @@ -{% extends "base_workspace.html.to" %} +{% from "components.html" import EmptyState %} + +{% extends "base_workspace.html" %} {% block workspace_content %} {% if not members %} - {% module EmptyState( + {{ EmptyState( 'There are currently no members in this Workspace.', actionLabel='Invite a new Member', actionHref='/members/new', icon='avatar' - )%} + )}} {% else %} @@ -59,17 +61,17 @@ {% for m in members %} {{ m['first_name'] }} {{ m['last_name'] }} - {% if m['num_projects'] == '0' %} No Project Access {% end %} + {% if m['num_projects'] == '0' %} No Project Access {% endif %} {{ m['status'] }} {{ m['workspace_role'] }} - {% end %} + {% endfor %}
    -{% end %} +{% endif %} -{% end %} +{% endblock %} diff --git a/templates/workspace_projects.html.to b/templates/workspace_projects.html similarity index 72% rename from templates/workspace_projects.html.to rename to templates/workspace_projects.html index a9f1a8aa..91826bb6 100644 --- a/templates/workspace_projects.html.to +++ b/templates/workspace_projects.html @@ -1,13 +1,15 @@ -{% extends "base_workspace.html.to" %} +{% from "components.html" import Icon %} + +{% extends "base_workspace.html" %} {% block workspace_content %} {% for project in projects %}
    -

    {{ project['name'] }} ({{ len(project['environments'])}} environments)

    +

    {{ project['name'] }} ({{ project['environments']|length }} environments)

    - {% module Icon('edit') %} + {{ Icon('edit') }} edit
    @@ -15,7 +17,7 @@ {% for environment in project['environments'] %}
  • - {% module Icon('link') %} + {{ Icon('link') }} {{ environment["name"]}} @@ -24,10 +26,10 @@ members
  • - {% end %} + {% endfor %} -{% end %} +{% endfor %} -{% end %} +{% endblock %} diff --git a/templates/workspaces.html.to b/templates/workspaces.html similarity index 91% rename from templates/workspaces.html.to rename to templates/workspaces.html index 21bbad7d..5f407766 100644 --- a/templates/workspaces.html.to +++ b/templates/workspaces.html @@ -1,4 +1,4 @@ -{% extends "base.html.to" %} +{% extends "base.html" %} {% block content %}
    @@ -23,9 +23,9 @@ {{ w['user_count'] }}Users - {% end %} + {% endfor %}
    -{% end %} +{% endblock %} From 4ee662665e877ca125c44d72d250f2a22e91ac03 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Wed, 1 Aug 2018 14:17:43 -0400 Subject: [PATCH 073/332] Requests index rendering --- Pipfile | 1 + Pipfile.lock | 10 +++- atst/app.py | 9 +++- atst/domain/requests.py | 45 ++++++++-------- atst/routes/__init__.py | 3 ++ atst/routes/requests.py | 52 +++++++++++++++++++ templates/components.html | 50 +++++++++++++++++- templates/{requests.html.to => requests.html} | 36 +++++++------ 8 files changed, 164 insertions(+), 42 deletions(-) create mode 100644 atst/routes/requests.py rename templates/{requests.html.to => requests.html} (81%) diff --git a/Pipfile b/Pipfile index 4110ccbf..620553f1 100644 --- a/Pipfile +++ b/Pipfile @@ -16,6 +16,7 @@ alembic = "*" flask = "*" flask-sqlalchemy = "*" flask-assets = "*" +flask-session = "*" [dev-packages] bandit = "*" diff --git a/Pipfile.lock b/Pipfile.lock index d6e5cf64..d55c6fcf 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "2ee6dd90ff3784e7b1781c680d690ac59118b4e3d72e8da3adf9e93d6e512bc7" + "sha256": "f097384512537988c799b892830b52e78bcc19133327213e9c6e2876210d62d3" }, "pipfile-spec": 6, "requires": { @@ -46,6 +46,14 @@ "index": "pypi", "version": "==0.12" }, + "flask-session": { + "hashes": [ + "sha256:a31c27e0c3287f00c825b3d9625aba585f4df4cccedb1e7dd5a69a215881a731", + "sha256:b9b32126bfc52c3169089f2ed9a40e34b589527bda48b633428e07d39d9c8792" + ], + "index": "pypi", + "version": "==0.3.1" + }, "flask-sqlalchemy": { "hashes": [ "sha256:3bc0fac969dd8c0ace01b32060f0c729565293302f0c4269beed154b46bec50b", diff --git a/atst/app.py b/atst/app.py index 087277fc..7dac78b7 100644 --- a/atst/app.py +++ b/atst/app.py @@ -2,15 +2,18 @@ import os import re from configparser import ConfigParser from redis import StrictRedis -from flask import Flask, request, g +from flask import Flask, request, g, session from unipath import Path from atst.api_client import ApiClient from atst.sessions import RedisSessions from atst.database import db from atst.assets import assets + from atst.routes import bp from atst.routes.workspaces import bp as workspace_routes +from atst.routes.requests import requests_bp + ENV = os.getenv("TORNADO_ENV", "dev") @@ -33,6 +36,7 @@ def make_app(config): app.register_blueprint(bp) app.register_blueprint(workspace_routes) + app.register_blueprint(requests_bp) return app @@ -48,7 +52,8 @@ def make_flask_callbacks(app): "id": "cce17030-4109-4719-b958-ed109dbb87c8", "first_name": "Amanda", "last_name": "Adamson", - "atat_role": "default" + "atat_role": "default", + "atat_permissions": [] } # TODO: Make me a macro diff --git a/atst/domain/requests.py b/atst/domain/requests.py index aa37b932..a513d660 100644 --- a/atst/domain/requests.py +++ b/atst/domain/requests.py @@ -4,6 +4,8 @@ from sqlalchemy.orm.exc import NoResultFound from sqlalchemy.orm.attributes import flag_modified from atst.models import Request, RequestStatusEvent +from atst.database import db + from .exceptions import NotFoundError @@ -28,67 +30,68 @@ def deep_merge(source, destination: dict): class Requests(object): AUTO_APPROVE_THRESHOLD = 1000000 - def __init__(self, db_session): - self.db_session = db_session - - def create(self, creator_id, body): + @classmethod + def create(cls, creator_id, body): request = Request(creator=creator_id, body=body) status_event = RequestStatusEvent(new_status="incomplete") request.status_events.append(status_event) - self.db_session.add(request) - self.db_session.commit() + db.session.add(request) + db.session.commit() return request - def exists(self, request_id, creator_id): - return self.db_session.query( + @classmethod + def exists(cls, request_id, creator_id): + return db.session.query( exists().where( and_(Request.id == request_id, Request.creator == creator_id) ) ).scalar() - def get(self, request_id): + @classmethod + def get(cls, request_id): try: - request = self.db_session.query(Request).filter_by(id=request_id).one() + request = db.session.query(Request).filter_by(id=request_id).one() except NoResultFound: raise NotFoundError("request") return request - def get_many(self, creator_id=None): + @classmethod + def get_many(cls, creator_id=None): filters = [] if creator_id: filters.append(Request.creator == creator_id) requests = ( - self.db_session.query(Request) + db.session.query(Request) .filter(*filters) .order_by(Request.time_created.desc()) .all() ) return requests - @tornado.gen.coroutine - def submit(self, request): + @classmethod + def submit(cls, request): request.status_events.append(RequestStatusEvent(new_status="submitted")) if Requests.should_auto_approve(request): request.status_events.append(RequestStatusEvent(new_status="approved")) - self.db_session.add(request) - self.db_session.commit() + db.session.add(request) + db.session.commit() return request - @tornado.gen.coroutine - def update(self, request_id, request_delta): + @classmethod + def update(cls, request_id, request_delta): try: # Query for request matching id, acquiring a row-level write lock. # https://www.postgresql.org/docs/10/static/sql-select.html#SQL-FOR-UPDATE-SHARE request = ( - self.db_session.query(Request) + db.session.query(Request) .filter_by(id=request_id) .with_for_update(of=Request) .one() @@ -105,8 +108,8 @@ class Requests(object): # since it doesn't track dictionary mutations by default. flag_modified(request, "body") - self.db_session.add(request) - self.db_session.commit() + db.session.add(request) + db.session.commit() @classmethod def should_auto_approve(cls, request): diff --git a/atst/routes/__init__.py b/atst/routes/__init__.py index 93fde8e2..de181ce2 100644 --- a/atst/routes/__init__.py +++ b/atst/routes/__init__.py @@ -1,4 +1,7 @@ from flask import Blueprint, render_template, g +import pendulum + +from atst.domain.requests import Requests bp = Blueprint("atst", __name__) diff --git a/atst/routes/requests.py b/atst/routes/requests.py new file mode 100644 index 00000000..6c37344d --- /dev/null +++ b/atst/routes/requests.py @@ -0,0 +1,52 @@ +from flask import Blueprint, g, render_template +import pendulum + +from atst.domain.requests import Requests + +requests_bp = Blueprint("requests", __name__) + +def map_request(user, request): + time_created = pendulum.instance(request.time_created) + is_new = time_created.add(days=1) > pendulum.now() + + return { + "order_id": request.id, + "is_new": is_new, + "status": request.status, + "app_count": 1, + "date": time_created.format("M/DD/YYYY"), + "full_name": "{} {}".format(user["first_name"], user["last_name"]), + } + + +@requests_bp.route("/requests", methods=["GET"]) +def requests_index(): + requests = [] + if "review_and_approve_jedi_workspace_request" in g.current_user["atat_permissions"]: + requests = Requests.get_many() + else: + requests = Requests.get_many(creator_id=g.current_user["id"]) + + mapped_requests = [map_request(g.current_user, r) for r in requests] + + return render_template("requests.html", requests=mapped_requests) + + +@requests_bp.route("/requests/new/", methods=["GET"]) +def requests_new(): + pass + + +@requests_bp.route("/requests/new//", methods=["GET"]) +def requests_form_update(): + pass + + +@requests_bp.route("/requests/verify/", methods=["GET"]) +def financial_verification(): + pass + + +@requests_bp.route("/requests/verify/", methods=["POST"]) +def update_financial_verification(): + pass diff --git a/templates/components.html b/templates/components.html index 0bc83991..04f6be36 100644 --- a/templates/components.html +++ b/templates/components.html @@ -31,7 +31,17 @@ {%- endmacro %} -{% macro EmptyState(self, message, actionLabel, actionHref, icon=None) -%} +{% macro Modal() -%} + +{%- endmacro %} + +{% macro EmptyState(message, actionLabel, actionHref, icon=None) -%}

    {{ message }}

    @@ -42,3 +52,41 @@ {{ actionLabel }}
    {%- endmacro %} + +{% macro Alert(title, message=None, actions=None, level='info') -%} +{% set role = 'alertdialog' if actions else 'alert' %} +{% set levels = { + 'warning': { + 'icon': 'alert', + 'tone': 'assertive' + }, + 'error': { + 'icon': 'alert', + 'tone': 'assertive' + }, + 'info': { + 'icon': 'info', + 'tone': 'polite' + }, + 'success': { + 'icon': 'ok', + 'tone': 'polite' + } +} %} + +
    + {{ Icon(levels.get(level).get('icon'), classes='alert__icon icon--large') }} + +
    +

    {{title}}

    + + {% if message %} +
    {{ message | safe }}
    + {% endif %} + + {% if actions %} +
    {{ actions | safe }}
    + {% endif %} +
    +
    +{%- endmacro %} diff --git a/templates/requests.html.to b/templates/requests.html similarity index 81% rename from templates/requests.html.to rename to templates/requests.html index bd0c9e8c..5d27ff1e 100644 --- a/templates/requests.html.to +++ b/templates/requests.html @@ -1,8 +1,10 @@ -{% extends "base.html.to" %} +{% extends "base.html" %} + +{% from "components.html" import Modal, Alert, EmptyState %} {% block modal %} - {% if modalOpen() %} - {% apply modal %} + {% if g.modalOpen %} + {% call Modal() %}

    Your request is now approved!

    @@ -17,34 +19,34 @@ usage in sync with your budget.

    - {% module Alert("You'll need these details: ", + {{ Alert("You'll need these details: ", message="

    Task Order Number

    Contracting Officer: Name, E-mail and Office

    " - ) %} + ) }} - {% end %} - {% end %} -{% end %} + {% endcall %} + {% endif %} +{% endblock %} {% block content %} {% if not requests %} - {% module EmptyState( + {{ EmptyState( 'There are currently no active requests for you to see.', actionLabel='Create a new JEDI Cloud Request', actionHref='/requests/new', icon='document' - )%} + ) }} {% else %} - {% module Alert('Pending Financial Verification', + {{ Alert('Pending Financial Verification', message="

    Your next step is to create a Task Order (T.O.) associated with JEDI Cloud. Please consult a Contracting Officer (KO) or Contracting Officer Representative (COR) to help with this step.

    " - ) %} + ) }}
    @@ -84,10 +86,10 @@ {% for r in requests %} - {{ r['order_id'] }} + {{ r['order_id'] }} {% if r['is_new'] %}New - {% end %} + {% endif %} {{ r['date'] }} {{ r['full_name'] }} {{ r['app_count'] }} @@ -97,13 +99,13 @@ Approval - {% end %} + {% endfor %}
    -{% end %} +{% endif %} -{% end %} +{% endblock %} From 5d7dde35611edca7f4f46d7a6e14d2fe9936b500 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Wed, 1 Aug 2018 16:25:08 -0400 Subject: [PATCH 074/332] Financial verification form rendering --- Pipfile | 1 + Pipfile.lock | 10 ++- atst/app.py | 1 + atst/forms/forms.py | 4 +- atst/routes/requests.py | 7 ++- config/base.ini | 1 + ...on.html.to => financial_verification.html} | 61 ++++++++++--------- templates/requests_new.html.to | 2 +- 8 files changed, 51 insertions(+), 36 deletions(-) rename templates/requests/{financial_verification.html.to => financial_verification.html} (87%) diff --git a/Pipfile b/Pipfile index 620553f1..04e23572 100644 --- a/Pipfile +++ b/Pipfile @@ -17,6 +17,7 @@ flask = "*" flask-sqlalchemy = "*" flask-assets = "*" flask-session = "*" +flask-wtf = "*" [dev-packages] bandit = "*" diff --git a/Pipfile.lock b/Pipfile.lock index d55c6fcf..5dcf8f6b 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "f097384512537988c799b892830b52e78bcc19133327213e9c6e2876210d62d3" + "sha256": "e04e11d9bd5c1dcc725de48b20902f5c416417e73774e557e45af7bd0c147ff5" }, "pipfile-spec": 6, "requires": { @@ -62,6 +62,14 @@ "index": "pypi", "version": "==2.3.2" }, + "flask-wtf": { + "hashes": [ + "sha256:5d14d55cfd35f613d99ee7cba0fc3fbbe63ba02f544d349158c14ca15561cc36", + "sha256:d9a9e366b32dcbb98ef17228e76be15702cd2600675668bca23f63a7947fd5ac" + ], + "index": "pypi", + "version": "==0.14.2" + }, "itsdangerous": { "hashes": [ "sha256:cbb3fcf8d3e33df861709ecaf89d9e6629cff0a217bc2848f1b41cd30d360519" diff --git a/atst/app.py b/atst/app.py index 7dac78b7..babaff7a 100644 --- a/atst/app.py +++ b/atst/app.py @@ -229,6 +229,7 @@ def make_config(): OVERRIDE_CONFIG_FILENAME = os.getenv("OVERRIDE_CONFIG_FULLPATH") config = ConfigParser() + config.optionxform = str config_files = [BASE_CONFIG_FILENAME, ENV_CONFIG_FILENAME] if OVERRIDE_CONFIG_FILENAME: diff --git a/atst/forms/forms.py b/atst/forms/forms.py index c3ea02c4..48f03295 100644 --- a/atst/forms/forms.py +++ b/atst/forms/forms.py @@ -1,9 +1,9 @@ import tornado from tornado.gen import Return -from wtforms_tornado import Form +from flask_wtf import FlaskForm -class ValidatedForm(Form): +class ValidatedForm(FlaskForm): @tornado.gen.coroutine def perform_extra_validation(self, *args, **kwargs): diff --git a/atst/routes/requests.py b/atst/routes/requests.py index 6c37344d..5903524c 100644 --- a/atst/routes/requests.py +++ b/atst/routes/requests.py @@ -2,6 +2,7 @@ from flask import Blueprint, g, render_template import pendulum from atst.domain.requests import Requests +from atst.forms.financial import FinancialForm requests_bp = Blueprint("requests", __name__) @@ -43,8 +44,10 @@ def requests_form_update(): @requests_bp.route("/requests/verify/", methods=["GET"]) -def financial_verification(): - pass +def financial_verification(request_id=None): + request = Requests.get(request_id) + form = FinancialForm(data=request.body.get('financial_verification')) + return render_template("requests/financial_verification.html", f=form) @requests_bp.route("/requests/verify/", methods=["POST"]) diff --git a/config/base.ini b/config/base.ini index e8be9197..fddfa26f 100644 --- a/config/base.ini +++ b/config/base.ini @@ -5,6 +5,7 @@ DEBUG = true AUTHNID_BASE_URL= https://localhost:8001 COOKIE_SECRET = some-secret-please-replace SECRET = change_me_into_something_secret +SECRET_KEY = change_me_into_something_secret CAC_URL = https://localhost:8001 PE_NUMBER_CSV_URL = http://c95e1ebb198426ee57b8-174bb05a294821bedbf46b6384fe9b1f.r31.cf5.rackcdn.com/penumbers.csv REDIS_URI = redis://localhost:6379 diff --git a/templates/requests/financial_verification.html.to b/templates/requests/financial_verification.html similarity index 87% rename from templates/requests/financial_verification.html.to rename to templates/requests/financial_verification.html index df5b12ab..0f0d8110 100644 --- a/templates/requests/financial_verification.html.to +++ b/templates/requests/financial_verification.html @@ -1,4 +1,4 @@ -{% extends "../base.html.to" %} +{% extends "base.html" %} {% block content %} @@ -14,15 +14,15 @@ {% block form_action %} -
    - {% end %} + + {% endblock %} - {% module xsrf_form_html() %} + {{ f.csrf_token }} {% block form %} - {% autoescape None %} + {% autoescape false %} {% if f.errors %} There were some errors, see below. - {% end %} + {% endif %}

    In order to get you access to the JEDI Cloud, we will need you to enter the details below that will help us verify and account for your Task Order.

    @@ -32,7 +32,7 @@
    {{ e }}
    - {% end %} + {% endfor %} {{ f.uii_ids.label }} {{ f.uii_ids(placeholder="Example: \nDI 0CVA5786950 \nUN1945326361234786950") }} @@ -40,7 +40,7 @@
    {{ e }}
    - {% end %} + {% endfor %} {{ f.pe_id.label }} {{ f.pe_id(placeholder="Example: 0203752A") }} @@ -48,7 +48,7 @@
    {{ e }}
    - {% end %} + {% endfor %} {{ f.treasury_code.label }} {{ f.treasury_code(placeholder="Example: 1200") }} @@ -56,7 +56,7 @@
    {{ e }}
    - {% end %} + {% endfor %} {{ f.ba_code.label }} {{ f.ba_code(placeholder="Example: 02") }} @@ -64,7 +64,7 @@
    {{ e }}
    - {% end %} + {% endfor %} @@ -76,7 +76,7 @@
    {{ e }}
    - {% end %} + {% endfor %} {{ f.lname_co.label }} {{ f.lname_co(placeholder="Contracting Officer last name") }} @@ -84,7 +84,7 @@
    {{ e }}
    - {% end %} + {% endfor %} {{ f.email_co.label }} {{ f.email_co(placeholder="jane@mail.mil") }} @@ -92,7 +92,7 @@
    {{ e }}
    - {% end %} + {% endfor %} {{ f.office_co.label }} {{ f.office_co(placeholder="Example: WHS") }} @@ -100,7 +100,7 @@
    {{ e }}
    - {% end %} + {% endfor %} @@ -113,7 +113,7 @@
    {{ e }}
    - {% end %} + {% endfor %} {{ f.lname_cor.label }} {{ f.lname_cor(placeholder="Contracting Officer Representative last name") }} @@ -121,7 +121,7 @@
    {{ e }}
    - {% end %} + {% endfor %} {{ f.email_cor.label }} {{ f.email_cor(placeholder="jane@mail.mil") }} @@ -129,7 +129,7 @@
    {{ e }}
    - {% end %} + {% endfor %} {{ f.office_cor.label }} {{ f.office_cor(placeholder="Example: WHS") }} @@ -137,7 +137,7 @@
    {{ e }}
    - {% end %} + {% endfor %}

    ↓ FIELDS NEEDED FOR MANUAL ENTRY OF TASK ORDER INFORMATION (only necessary if EDA info not available) @@ -149,7 +149,7 @@
    {{ e }}
    - {% end %} + {% endfor %} {{ f.funding_type_other.label }} {{ f.funding_type_other(placeholder="") }} @@ -157,7 +157,7 @@
    {{ e }}
    - {% end %} + {% endfor %} {{ f.clin_0001.label }} {{ f.clin_0001(placeholder="50,000") }} @@ -165,7 +165,7 @@
    {{ e }}
    - {% end %} + {% endfor %} {{ f.clin_0003.label }} {{ f.clin_0003(placeholder="13,000") }} @@ -173,7 +173,7 @@
    {{ e }}
    - {% end %} + {% endfor %} {{ f.clin_1001.label }} {{ f.clin_1001(placeholder="30,000") }} @@ -181,7 +181,7 @@
    {{ e }}
    - {% end %} + {% endfor %} {{ f.clin_1003.label }} {{ f.clin_1003(placeholder="7,000") }} @@ -189,7 +189,7 @@
    {{ e }}
    - {% end %} + {% endfor %} {{ f.clin_2001.label }} {{ f.clin_2001(placeholder="30,000") }} @@ -197,7 +197,7 @@
    {{ e }}
    - {% end %} + {% endfor %} {{ f.clin_2003.label }} {{ f.clin_2003(placeholder="7,000") }} @@ -205,15 +205,16 @@
    {{ e }}
    - {% end %} - {% end %} + {% endfor %} + {% endautoescape %} + {% endblock form %} {% block next %} - {% end %} + {% endblock %}
    -{% end %} +{% endblock %} diff --git a/templates/requests_new.html.to b/templates/requests_new.html.to index 5a309f26..c5f96ed5 100644 --- a/templates/requests_new.html.to +++ b/templates/requests_new.html.to @@ -22,7 +22,7 @@ {% end %} {% end %} - {% module xsrf_form_html() %} + {{ form.csrf_token }} {% block form %} form goes here {% end %} From 6f0ff7990415004134b74b625c3e9cbb44705719 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Thu, 2 Aug 2018 10:21:26 -0400 Subject: [PATCH 075/332] First page of request form rendering, but flow is still WIP --- atst/handlers/request_new.py | 3 +- atst/routes/requests.py | 199 +++++++++++++++++- templates/components.html | 53 +++++ templates/requests/menu.html | 13 ++ templates/requests/menu.html.to | 13 -- templates/requests/screen-0.html | 12 ++ templates/requests/screen-0.html.to | 12 -- templates/requests/screen-1.html | 46 ++++ templates/requests/screen-1.html.to | 45 ---- templates/requests/screen-2.html | 32 +++ templates/requests/screen-2.html.to | 31 --- .../{screen-3.html.to => screen-3.html} | 0 .../{screen-4.html.to => screen-4.html} | 0 .../{screen-5.html.to => screen-5.html} | 0 .../{sidebar.html.to => sidebar.html} | 0 templates/requests_new.html | 45 ++++ templates/requests_new.html.to | 46 ---- 17 files changed, 398 insertions(+), 152 deletions(-) create mode 100644 templates/requests/menu.html delete mode 100644 templates/requests/menu.html.to create mode 100644 templates/requests/screen-0.html delete mode 100644 templates/requests/screen-0.html.to create mode 100644 templates/requests/screen-1.html delete mode 100644 templates/requests/screen-1.html.to create mode 100644 templates/requests/screen-2.html delete mode 100644 templates/requests/screen-2.html.to rename templates/requests/{screen-3.html.to => screen-3.html} (100%) rename templates/requests/{screen-4.html.to => screen-4.html} (100%) rename templates/requests/{screen-5.html.to => screen-5.html} (100%) rename templates/requests/{sidebar.html.to => sidebar.html} (100%) create mode 100644 templates/requests_new.html delete mode 100644 templates/requests_new.html.to diff --git a/atst/handlers/request_new.py b/atst/handlers/request_new.py index 1d33daa0..30549e63 100644 --- a/atst/handlers/request_new.py +++ b/atst/handlers/request_new.py @@ -101,7 +101,6 @@ class RequestNew(BaseHandler): class JEDIRequestFlow(object): def __init__( self, - requests_repo, pe_numbers_repo, current_step, request=None, @@ -110,6 +109,8 @@ class JEDIRequestFlow(object): current_user=None, existing_request=None, ): + self.pe_numbers_repo = pe_numbers_repo + self.requests_repo = requests_repo self.pe_numbers_repo = pe_numbers_repo diff --git a/atst/routes/requests.py b/atst/routes/requests.py index 5903524c..565c268e 100644 --- a/atst/routes/requests.py +++ b/atst/routes/requests.py @@ -1,8 +1,14 @@ -from flask import Blueprint, g, render_template +from flask import Blueprint, g, render_template, url_for, redirect, request import pendulum +from collections import defaultdict from atst.domain.requests import Requests from atst.forms.financial import FinancialForm +from atst.forms.request import RequestForm +from atst.forms.org import OrgForm +from atst.forms.poc import POCForm +from atst.forms.review import ReviewForm + requests_bp = Blueprint("requests", __name__) @@ -34,13 +40,72 @@ def requests_index(): @requests_bp.route("/requests/new/", methods=["GET"]) -def requests_new(): +def requests_form_new(): pass @requests_bp.route("/requests/new//", methods=["GET"]) -def requests_form_update(): - pass +def requests_form_update(screen=1, request_id=None): + request = Requests.get(request_id) if request_id is not None else None + jedi_flow = JEDIRequestFlow(screen, request, request_id=request_id) + + return render_template( + "requests/screen-%d.html" % int(screen), + f=jedi_flow.form, + data=jedi_flow.current_step_data, + screens=jedi_flow.screens, + current=screen, + next_screen=screen + 1, + request_id=request_id, + can_submit=jedi_flow.can_submit + ) + +@requests_bp.route("/requests/new//", methods=["POST"]) +def requests_update(screen=1, request_id=None): + screen = int(screen) + post_data = str(request.data) + current_user = g.current_user + existing_request = Requests.get(request_id) if request_id is not None else None + jedi_flow = JEDIRequestFlow( + screen, + post_data=post_data, + request_id=request_id, + current_user=current_user, + existing_request=existing_request, + ) + + rerender_args = dict( + f=jedi_flow.form, + data=post_data, + screens=jedi_flow.screens, + current=screen, + next_screen=jedi_flow.next_screen, + request_id=jedi_flow.request_id, + ) + + if jedi_flow.validate(): + jedi_flow.create_or_update_request() + valid = jedi_flow.validate_warnings() + if valid: + if jedi_flow.next_screen > len(jedi_flow.screens): + where = "/requests" + else: + where = url_for( + "requests.requests_Form_update", screen=jedi_flow.next_screen, request_id=jedi_flow.request_id + ) + return redirect(where) + else: + return render_template( + "requests/screen-%d.html" % int(screen), + **rerender_args + ) + else: + return render_template( + "requests/screen-%d.html" % int(screen), + **rerender_args + ) + + @requests_bp.route("/requests/verify/", methods=["GET"]) @@ -53,3 +118,129 @@ def financial_verification(request_id=None): @requests_bp.route("/requests/verify/", methods=["POST"]) def update_financial_verification(): pass + + +class JEDIRequestFlow(object): + def __init__( + self, + current_step, + request=None, + post_data=None, + request_id=None, + current_user=None, + existing_request=None, + ): + self.current_step = current_step + self.request = request + + self.post_data = post_data + self.is_post = self.post_data is not None + + self.request_id = request_id + self.form = self._form() + + self.current_user = current_user + self.existing_request = existing_request + + def _form(self): + if self.is_post: + return self.form_class()(self.post_data) + elif self.request: + return self.form_class()(data=self.current_step_data) + else: + return self.form_class()() + + def validate(self): + return self.form.validate() + + def validate_warnings(self): + existing_request_data = ( + self.existing_request + and self.existing_request.body.get(self.form_section) + ) or None + + valid = self.form.perform_extra_validation( + existing_request_data, + ) + return valid + + @property + def current_screen(self): + return self.screens[self.current_step - 1] + + @property + def form_section(self): + return self.current_screen["section"] + + def form_class(self): + return self.current_screen["form"] + + @property + def current_step_data(self): + data = {} + + if self.is_post: + data = self.post_data + + if self.request: + if self.form_section == "review_submit": + data = self.request.body + else: + data = self.request.body.get(self.form_section, {}) + + return defaultdict(lambda: defaultdict(lambda: 'Input required'), data) + + @property + def can_submit(self): + return self.request and self.request.status != "incomplete" + + @property + def next_screen(self): + return self.current_step + 1 + + @property + def screens(self): + return [ + { + "title": "Details of Use", + "section": "details_of_use", + "form": RequestForm, + "subitems": [ + { + "title": "Overall request details", + "id": "overall-request-details", + }, + {"title": "Cloud Resources", "id": "cloud-resources"}, + {"title": "Support Staff", "id": "support-staff"}, + ], + "show": True, + }, + { + "title": "Information About You", + "section": "information_about_you", + "form": OrgForm, + "show": True, + }, + { + "title": "Primary Point of Contact", + "section": "primary_poc", + "form": POCForm, + "show": True, + }, + { + "title": "Review & Submit", + "section": "review_submit", + "form": ReviewForm, + "show":True, + }, + ] + + def create_or_update_request(self): + request_data = { + self.form_section: self.form.data + } + if self.request_id: + Requests.update(request_id, request_data) + else: + request = Requests.create(self.current_user["id"], request_data) + self.request_id = request.id diff --git a/templates/components.html b/templates/components.html index 04f6be36..027ede6f 100644 --- a/templates/components.html +++ b/templates/components.html @@ -90,3 +90,56 @@ {%- endmacro %} + +{% macro TextInput(field, placeholder='') -%} +
    + + + {{ field(placeholder=placeholder) | safe }} + + {% if field.errors %} + {% for error in field.errors %} + {{ error }} + {% endfor %} + {% endif %} +
    +{%- endmacro %} + +{% macro OptionsInput(field, inline=False) -%} +
    + +
    + + {{ field.label }} + + {% if field.description %} + {{ field.description | safe }} + {% endif %} + + {% if field.errors %} + {{ Icon('alert') }} + {% endif %} + + + {{ field() }} + + {% if field.errors %} + {% for error in field.errors %} + {{ error }} + {% endfor %} + {% endif %} + +
    +
    + +{%- endmacro %} diff --git a/templates/requests/menu.html b/templates/requests/menu.html new file mode 100644 index 00000000..f1642e46 --- /dev/null +++ b/templates/requests/menu.html @@ -0,0 +1,13 @@ +
    + +
    diff --git a/templates/requests/menu.html.to b/templates/requests/menu.html.to deleted file mode 100644 index 4bc77431..00000000 --- a/templates/requests/menu.html.to +++ /dev/null @@ -1,13 +0,0 @@ -
    - -
    \ No newline at end of file diff --git a/templates/requests/screen-0.html b/templates/requests/screen-0.html new file mode 100644 index 00000000..19f57d2e --- /dev/null +++ b/templates/requests/screen-0.html @@ -0,0 +1,12 @@ +{% extends '../requests_new.html.to' %} + +{% block form %} +

    New JEDI Request

    + +

    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Natus error omnis a, tenetur similique quo officiis voluptates eum recusandae dolorem minus dignissimos, magni consequatur, maxime debitis reprehenderit sint non iusto?

    + +New Application +Existing Application +Sandbox Environment + +{% endblock %} diff --git a/templates/requests/screen-0.html.to b/templates/requests/screen-0.html.to deleted file mode 100644 index 6fe78374..00000000 --- a/templates/requests/screen-0.html.to +++ /dev/null @@ -1,12 +0,0 @@ -{% extends '../requests_new.html.to' %} - -{% block form %} -

    New JEDI Request

    - -

    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Natus error omnis a, tenetur similique quo officiis voluptates eum recusandae dolorem minus dignissimos, magni consequatur, maxime debitis reprehenderit sint non iusto?

    - -New Application -Existing Application -Sandbox Environment - -{% end %} diff --git a/templates/requests/screen-1.html b/templates/requests/screen-1.html new file mode 100644 index 00000000..da6c5ae0 --- /dev/null +++ b/templates/requests/screen-1.html @@ -0,0 +1,46 @@ +{% extends 'requests_new.html' %} + +{% from "components.html" import Alert, TextInput, OptionsInput %} + +{% block subtitle %} +

    Details of Use

    +{% endblock %} + +{% block form %} + +{% if f.errors %} + {{ Alert('There were some errors', + message="

    Please see below.

    ", + level='error' + ) }} +{% endif %} + + +

    We’d like to know a little about how you plan to use JEDI Cloud services to process your request. Please answer the following questions to the best of your ability. Note that the CCPO does not directly help with migrating systems to JEDI Cloud. These questions are for learning about your cloud readiness and financial usage of the JEDI Cloud; your estimates will not be used for any department level reporting.

    +

    All fields are required, unless specified optional.

    + +

    General

    +{{ TextInput(f.dod_component) }} +{{ TextInput(f.jedi_usage,placeholder="e.g. We are migrating XYZ application to the cloud so that...") }} + +

    Cloud Readiness

    +{{ TextInput(f.num_software_systems,placeholder="Number of systems") }} +{{ OptionsInput(f.jedi_migration) }} +{{ OptionsInput(f.rationalization_software_systems) }} +{{ OptionsInput(f.technical_support_team) }} +{{ OptionsInput(f.organization_providing_assistance) }} +{{ OptionsInput(f.engineering_assessment) }} +{{ TextInput(f.data_transfers) }} +{{ TextInput(f.expected_completion_date) }} +{{ OptionsInput(f.cloud_native) }} + +

    Financial Usage

    +{{ TextInput(f.estimated_monthly_spend) }} +

    So this means you are spending approximately $X annually

    +{{ TextInput(f.dollar_value) }} +{{ TextInput(f.number_user_sessions) }} +{{ TextInput(f.average_daily_traffic) }} +{{ TextInput(f.start_date) }} + + +{% endblock %} diff --git a/templates/requests/screen-1.html.to b/templates/requests/screen-1.html.to deleted file mode 100644 index a8ed7887..00000000 --- a/templates/requests/screen-1.html.to +++ /dev/null @@ -1,45 +0,0 @@ -{% extends '../requests_new.html.to' %} - -{% block subtitle %} -

    Details of Use

    -{% end %} - -{% block form %} - -{% autoescape None %} -{% if f.errors %} - {% module Alert('There were some errors', - message="

    Please see below.

    ", - level='error' - ) %} -{% end %} - - -

    We’d like to know a little about how you plan to use JEDI Cloud services to process your request. Please answer the following questions to the best of your ability. Note that the CCPO does not directly help with migrating systems to JEDI Cloud. These questions are for learning about your cloud readiness and financial usage of the JEDI Cloud; your estimates will not be used for any department level reporting.

    -

    All fields are required, unless specified optional.

    - -

    General

    -{% module TextInput(f.dod_component) %} -{% module TextInput(f.jedi_usage,placeholder="e.g. We are migrating XYZ application to the cloud so that...") %} - -

    Cloud Readiness

    -{% module TextInput(f.num_software_systems,placeholder="Number of systems") %} -{% module OptionsInput(f.jedi_migration) %} -{% module OptionsInput(f.rationalization_software_systems) %} -{% module OptionsInput(f.technical_support_team) %} -{% module OptionsInput(f.organization_providing_assistance) %} -{% module OptionsInput(f.engineering_assessment) %} -{% module TextInput(f.data_transfers) %} -{% module TextInput(f.expected_completion_date) %} -{% module OptionsInput(f.cloud_native) %} - -

    Financial Usage

    -{% module TextInput(f.estimated_monthly_spend) %} -

    So this means you are spending approximately $X annually

    -{% module TextInput(f.dollar_value) %} -{% module TextInput(f.number_user_sessions) %} -{% module TextInput(f.average_daily_traffic) %} -{% module TextInput(f.start_date) %} - - -{% end %} diff --git a/templates/requests/screen-2.html b/templates/requests/screen-2.html new file mode 100644 index 00000000..24c8f749 --- /dev/null +++ b/templates/requests/screen-2.html @@ -0,0 +1,32 @@ +{% extends 'requests_new.html' %} + +{% from "components.html" import Alert, TextInput, OptionsInput %} + +{% block subtitle %} +

    Information About You

    +{% endblock %} + +{% block form %} + +{% if f.errors %} + {{ Alert('There were some errors', + message="

    Please see below.

    ", + level='error' + ) }} +{% endif %} + +

    Please tell us more about you.

    + +{{ TextInput(f.fname_request,placeholder='First Name') }} +{{ TextInput(f.lname_request,placeholder='Last Name') }} +{{ TextInput(f.email_request,placeholder='jane@mail.mil') }} +{{ TextInput(f.phone_number,placeholder='(123) 456-7890') }} + +

    We want to collect the following information from you for security auditing and determining priviledged user access

    + +{{ TextInput(f.service_branch,placeholder='e.g. US Air Force, US Army, US Navy, Marine Corps, Defense Media Agency') }} +{{ OptionsInput(f.citizenship) }} +{{ OptionsInput(f.designation) }} +{{ TextInput(f.date_latest_training) }} + +{% endblock %} diff --git a/templates/requests/screen-2.html.to b/templates/requests/screen-2.html.to deleted file mode 100644 index fb667dc5..00000000 --- a/templates/requests/screen-2.html.to +++ /dev/null @@ -1,31 +0,0 @@ -{% extends '../requests_new.html.to' %} - -{% block subtitle %} -

    Information About You

    -{% end %} - -{% block form %} - -{% autoescape None %} -{% if f.errors %} - {% module Alert('There were some errors', - message="

    Please see below.

    ", - level='error' - ) %} -{% end %} - -

    Please tell us more about you.

    - -{% module TextInput(f.fname_request,placeholder='First Name') %} -{% module TextInput(f.lname_request,placeholder='Last Name') %} -{% module TextInput(f.email_request,placeholder='jane@mail.mil') %} -{% module TextInput(f.phone_number,placeholder='(123) 456-7890') %} - -

    We want to collect the following information from you for security auditing and determining priviledged user access

    - -{% module TextInput(f.service_branch,placeholder='e.g. US Air Force, US Army, US Navy, Marine Corps, Defense Media Agency') %} -{% module OptionsInput(f.citizenship) %} -{% module OptionsInput(f.designation) %} -{% module TextInput(f.date_latest_training) %} - -{% end %} \ No newline at end of file diff --git a/templates/requests/screen-3.html.to b/templates/requests/screen-3.html similarity index 100% rename from templates/requests/screen-3.html.to rename to templates/requests/screen-3.html diff --git a/templates/requests/screen-4.html.to b/templates/requests/screen-4.html similarity index 100% rename from templates/requests/screen-4.html.to rename to templates/requests/screen-4.html diff --git a/templates/requests/screen-5.html.to b/templates/requests/screen-5.html similarity index 100% rename from templates/requests/screen-5.html.to rename to templates/requests/screen-5.html diff --git a/templates/requests/sidebar.html.to b/templates/requests/sidebar.html similarity index 100% rename from templates/requests/sidebar.html.to rename to templates/requests/sidebar.html diff --git a/templates/requests_new.html b/templates/requests_new.html new file mode 100644 index 00000000..559c2355 --- /dev/null +++ b/templates/requests_new.html @@ -0,0 +1,45 @@ +{% extends "base.html" %} + +{% block content %} + +
    + + {% include 'requests/menu.html' %} + +
    + +
    +

    New Request

    +
    {% block subtitle %}{% endblock %}
    +
    + +
    + {% block form_action %} + {% if request_id %} +
    + {% else %} + + {% endif %} + {% endblock %} + + {{ f.csrf_token }} + {% block form %} + form goes here + {% endblock %} + +
    + +
    + + {% block next %} + +
    + +
    + + {% endblock %} + + +
    + +{% endblock %} diff --git a/templates/requests_new.html.to b/templates/requests_new.html.to deleted file mode 100644 index c5f96ed5..00000000 --- a/templates/requests_new.html.to +++ /dev/null @@ -1,46 +0,0 @@ -{% extends "base.html.to" %} - -{% block content %} - -
    - - {% include 'requests/menu.html.to' %} - -
    - -
    -

    New Request

    -
    {% block subtitle %}{% end %}
    -
    - -
    - {% block form_action %} - {% if request_id %} -
    - {% else %} - - {% end %} - {% end %} - - {{ form.csrf_token }} - {% block form %} - form goes here - {% end %} - -
    - -
    - - {% block next %} - -
    - -
    - - {% end %} - - -
    - -{% end %} - From ed0893b4a0735490560ef0814d537a25256758b1 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Thu, 2 Aug 2018 10:36:25 -0400 Subject: [PATCH 076/332] Converted all form pages. Flow still not working --- atst/forms/financial.py | 4 +-- atst/forms/forms.py | 5 ++-- atst/routes/requests.py | 11 +++++-- templates/requests/screen-3.html | 23 +++++++------- templates/requests/screen-4.html | 33 +++++++++++---------- templates/requests/screen-5.html | 51 ++++++++++++++++---------------- 6 files changed, 65 insertions(+), 62 deletions(-) diff --git a/atst/forms/financial.py b/atst/forms/financial.py index 52b4ef28..fb66282b 100644 --- a/atst/forms/financial.py +++ b/atst/forms/financial.py @@ -36,7 +36,6 @@ def suggest_pe_id(pe_id): return None -@tornado.gen.coroutine def validate_pe_id(field, existing_request, pe_numbers_repo): try: pe_number = pe_numbers_repo.get(field.data) @@ -55,12 +54,11 @@ def validate_pe_id(field, existing_request, pe_numbers_repo): class FinancialForm(ValidatedForm): - @tornado.gen.coroutine def perform_extra_validation(self, existing_request, pe_numbers_repo): valid = True if not existing_request or existing_request.get('pe_id') != self.pe_id.data: valid = yield validate_pe_id(self.pe_id, existing_request, pe_numbers_repo) - raise Return(valid) + return valid task_order_id = StringField( "Task Order Number associated with this request.", validators=[Required()] diff --git a/atst/forms/forms.py b/atst/forms/forms.py index 48f03295..d60e3a2c 100644 --- a/atst/forms/forms.py +++ b/atst/forms/forms.py @@ -5,8 +5,7 @@ from flask_wtf import FlaskForm class ValidatedForm(FlaskForm): - @tornado.gen.coroutine def perform_extra_validation(self, *args, **kwargs): - """A coroutine that performs any applicable extra validation. Must + """Performs any applicable extra validation. Must return True if the form is valid or False otherwise.""" - raise Return(True) + return True diff --git a/atst/routes/requests.py b/atst/routes/requests.py index 565c268e..0c225a7f 100644 --- a/atst/routes/requests.py +++ b/atst/routes/requests.py @@ -63,7 +63,7 @@ def requests_form_update(screen=1, request_id=None): @requests_bp.route("/requests/new//", methods=["POST"]) def requests_update(screen=1, request_id=None): screen = int(screen) - post_data = str(request.data) + post_data = request.form current_user = g.current_user existing_request = Requests.get(request_id) if request_id is not None else None jedi_flow = JEDIRequestFlow( @@ -91,7 +91,7 @@ def requests_update(screen=1, request_id=None): where = "/requests" else: where = url_for( - "requests.requests_Form_update", screen=jedi_flow.next_screen, request_id=jedi_flow.request_id + "requests.requests_form_update", screen=jedi_flow.next_screen, request_id=jedi_flow.request_id ) return redirect(where) else: @@ -120,6 +120,11 @@ def update_financial_verification(): pass +@requests_bp.route("/requests/submit/", methods=["POST"]) +def requests_submit(request_id=None): + pass + + class JEDIRequestFlow(object): def __init__( self, @@ -240,7 +245,7 @@ class JEDIRequestFlow(object): self.form_section: self.form.data } if self.request_id: - Requests.update(request_id, request_data) + Requests.update(self.request_id, request_data) else: request = Requests.create(self.current_user["id"], request_data) self.request_id = request.id diff --git a/templates/requests/screen-3.html b/templates/requests/screen-3.html index af4ea66f..5bdbaf43 100644 --- a/templates/requests/screen-3.html +++ b/templates/requests/screen-3.html @@ -1,18 +1,19 @@ -{% extends '../requests_new.html.to' %} +{% extends 'requests_new.html' %} + +{% from "components.html" import Alert, TextInput %} {% block subtitle %}

    Primary Government/Military
    Point of Contact (POC)

    -{% end %} +{% endblock %} {% block form %} -{% autoescape None %} {% if f.errors %} - {% module Alert('There were some errors', + {{ Alert('There were some errors', message="

    Please see below.

    ", level='error' - ) %} -{% end %} + ) }} +{% endif %}

    Please designate a Primary Point of Contact that will be responsible for owning the workspace in the JEDI Cloud.

    The Point of Contact will become the primary owner of the workspace created to use the JEDI Cloud. As a workspace owner, this person will have the ability to: @@ -26,9 +27,9 @@ This POC may be you.

    -{% module TextInput(f.fname_poc,placeholder='First Name') %} -{% module TextInput(f.lname_poc,placeholder='Last Name') %} -{% module TextInput(f.email_poc,placeholder='jane@mail.mil') %} -{% module TextInput(f.dodid_poc,placeholder='10-digit number on the back of the CAC') %} +{{ TextInput(f.fname_poc,placeholder='First Name') }} +{{ TextInput(f.lname_poc,placeholder='Last Name') }} +{{ TextInput(f.email_poc,placeholder='jane@mail.mil') }} +{{ TextInput(f.dodid_poc,placeholder='10-digit number on the back of the CAC') }} -{% end %} \ No newline at end of file +{% endblock %} diff --git a/templates/requests/screen-4.html b/templates/requests/screen-4.html index 60dd06ac..37cfc5de 100644 --- a/templates/requests/screen-4.html +++ b/templates/requests/screen-4.html @@ -1,27 +1,28 @@ -{% extends '../requests_new.html.to' %} +{% extends 'requests_new.html' %} + +{% from "components.html" import Alert, TextInput %} {% block subtitle %}

    Review & Submit

    -{% end %} +{% endblock %} {% block form_action %} -
    - {% end %} + +{% endblock %} {% block form %} - {% autoescape None %} {% if f.errors %} - {% module Alert('There were some errors', + {{ Alert('There were some errors', message="

    Please complete all required fields before submitting.

    ", level='error' - ) %} - {% end %} + ) }} + {% endif %}

    Before you can submit your request, please take a moment to review the information entered in the form. You may make changes by clicking the edit link on each section. When all information looks right, go ahead and submit.

    -

    Details of Use Edit

    +

    Details of Use Edit

    @@ -107,7 +108,7 @@
    -

    Information About You Edit

    +

    Information About You Edit

    @@ -152,7 +153,7 @@
    -

    Primary Point of Contact Edit

    +

    Primary Point of Contact Edit

    @@ -178,15 +179,15 @@ -{% end %} +{% endblock %} {% block next %} {% if not can_submit %} - {% module Alert('There were some errors', + {{ Alert('There were some errors', message="

    Please complete all required fields before submitting.

    ", level='error' - ) %} -{% end %} + ) }} +{% endif %}
    @@ -194,4 +195,4 @@ -{% end %} +{% endblock %} diff --git a/templates/requests/screen-5.html b/templates/requests/screen-5.html index e8642f1e..845ed133 100644 --- a/templates/requests/screen-5.html +++ b/templates/requests/screen-5.html @@ -2,13 +2,12 @@ {% block form %} -{% autoescape None %} {% if f.errors %} - {% module Alert('There were some errors', + {{ Alert('There were some errors', message="

    Please complete all the fields before submitting.

    ", level='error' - ) %} -{% end %} + ) }} +{% endif %}

    Financial Verification

    @@ -20,7 +19,7 @@
    {{ e }}
    -{% end %} +{% endfor %} {{ f.uii_ids.label }} {{ f.uii_ids(placeholder="Example: \nDI 0CVA5786950 \nUN1945326361234786950") }} @@ -28,7 +27,7 @@
    {{ e }}
    -{% end %} +{% endfor %} {{ f.pe_id.label }} {{ f.pe_id(placeholder="Example: 0203752A") }} @@ -36,7 +35,7 @@
    {{ e }}
    -{% end %} +{% endfor %} {{ f.treasury_code.label }} {{ f.treasury_code(placeholder="Example: 1200") }} @@ -44,7 +43,7 @@
    {{ e }}
    -{% end %} +{% endfor %} {{ f.ba_code.label }} {{ f.ba_code(placeholder="Example: 02") }} @@ -52,7 +51,7 @@
    {{ e }}
    -{% end %} +{% endfor %} @@ -64,7 +63,7 @@
    {{ e }}
    -{% end %} +{% endfor %} {{ f.lname_co.label }} {{ f.lname_co(placeholder="Contracting Officer last name") }} @@ -72,7 +71,7 @@
    {{ e }}
    -{% end %} +{% endfor %} {{ f.email_co.label }} {{ f.email_co(placeholder="jane@mail.mil") }} @@ -80,7 +79,7 @@
    {{ e }}
    -{% end %} +{% endfor %} {{ f.office_co.label }} {{ f.office_co(placeholder="Example: WHS") }} @@ -88,7 +87,7 @@
    {{ e }}
    -{% end %} +{% endfor %} @@ -101,7 +100,7 @@
    {{ e }}
    -{% end %} +{% endfor %} {{ f.lname_cor.label }} {{ f.lname_cor(placeholder="Contracting Officer Representative last name") }} @@ -109,7 +108,7 @@
    {{ e }}
    -{% end %} +{% endfor %} {{ f.email_cor.label }} {{ f.email_cor(placeholder="jane@mail.mil") }} @@ -117,7 +116,7 @@
    {{ e }}
    -{% end %} +{% endfor %} {{ f.office_cor.label }} {{ f.office_cor(placeholder="Example: WHS") }} @@ -125,7 +124,7 @@
    {{ e }}
    -{% end %} +{% endfor %}

    ↓ FIELDS NEEDED FOR MANUAL ENTRY OF TASK ORDER INFORMATION (only necessary if EDA info not available) @@ -137,7 +136,7 @@
    {{ e }}
    -{% end %} +{% endfor %} {{ f.funding_type_other.label }} {{ f.funding_type_other(placeholder="") }} @@ -145,7 +144,7 @@
    {{ e }}
    -{% end %} +{% endfor %} {{ f.clin_0001.label }} {{ f.clin_0001(placeholder="50,000") }} @@ -153,7 +152,7 @@
    {{ e }}
    -{% end %} +{% endfor %} {{ f.clin_0003.label }} {{ f.clin_0003(placeholder="13,000") }} @@ -161,7 +160,7 @@
    {{ e }}
    -{% end %} +{% endfor %} {{ f.clin_1001.label }} {{ f.clin_1001(placeholder="30,000") }} @@ -169,7 +168,7 @@
    {{ e }}
    -{% end %} +{% endfor %} {{ f.clin_1003.label }} {{ f.clin_1003(placeholder="7,000") }} @@ -177,7 +176,7 @@
    {{ e }}
    -{% end %} +{% endfor %} {{ f.clin_2001.label }} {{ f.clin_2001(placeholder="30,000") }} @@ -185,7 +184,7 @@
    {{ e }}
    -{% end %} +{% endfor %} {{ f.clin_2003.label }} {{ f.clin_2003(placeholder="7,000") }} @@ -193,7 +192,7 @@
    {{ e }}
    -{% end %} +{% endfor %} -{% end %} +{% endblock %} From 4ffbbb34714dfd1b047fba784fa5a329676dcf4a Mon Sep 17 00:00:00 2001 From: richard-dds Date: Thu, 2 Aug 2018 10:59:05 -0400 Subject: [PATCH 077/332] Request flow seems to be working --- atst/app.py | 2 +- atst/routes/requests/__init__.py | 126 ++++++++++++++++++++ atst/routes/requests/jedi_request_flow.py | 135 ++++++++++++++++++++++ templates/components.html | 6 +- templates/requests/menu.html | 2 +- 5 files changed, 266 insertions(+), 5 deletions(-) create mode 100644 atst/routes/requests/__init__.py create mode 100644 atst/routes/requests/jedi_request_flow.py diff --git a/atst/app.py b/atst/app.py index babaff7a..cd432ea9 100644 --- a/atst/app.py +++ b/atst/app.py @@ -46,7 +46,7 @@ def make_flask_callbacks(app): def set_globals(): g.navigationContext = 'workspace' if re.match('\/workspaces\/[A-Za-z0-9]*', request.url) else 'global' g.dev = os.getenv("TORNADO_ENV", "dev") == "dev" - g.matchesPath = lambda href: re.match('^'+href, request.url) + g.matchesPath = lambda href: re.match('^'+href, request.path) g.modalOpen = request.args.get("modal", False) g.current_user = { "id": "cce17030-4109-4719-b958-ed109dbb87c8", diff --git a/atst/routes/requests/__init__.py b/atst/routes/requests/__init__.py new file mode 100644 index 00000000..aa747e71 --- /dev/null +++ b/atst/routes/requests/__init__.py @@ -0,0 +1,126 @@ +from flask import Blueprint, g, render_template, url_for, redirect, request +import pendulum + +from atst.routes.requests.jedi_request_flow import JEDIRequestFlow +from atst.domain.requests import Requests + + +requests_bp = Blueprint("requests", __name__) + +def map_request(user, request): + time_created = pendulum.instance(request.time_created) + is_new = time_created.add(days=1) > pendulum.now() + + return { + "order_id": request.id, + "is_new": is_new, + "status": request.status, + "app_count": 1, + "date": time_created.format("M/DD/YYYY"), + "full_name": "{} {}".format(user["first_name"], user["last_name"]), + } + + +@requests_bp.route("/requests", methods=["GET"]) +def requests_index(): + requests = [] + if "review_and_approve_jedi_workspace_request" in g.current_user["atat_permissions"]: + requests = Requests.get_many() + else: + requests = Requests.get_many(creator_id=g.current_user["id"]) + + mapped_requests = [map_request(g.current_user, r) for r in requests] + + return render_template("requests.html", requests=mapped_requests) + + +@requests_bp.route("/requests/new/", methods=["GET"]) +def requests_form_new(): + pass + + +@requests_bp.route("/requests/new//", methods=["GET"]) +def requests_form_update(screen=1, request_id=None): + request = Requests.get(request_id) if request_id is not None else None + jedi_flow = JEDIRequestFlow(screen, request, request_id=request_id) + + return render_template( + "requests/screen-%d.html" % int(screen), + f=jedi_flow.form, + data=jedi_flow.current_step_data, + screens=jedi_flow.screens, + current=screen, + next_screen=screen + 1, + request_id=request_id, + can_submit=jedi_flow.can_submit + ) + +@requests_bp.route("/requests/new//", methods=["POST"]) +def requests_update(screen=1, request_id=None): + screen = int(screen) + post_data = request.form + current_user = g.current_user + existing_request = Requests.get(request_id) if request_id is not None else None + jedi_flow = JEDIRequestFlow( + screen, + post_data=post_data, + request_id=request_id, + current_user=current_user, + existing_request=existing_request, + ) + + rerender_args = dict( + f=jedi_flow.form, + data=post_data, + screens=jedi_flow.screens, + current=screen, + next_screen=jedi_flow.next_screen, + request_id=jedi_flow.request_id, + ) + + if jedi_flow.validate(): + jedi_flow.create_or_update_request() + valid = jedi_flow.validate_warnings() + if valid: + if jedi_flow.next_screen > len(jedi_flow.screens): + where = "/requests" + else: + where = url_for( + "requests.requests_form_update", screen=jedi_flow.next_screen, request_id=jedi_flow.request_id + ) + return redirect(where) + else: + return render_template( + "requests/screen-%d.html" % int(screen), + **rerender_args + ) + else: + return render_template( + "requests/screen-%d.html" % int(screen), + **rerender_args + ) + + + + +@requests_bp.route("/requests/verify/", methods=["GET"]) +def financial_verification(request_id=None): + request = Requests.get(request_id) + form = FinancialForm(data=request.body.get('financial_verification')) + return render_template("requests/financial_verification.html", f=form) + + +@requests_bp.route("/requests/verify/", methods=["POST"]) +def update_financial_verification(): + pass + + +@requests_bp.route("/requests/submit/", methods=["POST"]) +def requests_submit(request_id=None): + request = Requests.get(request_id) + Requests.submit(request) + + if request.status == "approved": + return redirect("/requests?modal=True") + else: + return redirect("/requests") diff --git a/atst/routes/requests/jedi_request_flow.py b/atst/routes/requests/jedi_request_flow.py new file mode 100644 index 00000000..4befe5f5 --- /dev/null +++ b/atst/routes/requests/jedi_request_flow.py @@ -0,0 +1,135 @@ +from collections import defaultdict + +from atst.domain.requests import Requests +from atst.forms.financial import FinancialForm +from atst.forms.request import RequestForm +from atst.forms.org import OrgForm +from atst.forms.poc import POCForm +from atst.forms.review import ReviewForm + + + +class JEDIRequestFlow(object): + def __init__( + self, + current_step, + request=None, + post_data=None, + request_id=None, + current_user=None, + existing_request=None, + ): + self.current_step = current_step + self.request = request + + self.post_data = post_data + self.is_post = self.post_data is not None + + self.request_id = request_id + self.form = self._form() + + self.current_user = current_user + self.existing_request = existing_request + + def _form(self): + if self.is_post: + return self.form_class()(self.post_data) + elif self.request: + return self.form_class()(data=self.current_step_data) + else: + return self.form_class()() + + def validate(self): + return self.form.validate() + + def validate_warnings(self): + existing_request_data = ( + self.existing_request + and self.existing_request.body.get(self.form_section) + ) or None + + valid = self.form.perform_extra_validation( + existing_request_data, + ) + return valid + + @property + def current_screen(self): + return self.screens[self.current_step - 1] + + @property + def form_section(self): + return self.current_screen["section"] + + def form_class(self): + return self.current_screen["form"] + + @property + def current_step_data(self): + data = {} + + if self.is_post: + data = self.post_data + + if self.request: + if self.form_section == "review_submit": + data = self.request.body + else: + data = self.request.body.get(self.form_section, {}) + + return defaultdict(lambda: defaultdict(lambda: 'Input required'), data) + + @property + def can_submit(self): + return self.request and self.request.status != "incomplete" + + @property + def next_screen(self): + return self.current_step + 1 + + @property + def screens(self): + return [ + { + "title": "Details of Use", + "section": "details_of_use", + "form": RequestForm, + "subitems": [ + { + "title": "Overall request details", + "id": "overall-request-details", + }, + {"title": "Cloud Resources", "id": "cloud-resources"}, + {"title": "Support Staff", "id": "support-staff"}, + ], + "show": True, + }, + { + "title": "Information About You", + "section": "information_about_you", + "form": OrgForm, + "show": True, + }, + { + "title": "Primary Point of Contact", + "section": "primary_poc", + "form": POCForm, + "show": True, + }, + { + "title": "Review & Submit", + "section": "review_submit", + "form": ReviewForm, + "show":True, + }, + ] + + def create_or_update_request(self): + request_data = { + self.form_section: self.form.data + } + if self.request_id: + Requests.update(self.request_id, request_data) + else: + request = Requests.create(self.current_user["id"], request_data) + self.request_id = request.id diff --git a/templates/components.html b/templates/components.html index 027ede6f..ea214631 100644 --- a/templates/components.html +++ b/templates/components.html @@ -7,11 +7,11 @@ {% macro SidenavItem(label, href, active=False, icon=None, subnav=None) -%}
  • - {% if icon %} + {% if icon %} {{ Icon(icon, classes="sidenav__link-icon") }} - {% endif %} + {% endif %} - {{label}} + {{label}} {% if subnav and active %} diff --git a/templates/requests/menu.html b/templates/requests/menu.html index f1642e46..24b28d4f 100644 --- a/templates/requests/menu.html +++ b/templates/requests/menu.html @@ -2,7 +2,7 @@
  • - {% end %} - {% end %} -{% end %} + {% endcall %} + {% endif %} +{% endblock %} {% block content %} -{% module Alert('A Warning Alert', +{{ Alert('A Warning Alert', message="\

    This is a message. It is a very important message. Please note, proper semantic markup is required here, such as paragraph tags. Don't omit paragraph tags!

    \

    Also note the same for actions below. You'll need to include the full link markup.

    \ ", actions="Open a Modal Dialog", level='warning' -) %} +) }} -{% module Alert('A Success Alert', +{{ Alert('A Success Alert', message="

    Congratulations! You did a thing.

    ", level='success' -) %} +) }} -{% module Alert('An Error Alert', +{{ Alert('An Error Alert', message="

    Booooo. You're the worst.

    ", level='error' -) %} +) }} -{% module Alert('An Info Alert', +{{ Alert('An Info Alert', message="

    The more you know.

    " -) %} +) }}
    @@ -214,7 +216,7 @@
    - Inline Checkboxes {% module Icon('alert') %} + Inline Checkboxes {{ Icon('alert') }} @@ -234,7 +236,7 @@
    - Problem Radio Buttons {% module Icon('alert') %} + Problem Radio Buttons {{ Icon('alert') }} @@ -279,30 +281,30 @@
    Icons
    - {% module Icon('trash') %} 'trash'    - {% module Icon('document') %} 'document'    - {% module Icon('cloud') %} 'cloud'    - {% module Icon('chart') %} 'chart'    - {% module Icon('caret_up') %} 'caret_up'    - {% module Icon('caret_down') %} 'caret_down'    - {% module Icon('caret_right') %} 'caret_right'    - {% module Icon('caret_left') %} 'caret_left'    - {% module Icon('x') %} 'x'    - {% module Icon('search') %} 'search'    - {% module Icon('avatar') %} 'avatar'    - {% module Icon('download') %} 'download'    - {% module Icon('briefcase') %} 'briefcase'    - {% module Icon('bell') %} 'bell'    - {% module Icon('folder') %} 'folder'    - {% module Icon('help') %} 'help'    - {% module Icon('shield') %} 'shield'    - {% module Icon('info') %} 'info'    - {% module Icon('alert') %} 'alert'    - {% module Icon('link') %} 'link'    - {% module Icon('ok') %} 'ok'    - {% module Icon('checkmark') %} 'checkmark'    - {% module Icon('arrow-right') %} 'arrow-right'    - {% module Icon('arrow-down') %} 'arrow-down'    + {{ Icon('trash') }} 'trash'    + {{ Icon('document') }} 'document'    + {{ Icon('cloud') }} 'cloud'    + {{ Icon('chart') }} 'chart'    + {{ Icon('caret_up') }} 'caret_up'    + {{ Icon('caret_down') }} 'caret_down'    + {{ Icon('caret_right') }} 'caret_right'    + {{ Icon('caret_left') }} 'caret_left'    + {{ Icon('x') }} 'x'    + {{ Icon('search') }} 'search'    + {{ Icon('avatar') }} 'avatar'    + {{ Icon('download') }} 'download'    + {{ Icon('briefcase') }} 'briefcase'    + {{ Icon('bell') }} 'bell'    + {{ Icon('folder') }} 'folder'    + {{ Icon('help') }} 'help'    + {{ Icon('shield') }} 'shield'    + {{ Icon('info') }} 'info'    + {{ Icon('alert') }} 'alert'    + {{ Icon('link') }} 'link'    + {{ Icon('ok') }} 'ok'    + {{ Icon('checkmark') }} 'checkmark'    + {{ Icon('arrow-right') }} 'arrow-right'    + {{ Icon('arrow-down') }} 'arrow-down'   
    @@ -360,4 +362,4 @@ Action group link
    -{% end %} +{% endblock %} From bc8bd719b60047eec642d0589523fc851652cbc0 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Thu, 2 Aug 2018 13:44:01 -0400 Subject: [PATCH 086/332] Rename assets environment to play nicely with script/setup --- atst/app.py | 4 ++-- atst/assets.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/atst/app.py b/atst/app.py index cd54f15d..46b017bb 100644 --- a/atst/app.py +++ b/atst/app.py @@ -5,7 +5,7 @@ from flask import Flask, request, g from unipath import Path from atst.database import db -from atst.assets import assets +from atst.assets import environment as assets_environment from atst.routes import bp from atst.routes.workspaces import bp as workspace_routes @@ -29,7 +29,7 @@ def make_app(config): make_flask_callbacks(app) db.init_app(app) - assets.init_app(app) + assets_environment.init_app(app) app.register_blueprint(bp) app.register_blueprint(workspace_routes) diff --git a/atst/assets.py b/atst/assets.py index bed898ac..aef6b35e 100644 --- a/atst/assets.py +++ b/atst/assets.py @@ -1,7 +1,7 @@ from flask_assets import Environment, Bundle from atst.home import home -assets = Environment() +environment = Environment() css = Bundle( "../scss/atat.scss", @@ -10,4 +10,4 @@ css = Bundle( depends=("**/*.scss"), ) -assets.register("css", css) +environment.register("css", css) From f8cee60baa6a09f5297ad3d29f56b13d9ec8ff11 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Thu, 2 Aug 2018 13:44:54 -0400 Subject: [PATCH 087/332] Formatting --- atst/routes/requests/financial_verification.py | 5 ++++- atst/routes/requests/requests_form.py | 9 ++++++--- atst/routes/workspaces.py | 11 +++++++++-- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/atst/routes/requests/financial_verification.py b/atst/routes/requests/financial_verification.py index e0d08a37..4471b524 100644 --- a/atst/routes/requests/financial_verification.py +++ b/atst/routes/requests/financial_verification.py @@ -4,6 +4,7 @@ from . import requests_bp from atst.domain.requests import Requests from atst.forms.financial import FinancialForm + @requests_bp.route("/requests/verify/", methods=["GET"]) def financial_verification(request_id=None): request = Requests.get(request_id) @@ -30,7 +31,9 @@ def update_financial_verification(request_id): if valid: redirect(url_for("requests.financial_verification_submitted")) else: - return render_template("requests/financial_verification.html", **rerender_args) + return render_template( + "requests/financial_verification.html", **rerender_args + ) else: return render_template("requests/financial_verification.html", **rerender_args) diff --git a/atst/routes/requests/requests_form.py b/atst/routes/requests/requests_form.py index 4e9b5018..cd12fbcd 100644 --- a/atst/routes/requests/requests_form.py +++ b/atst/routes/requests/requests_form.py @@ -21,7 +21,9 @@ def requests_form_new(screen): ) -@requests_bp.route("/requests/new/", methods=["GET"], defaults={"request_id": None}) +@requests_bp.route( + "/requests/new/", methods=["GET"], defaults={"request_id": None} +) @requests_bp.route("/requests/new//", methods=["GET"]) def requests_form_update(screen=1, request_id=None): request = Requests.get(request_id) if request_id is not None else None @@ -39,7 +41,9 @@ def requests_form_update(screen=1, request_id=None): ) -@requests_bp.route("/requests/new/", methods=["POST"], defaults={"request_id": None}) +@requests_bp.route( + "/requests/new/", methods=["POST"], defaults={"request_id": None} +) @requests_bp.route("/requests/new//", methods=["POST"]) def requests_update(screen=1, request_id=None): screen = int(screen) @@ -84,7 +88,6 @@ def requests_update(screen=1, request_id=None): return render_template("requests/screen-%d.html" % int(screen), **rerender_args) - @requests_bp.route("/requests/submit/", methods=["POST"]) def requests_submit(request_id=None): request = Requests.get(request_id) diff --git a/atst/routes/workspaces.py b/atst/routes/workspaces.py index 1f3b47f2..43b3b050 100644 --- a/atst/routes/workspaces.py +++ b/atst/routes/workspaces.py @@ -14,18 +14,25 @@ mock_workspaces = [ } ] + @bp.route("/workspaces") def workspaces(): return render_template("workspaces.html", page=5, workspaces=mock_workspaces) + @bp.route("/workspaces//projects") def workspace_projects(workspace_id): projects_repo = Projects() projects = projects_repo.get_many(workspace_id) - return render_template("workspace_projects.html", workspace_id=workspace_id, projects=projects) + return render_template( + "workspace_projects.html", workspace_id=workspace_id, projects=projects + ) + @bp.route("/workspaces//members") def workspace_members(workspace_id): members_repo = Members() members = members_repo.get_many(workspace_id) - return render_template("workspace_members.html", workspace_id=workspace_id, members=members) + return render_template( + "workspace_members.html", workspace_id=workspace_id, members=members + ) From 92e65e75951db4d8bf927f07cebc380c3f9bd96b Mon Sep 17 00:00:00 2001 From: Luis Cielak Date: Mon, 30 Jul 2018 17:26:07 -0400 Subject: [PATCH 088/332] Add member placeholder info --- templates/member_edit.html.to | 73 ++++++++----------- .../navigation/workspace_navigation.html.to | 32 ++++---- templates/workspace_members.html | 16 ++-- 3 files changed, 51 insertions(+), 70 deletions(-) diff --git a/templates/member_edit.html.to b/templates/member_edit.html.to index 24893bf2..d454152c 100644 --- a/templates/member_edit.html.to +++ b/templates/member_edit.html.to @@ -16,40 +16,39 @@ level="info" ) %} -
    -
    -

    {{ member_name }}

    -
    Workspace Role
    {{member_workspace_role}}
    -
    -
    -
    -
    -
    DOD ID:
    -
    {{ member_id }}
    -
    -
    -
    Email:
    -
    {{ member_email }}
    -
    -
    - edit account details + +
    +
    +

    + {% if is_new_member %} + Add new member + {% else %} + {{ member_name }} + {% end %} +

    +
    Workspace Role {{member_workspace_role}}
    -
    {%- endmacro %} - -{% macro TextInput(field, placeholder='') -%} -
    - - - {{ field(placeholder=placeholder) | safe }} - - {% if field.errors %} - {% for error in field.errors %} - {{ error }} - {% endfor %} - {% endif %} -
    -{%- endmacro %} - -{% macro OptionsInput(field, inline=False) -%} -
    - -
    - - {{ field.label }} - - {% if field.description %} - {{ field.description | safe }} - {% endif %} - - {% if field.errors %} - {{ Icon('alert') }} - {% endif %} - - - {{ field() }} - - {% if field.errors %} - {% for error in field.errors %} - {{ error }} - {% endfor %} - {% endif %} - -
    -
    - -{%- endmacro %} From 46a608794d5f4c6b9e8a194507db830ac0869a8b Mon Sep 17 00:00:00 2001 From: Patrick Smith Date: Thu, 2 Aug 2018 10:47:31 -0400 Subject: [PATCH 091/332] Update alembic/env to work with flask app --- alembic/env.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/alembic/env.py b/alembic/env.py index 6a9d9749..91b96364 100644 --- a/alembic/env.py +++ b/alembic/env.py @@ -30,11 +30,10 @@ sys.path.append(parent_dir) from atst.app import make_config app_config = make_config() -config.set_main_option('sqlalchemy.url', app_config['default']['DATABASE_URI']) +config.set_main_option('sqlalchemy.url', app_config['DATABASE_URI']) -from atst.database import make_db +from atst.database import db from atst.models import * -db = make_db(app_config) target_metadata = Base.metadata From 5b764a51fb4758e30ec413c11b1ea11b461276f2 Mon Sep 17 00:00:00 2001 From: Patrick Smith Date: Thu, 2 Aug 2018 10:51:12 -0400 Subject: [PATCH 092/332] Add parcel/vue js deps --- package.json | 4 +- yarn.lock | 6585 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 6588 insertions(+), 1 deletion(-) create mode 100644 yarn.lock diff --git a/package.json b/package.json index 5e9a5920..9a474e0d 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,8 @@ "license": "MIT", "dependencies": { "npm": "^6.0.1", - "uswds": "^1.6.3" + "parcel": "^1.9.7", + "uswds": "^1.6.3", + "vue": "^2.5.17" } } diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 00000000..ca8a5e51 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,6585 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@mrmlnc/readdir-enhanced@^2.2.1": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde" + dependencies: + call-me-maybe "^1.0.1" + glob-to-regexp "^0.3.0" + +"@nodelib/fs.stat@^1.0.1": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.0.tgz#50c1e2260ac0ed9439a181de3725a0168d59c48a" + +"@types/node@^8.5.5": + version "8.10.23" + resolved "https://registry.yarnpkg.com/@types/node/-/node-8.10.23.tgz#e5ccfdafff42af5397c29669b6d7d65f7d629a00" + +JSONStream@^1.0.3, JSONStream@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.3.tgz#27b4b8fbbfeab4e71bcf551e7f27be8d952239bf" + dependencies: + jsonparse "^1.2.0" + through ">=2.2.7 <3" + +abbrev@1, abbrev@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + +acorn-dynamic-import@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-3.0.0.tgz#901ceee4c7faaef7e07ad2a47e890675da50a278" + dependencies: + acorn "^5.0.0" + +acorn-node@^1.2.0, acorn-node@^1.3.0, acorn-node@^1.5.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/acorn-node/-/acorn-node-1.5.2.tgz#2ca723df19d997b05824b69f6c7fb091fc42c322" + dependencies: + acorn "^5.7.1" + acorn-dynamic-import "^3.0.0" + xtend "^4.0.1" + +acorn@^5.0.0, acorn@^5.2.1, acorn@^5.7.1: + version "5.7.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.1.tgz#f095829297706a7c9776958c0afc8930a9b9d9d8" + +agent-base@4, agent-base@^4.1.0, agent-base@~4.2.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9" + dependencies: + es6-promisify "^5.0.0" + +agentkeepalive@^3.4.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-3.5.1.tgz#4eba75cf2ad258fc09efd506cdb8d8c2971d35a4" + dependencies: + humanize-ms "^1.2.1" + +ajv@^4.9.1: + version "4.11.8" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" + dependencies: + co "^4.6.0" + json-stable-stringify "^1.0.1" + +ajv@^5.1.0: + version "5.5.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" + dependencies: + co "^4.6.0" + fast-deep-equal "^1.0.0" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.3.0" + +alphanum-sort@^1.0.0, alphanum-sort@^1.0.1, alphanum-sort@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" + +ansi-align@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-2.0.0.tgz#c36aeccba563b89ceb556f3690f0b1d9e3547f7f" + dependencies: + string-width "^2.0.0" + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + dependencies: + color-convert "^1.9.0" + +ansi-to-html@^0.6.4: + version "0.6.6" + resolved "https://registry.yarnpkg.com/ansi-to-html/-/ansi-to-html-0.6.6.tgz#58a8d04b87ec9a85e3ad273c12a5fbc7147b9c42" + dependencies: + entities "^1.1.1" + +ansicolors@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.3.2.tgz#665597de86a9ffe3aa9bfbe6cae5c6ea426b4979" + +ansistyles@~0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/ansistyles/-/ansistyles-0.1.3.tgz#5de60415bda071bb37127854c864f41b23254539" + +anymatch@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + dependencies: + micromatch "^3.1.4" + normalize-path "^2.1.1" + +aproba@^1.0.3, aproba@^1.1.1, aproba@^1.1.2, aproba@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + +"aproba@^1.1.2 || 2": + version "2.0.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" + +archy@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" + +are-we-there-yet@~1.1.2: + version "1.1.5" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + dependencies: + sprintf-js "~1.0.2" + +arr-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + +arr-flatten@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + +arr-union@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + +array-filter@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-1.0.0.tgz#baf79e62e6ef4c2a4c0b831232daffec251f9d83" + +array-filter@~0.0.0: + version "0.0.1" + resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-0.0.1.tgz#7da8cf2e26628ed732803581fd21f67cacd2eeec" + +array-foreach@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-foreach/-/array-foreach-1.0.2.tgz#cd36e42f0f482108c406b35c3612a8970b2fccea" + +array-map@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/array-map/-/array-map-0.0.0.tgz#88a2bab73d1cf7bcd5c1b118a003f66f665fa662" + +array-reduce@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/array-reduce/-/array-reduce-0.0.0.tgz#173899d3ffd1c7d9383e4479525dbe278cab5f2b" + +array-unique@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + +asap@^2.0.0: + version "2.0.6" + resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" + +asn1.js@^4.0.0: + version "4.10.1" + resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0" + dependencies: + bn.js "^4.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +asn1@~0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + +assert-plus@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" + +assert@^1.1.1, assert@^1.4.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91" + dependencies: + util "0.10.3" + +assign-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + +async-each@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" + +async-limiter@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + +atob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.1.tgz#ae2d5a729477f289d60dd7f96a6314a22dd6c22a" + +autoprefixer@^6.3.1: + version "6.7.7" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-6.7.7.tgz#1dbd1c835658e35ce3f9984099db00585c782014" + dependencies: + browserslist "^1.7.6" + caniuse-db "^1.0.30000634" + normalize-range "^0.1.2" + num2fraction "^1.2.2" + postcss "^5.2.16" + postcss-value-parser "^3.2.3" + +aws-sign2@~0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" + +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + +aws4@^1.2.1, aws4@^1.6.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.7.0.tgz#d4d0e9b9dbfca77bf08eeb0a8a471550fe39e289" + +babel-code-frame@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" + dependencies: + chalk "^1.1.3" + esutils "^2.0.2" + js-tokens "^3.0.2" + +babel-core@^6.25.0, babel-core@^6.26.0: + version "6.26.3" + resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.3.tgz#b2e2f09e342d0f0c88e2f02e067794125e75c207" + dependencies: + babel-code-frame "^6.26.0" + babel-generator "^6.26.0" + babel-helpers "^6.24.1" + babel-messages "^6.23.0" + babel-register "^6.26.0" + babel-runtime "^6.26.0" + babel-template "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + convert-source-map "^1.5.1" + debug "^2.6.9" + json5 "^0.5.1" + lodash "^4.17.4" + minimatch "^3.0.4" + path-is-absolute "^1.0.1" + private "^0.1.8" + slash "^1.0.0" + source-map "^0.5.7" + +babel-generator@^6.25.0, babel-generator@^6.26.0: + version "6.26.1" + resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90" + dependencies: + babel-messages "^6.23.0" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + detect-indent "^4.0.0" + jsesc "^1.3.0" + lodash "^4.17.4" + source-map "^0.5.7" + trim-right "^1.0.1" + +babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664" + dependencies: + babel-helper-explode-assignable-expression "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-builder-react-jsx@^6.24.1: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.26.0.tgz#39ff8313b75c8b65dceff1f31d383e0ff2a408a0" + dependencies: + babel-runtime "^6.26.0" + babel-types "^6.26.0" + esutils "^2.0.2" + +babel-helper-call-delegate@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" + dependencies: + babel-helper-hoist-variables "^6.24.1" + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-define-map@^6.24.1: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz#a5f56dab41a25f97ecb498c7ebaca9819f95be5f" + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" + +babel-helper-explode-assignable-expression@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz#f25b82cf7dc10433c55f70592d5746400ac22caa" + dependencies: + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-function-name@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9" + dependencies: + babel-helper-get-function-arity "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-get-function-arity@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-hoist-variables@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz#1ecb27689c9d25513eadbc9914a73f5408be7a76" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-optimise-call-expression@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-regex@^6.24.1: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz#325c59f902f82f24b74faceed0363954f6495e72" + dependencies: + babel-runtime "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" + +babel-helper-remap-async-to-generator@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz#5ec581827ad723fecdd381f1c928390676e4551b" + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-replace-supers@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a" + dependencies: + babel-helper-optimise-call-expression "^6.24.1" + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helpers@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" + dependencies: + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-messages@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-check-es2015-constants@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-syntax-async-functions@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" + +babel-plugin-syntax-exponentiation-operator@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" + +babel-plugin-syntax-jsx@^6.8.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946" + +babel-plugin-syntax-trailing-function-commas@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" + +babel-plugin-transform-async-to-generator@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761" + dependencies: + babel-helper-remap-async-to-generator "^6.24.1" + babel-plugin-syntax-async-functions "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-arrow-functions@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-block-scoping@^6.23.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f" + dependencies: + babel-runtime "^6.26.0" + babel-template "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" + +babel-plugin-transform-es2015-classes@^6.23.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db" + dependencies: + babel-helper-define-map "^6.24.1" + babel-helper-function-name "^6.24.1" + babel-helper-optimise-call-expression "^6.24.1" + babel-helper-replace-supers "^6.24.1" + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-computed-properties@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3" + dependencies: + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-destructuring@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-duplicate-keys@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-for-of@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-function-name@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b" + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-literals@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015-modules-amd@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154" + dependencies: + babel-plugin-transform-es2015-modules-commonjs "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-es2015-modules-commonjs@^6.24.1, babel-plugin-transform-es2015-modules-commonjs@^6.26.0: + version "6.26.2" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz#58a793863a9e7ca870bdc5a881117ffac27db6f3" + dependencies: + babel-plugin-transform-strict-mode "^6.24.1" + babel-runtime "^6.26.0" + babel-template "^6.26.0" + babel-types "^6.26.0" + +babel-plugin-transform-es2015-modules-systemjs@^6.23.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23" + dependencies: + babel-helper-hoist-variables "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-modules-umd@^6.23.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468" + dependencies: + babel-plugin-transform-es2015-modules-amd "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-object-super@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d" + dependencies: + babel-helper-replace-supers "^6.24.1" + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-parameters@^6.23.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b" + dependencies: + babel-helper-call-delegate "^6.24.1" + babel-helper-get-function-arity "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-shorthand-properties@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-spread@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-sticky-regex@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc" + dependencies: + babel-helper-regex "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-template-literals@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-typeof-symbol@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-unicode-regex@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9" + dependencies: + babel-helper-regex "^6.24.1" + babel-runtime "^6.22.0" + regexpu-core "^2.0.0" + +babel-plugin-transform-exponentiation-operator@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz#2ab0c9c7f3098fa48907772bb813fe41e8de3a0e" + dependencies: + babel-helper-builder-binary-assignment-operator-visitor "^6.24.1" + babel-plugin-syntax-exponentiation-operator "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-react-jsx@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx/-/babel-plugin-transform-react-jsx-6.24.1.tgz#840a028e7df460dfc3a2d29f0c0d91f6376e66a3" + dependencies: + babel-helper-builder-react-jsx "^6.24.1" + babel-plugin-syntax-jsx "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-regenerator@^6.22.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f" + dependencies: + regenerator-transform "^0.10.0" + +babel-plugin-transform-strict-mode@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-preset-env@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.7.0.tgz#dea79fa4ebeb883cd35dab07e260c1c9c04df77a" + dependencies: + babel-plugin-check-es2015-constants "^6.22.0" + babel-plugin-syntax-trailing-function-commas "^6.22.0" + babel-plugin-transform-async-to-generator "^6.22.0" + babel-plugin-transform-es2015-arrow-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoped-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoping "^6.23.0" + babel-plugin-transform-es2015-classes "^6.23.0" + babel-plugin-transform-es2015-computed-properties "^6.22.0" + babel-plugin-transform-es2015-destructuring "^6.23.0" + babel-plugin-transform-es2015-duplicate-keys "^6.22.0" + babel-plugin-transform-es2015-for-of "^6.23.0" + babel-plugin-transform-es2015-function-name "^6.22.0" + babel-plugin-transform-es2015-literals "^6.22.0" + babel-plugin-transform-es2015-modules-amd "^6.22.0" + babel-plugin-transform-es2015-modules-commonjs "^6.23.0" + babel-plugin-transform-es2015-modules-systemjs "^6.23.0" + babel-plugin-transform-es2015-modules-umd "^6.23.0" + babel-plugin-transform-es2015-object-super "^6.22.0" + babel-plugin-transform-es2015-parameters "^6.23.0" + babel-plugin-transform-es2015-shorthand-properties "^6.22.0" + babel-plugin-transform-es2015-spread "^6.22.0" + babel-plugin-transform-es2015-sticky-regex "^6.22.0" + babel-plugin-transform-es2015-template-literals "^6.22.0" + babel-plugin-transform-es2015-typeof-symbol "^6.23.0" + babel-plugin-transform-es2015-unicode-regex "^6.22.0" + babel-plugin-transform-exponentiation-operator "^6.22.0" + babel-plugin-transform-regenerator "^6.22.0" + browserslist "^3.2.6" + invariant "^2.2.2" + semver "^5.3.0" + +babel-register@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" + dependencies: + babel-core "^6.26.0" + babel-runtime "^6.26.0" + core-js "^2.5.0" + home-or-tmp "^2.0.0" + lodash "^4.17.4" + mkdirp "^0.5.1" + source-map-support "^0.4.15" + +babel-runtime@^6.11.6, babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.11.0" + +babel-template@^6.24.1, babel-template@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" + dependencies: + babel-runtime "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + lodash "^4.17.4" + +babel-traverse@^6.24.1, babel-traverse@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" + dependencies: + babel-code-frame "^6.26.0" + babel-messages "^6.23.0" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + debug "^2.6.8" + globals "^9.18.0" + invariant "^2.2.2" + lodash "^4.17.4" + +babel-types@^6.15.0, babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" + dependencies: + babel-runtime "^6.26.0" + esutils "^2.0.2" + lodash "^4.17.4" + to-fast-properties "^1.0.3" + +babylon-walk@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/babylon-walk/-/babylon-walk-1.0.2.tgz#3b15a5ddbb482a78b4ce9c01c8ba181702d9d6ce" + dependencies: + babel-runtime "^6.11.6" + babel-types "^6.15.0" + lodash.clone "^4.5.0" + +babylon@^6.17.4, babylon@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" + +balanced-match@^0.4.2: + version "0.4.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + +base64-js@^1.0.2: + version "1.3.0" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3" + +base@^0.11.1: + version "0.11.2" + resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + dependencies: + cache-base "^1.0.1" + class-utils "^0.3.5" + component-emitter "^1.2.1" + define-property "^1.0.0" + isobject "^3.0.1" + mixin-deep "^1.2.0" + pascalcase "^0.1.1" + +bcrypt-pbkdf@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + dependencies: + tweetnacl "^0.14.3" + +bin-links@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/bin-links/-/bin-links-1.1.2.tgz#fb74bd54bae6b7befc6c6221f25322ac830d9757" + dependencies: + bluebird "^3.5.0" + cmd-shim "^2.0.2" + gentle-fs "^2.0.0" + graceful-fs "^4.1.11" + write-file-atomic "^2.3.0" + +binary-extensions@^1.0.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205" + +bindings@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.2.1.tgz#14ad6113812d2d37d72e67b4cacb4bb726505f11" + +block-stream@*: + version "0.0.9" + resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" + dependencies: + inherits "~2.0.0" + +bluebird@^3.0.5, bluebird@^3.5.0, bluebird@^3.5.1, bluebird@~3.5.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" + +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: + version "4.11.8" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" + +boolbase@^1.0.0, boolbase@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" + +boom@2.x.x: + version "2.10.1" + resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" + dependencies: + hoek "2.x.x" + +boxen@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/boxen/-/boxen-1.3.0.tgz#55c6c39a8ba58d9c61ad22cd877532deb665a20b" + dependencies: + ansi-align "^2.0.0" + camelcase "^4.0.0" + chalk "^2.0.1" + cli-boxes "^1.0.0" + string-width "^2.0.0" + term-size "^1.2.0" + widest-line "^2.0.0" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^2.3.0, braces@^2.3.1: + version "2.3.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + dependencies: + arr-flatten "^1.1.0" + array-unique "^0.3.2" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.0.1" + +brfs@^1.2.0: + version "1.6.1" + resolved "https://registry.yarnpkg.com/brfs/-/brfs-1.6.1.tgz#b78ce2336d818e25eea04a0947cba6d4fb8849c3" + dependencies: + quote-stream "^1.0.1" + resolve "^1.1.5" + static-module "^2.2.0" + through2 "^2.0.0" + +brorand@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + +browser-pack@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/browser-pack/-/browser-pack-6.1.0.tgz#c34ba10d0b9ce162b5af227c7131c92c2ecd5774" + dependencies: + JSONStream "^1.0.3" + combine-source-map "~0.8.0" + defined "^1.0.0" + safe-buffer "^5.1.1" + through2 "^2.0.0" + umd "^3.0.0" + +browser-resolve@^1.11.0, browser-resolve@^1.7.0: + version "1.11.3" + resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.3.tgz#9b7cbb3d0f510e4cb86bdbd796124d28b5890af6" + dependencies: + resolve "1.1.7" + +browserify-aes@^1.0.0, browserify-aes@^1.0.4: + version "1.2.0" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" + dependencies: + buffer-xor "^1.0.3" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.3" + inherits "^2.0.1" + safe-buffer "^5.0.1" + +browserify-cipher@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" + dependencies: + browserify-aes "^1.0.4" + browserify-des "^1.0.0" + evp_bytestokey "^1.0.0" + +browserify-des@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" + dependencies: + cipher-base "^1.0.1" + des.js "^1.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +browserify-rsa@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524" + dependencies: + bn.js "^4.1.0" + randombytes "^2.0.1" + +browserify-sign@^4.0.0: + version "4.0.4" + resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.4.tgz#aa4eb68e5d7b658baa6bf6a57e630cbd7a93d298" + dependencies: + bn.js "^4.1.1" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.2" + elliptic "^6.0.0" + inherits "^2.0.1" + parse-asn1 "^5.0.0" + +browserify-zlib@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" + dependencies: + pako "~1.0.5" + +browserify-zlib@~0.1.2: + version "0.1.4" + resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.1.4.tgz#bb35f8a519f600e0fa6b8485241c979d0141fb2d" + dependencies: + pako "~0.2.0" + +browserify@^13.0.0: + version "13.3.0" + resolved "https://registry.yarnpkg.com/browserify/-/browserify-13.3.0.tgz#b5a9c9020243f0c70e4675bec8223bc627e415ce" + dependencies: + JSONStream "^1.0.3" + assert "^1.4.0" + browser-pack "^6.0.1" + browser-resolve "^1.11.0" + browserify-zlib "~0.1.2" + buffer "^4.1.0" + cached-path-relative "^1.0.0" + concat-stream "~1.5.1" + console-browserify "^1.1.0" + constants-browserify "~1.0.0" + crypto-browserify "^3.0.0" + defined "^1.0.0" + deps-sort "^2.0.0" + domain-browser "~1.1.0" + duplexer2 "~0.1.2" + events "~1.1.0" + glob "^7.1.0" + has "^1.0.0" + htmlescape "^1.1.0" + https-browserify "~0.0.0" + inherits "~2.0.1" + insert-module-globals "^7.0.0" + labeled-stream-splicer "^2.0.0" + module-deps "^4.0.8" + os-browserify "~0.1.1" + parents "^1.0.1" + path-browserify "~0.0.0" + process "~0.11.0" + punycode "^1.3.2" + querystring-es3 "~0.2.0" + read-only-stream "^2.0.0" + readable-stream "^2.0.2" + resolve "^1.1.4" + shasum "^1.0.0" + shell-quote "^1.6.1" + stream-browserify "^2.0.0" + stream-http "^2.0.0" + string_decoder "~0.10.0" + subarg "^1.0.0" + syntax-error "^1.1.1" + through2 "^2.0.0" + timers-browserify "^1.0.1" + tty-browserify "~0.0.0" + url "~0.11.0" + util "~0.10.1" + vm-browserify "~0.0.1" + xtend "^4.0.0" + +browserslist@^1.3.6, browserslist@^1.5.2, browserslist@^1.7.6: + version "1.7.7" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-1.7.7.tgz#0bd76704258be829b2398bb50e4b62d1a166b0b9" + dependencies: + caniuse-db "^1.0.30000639" + electron-to-chromium "^1.2.7" + +browserslist@^3.2.6: + version "3.2.8" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-3.2.8.tgz#b0005361d6471f0f5952797a76fc985f1f978fc6" + dependencies: + caniuse-lite "^1.0.30000844" + electron-to-chromium "^1.3.47" + +browserslist@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.0.1.tgz#61c05ce2a5843c7d96166408bc23d58b5416e818" + dependencies: + caniuse-lite "^1.0.30000865" + electron-to-chromium "^1.3.52" + node-releases "^1.0.0-alpha.10" + +buffer-equal@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/buffer-equal/-/buffer-equal-0.0.1.tgz#91bc74b11ea405bc916bc6aa908faafa5b4aac4b" + +buffer-from@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" + +buffer-xor@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + +buffer@^4.1.0, buffer@^4.3.0: + version "4.9.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + isarray "^1.0.0" + +builtin-modules@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" + +builtin-status-codes@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" + +builtins@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88" + +byline@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/byline/-/byline-5.0.0.tgz#741c5216468eadc457b03410118ad77de8c1ddb1" + +byte-size@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/byte-size/-/byte-size-4.0.3.tgz#b7c095efc68eadf82985fccd9a2df43a74fa2ccd" + +cacache@^10.0.4: + version "10.0.4" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-10.0.4.tgz#6452367999eff9d4188aefd9a14e9d7c6a263460" + dependencies: + bluebird "^3.5.1" + chownr "^1.0.1" + glob "^7.1.2" + graceful-fs "^4.1.11" + lru-cache "^4.1.1" + mississippi "^2.0.0" + mkdirp "^0.5.1" + move-concurrently "^1.0.1" + promise-inflight "^1.0.1" + rimraf "^2.6.2" + ssri "^5.2.4" + unique-filename "^1.1.0" + y18n "^4.0.0" + +cacache@^11.0.1, cacache@^11.0.2, cacache@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-11.1.0.tgz#3d76dbc2e9da413acaad2557051960a4dad3e1a4" + dependencies: + bluebird "^3.5.1" + chownr "^1.0.1" + figgy-pudding "^3.1.0" + glob "^7.1.2" + graceful-fs "^4.1.11" + lru-cache "^4.1.3" + mississippi "^3.0.0" + mkdirp "^0.5.1" + move-concurrently "^1.0.1" + promise-inflight "^1.0.1" + rimraf "^2.6.2" + ssri "^6.0.0" + unique-filename "^1.1.0" + y18n "^4.0.0" + +cache-base@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + dependencies: + collection-visit "^1.0.0" + component-emitter "^1.2.1" + get-value "^2.0.6" + has-value "^1.0.0" + isobject "^3.0.1" + set-value "^2.0.0" + to-object-path "^0.3.0" + union-value "^1.0.0" + unset-value "^1.0.0" + +cached-path-relative@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cached-path-relative/-/cached-path-relative-1.0.1.tgz#d09c4b52800aa4c078e2dd81a869aac90d2e54e7" + +call-limit@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/call-limit/-/call-limit-1.1.0.tgz#6fd61b03f3da42a2cd0ec2b60f02bd0e71991fea" + +call-me-maybe@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b" + +camelcase@^4.0.0, camelcase@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" + +caniuse-api@^1.5.2: + version "1.6.1" + resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-1.6.1.tgz#b534e7c734c4f81ec5fbe8aca2ad24354b962c6c" + dependencies: + browserslist "^1.3.6" + caniuse-db "^1.0.30000529" + lodash.memoize "^4.1.2" + lodash.uniq "^4.5.0" + +caniuse-api@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0" + dependencies: + browserslist "^4.0.0" + caniuse-lite "^1.0.0" + lodash.memoize "^4.1.2" + lodash.uniq "^4.5.0" + +caniuse-db@^1.0.30000529, caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639: + version "1.0.30000872" + resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000872.tgz#3f6e53b63d373768bf99e896133d66ef89c49999" + +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000844, caniuse-lite@^1.0.30000865: + version "1.0.30000865" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000865.tgz#70026616e8afe6e1442f8bb4e1092987d81a2f25" + +capture-stack-trace@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz#4a6fa07399c26bba47f0b2496b4d0fb408c5550d" + +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + +chalk@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.1, chalk@^2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e" + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chokidar@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.4.tgz#356ff4e2b0e8e43e322d18a372460bbcf3accd26" + dependencies: + anymatch "^2.0.0" + async-each "^1.0.0" + braces "^2.3.0" + glob-parent "^3.1.0" + inherits "^2.0.1" + is-binary-path "^1.0.0" + is-glob "^4.0.0" + lodash.debounce "^4.0.8" + normalize-path "^2.1.1" + path-is-absolute "^1.0.0" + readdirp "^2.0.0" + upath "^1.0.5" + optionalDependencies: + fsevents "^1.2.2" + +chownr@^1.0.1, chownr@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" + +ci-info@^1.0.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.1.3.tgz#710193264bb05c77b8c90d02f5aaf22216a667b2" + +cidr-regex@^2.0.8: + version "2.0.9" + resolved "https://registry.yarnpkg.com/cidr-regex/-/cidr-regex-2.0.9.tgz#9c17bb2b18e15af07f7d0c3b994b961d687ed1c9" + dependencies: + ip-regex "^2.1.0" + +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +clap@^1.0.9: + version "1.2.3" + resolved "https://registry.yarnpkg.com/clap/-/clap-1.2.3.tgz#4f36745b32008492557f46412d66d50cb99bce51" + dependencies: + chalk "^1.1.3" + +class-utils@^0.3.5: + version "0.3.6" + resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + +classlist-polyfill@^1.0.3: + version "1.2.0" + resolved "https://registry.yarnpkg.com/classlist-polyfill/-/classlist-polyfill-1.2.0.tgz#935bc2dfd9458a876b279617514638bcaa964a2e" + +cli-boxes@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143" + +cli-columns@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/cli-columns/-/cli-columns-3.1.2.tgz#6732d972979efc2ae444a1f08e08fa139c96a18e" + dependencies: + string-width "^2.0.0" + strip-ansi "^3.0.1" + +cli-cursor@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" + dependencies: + restore-cursor "^2.0.0" + +cli-spinners@^1.1.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-1.3.1.tgz#002c1990912d0d59580c93bd36c056de99e4259a" + +cli-table3@^0.5.0: + version "0.5.1" + resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.5.1.tgz#0252372d94dfc40dbd8df06005f48f31f656f202" + dependencies: + object-assign "^4.1.0" + string-width "^2.1.1" + optionalDependencies: + colors "^1.1.2" + +cliui@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + wrap-ansi "^2.0.0" + +cliui@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" + dependencies: + string-width "^2.1.1" + strip-ansi "^4.0.0" + wrap-ansi "^2.0.0" + +clone@^1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" + +clone@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" + +clones@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/clones/-/clones-1.1.0.tgz#87e904132d6140c5c0b72006c08c0d05bd7b63b3" + +cmd-shim@^2.0.2, cmd-shim@~2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/cmd-shim/-/cmd-shim-2.0.2.tgz#6fcbda99483a8fd15d7d30a196ca69d688a2efdb" + dependencies: + graceful-fs "^4.1.2" + mkdirp "~0.5.0" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + +coa@~1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/coa/-/coa-1.0.4.tgz#a9ef153660d6a86a8bdec0289a5c684d217432fd" + dependencies: + q "^1.1.2" + +coa@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/coa/-/coa-2.0.1.tgz#f3f8b0b15073e35d70263fb1042cb2c023db38af" + dependencies: + q "^1.1.2" + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + +collection-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + dependencies: + map-visit "^1.0.0" + object-visit "^1.0.0" + +color-convert@^1.3.0, color-convert@^1.9.0, color-convert@^1.9.1: + version "1.9.2" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.2.tgz#49881b8fba67df12a96bdf3f56c0aab9e7913147" + dependencies: + color-name "1.1.1" + +color-name@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.1.tgz#4b1415304cf50028ea81643643bd82ea05803689" + +color-name@^1.0.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + +color-string@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-0.3.0.tgz#27d46fb67025c5c2fa25993bfbf579e47841b991" + dependencies: + color-name "^1.0.0" + +color-string@^1.5.2: + version "1.5.3" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.5.3.tgz#c9bbc5f01b58b5492f3d6857459cb6590ce204cc" + dependencies: + color-name "^1.0.0" + simple-swizzle "^0.2.2" + +color@^0.11.0: + version "0.11.4" + resolved "https://registry.yarnpkg.com/color/-/color-0.11.4.tgz#6d7b5c74fb65e841cd48792ad1ed5e07b904d764" + dependencies: + clone "^1.0.2" + color-convert "^1.3.0" + color-string "^0.3.0" + +color@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/color/-/color-3.0.0.tgz#d920b4328d534a3ac8295d68f7bd4ba6c427be9a" + dependencies: + color-convert "^1.9.1" + color-string "^1.5.2" + +colormin@^1.0.5: + version "1.1.2" + resolved "https://registry.yarnpkg.com/colormin/-/colormin-1.1.2.tgz#ea2f7420a72b96881a38aae59ec124a6f7298133" + dependencies: + color "^0.11.0" + css-color-names "0.0.4" + has "^1.0.1" + +colors@^1.1.2: + version "1.3.1" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.3.1.tgz#4accdb89cf2cabc7f982771925e9468784f32f3d" + +colors@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" + +columnify@~1.5.4: + version "1.5.4" + resolved "https://registry.yarnpkg.com/columnify/-/columnify-1.5.4.tgz#4737ddf1c7b69a8a7c340570782e947eec8e78bb" + dependencies: + strip-ansi "^3.0.0" + wcwidth "^1.0.0" + +combine-source-map@^0.8.0, combine-source-map@~0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/combine-source-map/-/combine-source-map-0.8.0.tgz#a58d0df042c186fcf822a8e8015f5450d2d79a8b" + dependencies: + convert-source-map "~1.1.0" + inline-source-map "~0.6.0" + lodash.memoize "~3.0.3" + source-map "~0.5.3" + +combined-stream@1.0.6, combined-stream@^1.0.5, combined-stream@~1.0.5: + version "1.0.6" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.6.tgz#723e7df6e801ac5613113a7e445a9b69cb632818" + dependencies: + delayed-stream "~1.0.0" + +command-exists@^1.2.6: + version "1.2.7" + resolved "https://registry.yarnpkg.com/command-exists/-/command-exists-1.2.7.tgz#16828f0c3ff2b0c58805861ef211b64fc15692a8" + +commander@^2.11.0, commander@^2.9.0, commander@~2.16.0: + version "2.16.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.16.0.tgz#f16390593996ceb4f3eeb020b31d78528f7f8a50" + +commander@~2.14.1: + version "2.14.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.14.1.tgz#2235123e37af8ca3c65df45b026dbd357b01b9aa" + +component-emitter@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + +concat-stream@^1.5.0, concat-stream@^1.5.2, concat-stream@^1.6.1, concat-stream@~1.6.0: + version "1.6.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + dependencies: + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + +concat-stream@~1.5.0, concat-stream@~1.5.1: + version "1.5.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.5.2.tgz#708978624d856af41a5a741defdd261da752c266" + dependencies: + inherits "~2.0.1" + readable-stream "~2.0.0" + typedarray "~0.0.5" + +config-chain@~1.1.11, config-chain@~1.1.5: + version "1.1.11" + resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.11.tgz#aba09747dfbe4c3e70e766a6e41586e1859fc6f2" + dependencies: + ini "^1.3.4" + proto-list "~1.2.1" + +configstore@^3.0.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/configstore/-/configstore-3.1.2.tgz#c6f25defaeef26df12dd33414b001fe81a543f8f" + dependencies: + dot-prop "^4.1.0" + graceful-fs "^4.1.2" + make-dir "^1.0.0" + unique-string "^1.0.0" + write-file-atomic "^2.0.0" + xdg-basedir "^3.0.0" + +console-browserify@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" + dependencies: + date-now "^0.1.4" + +console-control-strings@^1.0.0, console-control-strings@^1.1.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + +constants-browserify@^1.0.0, constants-browserify@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" + +convert-source-map@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5" + +convert-source-map@~1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.1.3.tgz#4829c877e9fe49b3161f3bf3673888e204699860" + +copy-concurrently@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0" + dependencies: + aproba "^1.1.1" + fs-write-stream-atomic "^1.0.8" + iferr "^0.1.5" + mkdirp "^0.5.1" + rimraf "^2.5.4" + run-queue "^1.0.0" + +copy-descriptor@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + +core-js@^2.4.0, core-js@^2.5.0: + version "2.5.7" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e" + +core-util-is@1.0.2, core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + +cosmiconfig@^5.0.0: + version "5.0.5" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.0.5.tgz#a809e3c2306891ce17ab70359dc8bdf661fe2cd0" + dependencies: + is-directory "^0.3.1" + js-yaml "^3.9.0" + parse-json "^4.0.0" + +create-ecdh@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff" + dependencies: + bn.js "^4.1.0" + elliptic "^6.0.0" + +create-error-class@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/create-error-class/-/create-error-class-3.0.2.tgz#06be7abef947a3f14a30fd610671d401bca8b7b6" + dependencies: + capture-stack-trace "^1.0.0" + +create-hash@^1.1.0, create-hash@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + md5.js "^1.3.4" + ripemd160 "^2.0.1" + sha.js "^2.4.0" + +create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: + version "1.1.7" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +cross-spawn@^5.0.1: + version "5.1.0" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" + dependencies: + lru-cache "^4.0.1" + shebang-command "^1.2.0" + which "^1.2.9" + +cross-spawn@^6.0.4: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + +cryptiles@2.x.x: + version "2.0.5" + resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" + dependencies: + boom "2.x.x" + +crypto-browserify@^3.0.0, crypto-browserify@^3.11.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" + dependencies: + browserify-cipher "^1.0.0" + browserify-sign "^4.0.0" + create-ecdh "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.0" + diffie-hellman "^5.0.0" + inherits "^2.0.1" + pbkdf2 "^3.0.3" + public-encrypt "^4.0.0" + randombytes "^2.0.0" + randomfill "^1.0.3" + +crypto-random-string@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" + +css-color-names@0.0.4, css-color-names@^0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0" + +css-declaration-sorter@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-3.0.1.tgz#d0e3056b0fd88dc1ea9dceff435adbe9c702a7f8" + dependencies: + postcss "^6.0.0" + timsort "^0.3.0" + +css-select-base-adapter@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/css-select-base-adapter/-/css-select-base-adapter-0.1.0.tgz#0102b3d14630df86c3eb9fa9f5456270106cf990" + +css-select@~1.3.0-rc0: + version "1.3.0-rc0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.3.0-rc0.tgz#6f93196aaae737666ea1036a8cb14a8fcb7a9231" + dependencies: + boolbase "^1.0.0" + css-what "2.1" + domutils "1.5.1" + nth-check "^1.0.1" + +css-tree@1.0.0-alpha.29: + version "1.0.0-alpha.29" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.29.tgz#3fa9d4ef3142cbd1c301e7664c1f352bd82f5a39" + dependencies: + mdn-data "~1.1.0" + source-map "^0.5.3" + +css-tree@1.0.0-alpha25: + version "1.0.0-alpha25" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha25.tgz#1bbfabfbf6eeef4f01d9108ff2edd0be2fe35597" + dependencies: + mdn-data "^1.0.0" + source-map "^0.5.3" + +css-unit-converter@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/css-unit-converter/-/css-unit-converter-1.1.1.tgz#d9b9281adcfd8ced935bdbaba83786897f64e996" + +css-url-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/css-url-regex/-/css-url-regex-1.1.0.tgz#83834230cc9f74c457de59eebd1543feeb83b7ec" + +css-what@2.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.0.tgz#9467d032c38cfaefb9f2d79501253062f87fa1bd" + +cssnano-preset-default@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-4.0.0.tgz#c334287b4f7d49fb2d170a92f9214655788e3b6b" + dependencies: + css-declaration-sorter "^3.0.0" + cssnano-util-raw-cache "^4.0.0" + postcss "^6.0.0" + postcss-calc "^6.0.0" + postcss-colormin "^4.0.0" + postcss-convert-values "^4.0.0" + postcss-discard-comments "^4.0.0" + postcss-discard-duplicates "^4.0.0" + postcss-discard-empty "^4.0.0" + postcss-discard-overridden "^4.0.0" + postcss-merge-longhand "^4.0.0" + postcss-merge-rules "^4.0.0" + postcss-minify-font-values "^4.0.0" + postcss-minify-gradients "^4.0.0" + postcss-minify-params "^4.0.0" + postcss-minify-selectors "^4.0.0" + postcss-normalize-charset "^4.0.0" + postcss-normalize-display-values "^4.0.0" + postcss-normalize-positions "^4.0.0" + postcss-normalize-repeat-style "^4.0.0" + postcss-normalize-string "^4.0.0" + postcss-normalize-timing-functions "^4.0.0" + postcss-normalize-unicode "^4.0.0" + postcss-normalize-url "^4.0.0" + postcss-normalize-whitespace "^4.0.0" + postcss-ordered-values "^4.0.0" + postcss-reduce-initial "^4.0.0" + postcss-reduce-transforms "^4.0.0" + postcss-svgo "^4.0.0" + postcss-unique-selectors "^4.0.0" + +cssnano-util-get-arguments@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz#ed3a08299f21d75741b20f3b81f194ed49cc150f" + +cssnano-util-get-match@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz#c0e4ca07f5386bb17ec5e52250b4f5961365156d" + +cssnano-util-raw-cache@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.0.tgz#be0a2856e25f185f5f7a2bcc0624e28b7f179a9f" + dependencies: + postcss "^6.0.0" + +cssnano-util-same-parent@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.0.tgz#d2a3de1039aa98bc4ec25001fa050330c2a16dac" + +cssnano@^3.4.0: + version "3.10.0" + resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-3.10.0.tgz#4f38f6cea2b9b17fa01490f23f1dc68ea65c1c38" + dependencies: + autoprefixer "^6.3.1" + decamelize "^1.1.2" + defined "^1.0.0" + has "^1.0.1" + object-assign "^4.0.1" + postcss "^5.0.14" + postcss-calc "^5.2.0" + postcss-colormin "^2.1.8" + postcss-convert-values "^2.3.4" + postcss-discard-comments "^2.0.4" + postcss-discard-duplicates "^2.0.1" + postcss-discard-empty "^2.0.1" + postcss-discard-overridden "^0.1.1" + postcss-discard-unused "^2.2.1" + postcss-filter-plugins "^2.0.0" + postcss-merge-idents "^2.1.5" + postcss-merge-longhand "^2.0.1" + postcss-merge-rules "^2.0.3" + postcss-minify-font-values "^1.0.2" + postcss-minify-gradients "^1.0.1" + postcss-minify-params "^1.0.4" + postcss-minify-selectors "^2.0.4" + postcss-normalize-charset "^1.1.0" + postcss-normalize-url "^3.0.7" + postcss-ordered-values "^2.1.0" + postcss-reduce-idents "^2.2.2" + postcss-reduce-initial "^1.0.0" + postcss-reduce-transforms "^1.0.3" + postcss-svgo "^2.1.1" + postcss-unique-selectors "^2.0.2" + postcss-value-parser "^3.2.3" + postcss-zindex "^2.0.1" + +cssnano@^4.0.0: + version "4.0.5" + resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-4.0.5.tgz#8789b5fdbe7be05d8a0f7e45c4c789ebe712f5aa" + dependencies: + cosmiconfig "^5.0.0" + cssnano-preset-default "^4.0.0" + is-resolvable "^1.0.0" + postcss "^6.0.0" + +csso@^3.5.0: + version "3.5.1" + resolved "https://registry.yarnpkg.com/csso/-/csso-3.5.1.tgz#7b9eb8be61628973c1b261e169d2f024008e758b" + dependencies: + css-tree "1.0.0-alpha.29" + +csso@~2.3.1: + version "2.3.2" + resolved "https://registry.yarnpkg.com/csso/-/csso-2.3.2.tgz#ddd52c587033f49e94b71fc55569f252e8ff5f85" + dependencies: + clap "^1.0.9" + source-map "^0.5.3" + +cyclist@~0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640" + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + dependencies: + assert-plus "^1.0.0" + +date-now@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" + +deasync@^0.1.13: + version "0.1.13" + resolved "https://registry.yarnpkg.com/deasync/-/deasync-0.1.13.tgz#815c2b69bbd1117cae570152cd895661c09f20ea" + dependencies: + bindings "~1.2.1" + nan "^2.0.7" + +debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + dependencies: + ms "2.0.0" + +debug@3.1.0, debug@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + dependencies: + ms "2.0.0" + +debuglog@*, debuglog@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" + +decamelize@^1.1.1, decamelize@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + +deep-extend@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + +deep-is@~0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + +defaults@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" + dependencies: + clone "^1.0.2" + +define-properties@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94" + dependencies: + foreach "^2.0.5" + object-keys "^1.0.8" + +define-property@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + dependencies: + is-descriptor "^1.0.0" + +define-property@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" + +defined@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + +deps-sort@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/deps-sort/-/deps-sort-2.0.0.tgz#091724902e84658260eb910748cccd1af6e21fb5" + dependencies: + JSONStream "^1.0.3" + shasum "^1.0.0" + subarg "^1.0.0" + through2 "^2.0.0" + +des.js@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc" + dependencies: + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + +detect-indent@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" + dependencies: + repeating "^2.0.0" + +detect-indent@~5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-5.0.0.tgz#3871cc0a6a002e8c3e5b3cf7f336264675f06b9d" + +detect-libc@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + +detect-newline@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-2.1.0.tgz#f41f1c10be4b00e87b5f13da680759f2c5bfd3e2" + +detective@^4.0.0: + version "4.7.1" + resolved "https://registry.yarnpkg.com/detective/-/detective-4.7.1.tgz#0eca7314338442febb6d65da54c10bb1c82b246e" + dependencies: + acorn "^5.2.1" + defined "^1.0.0" + +dezalgo@^1.0.0, dezalgo@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456" + dependencies: + asap "^2.0.0" + wrappy "1" + +diffie-hellman@^5.0.0: + version "5.0.3" + resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" + dependencies: + bn.js "^4.1.0" + miller-rabin "^4.0.0" + randombytes "^2.0.0" + +dom-serializer@0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82" + dependencies: + domelementtype "~1.1.1" + entities "~1.1.1" + +domain-browser@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" + +domain-browser@~1.1.0: + version "1.1.7" + resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.1.7.tgz#867aa4b093faa05f1de08c06f4d7b21fdf8698bc" + +domelementtype@1, domelementtype@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.0.tgz#b17aed82e8ab59e52dd9c19b1756e0fc187204c2" + +domelementtype@~1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.1.3.tgz#bd28773e2642881aec51544924299c5cd822185b" + +domhandler@^2.3.0: + version "2.4.2" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.2.tgz#8805097e933d65e85546f726d60f5eb88b44f803" + dependencies: + domelementtype "1" + +domready@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/domready/-/domready-1.0.8.tgz#91f252e597b65af77e745ae24dd0185d5e26d58c" + +domutils@1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf" + dependencies: + dom-serializer "0" + domelementtype "1" + +domutils@^1.5.1: + version "1.7.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" + dependencies: + dom-serializer "0" + domelementtype "1" + +dot-prop@^4.1.0, dot-prop@^4.1.1: + version "4.2.0" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57" + dependencies: + is-obj "^1.0.0" + +dotenv@^5.0.0, dotenv@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-5.0.1.tgz#a5317459bd3d79ab88cff6e44057a6a3fbb1fcef" + +duplexer2@^0.1.2, duplexer2@~0.1.0, duplexer2@~0.1.2, duplexer2@~0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1" + dependencies: + readable-stream "^2.0.2" + +duplexer3@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" + +duplexify@^3.4.2, duplexify@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.6.0.tgz#592903f5d80b38d037220541264d69a198fb3410" + dependencies: + end-of-stream "^1.0.0" + inherits "^2.0.1" + readable-stream "^2.0.0" + stream-shift "^1.0.0" + +ecc-jsbn@~0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" + dependencies: + jsbn "~0.1.0" + safer-buffer "^2.1.0" + +editor@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/editor/-/editor-1.0.0.tgz#60c7f87bd62bcc6a894fa8ccd6afb7823a24f742" + +editorconfig@^0.13.2: + version "0.13.3" + resolved "https://registry.yarnpkg.com/editorconfig/-/editorconfig-0.13.3.tgz#e5219e587951d60958fd94ea9a9a008cdeff1b34" + dependencies: + bluebird "^3.0.5" + commander "^2.9.0" + lru-cache "^3.2.0" + semver "^5.1.0" + sigmund "^1.0.1" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + +electron-to-chromium@^1.2.7, electron-to-chromium@^1.3.47, electron-to-chromium@^1.3.52: + version "1.3.55" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.55.tgz#f150e10b20b77d9d41afcca312efe0c3b1a7fdce" + +elem-dataset@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/elem-dataset/-/elem-dataset-1.1.1.tgz#18f07fa7fc71ebd49b0f9f63819cb03c8276577a" + +element-closest@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/element-closest/-/element-closest-2.0.2.tgz#72a740a107453382e28df9ce5dbb5a8df0f966ec" + +elliptic@^6.0.0: + version "6.4.0" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.0.tgz#cac9af8762c85836187003c8dfe193e5e2eae5df" + dependencies: + bn.js "^4.4.0" + brorand "^1.0.1" + hash.js "^1.0.0" + hmac-drbg "^1.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.0" + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + +encoding@^0.1.11: + version "0.1.12" + resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" + dependencies: + iconv-lite "~0.4.13" + +end-of-stream@^1.0.0, end-of-stream@^1.1.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" + dependencies: + once "^1.4.0" + +entities@^1.1.1, entities@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" + +err-code@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/err-code/-/err-code-1.1.2.tgz#06e0116d3028f6aef4806849eb0ea6a748ae6960" + +errno@~0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618" + dependencies: + prr "~1.0.1" + +error-ex@^1.2.0, error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + dependencies: + is-arrayish "^0.2.1" + +es-abstract@^1.5.1, es-abstract@^1.6.1: + version "1.12.0" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.12.0.tgz#9dbbdd27c6856f0001421ca18782d786bf8a6165" + dependencies: + es-to-primitive "^1.1.1" + function-bind "^1.1.1" + has "^1.0.1" + is-callable "^1.1.3" + is-regex "^1.0.4" + +es-to-primitive@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.1.1.tgz#45355248a88979034b6792e19bb81f2b7975dd0d" + dependencies: + is-callable "^1.1.1" + is-date-object "^1.0.1" + is-symbol "^1.0.1" + +es6-promise@^4.0.3: + version "4.2.4" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.4.tgz#dc4221c2b16518760bd8c39a52d8f356fc00ed29" + +es6-promisify@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" + dependencies: + es6-promise "^4.0.3" + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + +escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + +escodegen@^1.8.1: + version "1.11.0" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.11.0.tgz#b27a9389481d5bfd5bec76f7bb1eb3f8f4556589" + dependencies: + esprima "^3.1.3" + estraverse "^4.2.0" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.6.1" + +escodegen@~1.9.0: + version "1.9.1" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.9.1.tgz#dbae17ef96c8e4bedb1356f4504fa4cc2f7cb7e2" + dependencies: + esprima "^3.1.3" + estraverse "^4.2.0" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.6.1" + +esprima@^2.6.0: + version "2.7.3" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" + +esprima@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + +estraverse@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" + +esutils@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + +events@^1.0.0, events@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" + +evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" + dependencies: + md5.js "^1.3.4" + safe-buffer "^5.1.1" + +execa@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" + dependencies: + cross-spawn "^5.0.1" + get-stream "^3.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +expand-brackets@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + dependencies: + debug "^2.3.3" + define-property "^0.2.5" + extend-shallow "^2.0.1" + posix-character-classes "^0.1.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + dependencies: + is-extendable "^0.1.0" + +extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + +extend@~3.0.0, extend@~3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + +extglob@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + dependencies: + array-unique "^0.3.2" + define-property "^1.0.0" + expand-brackets "^2.1.4" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + +extsprintf@^1.2.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" + +falafel@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/falafel/-/falafel-2.1.0.tgz#96bb17761daba94f46d001738b3cedf3a67fe06c" + dependencies: + acorn "^5.0.0" + foreach "^2.0.5" + isarray "0.0.1" + object-keys "^1.0.6" + +fast-deep-equal@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" + +fast-glob@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.2.tgz#71723338ac9b4e0e2fff1d6748a2a13d5ed352bf" + dependencies: + "@mrmlnc/readdir-enhanced" "^2.2.1" + "@nodelib/fs.stat" "^1.0.1" + glob-parent "^3.1.0" + is-glob "^4.0.0" + merge2 "^1.2.1" + micromatch "^3.1.10" + +fast-json-stable-stringify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" + +fast-levenshtein@~2.0.4: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + +figgy-pudding@^3.0.0, figgy-pudding@^3.1.0, figgy-pudding@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.2.0.tgz#464626b73d7b0fc045a99753d191b0785957ff73" + +filesize@^3.6.0: + version "3.6.1" + resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.6.1.tgz#090bb3ee01b6f801a8a8be99d31710b3422bb317" + +fill-range@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + +find-npm-prefix@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/find-npm-prefix/-/find-npm-prefix-1.0.2.tgz#8d8ce2c78b3b4b9e66c8acc6a37c231eb841cfdf" + +find-up@^2.0.0, find-up@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + dependencies: + locate-path "^2.0.0" + +flatten@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782" + +flush-write-stream@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.0.3.tgz#c5d586ef38af6097650b49bc41b55fabb19f35bd" + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.4" + +for-in@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + +foreach@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + +form-data@~2.1.1: + version "2.1.4" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1" + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.5" + mime-types "^2.1.12" + +form-data@~2.3.1: + version "2.3.2" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.2.tgz#4970498be604c20c005d4f5c23aecd21d6b49099" + dependencies: + asynckit "^0.4.0" + combined-stream "1.0.6" + mime-types "^2.1.12" + +fragment-cache@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + dependencies: + map-cache "^0.2.2" + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + +from2@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/from2/-/from2-1.3.0.tgz#88413baaa5f9a597cfde9221d86986cd3c061dfd" + dependencies: + inherits "~2.0.1" + readable-stream "~1.1.10" + +from2@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.0" + +fs-minipass@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d" + dependencies: + minipass "^2.2.1" + +fs-vacuum@^1.2.10, fs-vacuum@~1.2.10: + version "1.2.10" + resolved "https://registry.yarnpkg.com/fs-vacuum/-/fs-vacuum-1.2.10.tgz#b7629bec07a4031a2548fdf99f5ecf1cc8b31e36" + dependencies: + graceful-fs "^4.1.2" + path-is-inside "^1.0.1" + rimraf "^2.5.2" + +fs-write-stream-atomic@^1.0.8, fs-write-stream-atomic@~1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" + dependencies: + graceful-fs "^4.1.2" + iferr "^0.1.5" + imurmurhash "^0.1.4" + readable-stream "1 || 2" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + +fsevents@^1.2.2: + version "1.2.4" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.4.tgz#f41dcb1af2582af3692da36fc55cbd8e1041c426" + dependencies: + nan "^2.9.2" + node-pre-gyp "^0.10.0" + +fstream@^1.0.0, fstream@^1.0.2: + version "1.0.11" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" + dependencies: + graceful-fs "^4.1.2" + inherits "~2.0.0" + mkdirp ">=0.5 0" + rimraf "2" + +fswatcher-child@^1.0.3: + version "1.0.5" + resolved "https://registry.yarnpkg.com/fswatcher-child/-/fswatcher-child-1.0.5.tgz#134d012ffa74918975617e00e56e4139f36cb140" + dependencies: + chokidar "^2.0.3" + +function-bind@^1.1.0, function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + +gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + +genfun@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/genfun/-/genfun-4.0.1.tgz#ed10041f2e4a7f1b0a38466d17a5c3e27df1dfc1" + +gentle-fs@^2.0.0, gentle-fs@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/gentle-fs/-/gentle-fs-2.0.1.tgz#585cfd612bfc5cd52471fdb42537f016a5ce3687" + dependencies: + aproba "^1.1.2" + fs-vacuum "^1.2.10" + graceful-fs "^4.1.11" + iferr "^0.1.5" + mkdirp "^0.5.1" + path-is-inside "^1.0.2" + read-cmd-shim "^1.0.1" + slide "^1.1.6" + +get-assigned-identifiers@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/get-assigned-identifiers/-/get-assigned-identifiers-1.2.0.tgz#6dbf411de648cbaf8d9169ebb0d2d576191e2ff1" + +get-caller-file@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" + +get-port@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/get-port/-/get-port-3.2.0.tgz#dd7ce7de187c06c8bf353796ac71e099f0980ebc" + +get-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + +get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + dependencies: + assert-plus "^1.0.0" + +glob-parent@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" + dependencies: + is-glob "^3.1.0" + path-dirname "^1.0.0" + +glob-to-regexp@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab" + +glob@^7.0.3, glob@^7.0.5, glob@^7.1.0, glob@^7.1.1, glob@^7.1.2, glob@~7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +global-dirs@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445" + dependencies: + ini "^1.3.4" + +globals@^9.18.0: + version "9.18.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" + +got@^6.7.1: + version "6.7.1" + resolved "https://registry.yarnpkg.com/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0" + dependencies: + create-error-class "^3.0.0" + duplexer3 "^0.1.4" + get-stream "^3.0.0" + is-redirect "^1.0.0" + is-retry-allowed "^1.0.0" + is-stream "^1.0.0" + lowercase-keys "^1.0.0" + safe-buffer "^5.0.1" + timed-out "^4.0.0" + unzip-response "^2.0.1" + url-parse-lax "^1.0.0" + +graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@~4.1.11: + version "4.1.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" + +grapheme-breaker@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/grapheme-breaker/-/grapheme-breaker-0.3.2.tgz#5b9e6b78c3832452d2ba2bb1cb830f96276410ac" + dependencies: + brfs "^1.2.0" + unicode-trie "^0.3.1" + +har-schema@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e" + +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + +har-validator@~4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a" + dependencies: + ajv "^4.9.1" + har-schema "^1.0.5" + +har-validator@~5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.0.3.tgz#ba402c266194f15956ef15e0fcf242993f6a7dfd" + dependencies: + ajv "^5.1.0" + har-schema "^2.0.0" + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + dependencies: + ansi-regex "^2.0.0" + +has-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + +has-unicode@^2.0.0, has-unicode@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + +has-value@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + dependencies: + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" + +has-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + dependencies: + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + +has-values@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + +has-values@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + +has@^1.0.0, has@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + dependencies: + function-bind "^1.1.1" + +hash-base@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918" + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +hash.js@^1.0.0, hash.js@^1.0.3: + version "1.1.5" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.5.tgz#e38ab4b85dfb1e0c40fe9265c0e9b54854c23812" + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + +hawk@~3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" + dependencies: + boom "2.x.x" + cryptiles "2.x.x" + hoek "2.x.x" + sntp "1.x.x" + +hex-color-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e" + +hmac-drbg@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + +hoek@2.x.x: + version "2.16.3" + resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" + +home-or-tmp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.1" + +hosted-git-info@^2.1.4, hosted-git-info@^2.6.0: + version "2.7.1" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047" + +hsl-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/hsl-regex/-/hsl-regex-1.0.0.tgz#d49330c789ed819e276a4c0d272dffa30b18fe6e" + +hsla-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/hsla-regex/-/hsla-regex-1.0.0.tgz#c1ce7a3168c8c6614033a4b5f7877f3b225f9c38" + +html-comment-regex@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.1.tgz#668b93776eaae55ebde8f3ad464b307a4963625e" + +htmlescape@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/htmlescape/-/htmlescape-1.1.1.tgz#3a03edc2214bca3b66424a3e7959349509cb0351" + +htmlnano@^0.1.9: + version "0.1.9" + resolved "https://registry.yarnpkg.com/htmlnano/-/htmlnano-0.1.9.tgz#e6137aea84d20311a3875c42eb2799a1ff352627" + dependencies: + cssnano "^3.4.0" + object-assign "^4.0.1" + posthtml "^0.11.3" + posthtml-render "^1.1.3" + svgo "^1.0.5" + uglify-es "^3.3.9" + +htmlparser2@^3.9.2: + version "3.9.2" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.9.2.tgz#1bdf87acca0f3f9e53fa4fcceb0f4b4cbb00b338" + dependencies: + domelementtype "^1.3.0" + domhandler "^2.3.0" + domutils "^1.5.1" + entities "^1.1.1" + inherits "^2.0.1" + readable-stream "^2.0.2" + +http-cache-semantics@^3.8.1: + version "3.8.1" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" + +http-errors@~1.6.2: + version "1.6.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.0" + statuses ">= 1.4.0 < 2" + +http-proxy-agent@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz#e4821beef5b2142a2026bd73926fe537631c5405" + dependencies: + agent-base "4" + debug "3.1.0" + +http-signature@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" + dependencies: + assert-plus "^0.2.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + dependencies: + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +https-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" + +https-browserify@~0.0.0: + version "0.0.1" + resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-0.0.1.tgz#3f91365cabe60b77ed0ebba24b454e3e09d95a82" + +https-proxy-agent@^2.2.0, https-proxy-agent@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz#51552970fa04d723e04c56d04178c3f92592bbc0" + dependencies: + agent-base "^4.1.0" + debug "^3.1.0" + +humanize-ms@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" + dependencies: + ms "^2.0.0" + +iconv-lite@^0.4.4, iconv-lite@~0.4.13: + version "0.4.23" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" + dependencies: + safer-buffer ">= 2.1.2 < 3" + +ieee754@^1.1.4: + version "1.1.12" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.12.tgz#50bf24e5b9c8bb98af4964c941cdb0918da7b60b" + +iferr@^0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" + +iferr@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/iferr/-/iferr-1.0.2.tgz#e9fde49a9da06dc4a4194c6c9ed6d08305037a6d" + +ignore-walk@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8" + dependencies: + minimatch "^3.0.4" + +import-lazy@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" + +imurmurhash@*, imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + +indexes-of@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607" + +indexof@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" + +inflight@^1.0.4, inflight@~1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + +inherits@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" + +ini@^1.3.4, ini@^1.3.5, ini@~1.3.0: + version "1.3.5" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" + +init-package-json@^1.10.3: + version "1.10.3" + resolved "https://registry.yarnpkg.com/init-package-json/-/init-package-json-1.10.3.tgz#45ffe2f610a8ca134f2bd1db5637b235070f6cbe" + dependencies: + glob "^7.1.1" + npm-package-arg "^4.0.0 || ^5.0.0 || ^6.0.0" + promzard "^0.3.0" + read "~1.0.1" + read-package-json "1 || 2" + semver "2.x || 3.x || 4 || 5" + validate-npm-package-license "^3.0.1" + validate-npm-package-name "^3.0.0" + +inline-source-map@~0.6.0: + version "0.6.2" + resolved "https://registry.yarnpkg.com/inline-source-map/-/inline-source-map-0.6.2.tgz#f9393471c18a79d1724f863fa38b586370ade2a5" + dependencies: + source-map "~0.5.3" + +insert-module-globals@^7.0.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/insert-module-globals/-/insert-module-globals-7.2.0.tgz#ec87e5b42728479e327bd5c5c71611ddfb4752ba" + dependencies: + JSONStream "^1.0.3" + acorn-node "^1.5.2" + combine-source-map "^0.8.0" + concat-stream "^1.6.1" + is-buffer "^1.1.0" + path-is-absolute "^1.0.1" + process "~0.11.0" + through2 "^2.0.0" + undeclared-identifiers "^1.1.2" + xtend "^4.0.0" + +invariant@^2.2.2: + version "2.2.4" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" + dependencies: + loose-envify "^1.0.0" + +invert-kv@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" + +ip-regex@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" + +ip@^1.1.4, ip@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" + +is-absolute-url@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.1.0.tgz#50530dfb84fcc9aa7dbe7852e83a37b93b9f2aa6" + +is-accessor-descriptor@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + dependencies: + kind-of "^3.0.2" + +is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + dependencies: + kind-of "^6.0.0" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + +is-arrayish@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" + +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + dependencies: + binary-extensions "^1.0.0" + +is-buffer@^1.1.0, is-buffer@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + +is-builtin-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" + dependencies: + builtin-modules "^1.0.0" + +is-callable@^1.1.1, is-callable@^1.1.3: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" + +is-ci@^1.0.10: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.1.0.tgz#247e4162e7860cebbdaf30b774d6b0ac7dcfe7a5" + dependencies: + ci-info "^1.0.0" + +is-cidr@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/is-cidr/-/is-cidr-2.0.6.tgz#4b01c9693d8e18399dacd18a4f3d60ea5871ac60" + dependencies: + cidr-regex "^2.0.8" + +is-color-stop@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-color-stop/-/is-color-stop-1.1.0.tgz#cfff471aee4dd5c9e158598fbe12967b5cdad345" + dependencies: + css-color-names "^0.0.4" + hex-color-regex "^1.1.0" + hsl-regex "^1.0.0" + hsla-regex "^1.0.0" + rgb-regex "^1.0.1" + rgba-regex "^1.0.0" + +is-data-descriptor@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + dependencies: + kind-of "^3.0.2" + +is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + dependencies: + kind-of "^6.0.0" + +is-date-object@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" + +is-descriptor@^0.1.0: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + +is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + +is-directory@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" + +is-extendable@^0.1.0, is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + +is-extendable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + dependencies: + is-plain-object "^2.0.4" + +is-extglob@^2.1.0, is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + +is-finite@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + +is-glob@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" + dependencies: + is-extglob "^2.1.0" + +is-glob@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.0.tgz#9521c76845cc2610a85203ddf080a958c2ffabc0" + dependencies: + is-extglob "^2.1.1" + +is-installed-globally@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.1.0.tgz#0dfd98f5a9111716dd535dda6492f67bf3d25a80" + dependencies: + global-dirs "^0.1.0" + is-path-inside "^1.0.0" + +is-npm@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-1.0.0.tgz#f2fb63a65e4905b406c86072765a1a4dc793b9f4" + +is-number@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + dependencies: + kind-of "^3.0.2" + +is-obj@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" + +is-path-inside@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" + dependencies: + path-is-inside "^1.0.1" + +is-plain-obj@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" + +is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + dependencies: + isobject "^3.0.1" + +is-redirect@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24" + +is-regex@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" + dependencies: + has "^1.0.1" + +is-resolvable@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" + +is-retry-allowed@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34" + +is-stream@^1.0.0, is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + +is-svg@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-svg/-/is-svg-2.1.0.tgz#cf61090da0d9efbcab8722deba6f032208dbb0e9" + dependencies: + html-comment-regex "^1.1.0" + +is-svg@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-svg/-/is-svg-3.0.0.tgz#9321dbd29c212e5ca99c4fa9794c714bcafa2f75" + dependencies: + html-comment-regex "^1.1.0" + +is-symbol@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.1.tgz#3cc59f00025194b6ab2e38dbae6689256b660572" + +is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + +is-url@^1.2.2: + version "1.2.4" + resolved "https://registry.yarnpkg.com/is-url/-/is-url-1.2.4.tgz#04a4df46d28c4cff3d73d01ff06abeb318a1aa52" + +is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + +is-wsl@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" + +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + +isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + +isarray@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.4.tgz#38e7bcbb0f3ba1b7933c86ba1894ddfc3781bbb7" + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + +isobject@^2.0.0, isobject@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + dependencies: + isarray "1.0.0" + +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + +js-base64@^2.1.9: + version "2.4.8" + resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.4.8.tgz#57a9b130888f956834aa40c5b165ba59c758f033" + +js-beautify@^1.7.5: + version "1.7.5" + resolved "https://registry.yarnpkg.com/js-beautify/-/js-beautify-1.7.5.tgz#69d9651ef60dbb649f65527b53674950138a7919" + dependencies: + config-chain "~1.1.5" + editorconfig "^0.13.2" + mkdirp "~0.5.0" + nopt "~3.0.1" + +"js-tokens@^3.0.0 || ^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + +js-tokens@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" + +js-yaml@^3.10.0, js-yaml@^3.9.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1" + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +js-yaml@~3.10.0: + version "3.10.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.10.0.tgz#2e78441646bd4682e963f22b6e92823c309c62dc" + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +js-yaml@~3.7.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.7.0.tgz#5c967ddd837a9bfdca5f2de84253abe8a1c03b80" + dependencies: + argparse "^1.0.7" + esprima "^2.6.0" + +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + +jsesc@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + +json-parse-better-errors@^1.0.0, json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" + +json-schema-traverse@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" + +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + +json-stable-stringify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" + dependencies: + jsonify "~0.0.0" + +json-stable-stringify@~0.0.0: + version "0.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-0.0.1.tgz#611c23e814db375527df851193db59dd2af27f45" + dependencies: + jsonify "~0.0.0" + +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + +json5@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" + +json5@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" + dependencies: + minimist "^1.2.0" + +jsonify@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" + +jsonparse@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" + +jsprim@^1.2.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.2.3" + verror "1.10.0" + +keyboardevent-key-polyfill@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/keyboardevent-key-polyfill/-/keyboardevent-key-polyfill-1.1.0.tgz#8a319d8e45a13172fca56286372f90c1d4c7014c" + +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + dependencies: + is-buffer "^1.1.5" + +kind-of@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + +kind-of@^6.0.0, kind-of@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" + +labeled-stream-splicer@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/labeled-stream-splicer/-/labeled-stream-splicer-2.0.1.tgz#9cffa32fd99e1612fd1d86a8db962416d5292926" + dependencies: + inherits "^2.0.1" + isarray "^2.0.4" + stream-splicer "^2.0.0" + +latest-version@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-3.1.0.tgz#a205383fea322b33b5ae3b18abee0dc2f356ee15" + dependencies: + package-json "^4.0.0" + +lazy-property@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lazy-property/-/lazy-property-1.0.0.tgz#84ddc4b370679ba8bd4cdcfa4c06b43d57111147" + +lcid@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" + dependencies: + invert-kv "^1.0.0" + +levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +libcipm@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/libcipm/-/libcipm-2.0.1.tgz#2f4ebf8562e0fc6e46f415373674e4cf3ac4b9ba" + dependencies: + bin-links "^1.1.2" + bluebird "^3.5.1" + find-npm-prefix "^1.0.2" + graceful-fs "^4.1.11" + lock-verify "^2.0.2" + mkdirp "^0.5.1" + npm-lifecycle "^2.0.3" + npm-logical-tree "^1.2.1" + npm-package-arg "^6.1.0" + pacote "^8.1.6" + protoduck "^5.0.0" + read-package-json "^2.0.13" + rimraf "^2.6.2" + worker-farm "^1.6.0" + +libnpmhook@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/libnpmhook/-/libnpmhook-4.0.1.tgz#63641654de772cbeb96a88527a7fd5456ec3c2d7" + dependencies: + figgy-pudding "^3.1.0" + npm-registry-fetch "^3.0.0" + +libnpx@^10.2.0: + version "10.2.0" + resolved "https://registry.yarnpkg.com/libnpx/-/libnpx-10.2.0.tgz#1bf4a1c9f36081f64935eb014041da10855e3102" + dependencies: + dotenv "^5.0.1" + npm-package-arg "^6.0.0" + rimraf "^2.6.2" + safe-buffer "^5.1.0" + update-notifier "^2.3.0" + which "^1.3.0" + y18n "^4.0.0" + yargs "^11.0.0" + +load-json-file@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + strip-bom "^3.0.0" + +locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + dependencies: + p-locate "^2.0.0" + path-exists "^3.0.0" + +lock-verify@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/lock-verify/-/lock-verify-2.0.2.tgz#148e4f85974915c9e3c34d694b7de9ecb18ee7a8" + dependencies: + npm-package-arg "^5.1.2 || 6" + semver "^5.4.1" + +lockfile@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/lockfile/-/lockfile-1.0.4.tgz#07f819d25ae48f87e538e6578b6964a4981a5609" + dependencies: + signal-exit "^3.0.2" + +lodash._baseindexof@*: + version "3.1.0" + resolved "https://registry.yarnpkg.com/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz#fe52b53a1c6761e42618d654e4a25789ed61822c" + +lodash._baseuniq@~4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz#0ebb44e456814af7905c6212fa2c9b2d51b841e8" + dependencies: + lodash._createset "~4.0.0" + lodash._root "~3.0.0" + +lodash._bindcallback@*: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" + +lodash._cacheindexof@*: + version "3.0.2" + resolved "https://registry.yarnpkg.com/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz#3dc69ac82498d2ee5e3ce56091bafd2adc7bde92" + +lodash._createcache@*: + version "3.1.2" + resolved "https://registry.yarnpkg.com/lodash._createcache/-/lodash._createcache-3.1.2.tgz#56d6a064017625e79ebca6b8018e17440bdcf093" + dependencies: + lodash._getnative "^3.0.0" + +lodash._createset@~4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/lodash._createset/-/lodash._createset-4.0.3.tgz#0f4659fbb09d75194fa9e2b88a6644d363c9fe26" + +lodash._getnative@*, lodash._getnative@^3.0.0: + version "3.9.1" + resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" + +lodash._root@~3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692" + +lodash.clone@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.clone/-/lodash.clone-4.5.0.tgz#195870450f5a13192478df4bc3d23d2dea1907b6" + +lodash.clonedeep@~4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" + +lodash.debounce@^4.0.7, lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + +lodash.memoize@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + +lodash.memoize@~3.0.3: + version "3.0.4" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-3.0.4.tgz#2dcbd2c287cbc0a55cc42328bd0c736150d53e3f" + +lodash.restparam@*: + version "3.6.1" + resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" + +lodash.union@~4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88" + +lodash.uniq@^4.5.0, lodash.uniq@~4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + +lodash.without@~4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.without/-/lodash.without-4.4.0.tgz#3cd4574a00b67bae373a94b748772640507b7aac" + +lodash@^4.17.4: + version "4.17.10" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" + +log-symbols@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" + dependencies: + chalk "^2.0.1" + +loose-envify@^1.0.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +lowercase-keys@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" + +lru-cache@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-3.2.0.tgz#71789b3b7f5399bec8565dda38aa30d2a097efee" + dependencies: + pseudomap "^1.0.1" + +lru-cache@^4.0.1, lru-cache@^4.1.1, lru-cache@^4.1.2, lru-cache@^4.1.3: + version "4.1.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.3.tgz#a1175cf3496dfc8436c156c334b4955992bce69c" + dependencies: + pseudomap "^1.0.2" + yallist "^2.1.2" + +magic-string@^0.22.4: + version "0.22.5" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.22.5.tgz#8e9cf5afddf44385c1da5bc2a6a0dbd10b03657e" + dependencies: + vlq "^0.2.2" + +make-dir@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" + dependencies: + pify "^3.0.0" + +"make-fetch-happen@^2.5.0 || 3 || 4", make-fetch-happen@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-4.0.1.tgz#141497cb878f243ba93136c83d8aba12c216c083" + dependencies: + agentkeepalive "^3.4.1" + cacache "^11.0.1" + http-cache-semantics "^3.8.1" + http-proxy-agent "^2.1.0" + https-proxy-agent "^2.2.1" + lru-cache "^4.1.2" + mississippi "^3.0.0" + node-fetch-npm "^2.0.2" + promise-retry "^1.1.1" + socks-proxy-agent "^4.0.0" + ssri "^6.0.0" + +make-fetch-happen@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-3.0.0.tgz#7b661d2372fc4710ab5cc8e1fa3c290eea69a961" + dependencies: + agentkeepalive "^3.4.1" + cacache "^10.0.4" + http-cache-semantics "^3.8.1" + http-proxy-agent "^2.1.0" + https-proxy-agent "^2.2.0" + lru-cache "^4.1.2" + mississippi "^3.0.0" + node-fetch-npm "^2.0.2" + promise-retry "^1.1.1" + socks-proxy-agent "^3.0.1" + ssri "^5.2.4" + +map-cache@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + +map-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + dependencies: + object-visit "^1.0.0" + +matches-selector@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/matches-selector/-/matches-selector-1.2.0.tgz#d1814e7e8f43e69d22ac33c9af727dc884ecf12a" + +math-expression-evaluator@^1.2.14: + version "1.2.17" + resolved "https://registry.yarnpkg.com/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz#de819fdbcd84dccd8fae59c6aeb79615b9d266ac" + +md5.js@^1.3.4: + version "1.3.4" + resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.4.tgz#e9bdbde94a20a5ac18b04340fc5764d5b09d901d" + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + +mdn-data@^1.0.0, mdn-data@~1.1.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-1.1.4.tgz#50b5d4ffc4575276573c4eedb8780812a8419f01" + +meant@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/meant/-/meant-1.0.1.tgz#66044fea2f23230ec806fb515efea29c44d2115d" + +mem@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/mem/-/mem-1.1.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76" + dependencies: + mimic-fn "^1.0.0" + +merge-source-map@1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/merge-source-map/-/merge-source-map-1.0.4.tgz#a5de46538dae84d4114cc5ea02b4772a6346701f" + dependencies: + source-map "^0.5.6" + +merge2@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.2.2.tgz#03212e3da8d86c4d8523cebd6318193414f94e34" + +micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4: + version "3.1.10" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.2" + +miller-rabin@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" + dependencies: + bn.js "^4.0.0" + brorand "^1.0.1" + +mime-db@~1.35.0: + version "1.35.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.35.0.tgz#0569d657466491283709663ad379a99b90d9ab47" + +mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.7: + version "2.1.19" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.19.tgz#71e464537a7ef81c15f2db9d97e913fc0ff606f0" + dependencies: + mime-db "~1.35.0" + +mime@1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" + +mimic-fn@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" + +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + +minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + +minimatch@^3.0.2, minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + dependencies: + brace-expansion "^1.1.7" + +minimist@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + +minimist@^1.1.0, minimist@^1.1.3, minimist@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + +minipass@^2.2.1, minipass@^2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.3.tgz#a7dcc8b7b833f5d368759cce544dccb55f50f233" + dependencies: + safe-buffer "^5.1.2" + yallist "^3.0.0" + +minizlib@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.1.0.tgz#11e13658ce46bc3a70a267aac58359d1e0c29ceb" + dependencies: + minipass "^2.2.1" + +mississippi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-2.0.0.tgz#3442a508fafc28500486feea99409676e4ee5a6f" + dependencies: + concat-stream "^1.5.0" + duplexify "^3.4.2" + end-of-stream "^1.1.0" + flush-write-stream "^1.0.0" + from2 "^2.1.0" + parallel-transform "^1.1.0" + pump "^2.0.1" + pumpify "^1.3.3" + stream-each "^1.1.0" + through2 "^2.0.0" + +mississippi@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022" + dependencies: + concat-stream "^1.5.0" + duplexify "^3.4.2" + end-of-stream "^1.1.0" + flush-write-stream "^1.0.0" + from2 "^2.1.0" + parallel-transform "^1.1.0" + pump "^3.0.0" + pumpify "^1.3.3" + stream-each "^1.1.0" + through2 "^2.0.0" + +mixin-deep@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + +"mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + dependencies: + minimist "0.0.8" + +module-deps@^4.0.8: + version "4.1.1" + resolved "https://registry.yarnpkg.com/module-deps/-/module-deps-4.1.1.tgz#23215833f1da13fd606ccb8087b44852dcb821fd" + dependencies: + JSONStream "^1.0.3" + browser-resolve "^1.7.0" + cached-path-relative "^1.0.0" + concat-stream "~1.5.0" + defined "^1.0.0" + detective "^4.0.0" + duplexer2 "^0.1.2" + inherits "^2.0.1" + parents "^1.0.0" + readable-stream "^2.0.2" + resolve "^1.1.3" + stream-combiner2 "^1.1.1" + subarg "^1.0.0" + through2 "^2.0.0" + xtend "^4.0.0" + +move-concurrently@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" + dependencies: + aproba "^1.1.1" + copy-concurrently "^1.0.0" + fs-write-stream-atomic "^1.0.8" + mkdirp "^0.5.1" + rimraf "^2.5.4" + run-queue "^1.0.3" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + +ms@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + +mute-stream@~0.0.4: + version "0.0.7" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" + +nan@^2.0.7, nan@^2.9.2: + version "2.10.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f" + +nanomatch@^1.2.9: + version "1.2.13" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + define-property "^2.0.2" + extend-shallow "^3.0.2" + fragment-cache "^0.2.1" + is-windows "^1.0.2" + kind-of "^6.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +needle@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.1.tgz#b5e325bd3aae8c2678902fa296f729455d1d3a7d" + dependencies: + debug "^2.1.2" + iconv-lite "^0.4.4" + sax "^1.2.4" + +nice-try@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.4.tgz#d93962f6c52f2c1558c0fbda6d512819f1efe1c4" + +node-fetch-npm@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/node-fetch-npm/-/node-fetch-npm-2.0.2.tgz#7258c9046182dca345b4208eda918daf33697ff7" + dependencies: + encoding "^0.1.11" + json-parse-better-errors "^1.0.0" + safe-buffer "^5.1.1" + +node-forge@^0.7.1: + version "0.7.5" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.7.5.tgz#6c152c345ce11c52f465c2abd957e8639cd674df" + +node-gyp@^3.6.2, node-gyp@^3.7.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.7.0.tgz#789478e8f6c45e277aa014f3e28f958f286f9203" + dependencies: + fstream "^1.0.0" + glob "^7.0.3" + graceful-fs "^4.1.2" + mkdirp "^0.5.0" + nopt "2 || 3" + npmlog "0 || 1 || 2 || 3 || 4" + osenv "0" + request ">=2.9.0 <2.82.0" + rimraf "2" + semver "~5.3.0" + tar "^2.0.0" + which "1" + +node-libs-browser@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.1.0.tgz#5f94263d404f6e44767d726901fff05478d600df" + dependencies: + assert "^1.1.1" + browserify-zlib "^0.2.0" + buffer "^4.3.0" + console-browserify "^1.1.0" + constants-browserify "^1.0.0" + crypto-browserify "^3.11.0" + domain-browser "^1.1.1" + events "^1.0.0" + https-browserify "^1.0.0" + os-browserify "^0.3.0" + path-browserify "0.0.0" + process "^0.11.10" + punycode "^1.2.4" + querystring-es3 "^0.2.0" + readable-stream "^2.3.3" + stream-browserify "^2.0.1" + stream-http "^2.7.2" + string_decoder "^1.0.0" + timers-browserify "^2.0.4" + tty-browserify "0.0.0" + url "^0.11.0" + util "^0.10.3" + vm-browserify "0.0.4" + +node-pre-gyp@^0.10.0: + version "0.10.3" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz#3070040716afdc778747b61b6887bf78880b80fc" + dependencies: + detect-libc "^1.0.2" + mkdirp "^0.5.1" + needle "^2.2.1" + nopt "^4.0.1" + npm-packlist "^1.1.6" + npmlog "^4.0.2" + rc "^1.2.7" + rimraf "^2.6.1" + semver "^5.3.0" + tar "^4" + +node-releases@^1.0.0-alpha.10: + version "1.0.0-alpha.10" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.0.0-alpha.10.tgz#61c8d5f9b5b2e05d84eba941d05b6f5202f68a2a" + dependencies: + semver "^5.3.0" + +"nopt@2 || 3", nopt@~3.0.1: + version "3.0.6" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" + dependencies: + abbrev "1" + +nopt@^4.0.1, nopt@~4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" + dependencies: + abbrev "1" + osenv "^0.1.4" + +normalize-package-data@^2.0.0, normalize-package-data@^2.3.2, normalize-package-data@^2.4.0, "normalize-package-data@~1.0.1 || ^2.0.0", normalize-package-data@~2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" + dependencies: + hosted-git-info "^2.1.4" + is-builtin-module "^1.0.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + +normalize-path@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + dependencies: + remove-trailing-separator "^1.0.1" + +normalize-range@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" + +normalize-url@^1.4.0: + version "1.9.1" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-1.9.1.tgz#2cc0d66b31ea23036458436e3620d85954c66c3c" + dependencies: + object-assign "^4.0.1" + prepend-http "^1.0.0" + query-string "^4.1.0" + sort-keys "^1.0.0" + +normalize-url@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-3.2.0.tgz#98d0948afc82829f374320f405fe9ca55a5f8567" + +npm-audit-report@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/npm-audit-report/-/npm-audit-report-1.3.1.tgz#e79ea1fcb5ffaf3031102b389d5222c2b0459632" + dependencies: + cli-table3 "^0.5.0" + console-control-strings "^1.1.0" + +npm-bundled@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.3.tgz#7e71703d973af3370a9591bafe3a63aca0be2308" + +npm-cache-filename@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/npm-cache-filename/-/npm-cache-filename-1.0.2.tgz#ded306c5b0bfc870a9e9faf823bc5f283e05ae11" + +npm-install-checks@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/npm-install-checks/-/npm-install-checks-3.0.0.tgz#d4aecdfd51a53e3723b7b2f93b2ee28e307bc0d7" + dependencies: + semver "^2.3.0 || 3.x || 4 || 5" + +npm-lifecycle@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/npm-lifecycle/-/npm-lifecycle-2.0.3.tgz#696bedf1143371163e9cc16fe872357e25d8d90e" + dependencies: + byline "^5.0.0" + graceful-fs "^4.1.11" + node-gyp "^3.6.2" + resolve-from "^4.0.0" + slide "^1.1.6" + uid-number "0.0.6" + umask "^1.1.0" + which "^1.3.0" + +npm-logical-tree@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/npm-logical-tree/-/npm-logical-tree-1.2.1.tgz#44610141ca24664cad35d1e607176193fd8f5b88" + +"npm-package-arg@^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0", "npm-package-arg@^4.0.0 || ^5.0.0 || ^6.0.0", "npm-package-arg@^5.1.2 || 6", npm-package-arg@^6.0.0, npm-package-arg@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-6.1.0.tgz#15ae1e2758a5027efb4c250554b85a737db7fcc1" + dependencies: + hosted-git-info "^2.6.0" + osenv "^0.1.5" + semver "^5.5.0" + validate-npm-package-name "^3.0.0" + +npm-packlist@^1.1.10, npm-packlist@^1.1.6, npm-packlist@~1.1.10: + version "1.1.11" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.1.11.tgz#84e8c683cbe7867d34b1d357d893ce29e28a02de" + dependencies: + ignore-walk "^3.0.1" + npm-bundled "^1.0.1" + +npm-pick-manifest@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/npm-pick-manifest/-/npm-pick-manifest-2.1.0.tgz#dc381bdd670c35d81655e1d5a94aa3dd4d87fce5" + dependencies: + npm-package-arg "^6.0.0" + semver "^5.4.1" + +npm-profile@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/npm-profile/-/npm-profile-3.0.2.tgz#58d568f1b56ef769602fd0aed8c43fa0e0de0f57" + dependencies: + aproba "^1.1.2 || 2" + make-fetch-happen "^2.5.0 || 3 || 4" + +npm-registry-client@^8.5.1: + version "8.6.0" + resolved "https://registry.yarnpkg.com/npm-registry-client/-/npm-registry-client-8.6.0.tgz#7f1529f91450732e89f8518e0f21459deea3e4c4" + dependencies: + concat-stream "^1.5.2" + graceful-fs "^4.1.6" + normalize-package-data "~1.0.1 || ^2.0.0" + npm-package-arg "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0" + once "^1.3.3" + request "^2.74.0" + retry "^0.10.0" + safe-buffer "^5.1.1" + semver "2 >=2.2.1 || 3.x || 4 || 5" + slide "^1.1.3" + ssri "^5.2.4" + optionalDependencies: + npmlog "2 || ^3.1.0 || ^4.0.0" + +npm-registry-fetch@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-1.1.1.tgz#710bc5947d9ee2c549375072dab6d5d17baf2eb2" + dependencies: + bluebird "^3.5.1" + figgy-pudding "^3.0.0" + lru-cache "^4.1.2" + make-fetch-happen "^3.0.0" + npm-package-arg "^6.0.0" + safe-buffer "^5.1.1" + +npm-registry-fetch@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-3.2.0.tgz#94ec859c4dd395f924e575cee471da6fd3906d53" + dependencies: + bluebird "^3.5.1" + figgy-pudding "^3.2.0" + lru-cache "^4.1.3" + make-fetch-happen "^4.0.1" + npm-package-arg "^6.1.0" + +npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + dependencies: + path-key "^2.0.0" + +npm-user-validate@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/npm-user-validate/-/npm-user-validate-1.0.0.tgz#8ceca0f5cea04d4e93519ef72d0557a75122e951" + +npm@^6.0.1: + version "6.3.0" + resolved "https://registry.yarnpkg.com/npm/-/npm-6.3.0.tgz#de7df51f6d1b05b088486097cf7993dbbcac752f" + dependencies: + JSONStream "^1.3.3" + abbrev "~1.1.1" + ansicolors "~0.3.2" + ansistyles "~0.1.3" + aproba "~1.2.0" + archy "~1.0.0" + bin-links "^1.1.2" + bluebird "~3.5.1" + byte-size "^4.0.3" + cacache "^11.1.0" + call-limit "~1.1.0" + chownr "~1.0.1" + cli-columns "^3.1.2" + cli-table3 "^0.5.0" + cmd-shim "~2.0.2" + columnify "~1.5.4" + config-chain "~1.1.11" + detect-indent "~5.0.0" + detect-newline "^2.1.0" + dezalgo "~1.0.3" + editor "~1.0.0" + figgy-pudding "^3.2.0" + find-npm-prefix "^1.0.2" + fs-vacuum "~1.2.10" + fs-write-stream-atomic "~1.0.10" + gentle-fs "^2.0.1" + glob "~7.1.2" + graceful-fs "~4.1.11" + has-unicode "~2.0.1" + hosted-git-info "^2.6.0" + iferr "^1.0.0" + inflight "~1.0.6" + inherits "~2.0.3" + ini "^1.3.5" + init-package-json "^1.10.3" + is-cidr "^2.0.6" + json-parse-better-errors "^1.0.2" + lazy-property "~1.0.0" + libcipm "^2.0.0" + libnpmhook "^4.0.1" + libnpx "^10.2.0" + lock-verify "^2.0.2" + lockfile "^1.0.4" + lodash._baseuniq "~4.6.0" + lodash.clonedeep "~4.5.0" + lodash.union "~4.6.0" + lodash.uniq "~4.5.0" + lodash.without "~4.4.0" + lru-cache "^4.1.3" + meant "~1.0.1" + mississippi "^3.0.0" + mkdirp "~0.5.1" + move-concurrently "^1.0.1" + node-gyp "^3.7.0" + nopt "~4.0.1" + normalize-package-data "~2.4.0" + npm-audit-report "^1.3.1" + npm-cache-filename "~1.0.2" + npm-install-checks "~3.0.0" + npm-lifecycle "^2.0.3" + npm-package-arg "^6.1.0" + npm-packlist "~1.1.10" + npm-pick-manifest "^2.1.0" + npm-profile "^3.0.2" + npm-registry-client "^8.5.1" + npm-registry-fetch "^1.1.0" + npm-user-validate "~1.0.0" + npmlog "~4.1.2" + once "~1.4.0" + opener "~1.4.3" + osenv "^0.1.5" + pacote "^8.1.6" + path-is-inside "~1.0.2" + promise-inflight "~1.0.1" + qrcode-terminal "^0.12.0" + query-string "^6.1.0" + qw "~1.0.1" + read "~1.0.7" + read-cmd-shim "~1.0.1" + read-installed "~4.0.3" + read-package-json "^2.0.13" + read-package-tree "^5.2.1" + readable-stream "^2.3.6" + request "^2.81.0" + retry "^0.12.0" + rimraf "~2.6.2" + safe-buffer "^5.1.2" + semver "^5.5.0" + sha "~2.0.1" + slide "~1.1.6" + sorted-object "~2.0.1" + sorted-union-stream "~2.1.3" + ssri "^6.0.0" + stringify-package "^1.0.0" + tar "^4.4.4" + text-table "~0.2.0" + tiny-relative-date "^1.3.0" + uid-number "0.0.6" + umask "~1.1.0" + unique-filename "~1.1.0" + unpipe "~1.0.0" + update-notifier "^2.5.0" + uuid "^3.3.2" + validate-npm-package-license "^3.0.3" + validate-npm-package-name "~3.0.0" + which "^1.3.1" + worker-farm "^1.6.0" + write-file-atomic "^2.3.0" + +"npmlog@0 || 1 || 2 || 3 || 4", "npmlog@2 || ^3.1.0 || ^4.0.0", npmlog@^4.0.2, npmlog@~4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + +nth-check@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.1.tgz#9929acdf628fc2c41098deab82ac580cf149aae4" + dependencies: + boolbase "~1.0.0" + +num2fraction@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + +oauth-sign@~0.8.1, oauth-sign@~0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" + +object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + +object-copy@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + +object-inspect@~1.4.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.4.1.tgz#37ffb10e71adaf3748d05f713b4c9452f402cbc4" + +object-keys@^1.0.6, object-keys@^1.0.8: + version "1.0.12" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.12.tgz#09c53855377575310cca62f55bb334abff7b3ed2" + +object-visit@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + dependencies: + isobject "^3.0.0" + +object.getownpropertydescriptors@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz#8758c846f5b407adab0f236e0986f14b051caa16" + dependencies: + define-properties "^1.1.2" + es-abstract "^1.5.1" + +object.pick@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + dependencies: + isobject "^3.0.1" + +object.values@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.0.4.tgz#e524da09b4f66ff05df457546ec72ac99f13069a" + dependencies: + define-properties "^1.1.2" + es-abstract "^1.6.1" + function-bind "^1.1.0" + has "^1.0.1" + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + dependencies: + ee-first "1.1.1" + +once@^1.3.0, once@^1.3.1, once@^1.3.3, once@^1.4.0, once@~1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + dependencies: + wrappy "1" + +onetime@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" + dependencies: + mimic-fn "^1.0.0" + +opener@~1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/opener/-/opener-1.4.3.tgz#5c6da2c5d7e5831e8ffa3964950f8d6674ac90b8" + +opn@^5.1.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/opn/-/opn-5.3.0.tgz#64871565c863875f052cfdf53d3e3cb5adb53b1c" + dependencies: + is-wsl "^1.1.0" + +optionator@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.4" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + wordwrap "~1.0.0" + +ora@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/ora/-/ora-2.1.0.tgz#6caf2830eb924941861ec53a173799e008b51e5b" + dependencies: + chalk "^2.3.1" + cli-cursor "^2.1.0" + cli-spinners "^1.1.0" + log-symbols "^2.2.0" + strip-ansi "^4.0.0" + wcwidth "^1.0.1" + +os-browserify@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" + +os-browserify@~0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.1.2.tgz#49ca0293e0b19590a5f5de10c7f265a617d8fe54" + +os-homedir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + +os-locale@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2" + dependencies: + execa "^0.7.0" + lcid "^1.0.0" + mem "^1.1.0" + +os-tmpdir@^1.0.0, os-tmpdir@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + +osenv@0, osenv@^0.1.4, osenv@^0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" + +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + +p-limit@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" + dependencies: + p-try "^1.0.0" + +p-locate@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + dependencies: + p-limit "^1.1.0" + +p-try@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + +package-json@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/package-json/-/package-json-4.0.1.tgz#8869a0401253661c4c4ca3da6c2121ed555f5eed" + dependencies: + got "^6.7.1" + registry-auth-token "^3.0.1" + registry-url "^3.0.3" + semver "^5.1.0" + +pacote@^8.1.6: + version "8.1.6" + resolved "https://registry.yarnpkg.com/pacote/-/pacote-8.1.6.tgz#8e647564d38156367e7a9dc47a79ca1ab278d46e" + dependencies: + bluebird "^3.5.1" + cacache "^11.0.2" + get-stream "^3.0.0" + glob "^7.1.2" + lru-cache "^4.1.3" + make-fetch-happen "^4.0.1" + minimatch "^3.0.4" + minipass "^2.3.3" + mississippi "^3.0.0" + mkdirp "^0.5.1" + normalize-package-data "^2.4.0" + npm-package-arg "^6.1.0" + npm-packlist "^1.1.10" + npm-pick-manifest "^2.1.0" + osenv "^0.1.5" + promise-inflight "^1.0.1" + promise-retry "^1.1.1" + protoduck "^5.0.0" + rimraf "^2.6.2" + safe-buffer "^5.1.2" + semver "^5.5.0" + ssri "^6.0.0" + tar "^4.4.3" + unique-filename "^1.1.0" + which "^1.3.0" + +pako@^0.2.5, pako@~0.2.0: + version "0.2.9" + resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75" + +pako@~1.0.5: + version "1.0.6" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.6.tgz#0101211baa70c4bca4a0f63f2206e97b7dfaf258" + +parallel-transform@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.1.0.tgz#d410f065b05da23081fcd10f28854c29bda33b06" + dependencies: + cyclist "~0.2.2" + inherits "^2.0.3" + readable-stream "^2.1.5" + +parcel@^1.9.7: + version "1.9.7" + resolved "https://registry.yarnpkg.com/parcel/-/parcel-1.9.7.tgz#77ca0cdb305d8e9365ded4762ee39ca760b0c219" + dependencies: + ansi-to-html "^0.6.4" + babel-code-frame "^6.26.0" + babel-core "^6.25.0" + babel-generator "^6.25.0" + babel-plugin-transform-es2015-modules-commonjs "^6.26.0" + babel-plugin-transform-react-jsx "^6.24.1" + babel-preset-env "^1.7.0" + babel-template "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + babylon "^6.17.4" + babylon-walk "^1.0.2" + browserslist "^3.2.6" + chalk "^2.1.0" + clone "^2.1.1" + command-exists "^1.2.6" + commander "^2.11.0" + cross-spawn "^6.0.4" + cssnano "^4.0.0" + deasync "^0.1.13" + dotenv "^5.0.0" + fast-glob "^2.2.2" + filesize "^3.6.0" + fswatcher-child "^1.0.3" + get-port "^3.2.0" + grapheme-breaker "^0.3.2" + htmlnano "^0.1.9" + is-glob "^4.0.0" + is-url "^1.2.2" + js-yaml "^3.10.0" + json5 "^1.0.1" + micromatch "^3.0.4" + mkdirp "^0.5.1" + node-forge "^0.7.1" + node-libs-browser "^2.0.0" + opn "^5.1.0" + ora "^2.1.0" + physical-cpu-count "^2.0.0" + postcss "^6.0.19" + postcss-value-parser "^3.3.0" + posthtml "^0.11.2" + posthtml-parser "^0.4.0" + posthtml-render "^1.1.3" + resolve "^1.4.0" + semver "^5.4.1" + serialize-to-js "^1.1.1" + serve-static "^1.12.4" + source-map "0.6.1" + strip-ansi "^4.0.0" + terser "^3.7.3" + toml "^2.3.3" + tomlify-j0.4 "^3.0.0" + v8-compile-cache "^2.0.0" + ws "^5.1.1" + +parents@^1.0.0, parents@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parents/-/parents-1.0.1.tgz#fedd4d2bf193a77745fe71e371d73c3307d9c751" + dependencies: + path-platform "~0.11.15" + +parse-asn1@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.1.tgz#f6bf293818332bd0dab54efb16087724745e6ca8" + dependencies: + asn1.js "^4.0.0" + browserify-aes "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.0" + pbkdf2 "^3.0.3" + +parse-json@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" + dependencies: + error-ex "^1.2.0" + +parse-json@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" + dependencies: + error-ex "^1.3.1" + json-parse-better-errors "^1.0.1" + +parseurl@~1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" + +pascalcase@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + +path-browserify@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a" + +path-browserify@~0.0.0: + version "0.0.1" + resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a" + +path-dirname@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + +path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + +path-is-inside@^1.0.1, path-is-inside@^1.0.2, path-is-inside@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + +path-key@^2.0.0, path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + +path-parse@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" + +path-platform@~0.11.15: + version "0.11.15" + resolved "https://registry.yarnpkg.com/path-platform/-/path-platform-0.11.15.tgz#e864217f74c36850f0852b78dc7bf7d4a5721bf2" + +path-type@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" + dependencies: + pify "^2.0.0" + +pbkdf2@^3.0.3: + version "3.0.16" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.16.tgz#7404208ec6b01b62d85bf83853a8064f8d9c2a5c" + dependencies: + create-hash "^1.1.2" + create-hmac "^1.1.4" + ripemd160 "^2.0.1" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +performance-now@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" + +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + +physical-cpu-count@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/physical-cpu-count/-/physical-cpu-count-2.0.0.tgz#18de2f97e4bf7a9551ad7511942b5496f7aba660" + +pify@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + +pify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" + +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + +postcss-calc@^5.2.0: + version "5.3.1" + resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-5.3.1.tgz#77bae7ca928ad85716e2fda42f261bf7c1d65b5e" + dependencies: + postcss "^5.0.2" + postcss-message-helpers "^2.0.0" + reduce-css-calc "^1.2.6" + +postcss-calc@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-6.0.1.tgz#3d24171bbf6e7629d422a436ebfe6dd9511f4330" + dependencies: + css-unit-converter "^1.1.1" + postcss "^6.0.0" + postcss-selector-parser "^2.2.2" + reduce-css-calc "^2.0.0" + +postcss-colormin@^2.1.8: + version "2.2.2" + resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-2.2.2.tgz#6631417d5f0e909a3d7ec26b24c8a8d1e4f96e4b" + dependencies: + colormin "^1.0.5" + postcss "^5.0.13" + postcss-value-parser "^3.2.3" + +postcss-colormin@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-4.0.1.tgz#6f1c18a0155bc69613f2ff13843e2e4ae8ff0bbe" + dependencies: + browserslist "^4.0.0" + color "^3.0.0" + has "^1.0.0" + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + +postcss-convert-values@^2.3.4: + version "2.6.1" + resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-2.6.1.tgz#bbd8593c5c1fd2e3d1c322bb925dcae8dae4d62d" + dependencies: + postcss "^5.0.11" + postcss-value-parser "^3.1.2" + +postcss-convert-values@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-4.0.0.tgz#77d77d9aed1dc4e6956e651cc349d53305876f62" + dependencies: + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + +postcss-discard-comments@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-2.0.4.tgz#befe89fafd5b3dace5ccce51b76b81514be00e3d" + dependencies: + postcss "^5.0.14" + +postcss-discard-comments@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-4.0.0.tgz#9684a299e76b3e93263ef8fd2adbf1a1c08fd88d" + dependencies: + postcss "^6.0.0" + +postcss-discard-duplicates@^2.0.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-2.1.0.tgz#b9abf27b88ac188158a5eb12abcae20263b91932" + dependencies: + postcss "^5.0.4" + +postcss-discard-duplicates@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.0.tgz#42f3c267f85fa909e042c35767ecfd65cb2bd72c" + dependencies: + postcss "^6.0.0" + +postcss-discard-empty@^2.0.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-2.1.0.tgz#d2b4bd9d5ced5ebd8dcade7640c7d7cd7f4f92b5" + dependencies: + postcss "^5.0.14" + +postcss-discard-empty@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-4.0.0.tgz#55e18a59c74128e38c7d2804bcfa4056611fb97f" + dependencies: + postcss "^6.0.0" + +postcss-discard-overridden@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-0.1.1.tgz#8b1eaf554f686fb288cd874c55667b0aa3668d58" + dependencies: + postcss "^5.0.16" + +postcss-discard-overridden@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-4.0.0.tgz#4a0bf85978784cf1f81ed2c1c1fd9d964a1da1fa" + dependencies: + postcss "^6.0.0" + +postcss-discard-unused@^2.2.1: + version "2.2.3" + resolved "https://registry.yarnpkg.com/postcss-discard-unused/-/postcss-discard-unused-2.2.3.tgz#bce30b2cc591ffc634322b5fb3464b6d934f4433" + dependencies: + postcss "^5.0.14" + uniqs "^2.0.0" + +postcss-filter-plugins@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/postcss-filter-plugins/-/postcss-filter-plugins-2.0.3.tgz#82245fdf82337041645e477114d8e593aa18b8ec" + dependencies: + postcss "^5.0.4" + +postcss-merge-idents@^2.1.5: + version "2.1.7" + resolved "https://registry.yarnpkg.com/postcss-merge-idents/-/postcss-merge-idents-2.1.7.tgz#4c5530313c08e1d5b3bbf3d2bbc747e278eea270" + dependencies: + has "^1.0.1" + postcss "^5.0.10" + postcss-value-parser "^3.1.1" + +postcss-merge-longhand@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-2.0.2.tgz#23d90cd127b0a77994915332739034a1a4f3d658" + dependencies: + postcss "^5.0.4" + +postcss-merge-longhand@^4.0.0: + version "4.0.4" + resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-4.0.4.tgz#bffc7c6ffa146591c993a0bb8373d65f9a06d4d0" + dependencies: + css-color-names "0.0.4" + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + stylehacks "^4.0.0" + +postcss-merge-rules@^2.0.3: + version "2.1.2" + resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-2.1.2.tgz#d1df5dfaa7b1acc3be553f0e9e10e87c61b5f721" + dependencies: + browserslist "^1.5.2" + caniuse-api "^1.5.2" + postcss "^5.0.4" + postcss-selector-parser "^2.2.2" + vendors "^1.0.0" + +postcss-merge-rules@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-4.0.1.tgz#430fd59b3f2ed2e8afcd0b31278eda39854abb10" + dependencies: + browserslist "^4.0.0" + caniuse-api "^3.0.0" + cssnano-util-same-parent "^4.0.0" + postcss "^6.0.0" + postcss-selector-parser "^3.0.0" + vendors "^1.0.0" + +postcss-message-helpers@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-message-helpers/-/postcss-message-helpers-2.0.0.tgz#a4f2f4fab6e4fe002f0aed000478cdf52f9ba60e" + +postcss-minify-font-values@^1.0.2: + version "1.0.5" + resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-1.0.5.tgz#4b58edb56641eba7c8474ab3526cafd7bbdecb69" + dependencies: + object-assign "^4.0.1" + postcss "^5.0.4" + postcss-value-parser "^3.0.2" + +postcss-minify-font-values@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-4.0.0.tgz#4cc33d283d6a81759036e757ef981d92cbd85bed" + dependencies: + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + +postcss-minify-gradients@^1.0.1: + version "1.0.5" + resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-1.0.5.tgz#5dbda11373703f83cfb4a3ea3881d8d75ff5e6e1" + dependencies: + postcss "^5.0.12" + postcss-value-parser "^3.3.0" + +postcss-minify-gradients@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-4.0.0.tgz#3fc3916439d27a9bb8066db7cdad801650eb090e" + dependencies: + cssnano-util-get-arguments "^4.0.0" + is-color-stop "^1.0.0" + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + +postcss-minify-params@^1.0.4: + version "1.2.2" + resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-1.2.2.tgz#ad2ce071373b943b3d930a3fa59a358c28d6f1f3" + dependencies: + alphanum-sort "^1.0.1" + postcss "^5.0.2" + postcss-value-parser "^3.0.2" + uniqs "^2.0.0" + +postcss-minify-params@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-4.0.0.tgz#05e9166ee48c05af651989ce84d39c1b4d790674" + dependencies: + alphanum-sort "^1.0.0" + cssnano-util-get-arguments "^4.0.0" + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + uniqs "^2.0.0" + +postcss-minify-selectors@^2.0.4: + version "2.1.1" + resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-2.1.1.tgz#b2c6a98c0072cf91b932d1a496508114311735bf" + dependencies: + alphanum-sort "^1.0.2" + has "^1.0.1" + postcss "^5.0.14" + postcss-selector-parser "^2.0.0" + +postcss-minify-selectors@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-4.0.0.tgz#b1e9f6c463416d3fcdcb26e7b785d95f61578aad" + dependencies: + alphanum-sort "^1.0.0" + has "^1.0.0" + postcss "^6.0.0" + postcss-selector-parser "^3.0.0" + +postcss-normalize-charset@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-1.1.1.tgz#ef9ee71212d7fe759c78ed162f61ed62b5cb93f1" + dependencies: + postcss "^5.0.5" + +postcss-normalize-charset@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-4.0.0.tgz#24527292702d5e8129eafa3d1de49ed51a6ab730" + dependencies: + postcss "^6.0.0" + +postcss-normalize-display-values@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.0.tgz#950e0c7be3445770a160fffd6b6644c3c0cd8f89" + dependencies: + cssnano-util-get-match "^4.0.0" + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-positions@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-positions/-/postcss-normalize-positions-4.0.0.tgz#ee9343ab981b822c63ab72615ecccd08564445a3" + dependencies: + cssnano-util-get-arguments "^4.0.0" + has "^1.0.0" + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-repeat-style@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.0.tgz#b711c592cf16faf9ff575e42fa100b6799083eff" + dependencies: + cssnano-util-get-arguments "^4.0.0" + cssnano-util-get-match "^4.0.0" + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-string/-/postcss-normalize-string-4.0.0.tgz#718cb6d30a6fac6ac6a830e32c06c07dbc66fe5d" + dependencies: + has "^1.0.0" + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-timing-functions@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.0.tgz#0351f29886aa981d43d91b2c2bd1aea6d0af6d23" + dependencies: + cssnano-util-get-match "^4.0.0" + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-unicode@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.0.tgz#5acd5d47baea5d17674b2ccc4ae5166fa88cdf97" + dependencies: + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-url@^3.0.7: + version "3.0.8" + resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-3.0.8.tgz#108f74b3f2fcdaf891a2ffa3ea4592279fc78222" + dependencies: + is-absolute-url "^2.0.0" + normalize-url "^1.4.0" + postcss "^5.0.14" + postcss-value-parser "^3.2.3" + +postcss-normalize-url@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-4.0.0.tgz#b7a9c8ad26cf26694c146eb2d68bd0cf49956f0d" + dependencies: + is-absolute-url "^2.0.0" + normalize-url "^3.0.0" + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-whitespace@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.0.tgz#1da7e76b10ae63c11827fa04fc3bb4a1efe99cc0" + dependencies: + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + +postcss-ordered-values@^2.1.0: + version "2.2.3" + resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-2.2.3.tgz#eec6c2a67b6c412a8db2042e77fe8da43f95c11d" + dependencies: + postcss "^5.0.4" + postcss-value-parser "^3.0.1" + +postcss-ordered-values@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-4.0.0.tgz#58b40c74f72e022eb34152c12e4b0f9354482fc2" + dependencies: + cssnano-util-get-arguments "^4.0.0" + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + +postcss-reduce-idents@^2.2.2: + version "2.4.0" + resolved "https://registry.yarnpkg.com/postcss-reduce-idents/-/postcss-reduce-idents-2.4.0.tgz#c2c6d20cc958284f6abfbe63f7609bf409059ad3" + dependencies: + postcss "^5.0.4" + postcss-value-parser "^3.0.2" + +postcss-reduce-initial@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-1.0.1.tgz#68f80695f045d08263a879ad240df8dd64f644ea" + dependencies: + postcss "^5.0.4" + +postcss-reduce-initial@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-4.0.1.tgz#f2d58f50cea2b0c5dc1278d6ea5ed0ff5829c293" + dependencies: + browserslist "^4.0.0" + caniuse-api "^3.0.0" + has "^1.0.0" + postcss "^6.0.0" + +postcss-reduce-transforms@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-1.0.4.tgz#ff76f4d8212437b31c298a42d2e1444025771ae1" + dependencies: + has "^1.0.1" + postcss "^5.0.8" + postcss-value-parser "^3.0.1" + +postcss-reduce-transforms@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.0.tgz#f645fc7440c35274f40de8104e14ad7163edf188" + dependencies: + cssnano-util-get-match "^4.0.0" + has "^1.0.0" + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + +postcss-selector-parser@^2.0.0, postcss-selector-parser@^2.2.2: + version "2.2.3" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-2.2.3.tgz#f9437788606c3c9acee16ffe8d8b16297f27bb90" + dependencies: + flatten "^1.0.2" + indexes-of "^1.0.1" + uniq "^1.0.1" + +postcss-selector-parser@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-3.1.1.tgz#4f875f4afb0c96573d5cf4d74011aee250a7e865" + dependencies: + dot-prop "^4.1.1" + indexes-of "^1.0.1" + uniq "^1.0.1" + +postcss-svgo@^2.1.1: + version "2.1.6" + resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-2.1.6.tgz#b6df18aa613b666e133f08adb5219c2684ac108d" + dependencies: + is-svg "^2.0.0" + postcss "^5.0.14" + postcss-value-parser "^3.2.3" + svgo "^0.7.0" + +postcss-svgo@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-4.0.0.tgz#c0bbad02520fc636c9d78b0e8403e2e515c32285" + dependencies: + is-svg "^3.0.0" + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + svgo "^1.0.0" + +postcss-unique-selectors@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-2.0.2.tgz#981d57d29ddcb33e7b1dfe1fd43b8649f933ca1d" + dependencies: + alphanum-sort "^1.0.1" + postcss "^5.0.4" + uniqs "^2.0.0" + +postcss-unique-selectors@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-4.0.0.tgz#04c1e9764c75874261303402c41f0e9769fc5501" + dependencies: + alphanum-sort "^1.0.0" + postcss "^6.0.0" + uniqs "^2.0.0" + +postcss-value-parser@^3.0.0, postcss-value-parser@^3.0.1, postcss-value-parser@^3.0.2, postcss-value-parser@^3.1.1, postcss-value-parser@^3.1.2, postcss-value-parser@^3.2.3, postcss-value-parser@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz#87f38f9f18f774a4ab4c8a232f5c5ce8872a9d15" + +postcss-zindex@^2.0.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/postcss-zindex/-/postcss-zindex-2.2.0.tgz#d2109ddc055b91af67fc4cb3b025946639d2af22" + dependencies: + has "^1.0.1" + postcss "^5.0.4" + uniqs "^2.0.0" + +postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0.13, postcss@^5.0.14, postcss@^5.0.16, postcss@^5.0.2, postcss@^5.0.4, postcss@^5.0.5, postcss@^5.0.8, postcss@^5.2.16: + version "5.2.18" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-5.2.18.tgz#badfa1497d46244f6390f58b319830d9107853c5" + dependencies: + chalk "^1.1.3" + js-base64 "^2.1.9" + source-map "^0.5.6" + supports-color "^3.2.3" + +postcss@^6.0.0, postcss@^6.0.19: + version "6.0.23" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.23.tgz#61c82cc328ac60e677645f979054eb98bc0e3324" + dependencies: + chalk "^2.4.1" + source-map "^0.6.1" + supports-color "^5.4.0" + +posthtml-parser@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/posthtml-parser/-/posthtml-parser-0.3.3.tgz#3fe986fca9f00c0f109d731ba590b192f26e776d" + dependencies: + htmlparser2 "^3.9.2" + isobject "^2.1.0" + object-assign "^4.1.1" + +posthtml-parser@^0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/posthtml-parser/-/posthtml-parser-0.4.1.tgz#95b78fef766fbbe0a6f861b6e95582bc3d1ff933" + dependencies: + htmlparser2 "^3.9.2" + object-assign "^4.1.1" + +posthtml-render@^1.1.0, posthtml-render@^1.1.3: + version "1.1.4" + resolved "https://registry.yarnpkg.com/posthtml-render/-/posthtml-render-1.1.4.tgz#95dac09892f4f183fad5ac823f08f42c0256551e" + +posthtml@^0.11.2, posthtml@^0.11.3: + version "0.11.3" + resolved "https://registry.yarnpkg.com/posthtml/-/posthtml-0.11.3.tgz#17ea2921b0555b7455f33c977bd16d8b8cb74f27" + dependencies: + object-assign "^4.1.1" + posthtml-parser "^0.3.3" + posthtml-render "^1.1.0" + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + +prepend-http@^1.0.0, prepend-http@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" + +private@^0.1.6, private@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" + +process-nextick-args@~1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" + +process-nextick-args@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" + +process@^0.11.10, process@~0.11.0: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + +promise-inflight@^1.0.1, promise-inflight@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" + +promise-retry@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-1.1.1.tgz#6739e968e3051da20ce6497fb2b50f6911df3d6d" + dependencies: + err-code "^1.0.0" + retry "^0.10.0" + +promzard@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/promzard/-/promzard-0.3.0.tgz#26a5d6ee8c7dee4cb12208305acfb93ba382a9ee" + dependencies: + read "1" + +proto-list@~1.2.1: + version "1.2.4" + resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" + +protoduck@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/protoduck/-/protoduck-5.0.0.tgz#752145e6be0ad834cb25716f670a713c860dce70" + dependencies: + genfun "^4.0.1" + +prr@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" + +pseudomap@^1.0.1, pseudomap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + +public-encrypt@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.2.tgz#46eb9107206bf73489f8b85b69d91334c6610994" + dependencies: + bn.js "^4.1.0" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + parse-asn1 "^5.0.0" + randombytes "^2.0.1" + +pump@^2.0.0, pump@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pumpify@^1.3.3: + version "1.5.1" + resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce" + dependencies: + duplexify "^3.6.0" + inherits "^2.0.3" + pump "^2.0.0" + +punycode@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + +punycode@^1.2.4, punycode@^1.3.2, punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + +q@^1.1.2: + version "1.5.1" + resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" + +qrcode-terminal@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/qrcode-terminal/-/qrcode-terminal-0.12.0.tgz#bb5b699ef7f9f0505092a3748be4464fe71b5819" + +qs@~6.4.0: + version "6.4.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" + +qs@~6.5.1: + version "6.5.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" + +query-string@^4.1.0: + version "4.3.4" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.4.tgz#bbb693b9ca915c232515b228b1a02b609043dbeb" + dependencies: + object-assign "^4.1.0" + strict-uri-encode "^1.0.0" + +query-string@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-6.1.0.tgz#01e7d69f6a0940dac67a937d6c6325647aa4532a" + dependencies: + decode-uri-component "^0.2.0" + strict-uri-encode "^2.0.0" + +querystring-es3@^0.2.0, querystring-es3@~0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" + +querystring@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + +quote-stream@^1.0.1, quote-stream@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/quote-stream/-/quote-stream-1.0.2.tgz#84963f8c9c26b942e153feeb53aae74652b7e0b2" + dependencies: + buffer-equal "0.0.1" + minimist "^1.1.3" + through2 "^2.0.0" + +qw@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/qw/-/qw-1.0.1.tgz#efbfdc740f9ad054304426acb183412cc8b996d4" + +randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: + version "2.0.6" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.6.tgz#d302c522948588848a8d300c932b44c24231da80" + dependencies: + safe-buffer "^5.1.0" + +randomfill@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" + dependencies: + randombytes "^2.0.5" + safe-buffer "^5.1.0" + +range-parser@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" + +rc@^1.0.1, rc@^1.1.6, rc@^1.2.7: + version "1.2.8" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + dependencies: + deep-extend "^0.6.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + +read-cmd-shim@^1.0.1, read-cmd-shim@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/read-cmd-shim/-/read-cmd-shim-1.0.1.tgz#2d5d157786a37c055d22077c32c53f8329e91c7b" + dependencies: + graceful-fs "^4.1.2" + +read-installed@~4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/read-installed/-/read-installed-4.0.3.tgz#ff9b8b67f187d1e4c29b9feb31f6b223acd19067" + dependencies: + debuglog "^1.0.1" + read-package-json "^2.0.0" + readdir-scoped-modules "^1.0.0" + semver "2 || 3 || 4 || 5" + slide "~1.1.3" + util-extend "^1.0.1" + optionalDependencies: + graceful-fs "^4.1.2" + +read-only-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-only-stream/-/read-only-stream-2.0.0.tgz#2724fd6a8113d73764ac288d4386270c1dbf17f0" + dependencies: + readable-stream "^2.0.2" + +"read-package-json@1 || 2", read-package-json@^2.0.0, read-package-json@^2.0.13: + version "2.0.13" + resolved "https://registry.yarnpkg.com/read-package-json/-/read-package-json-2.0.13.tgz#2e82ebd9f613baa6d2ebe3aa72cefe3f68e41f4a" + dependencies: + glob "^7.1.1" + json-parse-better-errors "^1.0.1" + normalize-package-data "^2.0.0" + slash "^1.0.0" + optionalDependencies: + graceful-fs "^4.1.2" + +read-package-tree@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/read-package-tree/-/read-package-tree-5.2.1.tgz#6218b187d6fac82289ce4387bbbaf8eef536ad63" + dependencies: + debuglog "^1.0.1" + dezalgo "^1.0.0" + once "^1.3.0" + read-package-json "^2.0.0" + readdir-scoped-modules "^1.0.0" + +read-pkg-up@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" + dependencies: + find-up "^2.0.0" + read-pkg "^2.0.0" + +read-pkg@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" + dependencies: + load-json-file "^2.0.0" + normalize-package-data "^2.3.2" + path-type "^2.0.0" + +read@1, read@~1.0.1, read@~1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/read/-/read-1.0.7.tgz#b3da19bd052431a97671d44a42634adf710b40c4" + dependencies: + mute-stream "~0.0.4" + +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.3: + version "2.3.6" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@~1.1.10: + version "1.1.14" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +readable-stream@~2.0.0: + version "2.0.6" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + string_decoder "~0.10.x" + util-deprecate "~1.0.1" + +readdir-scoped-modules@*, readdir-scoped-modules@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/readdir-scoped-modules/-/readdir-scoped-modules-1.0.2.tgz#9fafa37d286be5d92cbaebdee030dc9b5f406747" + dependencies: + debuglog "^1.0.1" + dezalgo "^1.0.0" + graceful-fs "^4.1.2" + once "^1.3.0" + +readdirp@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" + dependencies: + graceful-fs "^4.1.2" + minimatch "^3.0.2" + readable-stream "^2.0.2" + set-immediate-shim "^1.0.1" + +receptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/receptor/-/receptor-1.0.0.tgz#bf54477e0387e44bebf3855120bbda5adea08f8b" + dependencies: + element-closest "^2.0.1" + keyboardevent-key-polyfill "^1.0.2" + matches-selector "^1.0.0" + object-assign "^4.1.0" + +reduce-css-calc@^1.2.6: + version "1.3.0" + resolved "https://registry.yarnpkg.com/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz#747c914e049614a4c9cfbba629871ad1d2927716" + dependencies: + balanced-match "^0.4.2" + math-expression-evaluator "^1.2.14" + reduce-function-call "^1.0.1" + +reduce-css-calc@^2.0.0: + version "2.1.4" + resolved "https://registry.yarnpkg.com/reduce-css-calc/-/reduce-css-calc-2.1.4.tgz#c20e9cda8445ad73d4ff4bea960c6f8353791708" + dependencies: + css-unit-converter "^1.1.1" + postcss-value-parser "^3.3.0" + +reduce-function-call@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/reduce-function-call/-/reduce-function-call-1.0.2.tgz#5a200bf92e0e37751752fe45b0ab330fd4b6be99" + dependencies: + balanced-match "^0.4.2" + +regenerate@^1.2.1: + version "1.4.0" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" + +regenerator-runtime@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" + +regenerator-transform@^0.10.0: + version "0.10.1" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd" + dependencies: + babel-runtime "^6.18.0" + babel-types "^6.19.0" + private "^0.1.6" + +regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + +regexpu-core@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" + dependencies: + regenerate "^1.2.1" + regjsgen "^0.2.0" + regjsparser "^0.1.4" + +registry-auth-token@^3.0.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.3.2.tgz#851fd49038eecb586911115af845260eec983f20" + dependencies: + rc "^1.1.6" + safe-buffer "^5.0.1" + +registry-url@^3.0.3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942" + dependencies: + rc "^1.0.1" + +regjsgen@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" + +regjsparser@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" + dependencies: + jsesc "~0.5.0" + +remove-trailing-separator@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + +repeat-element@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" + +repeat-string@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + +repeating@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" + dependencies: + is-finite "^1.0.0" + +"request@>=2.9.0 <2.82.0": + version "2.81.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" + dependencies: + aws-sign2 "~0.6.0" + aws4 "^1.2.1" + caseless "~0.12.0" + combined-stream "~1.0.5" + extend "~3.0.0" + forever-agent "~0.6.1" + form-data "~2.1.1" + har-validator "~4.2.1" + hawk "~3.1.3" + http-signature "~1.1.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.7" + oauth-sign "~0.8.1" + performance-now "^0.2.0" + qs "~6.4.0" + safe-buffer "^5.0.1" + stringstream "~0.0.4" + tough-cookie "~2.3.0" + tunnel-agent "^0.6.0" + uuid "^3.0.0" + +request@^2.74.0, request@^2.81.0: + version "2.87.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.87.0.tgz#32f00235cd08d482b4d0d68db93a829c0ed5756e" + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.6.0" + caseless "~0.12.0" + combined-stream "~1.0.5" + extend "~3.0.1" + forever-agent "~0.6.1" + form-data "~2.3.1" + har-validator "~5.0.3" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.17" + oauth-sign "~0.8.2" + performance-now "^2.1.0" + qs "~6.5.1" + safe-buffer "^5.1.1" + tough-cookie "~2.3.3" + tunnel-agent "^0.6.0" + uuid "^3.1.0" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + +require-main-filename@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + +resolve-id-refs@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/resolve-id-refs/-/resolve-id-refs-0.1.0.tgz#3126624b887489da8fc0ae889632f8413ac6c3ec" + +resolve-url@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + +resolve@1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" + +resolve@^1.1.3, resolve@^1.1.4, resolve@^1.1.5, resolve@^1.4.0: + version "1.8.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.8.1.tgz#82f1ec19a423ac1fbd080b0bab06ba36e84a7a26" + dependencies: + path-parse "^1.0.5" + +restore-cursor@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" + dependencies: + onetime "^2.0.0" + signal-exit "^3.0.2" + +ret@~0.1.10: + version "0.1.15" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + +retry@^0.10.0: + version "0.10.1" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.10.1.tgz#e76388d217992c252750241d3d3956fed98d8ff4" + +retry@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" + +rgb-regex@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/rgb-regex/-/rgb-regex-1.0.1.tgz#c0e0d6882df0e23be254a475e8edd41915feaeb1" + +rgba-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3" + +rimraf@2, rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@~2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" + dependencies: + glob "^7.0.5" + +ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + +run-queue@^1.0.0, run-queue@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47" + dependencies: + aproba "^1.1.1" + +safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + +safe-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + dependencies: + ret "~0.1.10" + +"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + +safer-eval@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/safer-eval/-/safer-eval-1.2.3.tgz#73ba74a34bc8a07d6a44135c815fd18a8eebe7a0" + dependencies: + clones "^1.1.0" + +sax@^1.2.4, sax@~1.2.1, sax@~1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + +semver-diff@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36" + dependencies: + semver "^5.0.3" + +"semver@2 >=2.2.1 || 3.x || 4 || 5", "semver@2 || 3 || 4 || 5", "semver@2.x || 3.x || 4 || 5", "semver@^2.3.0 || 3.x || 4 || 5", semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" + +semver@~5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" + +send@0.16.2: + version "0.16.2" + resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1" + dependencies: + debug "2.6.9" + depd "~1.1.2" + destroy "~1.0.4" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "~1.6.2" + mime "1.4.1" + ms "2.0.0" + on-finished "~2.3.0" + range-parser "~1.2.0" + statuses "~1.4.0" + +serialize-to-js@^1.1.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/serialize-to-js/-/serialize-to-js-1.2.1.tgz#2e87f61f938826d24c463a7cbd0dd2929ec38008" + dependencies: + js-beautify "^1.7.5" + safer-eval "^1.2.3" + +serve-static@^1.12.4: + version "1.13.2" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1" + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.2" + send "0.16.2" + +set-blocking@^2.0.0, set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + +set-immediate-shim@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" + +set-value@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1" + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.1" + to-object-path "^0.3.0" + +set-value@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274" + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" + +setimmediate@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + +setprototypeof@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" + +sha.js@^2.4.0, sha.js@^2.4.8, sha.js@~2.4.4: + version "2.4.11" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +sha@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/sha/-/sha-2.0.1.tgz#6030822fbd2c9823949f8f72ed6411ee5cf25aae" + dependencies: + graceful-fs "^4.1.2" + readable-stream "^2.0.2" + +shallow-copy@~0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/shallow-copy/-/shallow-copy-0.0.1.tgz#415f42702d73d810330292cc5ee86eae1a11a170" + +shasum@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/shasum/-/shasum-1.0.2.tgz#e7012310d8f417f4deb5712150e5678b87ae565f" + dependencies: + json-stable-stringify "~0.0.0" + sha.js "~2.4.4" + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + dependencies: + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + +shell-quote@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.6.1.tgz#f4781949cce402697127430ea3b3c5476f481767" + dependencies: + array-filter "~0.0.0" + array-map "~0.0.0" + array-reduce "~0.0.0" + jsonify "~0.0.0" + +sigmund@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" + +signal-exit@^3.0.0, signal-exit@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + +simple-concat@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.0.tgz#7344cbb8b6e26fb27d66b2fc86f9f6d5997521c6" + +simple-swizzle@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" + dependencies: + is-arrayish "^0.3.1" + +slash@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" + +slide@^1.1.3, slide@^1.1.6, slide@~1.1.3, slide@~1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" + +smart-buffer@^1.0.13: + version "1.1.15" + resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-1.1.15.tgz#7f114b5b65fab3e2a35aa775bb12f0d1c649bf16" + +smart-buffer@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.0.1.tgz#07ea1ca8d4db24eb4cac86537d7d18995221ace3" + +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + dependencies: + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" + +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + dependencies: + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + dependencies: + base "^0.11.1" + debug "^2.2.0" + define-property "^0.2.5" + extend-shallow "^2.0.1" + map-cache "^0.2.2" + source-map "^0.5.6" + source-map-resolve "^0.5.0" + use "^3.1.0" + +sntp@1.x.x: + version "1.0.9" + resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" + dependencies: + hoek "2.x.x" + +socks-proxy-agent@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-3.0.1.tgz#2eae7cf8e2a82d34565761539a7f9718c5617659" + dependencies: + agent-base "^4.1.0" + socks "^1.1.10" + +socks-proxy-agent@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-4.0.1.tgz#5936bf8b707a993079c6f37db2091821bffa6473" + dependencies: + agent-base "~4.2.0" + socks "~2.2.0" + +socks@^1.1.10: + version "1.1.10" + resolved "https://registry.yarnpkg.com/socks/-/socks-1.1.10.tgz#5b8b7fc7c8f341c53ed056e929b7bf4de8ba7b5a" + dependencies: + ip "^1.1.4" + smart-buffer "^1.0.13" + +socks@~2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/socks/-/socks-2.2.1.tgz#68ad678b3642fbc5d99c64c165bc561eab0215f9" + dependencies: + ip "^1.1.5" + smart-buffer "^4.0.1" + +sort-keys@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad" + dependencies: + is-plain-obj "^1.0.0" + +sorted-object@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/sorted-object/-/sorted-object-2.0.1.tgz#7d631f4bd3a798a24af1dffcfbfe83337a5df5fc" + +sorted-union-stream@~2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/sorted-union-stream/-/sorted-union-stream-2.1.3.tgz#c7794c7e077880052ff71a8d4a2dbb4a9a638ac7" + dependencies: + from2 "^1.3.0" + stream-iterate "^1.1.0" + +source-map-resolve@^0.5.0: + version "0.5.2" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" + dependencies: + atob "^2.1.1" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + +source-map-support@^0.4.15: + version "0.4.18" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" + dependencies: + source-map "^0.5.6" + +source-map-support@~0.5.6: + version "0.5.6" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.6.tgz#4435cee46b1aab62b8e8610ce60f788091c51c13" + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map-url@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" + +source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + +source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.3: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + +spdx-correct@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.0.0.tgz#05a5b4d7153a195bc92c3c425b69f3b2a9524c82" + dependencies: + spdx-expression-parse "^3.0.0" + spdx-license-ids "^3.0.0" + +spdx-exceptions@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz#2c7ae61056c714a5b9b9b2b2af7d311ef5c78fe9" + +spdx-expression-parse@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz#7a7cd28470cc6d3a1cfe6d66886f6bc430d3ac87" + +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + dependencies: + extend-shallow "^3.0.0" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + +sshpk@^1.7.0: + version "1.14.2" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.14.2.tgz#c6fc61648a3d9c4e764fd3fcdf4ea105e492ba98" + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + dashdash "^1.12.0" + getpass "^0.1.1" + safer-buffer "^2.0.2" + optionalDependencies: + bcrypt-pbkdf "^1.0.0" + ecc-jsbn "~0.1.1" + jsbn "~0.1.0" + tweetnacl "~0.14.0" + +ssri@^5.2.4: + version "5.3.0" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-5.3.0.tgz#ba3872c9c6d33a0704a7d71ff045e5ec48999d06" + dependencies: + safe-buffer "^5.1.1" + +ssri@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.0.tgz#fc21bfc90e03275ac3e23d5a42e38b8a1cbc130d" + +stable@~0.1.6: + version "0.1.8" + resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" + +static-eval@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/static-eval/-/static-eval-2.0.0.tgz#0e821f8926847def7b4b50cda5d55c04a9b13864" + dependencies: + escodegen "^1.8.1" + +static-extend@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" + +static-module@^2.2.0: + version "2.2.5" + resolved "https://registry.yarnpkg.com/static-module/-/static-module-2.2.5.tgz#bd40abceae33da6b7afb84a0e4329ff8852bfbbf" + dependencies: + concat-stream "~1.6.0" + convert-source-map "^1.5.1" + duplexer2 "~0.1.4" + escodegen "~1.9.0" + falafel "^2.1.0" + has "^1.0.1" + magic-string "^0.22.4" + merge-source-map "1.0.4" + object-inspect "~1.4.0" + quote-stream "~1.0.2" + readable-stream "~2.3.3" + shallow-copy "~0.0.1" + static-eval "^2.0.0" + through2 "~2.0.3" + +"statuses@>= 1.4.0 < 2": + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + +statuses@~1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" + +stream-browserify@^2.0.0, stream-browserify@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db" + dependencies: + inherits "~2.0.1" + readable-stream "^2.0.2" + +stream-combiner2@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/stream-combiner2/-/stream-combiner2-1.1.1.tgz#fb4d8a1420ea362764e21ad4780397bebcb41cbe" + dependencies: + duplexer2 "~0.1.0" + readable-stream "^2.0.2" + +stream-each@^1.1.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae" + dependencies: + end-of-stream "^1.1.0" + stream-shift "^1.0.0" + +stream-http@^2.0.0, stream-http@^2.7.2: + version "2.8.3" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc" + dependencies: + builtin-status-codes "^3.0.0" + inherits "^2.0.1" + readable-stream "^2.3.6" + to-arraybuffer "^1.0.0" + xtend "^4.0.0" + +stream-iterate@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/stream-iterate/-/stream-iterate-1.2.0.tgz#2bd7c77296c1702a46488b8ad41f79865eecd4e1" + dependencies: + readable-stream "^2.1.5" + stream-shift "^1.0.0" + +stream-shift@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" + +stream-splicer@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/stream-splicer/-/stream-splicer-2.0.0.tgz#1b63be438a133e4b671cc1935197600175910d83" + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.2" + +strict-uri-encode@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" + +strict-uri-encode@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546" + +string-width@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +string_decoder@^1.0.0, string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + dependencies: + safe-buffer "~5.1.0" + +string_decoder@~0.10.0, string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + +stringify-package@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/stringify-package/-/stringify-package-1.0.0.tgz#e02828089333d7d45cd8c287c30aa9a13375081b" + +stringstream@~0.0.4: + version "0.0.6" + resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.6.tgz#7880225b0d4ad10e30927d167a1d6f2fd3b33a72" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + dependencies: + ansi-regex "^3.0.0" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + +strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + +stylehacks@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-4.0.0.tgz#64b323951c4a24e5fc7b2ec06c137bf32d155e8a" + dependencies: + browserslist "^4.0.0" + postcss "^6.0.0" + postcss-selector-parser "^3.0.0" + +subarg@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/subarg/-/subarg-1.0.0.tgz#f62cf17581e996b48fc965699f54c06ae268b8d2" + dependencies: + minimist "^1.1.0" + +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + +supports-color@^3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" + dependencies: + has-flag "^1.0.0" + +supports-color@^5.3.0, supports-color@^5.4.0: + version "5.4.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54" + dependencies: + has-flag "^3.0.0" + +svgo@^0.7.0: + version "0.7.2" + resolved "https://registry.yarnpkg.com/svgo/-/svgo-0.7.2.tgz#9f5772413952135c6fefbf40afe6a4faa88b4bb5" + dependencies: + coa "~1.0.1" + colors "~1.1.2" + csso "~2.3.1" + js-yaml "~3.7.0" + mkdirp "~0.5.1" + sax "~1.2.1" + whet.extend "~0.9.9" + +svgo@^1.0.0, svgo@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/svgo/-/svgo-1.0.5.tgz#7040364c062a0538abacff4401cea6a26a7a389a" + dependencies: + coa "~2.0.1" + colors "~1.1.2" + css-select "~1.3.0-rc0" + css-select-base-adapter "~0.1.0" + css-tree "1.0.0-alpha25" + css-url-regex "^1.1.0" + csso "^3.5.0" + js-yaml "~3.10.0" + mkdirp "~0.5.1" + object.values "^1.0.4" + sax "~1.2.4" + stable "~0.1.6" + unquote "~1.1.1" + util.promisify "~1.0.0" + +syntax-error@^1.1.1: + version "1.4.0" + resolved "https://registry.yarnpkg.com/syntax-error/-/syntax-error-1.4.0.tgz#2d9d4ff5c064acb711594a3e3b95054ad51d907c" + dependencies: + acorn-node "^1.2.0" + +tar@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" + dependencies: + block-stream "*" + fstream "^1.0.2" + inherits "2" + +tar@^4, tar@^4.4.3, tar@^4.4.4: + version "4.4.6" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.6.tgz#63110f09c00b4e60ac8bcfe1bf3c8660235fbc9b" + dependencies: + chownr "^1.0.1" + fs-minipass "^1.2.5" + minipass "^2.3.3" + minizlib "^1.1.0" + mkdirp "^0.5.0" + safe-buffer "^5.1.2" + yallist "^3.0.2" + +term-size@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/term-size/-/term-size-1.2.0.tgz#458b83887f288fc56d6fffbfad262e26638efa69" + dependencies: + execa "^0.7.0" + +terser@^3.7.3: + version "3.8.1" + resolved "https://registry.yarnpkg.com/terser/-/terser-3.8.1.tgz#cb70070ac9e0a71add169dfb63c0a64fca2738ac" + dependencies: + commander "~2.16.0" + source-map "~0.6.1" + source-map-support "~0.5.6" + +text-table@~0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + +through2@^2.0.0, through2@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be" + dependencies: + readable-stream "^2.1.5" + xtend "~4.0.1" + +"through@>=2.2.7 <3": + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + +timed-out@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" + +timers-browserify@^1.0.1: + version "1.4.2" + resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-1.4.2.tgz#c9c58b575be8407375cb5e2462dacee74359f41d" + dependencies: + process "~0.11.0" + +timers-browserify@^2.0.4: + version "2.0.10" + resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.10.tgz#1d28e3d2aadf1d5a5996c4e9f95601cd053480ae" + dependencies: + setimmediate "^1.0.4" + +timsort@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" + +tiny-inflate@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/tiny-inflate/-/tiny-inflate-1.0.2.tgz#93d9decffc8805bd57eae4310f0b745e9b6fb3a7" + +tiny-relative-date@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/tiny-relative-date/-/tiny-relative-date-1.3.0.tgz#fa08aad501ed730f31cc043181d995c39a935e07" + +to-arraybuffer@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" + +to-fast-properties@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" + +to-object-path@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + dependencies: + kind-of "^3.0.2" + +to-regex-range@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + dependencies: + is-number "^3.0.0" + repeat-string "^1.6.1" + +to-regex@^3.0.1, to-regex@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + dependencies: + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" + +toml@^2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/toml/-/toml-2.3.3.tgz#8d683d729577cb286231dfc7a8affe58d31728fb" + +tomlify-j0.4@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/tomlify-j0.4/-/tomlify-j0.4-3.0.0.tgz#99414d45268c3a3b8bf38be82145b7bba34b7473" + +tough-cookie@~2.3.0, tough-cookie@~2.3.3: + version "2.3.4" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.4.tgz#ec60cee38ac675063ffc97a5c18970578ee83655" + dependencies: + punycode "^1.4.1" + +trim-right@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" + +tty-browserify@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" + +tty-browserify@~0.0.0: + version "0.0.1" + resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.1.tgz#3f05251ee17904dfd0677546670db9651682b811" + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + dependencies: + safe-buffer "^5.0.1" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + dependencies: + prelude-ls "~1.1.2" + +typedarray@^0.0.6, typedarray@~0.0.5: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + +typescript@^2.4.1: + version "2.9.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.9.2.tgz#1cbf61d05d6b96269244eb6a3bce4bd914e0f00c" + +uglify-es@^3.3.9: + version "3.3.10" + resolved "https://registry.yarnpkg.com/uglify-es/-/uglify-es-3.3.10.tgz#8b0b7992cebe20edc26de1bf325cef797b8f3fa5" + dependencies: + commander "~2.14.1" + source-map "~0.6.1" + +uid-number@0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" + +umask@^1.1.0, umask@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/umask/-/umask-1.1.0.tgz#f29cebf01df517912bb58ff9c4e50fde8e33320d" + +umd@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/umd/-/umd-3.0.3.tgz#aa9fe653c42b9097678489c01000acb69f0b26cf" + +undeclared-identifiers@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/undeclared-identifiers/-/undeclared-identifiers-1.1.2.tgz#7d850a98887cff4bd0bf64999c014d08ed6d1acc" + dependencies: + acorn-node "^1.3.0" + get-assigned-identifiers "^1.2.0" + simple-concat "^1.0.0" + xtend "^4.0.1" + +unicode-trie@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/unicode-trie/-/unicode-trie-0.3.1.tgz#d671dddd89101a08bac37b6a5161010602052085" + dependencies: + pako "^0.2.5" + tiny-inflate "^1.0.0" + +union-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^0.4.3" + +uniq@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" + +uniqs@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02" + +unique-filename@^1.1.0, unique-filename@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.0.tgz#d05f2fe4032560871f30e93cbe735eea201514f3" + dependencies: + unique-slug "^2.0.0" + +unique-slug@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.0.tgz#db6676e7c7cc0629878ff196097c78855ae9f4ab" + dependencies: + imurmurhash "^0.1.4" + +unique-string@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a" + dependencies: + crypto-random-string "^1.0.0" + +unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + +unquote@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/unquote/-/unquote-1.1.1.tgz#8fded7324ec6e88a0ff8b905e7c098cdc086d544" + +unset-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + +unzip-response@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97" + +upath@^1.0.5: + version "1.1.0" + resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.0.tgz#35256597e46a581db4793d0ce47fa9aebfc9fabd" + +update-notifier@^2.3.0, update-notifier@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-2.5.0.tgz#d0744593e13f161e406acb1d9408b72cad08aff6" + dependencies: + boxen "^1.2.1" + chalk "^2.0.1" + configstore "^3.0.0" + import-lazy "^2.1.0" + is-ci "^1.0.10" + is-installed-globally "^0.1.0" + is-npm "^1.0.0" + latest-version "^3.0.0" + semver-diff "^2.0.0" + xdg-basedir "^3.0.0" + +urix@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + +url-parse-lax@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" + dependencies: + prepend-http "^1.0.1" + +url@^0.11.0, url@~0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" + dependencies: + punycode "1.3.2" + querystring "0.2.0" + +use@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + +uswds@^1.6.3: + version "1.6.7" + resolved "https://registry.yarnpkg.com/uswds/-/uswds-1.6.7.tgz#85ffa94a26da333e7e709b9fbc7292edab04ac82" + dependencies: + "@types/node" "^8.5.5" + array-filter "^1.0.0" + array-foreach "^1.0.2" + browserify "^13.0.0" + classlist-polyfill "^1.0.3" + domready "^1.0.8" + elem-dataset "^1.1.1" + lodash.debounce "^4.0.7" + object-assign "^4.1.1" + receptor "^1.0.0" + resolve-id-refs "^0.1.0" + typescript "^2.4.1" + yargs "^8.0.2" + +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + +util-extend@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/util-extend/-/util-extend-1.0.3.tgz#a7c216d267545169637b3b6edc6ca9119e2ff93f" + +util.promisify@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.0.tgz#440f7165a459c9a16dc145eb8e72f35687097030" + dependencies: + define-properties "^1.1.2" + object.getownpropertydescriptors "^2.0.3" + +util@0.10.3: + version "0.10.3" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" + dependencies: + inherits "2.0.1" + +util@^0.10.3, util@~0.10.1: + version "0.10.4" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.4.tgz#3aa0125bfe668a4672de58857d3ace27ecb76901" + dependencies: + inherits "2.0.3" + +uuid@^3.0.0, uuid@^3.1.0, uuid@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" + +v8-compile-cache@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.0.0.tgz#526492e35fc616864284700b7043e01baee09f0a" + +validate-npm-package-license@^3.0.1, validate-npm-package-license@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz#81643bcbef1bdfecd4623793dc4648948ba98338" + dependencies: + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" + +validate-npm-package-name@^3.0.0, validate-npm-package-name@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz#5fa912d81eb7d0c74afc140de7317f0ca7df437e" + dependencies: + builtins "^1.0.3" + +vendors@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.2.tgz#7fcb5eef9f5623b156bcea89ec37d63676f21801" + +verror@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + +vlq@^0.2.2: + version "0.2.3" + resolved "https://registry.yarnpkg.com/vlq/-/vlq-0.2.3.tgz#8f3e4328cf63b1540c0d67e1b2778386f8975b26" + +vm-browserify@0.0.4, vm-browserify@~0.0.1: + version "0.0.4" + resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73" + dependencies: + indexof "0.0.1" + +vue@^2.5.17: + version "2.5.17" + resolved "https://registry.yarnpkg.com/vue/-/vue-2.5.17.tgz#0f8789ad718be68ca1872629832ed533589c6ada" + +wcwidth@^1.0.0, wcwidth@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" + dependencies: + defaults "^1.0.3" + +whet.extend@~0.9.9: + version "0.9.9" + resolved "https://registry.yarnpkg.com/whet.extend/-/whet.extend-0.9.9.tgz#f877d5bf648c97e5aa542fadc16d6a259b9c11a1" + +which-module@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + +which@1, which@^1.2.9, which@^1.3.0, which@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + dependencies: + isexe "^2.0.0" + +wide-align@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" + dependencies: + string-width "^1.0.2 || 2" + +widest-line@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-2.0.0.tgz#0142a4e8a243f8882c0233aa0e0281aa76152273" + dependencies: + string-width "^2.1.1" + +wordwrap@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + +worker-farm@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.6.0.tgz#aecc405976fab5a95526180846f0dba288f3a4a0" + dependencies: + errno "~0.1.7" + +wrap-ansi@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + +write-file-atomic@^2.0.0, write-file-atomic@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.3.0.tgz#1ff61575c2e2a4e8e510d6fa4e243cce183999ab" + dependencies: + graceful-fs "^4.1.11" + imurmurhash "^0.1.4" + signal-exit "^3.0.2" + +ws@^5.1.1: + version "5.2.2" + resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.2.tgz#dffef14866b8e8dc9133582514d1befaf96e980f" + dependencies: + async-limiter "~1.0.0" + +xdg-basedir@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" + +xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" + +y18n@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" + +y18n@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" + +yallist@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + +yallist@^3.0.0, yallist@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.2.tgz#8452b4bb7e83c7c188d8041c1a837c773d6d8bb9" + +yargs-parser@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-7.0.0.tgz#8d0ac42f16ea55debd332caf4c4038b3e3f5dfd9" + dependencies: + camelcase "^4.1.0" + +yargs-parser@^9.0.2: + version "9.0.2" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-9.0.2.tgz#9ccf6a43460fe4ed40a9bb68f48d43b8a68cc077" + dependencies: + camelcase "^4.1.0" + +yargs@^11.0.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-11.1.0.tgz#90b869934ed6e871115ea2ff58b03f4724ed2d77" + dependencies: + cliui "^4.0.0" + decamelize "^1.1.1" + find-up "^2.1.0" + get-caller-file "^1.0.1" + os-locale "^2.0.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1" + yargs-parser "^9.0.2" + +yargs@^8.0.2: + version "8.0.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-8.0.2.tgz#6299a9055b1cefc969ff7e79c1d918dceb22c360" + dependencies: + camelcase "^4.1.0" + cliui "^3.2.0" + decamelize "^1.1.1" + get-caller-file "^1.0.1" + os-locale "^2.0.0" + read-pkg-up "^2.0.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1" + yargs-parser "^7.0.0" From 015adaf30f9f285e2a949d60ed72bc804fac37f8 Mon Sep 17 00:00:00 2001 From: Patrick Smith Date: Thu, 2 Aug 2018 13:51:54 -0400 Subject: [PATCH 093/332] Working parcel setup --- package.json | 5 + static/js/index.js | 4 + static/js/thing.js | 7 + {scss => static/scss}/README.md | 0 {scss => static/scss}/atat.scss | 2 +- {scss => static/scss}/components/_alerts.scss | 0 .../scss}/components/_empty_state.scss | 0 {scss => static/scss}/components/_footer.scss | 0 .../scss}/components/_global_layout.scss | 0 .../scss}/components/_global_navigation.scss | 0 {scss => static/scss}/components/_modal.scss | 0 .../scss}/components/_progress_menu.scss | 4 +- .../scss}/components/_search_bar.scss | 2 +- .../scss}/components/_site_action.scss | 0 {scss => static/scss}/components/_topbar.scss | 0 .../scss}/components/_workspace_layout.scss | 0 {scss => static/scss}/core/_grid.scss | 0 {scss => static/scss}/core/_util.scss | 0 {scss => static/scss}/core/_variables.scss | 0 .../scss}/elements/_action_group.scss | 0 .../scss}/elements/_block_lists.scss | 0 {scss => static/scss}/elements/_buttons.scss | 0 {scss => static/scss}/elements/_diff.scss | 0 .../scss}/elements/_icon_link.scss | 0 {scss => static/scss}/elements/_icons.scss | 0 {scss => static/scss}/elements/_inputs.scss | 0 {scss => static/scss}/elements/_labels.scss | 0 {scss => static/scss}/elements/_panels.scss | 0 {scss => static/scss}/elements/_sidenav.scss | 0 {scss => static/scss}/elements/_tables.scss | 0 .../scss}/elements/_typography.scss | 0 {scss => static/scss}/sections/_login.scss | 0 .../scss}/sections/_member_edit.scss | 0 .../scss}/sections/_project_edit.scss | 0 .../scss}/sections/_projects_list.scss | 0 .../scss}/sections/_request_approval.scss | 0 templates/base.html | 5 +- templates/home.html | 1 + yarn.lock | 391 +++++++++++++++--- 39 files changed, 349 insertions(+), 72 deletions(-) create mode 100644 static/js/index.js create mode 100644 static/js/thing.js rename {scss => static/scss}/README.md (100%) rename {scss => static/scss}/atat.scss (94%) rename {scss => static/scss}/components/_alerts.scss (100%) rename {scss => static/scss}/components/_empty_state.scss (100%) rename {scss => static/scss}/components/_footer.scss (100%) rename {scss => static/scss}/components/_global_layout.scss (100%) rename {scss => static/scss}/components/_global_navigation.scss (100%) rename {scss => static/scss}/components/_modal.scss (100%) rename {scss => static/scss}/components/_progress_menu.scss (96%) rename {scss => static/scss}/components/_search_bar.scss (95%) rename {scss => static/scss}/components/_site_action.scss (100%) rename {scss => static/scss}/components/_topbar.scss (100%) rename {scss => static/scss}/components/_workspace_layout.scss (100%) rename {scss => static/scss}/core/_grid.scss (100%) rename {scss => static/scss}/core/_util.scss (100%) rename {scss => static/scss}/core/_variables.scss (100%) rename {scss => static/scss}/elements/_action_group.scss (100%) rename {scss => static/scss}/elements/_block_lists.scss (100%) rename {scss => static/scss}/elements/_buttons.scss (100%) rename {scss => static/scss}/elements/_diff.scss (100%) rename {scss => static/scss}/elements/_icon_link.scss (100%) rename {scss => static/scss}/elements/_icons.scss (100%) rename {scss => static/scss}/elements/_inputs.scss (100%) rename {scss => static/scss}/elements/_labels.scss (100%) rename {scss => static/scss}/elements/_panels.scss (100%) rename {scss => static/scss}/elements/_sidenav.scss (100%) rename {scss => static/scss}/elements/_tables.scss (100%) rename {scss => static/scss}/elements/_typography.scss (100%) rename {scss => static/scss}/sections/_login.scss (100%) rename {scss => static/scss}/sections/_member_edit.scss (100%) rename {scss => static/scss}/sections/_project_edit.scss (100%) rename {scss => static/scss}/sections/_projects_list.scss (100%) rename {scss => static/scss}/sections/_request_approval.scss (100%) diff --git a/package.json b/package.json index 9a474e0d..4d7b794e 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,8 @@ "description": "ATST Stateless Services", "main": "index.js", "scripts": { + "watch": "parcel watch static/js/index.js -d static/assets -o index.js --no-autoinstall", + "build": "parcel build static/js/index.js -d static/assets -o index.js --no-autoinstall", "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", @@ -13,5 +15,8 @@ "parcel": "^1.9.7", "uswds": "^1.6.3", "vue": "^2.5.17" + }, + "devDependencies": { + "node-sass": "^4.9.2" } } diff --git a/static/js/index.js b/static/js/index.js new file mode 100644 index 00000000..9cc49957 --- /dev/null +++ b/static/js/index.js @@ -0,0 +1,4 @@ +import classes from '../scss/atat.scss' + +import './thing' + diff --git a/static/js/thing.js b/static/js/thing.js new file mode 100644 index 00000000..033b8cd3 --- /dev/null +++ b/static/js/thing.js @@ -0,0 +1,7 @@ +console.log('hanlo again') +window.onload = function() { + console.log('boop') + const thing = document.querySelector('#hello') + thing.innerHTML = 'hanlo friendo' +} + diff --git a/scss/README.md b/static/scss/README.md similarity index 100% rename from scss/README.md rename to static/scss/README.md diff --git a/scss/atat.scss b/static/scss/atat.scss similarity index 94% rename from scss/atat.scss rename to static/scss/atat.scss index b4ae7797..040cc201 100644 --- a/scss/atat.scss +++ b/static/scss/atat.scss @@ -1,5 +1,5 @@ @import 'core/variables'; -@import '../node_modules/uswds/src/stylesheets/uswds'; +@import '../../node_modules/uswds/src/stylesheets/uswds'; @import 'core/grid'; @import 'core/util'; diff --git a/scss/components/_alerts.scss b/static/scss/components/_alerts.scss similarity index 100% rename from scss/components/_alerts.scss rename to static/scss/components/_alerts.scss diff --git a/scss/components/_empty_state.scss b/static/scss/components/_empty_state.scss similarity index 100% rename from scss/components/_empty_state.scss rename to static/scss/components/_empty_state.scss diff --git a/scss/components/_footer.scss b/static/scss/components/_footer.scss similarity index 100% rename from scss/components/_footer.scss rename to static/scss/components/_footer.scss diff --git a/scss/components/_global_layout.scss b/static/scss/components/_global_layout.scss similarity index 100% rename from scss/components/_global_layout.scss rename to static/scss/components/_global_layout.scss diff --git a/scss/components/_global_navigation.scss b/static/scss/components/_global_navigation.scss similarity index 100% rename from scss/components/_global_navigation.scss rename to static/scss/components/_global_navigation.scss diff --git a/scss/components/_modal.scss b/static/scss/components/_modal.scss similarity index 100% rename from scss/components/_modal.scss rename to static/scss/components/_modal.scss diff --git a/scss/components/_progress_menu.scss b/static/scss/components/_progress_menu.scss similarity index 96% rename from scss/components/_progress_menu.scss rename to static/scss/components/_progress_menu.scss index 3ca7bb72..a675dfb7 100644 --- a/scss/components/_progress_menu.scss +++ b/static/scss/components/_progress_menu.scss @@ -88,7 +88,7 @@ } &--complete:before { - content: url('/static/icons/checkmark.svg'); + content: url('#{$asset-path}/icons/checkmark.svg'); background-color: $color-blue; border: 2px solid $color-blue; font-size: $h6-font-size; @@ -100,4 +100,4 @@ } } -} \ No newline at end of file +} diff --git a/scss/components/_search_bar.scss b/static/scss/components/_search_bar.scss similarity index 95% rename from scss/components/_search_bar.scss rename to static/scss/components/_search_bar.scss index f5c031f8..dbc795d2 100644 --- a/scss/components/_search_bar.scss +++ b/static/scss/components/_search_bar.scss @@ -62,7 +62,7 @@ text-align: center; &:after { - content: url('/static/icons/search.svg'); + content: url('#{$asset-path}/icons/search.svg'); display: inline-block; width: 1.6rem; height: 1.6rem; diff --git a/scss/components/_site_action.scss b/static/scss/components/_site_action.scss similarity index 100% rename from scss/components/_site_action.scss rename to static/scss/components/_site_action.scss diff --git a/scss/components/_topbar.scss b/static/scss/components/_topbar.scss similarity index 100% rename from scss/components/_topbar.scss rename to static/scss/components/_topbar.scss diff --git a/scss/components/_workspace_layout.scss b/static/scss/components/_workspace_layout.scss similarity index 100% rename from scss/components/_workspace_layout.scss rename to static/scss/components/_workspace_layout.scss diff --git a/scss/core/_grid.scss b/static/scss/core/_grid.scss similarity index 100% rename from scss/core/_grid.scss rename to static/scss/core/_grid.scss diff --git a/scss/core/_util.scss b/static/scss/core/_util.scss similarity index 100% rename from scss/core/_util.scss rename to static/scss/core/_util.scss diff --git a/scss/core/_variables.scss b/static/scss/core/_variables.scss similarity index 100% rename from scss/core/_variables.scss rename to static/scss/core/_variables.scss diff --git a/scss/elements/_action_group.scss b/static/scss/elements/_action_group.scss similarity index 100% rename from scss/elements/_action_group.scss rename to static/scss/elements/_action_group.scss diff --git a/scss/elements/_block_lists.scss b/static/scss/elements/_block_lists.scss similarity index 100% rename from scss/elements/_block_lists.scss rename to static/scss/elements/_block_lists.scss diff --git a/scss/elements/_buttons.scss b/static/scss/elements/_buttons.scss similarity index 100% rename from scss/elements/_buttons.scss rename to static/scss/elements/_buttons.scss diff --git a/scss/elements/_diff.scss b/static/scss/elements/_diff.scss similarity index 100% rename from scss/elements/_diff.scss rename to static/scss/elements/_diff.scss diff --git a/scss/elements/_icon_link.scss b/static/scss/elements/_icon_link.scss similarity index 100% rename from scss/elements/_icon_link.scss rename to static/scss/elements/_icon_link.scss diff --git a/scss/elements/_icons.scss b/static/scss/elements/_icons.scss similarity index 100% rename from scss/elements/_icons.scss rename to static/scss/elements/_icons.scss diff --git a/scss/elements/_inputs.scss b/static/scss/elements/_inputs.scss similarity index 100% rename from scss/elements/_inputs.scss rename to static/scss/elements/_inputs.scss diff --git a/scss/elements/_labels.scss b/static/scss/elements/_labels.scss similarity index 100% rename from scss/elements/_labels.scss rename to static/scss/elements/_labels.scss diff --git a/scss/elements/_panels.scss b/static/scss/elements/_panels.scss similarity index 100% rename from scss/elements/_panels.scss rename to static/scss/elements/_panels.scss diff --git a/scss/elements/_sidenav.scss b/static/scss/elements/_sidenav.scss similarity index 100% rename from scss/elements/_sidenav.scss rename to static/scss/elements/_sidenav.scss diff --git a/scss/elements/_tables.scss b/static/scss/elements/_tables.scss similarity index 100% rename from scss/elements/_tables.scss rename to static/scss/elements/_tables.scss diff --git a/scss/elements/_typography.scss b/static/scss/elements/_typography.scss similarity index 100% rename from scss/elements/_typography.scss rename to static/scss/elements/_typography.scss diff --git a/scss/sections/_login.scss b/static/scss/sections/_login.scss similarity index 100% rename from scss/sections/_login.scss rename to static/scss/sections/_login.scss diff --git a/scss/sections/_member_edit.scss b/static/scss/sections/_member_edit.scss similarity index 100% rename from scss/sections/_member_edit.scss rename to static/scss/sections/_member_edit.scss diff --git a/scss/sections/_project_edit.scss b/static/scss/sections/_project_edit.scss similarity index 100% rename from scss/sections/_project_edit.scss rename to static/scss/sections/_project_edit.scss diff --git a/scss/sections/_projects_list.scss b/static/scss/sections/_projects_list.scss similarity index 100% rename from scss/sections/_projects_list.scss rename to static/scss/sections/_projects_list.scss diff --git a/scss/sections/_request_approval.scss b/static/scss/sections/_request_approval.scss similarity index 100% rename from scss/sections/_request_approval.scss rename to static/scss/sections/_request_approval.scss diff --git a/templates/base.html b/templates/base.html index 2414f6f1..aaae0374 100644 --- a/templates/base.html +++ b/templates/base.html @@ -8,9 +8,7 @@ {% block title %}JEDI{% endblock %} - {% assets "css" %} - - {% endassets %} + @@ -34,5 +32,6 @@ {% include 'footer.html' %} {% block modal %}{% endblock %} + diff --git a/templates/home.html b/templates/home.html index 0df70037..056d62b8 100644 --- a/templates/home.html +++ b/templates/home.html @@ -5,6 +5,7 @@

    Home

    +
    diff --git a/yarn.lock b/yarn.lock index ca8a5e51..b8e561fc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -78,6 +78,10 @@ alphanum-sort@^1.0.0, alphanum-sort@^1.0.1, alphanum-sort@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" +amdefine@>=0.0.4: + version "1.0.1" + resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" + ansi-align@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-2.0.0.tgz#c36aeccba563b89ceb556f3690f0b1d9e3547f7f" @@ -168,6 +172,10 @@ array-filter@~0.0.0: version "0.0.1" resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-0.0.1.tgz#7da8cf2e26628ed732803581fd21f67cacd2eeec" +array-find-index@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" + array-foreach@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/array-foreach/-/array-foreach-1.0.2.tgz#cd36e42f0f482108c406b35c3612a8970b2fccea" @@ -222,6 +230,10 @@ async-each@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" +async-foreach@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/async-foreach/-/async-foreach-0.1.3.tgz#36121f845c0578172de419a97dbeb1d16ec34542" + async-limiter@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" @@ -1115,6 +1127,21 @@ call-me-maybe@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b" +camelcase-keys@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" + dependencies: + camelcase "^2.0.0" + map-obj "^1.0.0" + +camelcase@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" + +camelcase@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" + camelcase@^4.0.0, camelcase@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" @@ -1153,7 +1180,7 @@ caseless@~0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" -chalk@^1.1.3: +chalk@^1.1.1, chalk@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" dependencies: @@ -1544,6 +1571,13 @@ create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: safe-buffer "^5.0.1" sha.js "^2.4.8" +cross-spawn@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-3.0.1.tgz#1256037ecb9f0c5f79e3d6ef135e30770184b982" + dependencies: + lru-cache "^4.0.1" + which "^1.2.9" + cross-spawn@^5.0.1: version "5.1.0" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" @@ -1750,6 +1784,12 @@ csso@~2.3.1: clap "^1.0.9" source-map "^0.5.3" +currently-unhandled@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" + dependencies: + array-find-index "^1.0.1" + cyclist@~0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640" @@ -1783,7 +1823,7 @@ debug@3.1.0, debug@^3.1.0: dependencies: ms "2.0.0" -debuglog@*, debuglog@^1.0.1: +debuglog@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" @@ -2280,6 +2320,13 @@ find-npm-prefix@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/find-npm-prefix/-/find-npm-prefix-1.0.2.tgz#8d8ce2c78b3b4b9e66c8acc6a37c231eb841cfdf" +find-up@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" + dependencies: + path-exists "^2.0.0" + pinkie-promise "^2.0.0" + find-up@^2.0.0, find-up@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" @@ -2415,6 +2462,12 @@ gauge@~2.7.3: strip-ansi "^3.0.1" wide-align "^1.1.0" +gaze@^1.0.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/gaze/-/gaze-1.1.3.tgz#c441733e13b927ac8c0ff0b4c3b033f28812924a" + dependencies: + globule "^1.0.0" + genfun@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/genfun/-/genfun-4.0.1.tgz#ed10041f2e4a7f1b0a38466d17a5c3e27df1dfc1" @@ -2444,6 +2497,10 @@ get-port@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/get-port/-/get-port-3.2.0.tgz#dd7ce7de187c06c8bf353796ac71e099f0980ebc" +get-stdin@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" + get-stream@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" @@ -2469,7 +2526,17 @@ glob-to-regexp@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab" -glob@^7.0.3, glob@^7.0.5, glob@^7.1.0, glob@^7.1.1, glob@^7.1.2, glob@~7.1.2: +glob@^6.0.4: + version "6.0.4" + resolved "https://registry.yarnpkg.com/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22" + dependencies: + inflight "^1.0.4" + inherits "2" + minimatch "2 || 3" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.0, glob@^7.1.1, glob@^7.1.2, glob@~7.1.1, glob@~7.1.2: version "7.1.2" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" dependencies: @@ -2490,6 +2557,14 @@ globals@^9.18.0: version "9.18.0" resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" +globule@^1.0.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/globule/-/globule-1.2.1.tgz#5dffb1b191f22d20797a9369b49eab4e9839696d" + dependencies: + glob "~7.1.1" + lodash "~4.17.10" + minimatch "~3.0.2" + got@^6.7.1: version "6.7.1" resolved "https://registry.yarnpkg.com/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0" @@ -2763,10 +2838,20 @@ import-lazy@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" -imurmurhash@*, imurmurhash@^0.1.4: +imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" +in-publish@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/in-publish/-/in-publish-2.0.0.tgz#e20ff5e3a2afc2690320b6dc552682a9c7fadf51" + +indent-string@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" + dependencies: + repeating "^2.0.0" + indexes-of@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607" @@ -3074,6 +3159,10 @@ is-url@^1.2.2: version "1.2.4" resolved "https://registry.yarnpkg.com/is-url/-/is-url-1.2.4.tgz#04a4df46d28c4cff3d73d01ff06abeb318a1aa52" +is-utf8@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" + is-windows@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" @@ -3112,7 +3201,7 @@ isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" -js-base64@^2.1.9: +js-base64@^2.1.8, js-base64@^2.1.9: version "2.4.8" resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.4.8.tgz#57a9b130888f956834aa40c5b165ba59c758f033" @@ -3315,6 +3404,16 @@ libnpx@^10.2.0: y18n "^4.0.0" yargs "^11.0.0" +load-json-file@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + pinkie-promise "^2.0.0" + strip-bom "^2.0.0" + load-json-file@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" @@ -3344,10 +3443,6 @@ lockfile@^1.0.4: dependencies: signal-exit "^3.0.2" -lodash._baseindexof@*: - version "3.1.0" - resolved "https://registry.yarnpkg.com/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz#fe52b53a1c6761e42618d654e4a25789ed61822c" - lodash._baseuniq@~4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz#0ebb44e456814af7905c6212fa2c9b2d51b841e8" @@ -3355,37 +3450,23 @@ lodash._baseuniq@~4.6.0: lodash._createset "~4.0.0" lodash._root "~3.0.0" -lodash._bindcallback@*: - version "3.0.1" - resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" - -lodash._cacheindexof@*: - version "3.0.2" - resolved "https://registry.yarnpkg.com/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz#3dc69ac82498d2ee5e3ce56091bafd2adc7bde92" - -lodash._createcache@*: - version "3.1.2" - resolved "https://registry.yarnpkg.com/lodash._createcache/-/lodash._createcache-3.1.2.tgz#56d6a064017625e79ebca6b8018e17440bdcf093" - dependencies: - lodash._getnative "^3.0.0" - lodash._createset@~4.0.0: version "4.0.3" resolved "https://registry.yarnpkg.com/lodash._createset/-/lodash._createset-4.0.3.tgz#0f4659fbb09d75194fa9e2b88a6644d363c9fe26" -lodash._getnative@*, lodash._getnative@^3.0.0: - version "3.9.1" - resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" - lodash._root@~3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692" +lodash.assign@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" + lodash.clone@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.clone/-/lodash.clone-4.5.0.tgz#195870450f5a13192478df4bc3d23d2dea1907b6" -lodash.clonedeep@~4.5.0: +lodash.clonedeep@^4.3.2, lodash.clonedeep@~4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" @@ -3401,9 +3482,9 @@ lodash.memoize@~3.0.3: version "3.0.4" resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-3.0.4.tgz#2dcbd2c287cbc0a55cc42328bd0c736150d53e3f" -lodash.restparam@*: - version "3.6.1" - resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" +lodash.mergewith@^4.6.0: + version "4.6.1" + resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.1.tgz#639057e726c3afbdb3e7d42741caa8d6e4335927" lodash.union@~4.6.0: version "4.6.0" @@ -3417,7 +3498,7 @@ lodash.without@~4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.without/-/lodash.without-4.4.0.tgz#3cd4574a00b67bae373a94b748772640507b7aac" -lodash@^4.17.4: +lodash@^4.0.0, lodash@^4.17.4, lodash@~4.17.10: version "4.17.10" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" @@ -3433,6 +3514,13 @@ loose-envify@^1.0.0: dependencies: js-tokens "^3.0.0 || ^4.0.0" +loud-rejection@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" + dependencies: + currently-unhandled "^0.4.1" + signal-exit "^3.0.0" + lowercase-keys@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" @@ -3498,6 +3586,10 @@ map-cache@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" +map-obj@^1.0.0, map-obj@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" + map-visit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" @@ -3533,6 +3625,21 @@ mem@^1.1.0: dependencies: mimic-fn "^1.0.0" +meow@^3.7.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" + dependencies: + camelcase-keys "^2.0.0" + decamelize "^1.1.2" + loud-rejection "^1.0.0" + map-obj "^1.0.1" + minimist "^1.1.3" + normalize-package-data "^2.3.4" + object-assign "^4.0.1" + read-pkg-up "^1.0.1" + redent "^1.0.0" + trim-newlines "^1.0.0" + merge-source-map@1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/merge-source-map/-/merge-source-map-1.0.4.tgz#a5de46538dae84d4114cc5ea02b4772a6346701f" @@ -3594,7 +3701,7 @@ minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" -minimatch@^3.0.2, minimatch@^3.0.4: +"minimatch@2 || 3", minimatch@^3.0.2, minimatch@^3.0.4, minimatch@~3.0.2: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" dependencies: @@ -3707,7 +3814,7 @@ mute-stream@~0.0.4: version "0.0.7" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" -nan@^2.0.7, nan@^2.9.2: +nan@^2.0.7, nan@^2.10.0, nan@^2.9.2: version "2.10.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f" @@ -3751,7 +3858,7 @@ node-forge@^0.7.1: version "0.7.5" resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.7.5.tgz#6c152c345ce11c52f465c2abd957e8639cd674df" -node-gyp@^3.6.2, node-gyp@^3.7.0: +node-gyp@^3.3.1, node-gyp@^3.6.2, node-gyp@^3.7.0: version "3.7.0" resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.7.0.tgz#789478e8f6c45e277aa014f3e28f958f286f9203" dependencies: @@ -3817,6 +3924,30 @@ node-releases@^1.0.0-alpha.10: dependencies: semver "^5.3.0" +node-sass@^4.9.2: + version "4.9.2" + resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.9.2.tgz#5e63fe6bd0f2ae3ac9d6c14ede8620e2b8bdb437" + dependencies: + async-foreach "^0.1.3" + chalk "^1.1.1" + cross-spawn "^3.0.0" + gaze "^1.0.0" + get-stdin "^4.0.1" + glob "^7.0.3" + in-publish "^2.0.0" + lodash.assign "^4.2.0" + lodash.clonedeep "^4.3.2" + lodash.mergewith "^4.6.0" + meow "^3.7.0" + mkdirp "^0.5.1" + nan "^2.10.0" + node-gyp "^3.3.1" + npmlog "^4.0.0" + request "2.87.0" + sass-graph "^2.2.4" + stdout-stream "^1.4.0" + "true-case-path" "^1.0.2" + "nopt@2 || 3", nopt@~3.0.1: version "3.0.6" resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" @@ -3830,7 +3961,7 @@ nopt@^4.0.1, nopt@~4.0.1: abbrev "1" osenv "^0.1.4" -normalize-package-data@^2.0.0, normalize-package-data@^2.3.2, normalize-package-data@^2.4.0, "normalize-package-data@~1.0.1 || ^2.0.0", normalize-package-data@~2.4.0: +normalize-package-data@^2.0.0, normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, normalize-package-data@^2.4.0, "normalize-package-data@~1.0.1 || ^2.0.0", normalize-package-data@~2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" dependencies: @@ -4092,7 +4223,7 @@ npm@^6.0.1: worker-farm "^1.6.0" write-file-atomic "^2.3.0" -"npmlog@0 || 1 || 2 || 3 || 4", "npmlog@2 || ^3.1.0 || ^4.0.0", npmlog@^4.0.2, npmlog@~4.1.2: +"npmlog@0 || 1 || 2 || 3 || 4", "npmlog@2 || ^3.1.0 || ^4.0.0", npmlog@^4.0.0, npmlog@^4.0.2, npmlog@~4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" dependencies: @@ -4229,6 +4360,12 @@ os-homedir@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" +os-locale@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" + dependencies: + lcid "^1.0.0" + os-locale@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2" @@ -4431,6 +4568,12 @@ path-dirname@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" +path-exists@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" + dependencies: + pinkie-promise "^2.0.0" + path-exists@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" @@ -4455,6 +4598,14 @@ path-platform@~0.11.15: version "0.11.15" resolved "https://registry.yarnpkg.com/path-platform/-/path-platform-0.11.15.tgz#e864217f74c36850f0852b78dc7bf7d4a5721bf2" +path-type@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" + dependencies: + graceful-fs "^4.1.2" + pify "^2.0.0" + pinkie-promise "^2.0.0" + path-type@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" @@ -4491,6 +4642,16 @@ pify@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + posix-character-classes@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" @@ -5188,6 +5349,13 @@ read-package-tree@^5.2.1: read-package-json "^2.0.0" readdir-scoped-modules "^1.0.0" +read-pkg-up@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" + dependencies: + find-up "^1.0.0" + read-pkg "^1.0.0" + read-pkg-up@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" @@ -5195,6 +5363,14 @@ read-pkg-up@^2.0.0: find-up "^2.0.0" read-pkg "^2.0.0" +read-pkg@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" + dependencies: + load-json-file "^1.0.0" + normalize-package-data "^2.3.2" + path-type "^1.0.0" + read-pkg@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" @@ -5209,7 +5385,7 @@ read@1, read@~1.0.1, read@~1.0.7: dependencies: mute-stream "~0.0.4" -"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.3: +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.3: version "2.3.6" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" dependencies: @@ -5241,7 +5417,7 @@ readable-stream@~2.0.0: string_decoder "~0.10.x" util-deprecate "~1.0.1" -readdir-scoped-modules@*, readdir-scoped-modules@^1.0.0: +readdir-scoped-modules@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/readdir-scoped-modules/-/readdir-scoped-modules-1.0.2.tgz#9fafa37d286be5d92cbaebdee030dc9b5f406747" dependencies: @@ -5268,6 +5444,13 @@ receptor@^1.0.0: matches-selector "^1.0.0" object-assign "^4.1.0" +redent@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" + dependencies: + indent-string "^2.1.0" + strip-indent "^1.0.1" + reduce-css-calc@^1.2.6: version "1.3.0" resolved "https://registry.yarnpkg.com/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz#747c914e049614a4c9cfbba629871ad1d2927716" @@ -5361,6 +5544,31 @@ repeating@^2.0.0: dependencies: is-finite "^1.0.0" +request@2.87.0, request@^2.74.0, request@^2.81.0: + version "2.87.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.87.0.tgz#32f00235cd08d482b4d0d68db93a829c0ed5756e" + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.6.0" + caseless "~0.12.0" + combined-stream "~1.0.5" + extend "~3.0.1" + forever-agent "~0.6.1" + form-data "~2.3.1" + har-validator "~5.0.3" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.17" + oauth-sign "~0.8.2" + performance-now "^2.1.0" + qs "~6.5.1" + safe-buffer "^5.1.1" + tough-cookie "~2.3.3" + tunnel-agent "^0.6.0" + uuid "^3.1.0" + "request@>=2.9.0 <2.82.0": version "2.81.0" resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" @@ -5388,31 +5596,6 @@ repeating@^2.0.0: tunnel-agent "^0.6.0" uuid "^3.0.0" -request@^2.74.0, request@^2.81.0: - version "2.87.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.87.0.tgz#32f00235cd08d482b4d0d68db93a829c0ed5756e" - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.6.0" - caseless "~0.12.0" - combined-stream "~1.0.5" - extend "~3.0.1" - forever-agent "~0.6.1" - form-data "~2.3.1" - har-validator "~5.0.3" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.17" - oauth-sign "~0.8.2" - performance-now "^2.1.0" - qs "~6.5.1" - safe-buffer "^5.1.1" - tough-cookie "~2.3.3" - tunnel-agent "^0.6.0" - uuid "^3.1.0" - require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" @@ -5509,10 +5692,26 @@ safer-eval@^1.2.3: dependencies: clones "^1.1.0" +sass-graph@^2.2.4: + version "2.2.4" + resolved "https://registry.yarnpkg.com/sass-graph/-/sass-graph-2.2.4.tgz#13fbd63cd1caf0908b9fd93476ad43a51d1e0b49" + dependencies: + glob "^7.0.0" + lodash "^4.0.0" + scss-tokenizer "^0.2.3" + yargs "^7.0.0" + sax@^1.2.4, sax@~1.2.1, sax@~1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" +scss-tokenizer@^0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz#8eb06db9a9723333824d3f5530641149847ce5d1" + dependencies: + js-base64 "^2.1.8" + source-map "^0.4.2" + semver-diff@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36" @@ -5782,6 +5981,12 @@ source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" +source-map@^0.4.2: + version "0.4.4" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" + dependencies: + amdefine ">=0.0.4" + source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.3: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" @@ -5887,6 +6092,12 @@ statuses@~1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" +stdout-stream@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/stdout-stream/-/stdout-stream-1.4.0.tgz#a2c7c8587e54d9427ea9edb3ac3f2cd522df378b" + dependencies: + readable-stream "^2.0.1" + stream-browserify@^2.0.0, stream-browserify@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db" @@ -5944,7 +6155,7 @@ strict-uri-encode@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546" -string-width@^1.0.1: +string-width@^1.0.1, string-width@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" dependencies: @@ -5989,6 +6200,12 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" +strip-bom@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" + dependencies: + is-utf8 "^0.2.0" + strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" @@ -5997,6 +6214,12 @@ strip-eof@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" +strip-indent@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" + dependencies: + get-stdin "^4.0.1" + strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" @@ -6189,10 +6412,20 @@ tough-cookie@~2.3.0, tough-cookie@~2.3.3: dependencies: punycode "^1.4.1" +trim-newlines@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" + trim-right@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" +"true-case-path@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/true-case-path/-/true-case-path-1.0.2.tgz#7ec91130924766c7f573be3020c34f8fdfd00d62" + dependencies: + glob "^6.0.4" + tty-browserify@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" @@ -6456,6 +6689,10 @@ whet.extend@~0.9.9: version "0.9.9" resolved "https://registry.yarnpkg.com/whet.extend/-/whet.extend-0.9.9.tgz#f877d5bf648c97e5aa542fadc16d6a259b9c11a1" +which-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" + which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" @@ -6537,6 +6774,12 @@ yallist@^3.0.0, yallist@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.2.tgz#8452b4bb7e83c7c188d8041c1a837c773d6d8bb9" +yargs-parser@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-5.0.0.tgz#275ecf0d7ffe05c77e64e7c86e4cd94bf0e1228a" + dependencies: + camelcase "^3.0.0" + yargs-parser@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-7.0.0.tgz#8d0ac42f16ea55debd332caf4c4038b3e3f5dfd9" @@ -6566,6 +6809,24 @@ yargs@^11.0.0: y18n "^3.2.1" yargs-parser "^9.0.2" +yargs@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-7.1.0.tgz#6ba318eb16961727f5d284f8ea003e8d6154d0c8" + dependencies: + camelcase "^3.0.0" + cliui "^3.2.0" + decamelize "^1.1.1" + get-caller-file "^1.0.1" + os-locale "^1.4.0" + read-pkg-up "^1.0.1" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^1.0.2" + which-module "^1.0.0" + y18n "^3.2.1" + yargs-parser "^5.0.0" + yargs@^8.0.2: version "8.0.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-8.0.2.tgz#6299a9055b1cefc969ff7e79c1d918dceb22c360" From b67b4cca4440be4b1b4ca3c50cf22af0653aaac6 Mon Sep 17 00:00:00 2001 From: Patrick Smith Date: Thu, 2 Aug 2018 14:33:21 -0400 Subject: [PATCH 094/332] Move styles to "styles" directory --- static/js/index.js | 2 +- static/{scss => styles}/README.md | 0 static/{scss => styles}/atat.scss | 0 static/{scss => styles}/components/_alerts.scss | 0 static/{scss => styles}/components/_empty_state.scss | 0 static/{scss => styles}/components/_footer.scss | 0 static/{scss => styles}/components/_global_layout.scss | 0 static/{scss => styles}/components/_global_navigation.scss | 0 static/{scss => styles}/components/_modal.scss | 0 static/{scss => styles}/components/_progress_menu.scss | 0 static/{scss => styles}/components/_search_bar.scss | 0 static/{scss => styles}/components/_site_action.scss | 0 static/{scss => styles}/components/_topbar.scss | 0 static/{scss => styles}/components/_workspace_layout.scss | 0 static/{scss => styles}/core/_grid.scss | 0 static/{scss => styles}/core/_util.scss | 0 static/{scss => styles}/core/_variables.scss | 0 static/{scss => styles}/elements/_action_group.scss | 0 static/{scss => styles}/elements/_block_lists.scss | 0 static/{scss => styles}/elements/_buttons.scss | 0 static/{scss => styles}/elements/_diff.scss | 0 static/{scss => styles}/elements/_icon_link.scss | 0 static/{scss => styles}/elements/_icons.scss | 0 static/{scss => styles}/elements/_inputs.scss | 0 static/{scss => styles}/elements/_labels.scss | 0 static/{scss => styles}/elements/_panels.scss | 0 static/{scss => styles}/elements/_sidenav.scss | 0 static/{scss => styles}/elements/_tables.scss | 0 static/{scss => styles}/elements/_typography.scss | 0 static/{scss => styles}/sections/_login.scss | 0 static/{scss => styles}/sections/_member_edit.scss | 0 static/{scss => styles}/sections/_project_edit.scss | 0 static/{scss => styles}/sections/_projects_list.scss | 0 static/{scss => styles}/sections/_request_approval.scss | 0 34 files changed, 1 insertion(+), 1 deletion(-) rename static/{scss => styles}/README.md (100%) rename static/{scss => styles}/atat.scss (100%) rename static/{scss => styles}/components/_alerts.scss (100%) rename static/{scss => styles}/components/_empty_state.scss (100%) rename static/{scss => styles}/components/_footer.scss (100%) rename static/{scss => styles}/components/_global_layout.scss (100%) rename static/{scss => styles}/components/_global_navigation.scss (100%) rename static/{scss => styles}/components/_modal.scss (100%) rename static/{scss => styles}/components/_progress_menu.scss (100%) rename static/{scss => styles}/components/_search_bar.scss (100%) rename static/{scss => styles}/components/_site_action.scss (100%) rename static/{scss => styles}/components/_topbar.scss (100%) rename static/{scss => styles}/components/_workspace_layout.scss (100%) rename static/{scss => styles}/core/_grid.scss (100%) rename static/{scss => styles}/core/_util.scss (100%) rename static/{scss => styles}/core/_variables.scss (100%) rename static/{scss => styles}/elements/_action_group.scss (100%) rename static/{scss => styles}/elements/_block_lists.scss (100%) rename static/{scss => styles}/elements/_buttons.scss (100%) rename static/{scss => styles}/elements/_diff.scss (100%) rename static/{scss => styles}/elements/_icon_link.scss (100%) rename static/{scss => styles}/elements/_icons.scss (100%) rename static/{scss => styles}/elements/_inputs.scss (100%) rename static/{scss => styles}/elements/_labels.scss (100%) rename static/{scss => styles}/elements/_panels.scss (100%) rename static/{scss => styles}/elements/_sidenav.scss (100%) rename static/{scss => styles}/elements/_tables.scss (100%) rename static/{scss => styles}/elements/_typography.scss (100%) rename static/{scss => styles}/sections/_login.scss (100%) rename static/{scss => styles}/sections/_member_edit.scss (100%) rename static/{scss => styles}/sections/_project_edit.scss (100%) rename static/{scss => styles}/sections/_projects_list.scss (100%) rename static/{scss => styles}/sections/_request_approval.scss (100%) diff --git a/static/js/index.js b/static/js/index.js index 9cc49957..91a30f3e 100644 --- a/static/js/index.js +++ b/static/js/index.js @@ -1,4 +1,4 @@ -import classes from '../scss/atat.scss' +import classes from '../styles/atat.scss' import './thing' diff --git a/static/scss/README.md b/static/styles/README.md similarity index 100% rename from static/scss/README.md rename to static/styles/README.md diff --git a/static/scss/atat.scss b/static/styles/atat.scss similarity index 100% rename from static/scss/atat.scss rename to static/styles/atat.scss diff --git a/static/scss/components/_alerts.scss b/static/styles/components/_alerts.scss similarity index 100% rename from static/scss/components/_alerts.scss rename to static/styles/components/_alerts.scss diff --git a/static/scss/components/_empty_state.scss b/static/styles/components/_empty_state.scss similarity index 100% rename from static/scss/components/_empty_state.scss rename to static/styles/components/_empty_state.scss diff --git a/static/scss/components/_footer.scss b/static/styles/components/_footer.scss similarity index 100% rename from static/scss/components/_footer.scss rename to static/styles/components/_footer.scss diff --git a/static/scss/components/_global_layout.scss b/static/styles/components/_global_layout.scss similarity index 100% rename from static/scss/components/_global_layout.scss rename to static/styles/components/_global_layout.scss diff --git a/static/scss/components/_global_navigation.scss b/static/styles/components/_global_navigation.scss similarity index 100% rename from static/scss/components/_global_navigation.scss rename to static/styles/components/_global_navigation.scss diff --git a/static/scss/components/_modal.scss b/static/styles/components/_modal.scss similarity index 100% rename from static/scss/components/_modal.scss rename to static/styles/components/_modal.scss diff --git a/static/scss/components/_progress_menu.scss b/static/styles/components/_progress_menu.scss similarity index 100% rename from static/scss/components/_progress_menu.scss rename to static/styles/components/_progress_menu.scss diff --git a/static/scss/components/_search_bar.scss b/static/styles/components/_search_bar.scss similarity index 100% rename from static/scss/components/_search_bar.scss rename to static/styles/components/_search_bar.scss diff --git a/static/scss/components/_site_action.scss b/static/styles/components/_site_action.scss similarity index 100% rename from static/scss/components/_site_action.scss rename to static/styles/components/_site_action.scss diff --git a/static/scss/components/_topbar.scss b/static/styles/components/_topbar.scss similarity index 100% rename from static/scss/components/_topbar.scss rename to static/styles/components/_topbar.scss diff --git a/static/scss/components/_workspace_layout.scss b/static/styles/components/_workspace_layout.scss similarity index 100% rename from static/scss/components/_workspace_layout.scss rename to static/styles/components/_workspace_layout.scss diff --git a/static/scss/core/_grid.scss b/static/styles/core/_grid.scss similarity index 100% rename from static/scss/core/_grid.scss rename to static/styles/core/_grid.scss diff --git a/static/scss/core/_util.scss b/static/styles/core/_util.scss similarity index 100% rename from static/scss/core/_util.scss rename to static/styles/core/_util.scss diff --git a/static/scss/core/_variables.scss b/static/styles/core/_variables.scss similarity index 100% rename from static/scss/core/_variables.scss rename to static/styles/core/_variables.scss diff --git a/static/scss/elements/_action_group.scss b/static/styles/elements/_action_group.scss similarity index 100% rename from static/scss/elements/_action_group.scss rename to static/styles/elements/_action_group.scss diff --git a/static/scss/elements/_block_lists.scss b/static/styles/elements/_block_lists.scss similarity index 100% rename from static/scss/elements/_block_lists.scss rename to static/styles/elements/_block_lists.scss diff --git a/static/scss/elements/_buttons.scss b/static/styles/elements/_buttons.scss similarity index 100% rename from static/scss/elements/_buttons.scss rename to static/styles/elements/_buttons.scss diff --git a/static/scss/elements/_diff.scss b/static/styles/elements/_diff.scss similarity index 100% rename from static/scss/elements/_diff.scss rename to static/styles/elements/_diff.scss diff --git a/static/scss/elements/_icon_link.scss b/static/styles/elements/_icon_link.scss similarity index 100% rename from static/scss/elements/_icon_link.scss rename to static/styles/elements/_icon_link.scss diff --git a/static/scss/elements/_icons.scss b/static/styles/elements/_icons.scss similarity index 100% rename from static/scss/elements/_icons.scss rename to static/styles/elements/_icons.scss diff --git a/static/scss/elements/_inputs.scss b/static/styles/elements/_inputs.scss similarity index 100% rename from static/scss/elements/_inputs.scss rename to static/styles/elements/_inputs.scss diff --git a/static/scss/elements/_labels.scss b/static/styles/elements/_labels.scss similarity index 100% rename from static/scss/elements/_labels.scss rename to static/styles/elements/_labels.scss diff --git a/static/scss/elements/_panels.scss b/static/styles/elements/_panels.scss similarity index 100% rename from static/scss/elements/_panels.scss rename to static/styles/elements/_panels.scss diff --git a/static/scss/elements/_sidenav.scss b/static/styles/elements/_sidenav.scss similarity index 100% rename from static/scss/elements/_sidenav.scss rename to static/styles/elements/_sidenav.scss diff --git a/static/scss/elements/_tables.scss b/static/styles/elements/_tables.scss similarity index 100% rename from static/scss/elements/_tables.scss rename to static/styles/elements/_tables.scss diff --git a/static/scss/elements/_typography.scss b/static/styles/elements/_typography.scss similarity index 100% rename from static/scss/elements/_typography.scss rename to static/styles/elements/_typography.scss diff --git a/static/scss/sections/_login.scss b/static/styles/sections/_login.scss similarity index 100% rename from static/scss/sections/_login.scss rename to static/styles/sections/_login.scss diff --git a/static/scss/sections/_member_edit.scss b/static/styles/sections/_member_edit.scss similarity index 100% rename from static/scss/sections/_member_edit.scss rename to static/styles/sections/_member_edit.scss diff --git a/static/scss/sections/_project_edit.scss b/static/styles/sections/_project_edit.scss similarity index 100% rename from static/scss/sections/_project_edit.scss rename to static/styles/sections/_project_edit.scss diff --git a/static/scss/sections/_projects_list.scss b/static/styles/sections/_projects_list.scss similarity index 100% rename from static/scss/sections/_projects_list.scss rename to static/styles/sections/_projects_list.scss diff --git a/static/scss/sections/_request_approval.scss b/static/styles/sections/_request_approval.scss similarity index 100% rename from static/scss/sections/_request_approval.scss rename to static/styles/sections/_request_approval.scss From dea0962f7cfe2a74a758251912be22082749e07a Mon Sep 17 00:00:00 2001 From: Patrick Smith Date: Thu, 2 Aug 2018 14:54:07 -0400 Subject: [PATCH 095/332] Use flask-webassets to version js/css bundle --- atst/assets.py | 12 ++++++++---- package.json | 2 +- templates/base.html | 8 ++++++-- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/atst/assets.py b/atst/assets.py index aef6b35e..6c8fd7e8 100644 --- a/atst/assets.py +++ b/atst/assets.py @@ -4,10 +4,14 @@ from atst.home import home environment = Environment() css = Bundle( - "../scss/atat.scss", - filters="scss", - output="../static/assets/out.%(version)s.css", - depends=("**/*.scss"), + "../static/assets/index.css", + output="../static/assets/styles.%(version)s.css", ) environment.register("css", css) + +js = Bundle( + '../static/assets/index.js', + output='../static/assets/index.%(version)s.js' +) +environment.register('js_all', js) diff --git a/package.json b/package.json index 4d7b794e..421c767b 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "index.js", "scripts": { "watch": "parcel watch static/js/index.js -d static/assets -o index.js --no-autoinstall", - "build": "parcel build static/js/index.js -d static/assets -o index.js --no-autoinstall", + "build": "parcel build static/js/index.js -d static/assets -o index.js", "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", diff --git a/templates/base.html b/templates/base.html index aaae0374..acc3e6e7 100644 --- a/templates/base.html +++ b/templates/base.html @@ -8,7 +8,9 @@ {% block title %}JEDI{% endblock %} - + {% assets "css" %} + + {% endassets %} @@ -32,6 +34,8 @@ {% include 'footer.html' %} {% block modal %}{% endblock %} - + {% assets "js_all" %} + {% endassets %} From e3ac0997aa4e0bb878036a3e1f6489db9236a57e Mon Sep 17 00:00:00 2001 From: Andrew Croce Date: Fri, 3 Aug 2018 09:10:40 -0400 Subject: [PATCH 109/332] Remove styles and js from assets --- static/js/index.js | 4 - static/js/thing.js | 7 - static/styles/README.md | 82 ------ static/styles/atat.scss | 36 --- static/styles/components/_alerts.scss | 76 ------ static/styles/components/_empty_state.scss | 27 -- static/styles/components/_footer.scss | 6 - static/styles/components/_global_layout.scss | 36 --- .../styles/components/_global_navigation.scss | 30 --- static/styles/components/_modal.scss | 47 ---- static/styles/components/_progress_menu.scss | 103 -------- static/styles/components/_search_bar.scss | 72 ------ static/styles/components/_site_action.scss | 15 -- static/styles/components/_topbar.scss | 71 ------ .../styles/components/_workspace_layout.scss | 26 -- static/styles/core/_grid.scss | 45 ---- static/styles/core/_util.scss | 33 --- static/styles/core/_variables.scss | 167 ------------ static/styles/elements/_action_group.scss | 19 -- static/styles/elements/_block_lists.scss | 90 ------- static/styles/elements/_buttons.scss | 5 - static/styles/elements/_diff.scss | 36 --- static/styles/elements/_icon_link.scss | 66 ----- static/styles/elements/_icons.scss | 52 ---- static/styles/elements/_inputs.scss | 241 ------------------ static/styles/elements/_labels.scss | 34 --- static/styles/elements/_panels.scss | 67 ----- static/styles/elements/_sidenav.scss | 87 ------- static/styles/elements/_tables.scss | 92 ------- static/styles/elements/_typography.scss | 59 ----- static/styles/sections/_login.scss | 3 - static/styles/sections/_member_edit.scss | 41 --- static/styles/sections/_project_edit.scss | 19 -- static/styles/sections/_projects_list.scss | 22 -- static/styles/sections/_request_approval.scss | 97 ------- 35 files changed, 1913 deletions(-) delete mode 100644 static/js/index.js delete mode 100644 static/js/thing.js delete mode 100644 static/styles/README.md delete mode 100644 static/styles/atat.scss delete mode 100644 static/styles/components/_alerts.scss delete mode 100644 static/styles/components/_empty_state.scss delete mode 100644 static/styles/components/_footer.scss delete mode 100644 static/styles/components/_global_layout.scss delete mode 100644 static/styles/components/_global_navigation.scss delete mode 100644 static/styles/components/_modal.scss delete mode 100644 static/styles/components/_progress_menu.scss delete mode 100644 static/styles/components/_search_bar.scss delete mode 100644 static/styles/components/_site_action.scss delete mode 100644 static/styles/components/_topbar.scss delete mode 100644 static/styles/components/_workspace_layout.scss delete mode 100644 static/styles/core/_grid.scss delete mode 100644 static/styles/core/_util.scss delete mode 100644 static/styles/core/_variables.scss delete mode 100644 static/styles/elements/_action_group.scss delete mode 100644 static/styles/elements/_block_lists.scss delete mode 100644 static/styles/elements/_buttons.scss delete mode 100644 static/styles/elements/_diff.scss delete mode 100644 static/styles/elements/_icon_link.scss delete mode 100644 static/styles/elements/_icons.scss delete mode 100644 static/styles/elements/_inputs.scss delete mode 100644 static/styles/elements/_labels.scss delete mode 100644 static/styles/elements/_panels.scss delete mode 100644 static/styles/elements/_sidenav.scss delete mode 100644 static/styles/elements/_tables.scss delete mode 100644 static/styles/elements/_typography.scss delete mode 100644 static/styles/sections/_login.scss delete mode 100644 static/styles/sections/_member_edit.scss delete mode 100644 static/styles/sections/_project_edit.scss delete mode 100644 static/styles/sections/_projects_list.scss delete mode 100644 static/styles/sections/_request_approval.scss diff --git a/static/js/index.js b/static/js/index.js deleted file mode 100644 index 91a30f3e..00000000 --- a/static/js/index.js +++ /dev/null @@ -1,4 +0,0 @@ -import classes from '../styles/atat.scss' - -import './thing' - diff --git a/static/js/thing.js b/static/js/thing.js deleted file mode 100644 index 033b8cd3..00000000 --- a/static/js/thing.js +++ /dev/null @@ -1,7 +0,0 @@ -console.log('hanlo again') -window.onload = function() { - console.log('boop') - const thing = document.querySelector('#hello') - thing.innerHTML = 'hanlo friendo' -} - diff --git a/static/styles/README.md b/static/styles/README.md deleted file mode 100644 index 2df6de9d..00000000 --- a/static/styles/README.md +++ /dev/null @@ -1,82 +0,0 @@ -# Styling AT-ST - -AT-ST's user interface components are based on the (U.S. Web Design System)[https://designsystem.digital.gov/components/]. Please refer there when deciding how to implement a UI feature. - -## CSS Architecture -### (Copied from https://github.com/uswds/uswds#css-architecture) -## CSS architecture - -* The CSS foundation of this site is built with the **[Sass](https://sass-lang.com)** preprocessor language. -* Uses **[Bourbon](http://bourbon.io/)** for its simple and lightweight Sass mixin library, and the **[Neat](http://neat.bourbon.io/)** library for the grid framework. Bourbon and Neat are open-source products from **[thoughtbot](https://thoughtbot.com/)**. -* The CSS organization and naming conventions follow **[18F’s CSS Front End Guide](https://frontend.18f.gov/css/)**. -* CSS selectors are **prefixed** with `usa` (For example: `.usa-button`). This identifier helps the design system avoid conflicts with other styles on a site which are not part of the U.S. Web Design System. -* Uses a **[modified BEM](https://frontend.18f.gov/css/naming/)** approach created by 18F for naming CSS selectors. Objects in CSS are separated by single dashes. Multi-word objects are separated by an underscore (For example: `.usa-button-cool_feature-active`). -* Uses **modular CSS** for scalable, modular, and flexible code. -* Uses **nesting** when appropriate. Nest minimally with up to two levels of nesting. -* Hard-coded magic numbers are avoided and, if necessary, defined in the `core/variables` scss file. -* Media queries are built **mobile first**. -* **Spacing units** are as much as possible defined as rem or em units so they scale appropriately with text size. Pixels can be used for detail work and should not exceed 5px (For example: 3px borders). - -**For more information, visit:** -[18F’s CSS Front End Guide](https://frontend.18f.gov/css/) - -Overrides and Modifications ---- - -When making modifications to the default USWDS components, please refer to the original source, and make a `.scss` file of the same name. Annotate the top of the file with a reference to the USWDS documentation and source code. - -Row/Column System ---- - -A simple, flexbox-powered row/column system. - -``` -
    -
    -
    -
    -
    -``` - -To make a column expand to fill up all available space relative to its sibling columns: - -``` -
    -
    -
    -
    -
    -``` - -To add uniform padding to rows and columns: - -``` -
    -
    -
    -
    -
    -``` - -Layouts and behaviors for specific row/col use cases should be handled on a case by case basis: - -``` -
    -
    -
    -
    -
    - -... - -.foo.row { - .col { - flex: 1; - } - .foo__bar { - flex: 2; - } -} -``` - -Page templates that inherit from the `base.html` template should render `.col` elements at their top level, with no other wrapping elements. diff --git a/static/styles/atat.scss b/static/styles/atat.scss deleted file mode 100644 index 040cc201..00000000 --- a/static/styles/atat.scss +++ /dev/null @@ -1,36 +0,0 @@ -@import 'core/variables'; -@import '../../node_modules/uswds/src/stylesheets/uswds'; - -@import 'core/grid'; -@import 'core/util'; - -@import 'elements/typography'; -@import 'elements/icons'; -@import 'elements/icon_link'; -@import 'elements/inputs'; -@import 'elements/buttons'; -@import 'elements/panels'; -@import 'elements/block_lists'; -@import 'elements/tables'; -@import 'elements/sidenav'; -@import 'elements/action_group'; -@import 'elements/labels'; -@import 'elements/diff'; - -@import 'components/topbar'; -@import 'components/global_layout'; -@import 'components/global_navigation'; -@import 'components/workspace_layout'; -@import 'components/site_action'; -@import 'components/empty_state'; -@import 'components/alerts'; -@import 'components/modal'; -@import 'components/footer'; -@import 'components/progress_menu.scss'; -@import 'components/search_bar'; - -@import 'sections/login'; -@import 'sections/request_approval'; -@import 'sections/projects_list'; -@import 'sections/project_edit'; -@import 'sections/member_edit'; diff --git a/static/styles/components/_alerts.scss b/static/styles/components/_alerts.scss deleted file mode 100644 index f48042b9..00000000 --- a/static/styles/components/_alerts.scss +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Alerts - * @see https://designsystem.digital.gov/components/alerts/ - * @source https://github.com/uswds/uswds/blob/develop/src/stylesheets/components/_alerts.scss - */ - -@mixin alert { - padding: $gap * 2; - border-left-width: $gap / 2; - border-left-style: solid; - @include panel-margin; -} - -@mixin alert-level($level) { - $background-color: $color-aqua-lightest; - $border-color: $color-blue; - - @if $level == 'success' { - $background-color: $color-green-lightest; - $border-color: $color-green; - - } @else if $level == 'warning' { - $background-color: $color-gold-lightest; - $border-color: $color-gold; - - } @else if $level == 'error' { - $background-color: $color-red-lightest; - $border-color: $color-red; - } - - background-color: $background-color; - border-color: $border-color; - display: flex; - flex-direction: row; - align-items: flex-start; - - .alert__icon { - @include icon-color($border-color); - flex-grow: 0; - flex-shrink: 0; - margin-right: $gap * 2; - margin-left: 0; - } - - .alert__title { - @include h3; - margin-top: 0; - } - - .alert__content { - .alert__message { - &:last-child { - > *:last-child { - margin-bottom: 0; - } - } - } - } -} - -.alert { - @include alert; - @include alert-level('info'); - - &.alert--success { - @include alert-level('success'); - } - - &.alert--warning { - @include alert-level('warning'); - } - - &.alert--error { - @include alert-level('error'); - } -} diff --git a/static/styles/components/_empty_state.scss b/static/styles/components/_empty_state.scss deleted file mode 100644 index be8675ad..00000000 --- a/static/styles/components/_empty_state.scss +++ /dev/null @@ -1,27 +0,0 @@ -.empty-state { - text-align: center; - padding: 6rem ($gap * 2) 0; - display: flex; - flex-direction: column; - align-items: center; - - @include media($medium-screen) { - padding: 8rem ($gap * 4) 0; - } - - .icon { - @include icon-size(50); - @include icon-color($color-gray-light); - } - - p { - @include h2; - line-height: 1.2; - max-width: 15em; - color: $color-gray; - - @include media($large-screen) { - @include h1; - } - } -} diff --git a/static/styles/components/_footer.scss b/static/styles/components/_footer.scss deleted file mode 100644 index 964ff393..00000000 --- a/static/styles/components/_footer.scss +++ /dev/null @@ -1,6 +0,0 @@ -.app-footer { - background-color: $color-gray-lightest; - border-top: 1px solid $color-gray-lighter; - padding-left: $gap*4; - padding-bottom: $gap*2; -} diff --git a/static/styles/components/_global_layout.scss b/static/styles/components/_global_layout.scss deleted file mode 100644 index d79890c5..00000000 --- a/static/styles/components/_global_layout.scss +++ /dev/null @@ -1,36 +0,0 @@ -body { - background-color: $color-gray-lightest; - display: flex; - flex-direction: column; - justify-content: flex-start; - min-height: 100vh; - - > footer { - margin-top: auto; - } - - &.modalOpen { - overflow-y: hidden; - } -} - -.global-layout { - display: flex; - flex-wrap: nowrap; - flex-grow: 1; - - .global-navigation { - margin-top: -1px; - } - - .global-panel-container { - margin: $gap; - max-width: $site-max-width; - overflow-x: hidden; - flex-grow: 1; - - @include media($medium-screen) { - margin: $gap * 2; - } - } -} diff --git a/static/styles/components/_global_navigation.scss b/static/styles/components/_global_navigation.scss deleted file mode 100644 index b975270a..00000000 --- a/static/styles/components/_global_navigation.scss +++ /dev/null @@ -1,30 +0,0 @@ -.global-navigation { - background-color: $color-white; - - .sidenav__link { - padding-right: $gap; - - @include media($large-screen) { - padding-right: $gap * 2; - } - } - - .sidenav__link-label { - @include hide; - - @include media($large-screen) { - @include unhide; - padding-left: $gap; - } - } - - &.global-navigation__context--workspace { - .sidenav__link { - padding-right: $gap; - } - - .sidenav__link-label { - @include hide; - } - } -} diff --git a/static/styles/components/_modal.scss b/static/styles/components/_modal.scss deleted file mode 100644 index 868476b9..00000000 --- a/static/styles/components/_modal.scss +++ /dev/null @@ -1,47 +0,0 @@ -.modal { - position: fixed; - z-index: 3; - left: 0; - right: 0; - top: 0; - bottom: 0; - background-color: $color-overlay; - - .modal__dialog { - padding: $gap; - height: 100vh; - display: flex; - justify-content: center; - align-items: center; - flex-direction: column; - - @include media($medium-screen) { - padding: $gap * 2; - } - - @include media($large-screen) { - padding: $gap * 4; - } - - .modal__body { - background-color: $color-white; - padding: $gap * 2; - flex-grow: 1; - overflow-y: auto; - max-width: 80rem; - - @include media($medium-screen) { - padding: $gap * 4; - flex-grow: 0; - } - - h1, h2 { - @include h3; - } - - :first-child { - margin-top: 0; - } - } - } -} diff --git a/static/styles/components/_progress_menu.scss b/static/styles/components/_progress_menu.scss deleted file mode 100644 index a675dfb7..00000000 --- a/static/styles/components/_progress_menu.scss +++ /dev/null @@ -1,103 +0,0 @@ -.progress-menu { - display: block; - - ul { - list-style: none; - margin: 0; - padding: 0; - } - - &--three { - .progress-menu__item { - width: 32%; - } - } - - &--four { - .progress-menu__item { - width: 24%; - } - } - - &--five { - .progress-menu__item { - width: 19%; - } - } - - &__item { - display: inline-block; - font-weight: $font-bold; - position: relative; - vertical-align: top; - - a { - display: block; - position: relative; - padding: ($gap * 4) ($gap * 2); - margin: 0 ($gap * 2); - text-decoration: none; - text-align: center; - z-index: 2; - color: $color-black; - } - - a.active { - color: $color-blue; - } - - - - &:first-child:after { - display: none; - } - - &:after { - display: inline-block; - height: 1px; - content: " "; - color: $color-gray-lightest; - text-shadow: none; - background-color: $color-gray-light; - position: absolute; - top: 1.1rem; - width: 100%; - right: 50%; - border-right: 2.2rem solid transparent; - border-left: 2.2rem solid transparent; - background-clip: padding-box; - z-index: 1; - } - - &:before { - content: ""; - display: block; - text-align: center; - width: 2rem; - height: 2rem; - border: 1px solid $color-gray; - border-radius: 100%; - position: absolute; - left: 50%; - margin-left: -1rem; - z-index: 1; - } - - &--active:before { - border: 2px solid $color-blue; - } - - &--complete:before { - content: url('#{$asset-path}/icons/checkmark.svg'); - background-color: $color-blue; - border: 2px solid $color-blue; - font-size: $h6-font-size; - padding: 1px 2px; - } - - &--incomplete:before { - border: 2px solid $color-gray-light; - } - - } -} diff --git a/static/styles/components/_search_bar.scss b/static/styles/components/_search_bar.scss deleted file mode 100644 index dbc795d2..00000000 --- a/static/styles/components/_search_bar.scss +++ /dev/null @@ -1,72 +0,0 @@ -.search-bar { - @include grid-row; - @include panel-base; - @include panel-theme-default; - @include panel-margin; - padding: $gap; - flex-wrap: wrap; - - .usa-input { - margin: 0; - flex-grow: 1; - flex-shrink: 0; - flex-basis: 100%; - height: $search-input-height; - position: relative; - margin-top: $gap; - - @include media($large-screen) { - flex-shrink: 1; - flex-basis: auto; - margin-top: 0; - margin-left: $gap; - } - - label { - @include hide; - } - - &:first-child { - margin-left: 0; - margin-top: 0; - } - } - - .search-input { - @include media($medium-screen) { - flex-basis: 50%; - } - - @media (min-width:800px) and (max-width:900px) { - flex-basis: auto; - } - - input[type='search'] { - width: auto; - height: $search-input-height; - width: calc(100% - #{$search-button-width}); - max-width: none; - font-size: 1.6rem; - } - - button { - position: absolute; - top: 0; - right: 0; - margin: 0; - padding: 0; - height: $search-input-height; - width: $search-button-width; - border-top-left-radius: 0; - border-bottom-left-radius: 0; - text-align: center; - - &:after { - content: url('#{$asset-path}/icons/search.svg'); - display: inline-block; - width: 1.6rem; - height: 1.6rem; - } - } - } -} diff --git a/static/styles/components/_site_action.scss b/static/styles/components/_site_action.scss deleted file mode 100644 index 98af0b18..00000000 --- a/static/styles/components/_site_action.scss +++ /dev/null @@ -1,15 +0,0 @@ -.site-action { - border-bottom: 1px solid $color-gray-lightest; - display: block; - padding-top: 0.5rem; - padding-bottom: 0.5rem; - margin-top: 0.25rem; - - a { - font-size: 1.3rem; - text-transform: uppercase; - text-decoration: none; - color: $color-primary !important; - } - -} \ No newline at end of file diff --git a/static/styles/components/_topbar.scss b/static/styles/components/_topbar.scss deleted file mode 100644 index e56a95fa..00000000 --- a/static/styles/components/_topbar.scss +++ /dev/null @@ -1,71 +0,0 @@ -.topbar { - background-color: $color-white; - border-bottom: 1px solid $color-black; - - .topbar__navigation { - display: flex; - flex-direction: row; - align-items: stretch; - justify-content: space-between; - - .topbar__link { - color: $color-black; - display: inline-flex; - align-items: center; - height: $topbar-height; - padding: 0 ($gap * 2); - text-decoration: none; - - .topbar__link-label { - @include h5; - } - - .topbar__link-icon { - margin-left: $gap; - } - - &.topbar__link--shield { - width: $icon-bar-width; - justify-content: center; - padding: 0; - - .topbar__link-icon { - margin: 0; - } - } - - &:hover { - background-color: $color-primary-darker; - color: $color-white; - - .topbar__link-icon { - @include icon-style-inverted; - } - } - } - - .topbar__context { - display: flex; - flex-grow: 1; - flex-direction: row; - align-items: stretch; - justify-content: space-between; - - &.topbar__context--workspace { - background-color: $color-primary; - - .topbar__link { - color: $color-white; - - .topbar__link-icon { - @include icon-style-inverted; - } - - &:hover { - background-color: $color-primary-darker; - } - } - } - } - } -} diff --git a/static/styles/components/_workspace_layout.scss b/static/styles/components/_workspace_layout.scss deleted file mode 100644 index e2cf4c24..00000000 --- a/static/styles/components/_workspace_layout.scss +++ /dev/null @@ -1,26 +0,0 @@ -.workspace-panel-container { - @include media($large-screen) { - @include grid-row; - } -} - -.workspace-navigation { - @include panel-margin; - - ul { - display: flex; - flex-wrap: wrap; - li { - flex-grow: 1; - } - } - - @include media($large-screen) { - width: 20rem; - margin-right: $gap * 2; - - ul { - display: block; - } - } -} diff --git a/static/styles/core/_grid.scss b/static/styles/core/_grid.scss deleted file mode 100644 index b24327c3..00000000 --- a/static/styles/core/_grid.scss +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Grid - * @see https://designsystem.digital.gov/components/grids/ - * @source https://github.com/uswds/uswds/blob/develop/src/stylesheets/core/_grid.scss - */ - -// Roll our own simple grid system -// USWDS grid system is fairly outdated and does not serve the needs of this project -// We are implementing a simple flexbox row/column system - -@mixin grid-row { - display: flex; - flex-direction: row; - flex-wrap: nowrap; -} - -@mixin grid-pad { - @include padding(null $site-margins-mobile); - - @include media($medium-screen) { - @include padding(null $site-margins); - } -} - -.row { - @include grid-row; - - &.row--pad { - @include grid-pad; - } - - &.row--max { - max-width: $site-max-width; - } -} - -.col { - &.col--pad { - @include grid-pad; - } - - &.col--grow { - flex-grow: 1; - } -} diff --git a/static/styles/core/_util.scss b/static/styles/core/_util.scss deleted file mode 100644 index 48957b6c..00000000 --- a/static/styles/core/_util.scss +++ /dev/null @@ -1,33 +0,0 @@ -.nowrap { - white-space: nowrap; -} - -@mixin hide { - border: 0; - clip: rect(0 0 0 0); - height: 1px; - margin: -1px; - overflow: hidden; - padding: 0; - position: absolute; - width: 1px; -} - -.hide { - @include hide; -} - -@mixin unhide { - border: unset; - clip: unset; - height: unset; - margin: unset; - overflow: unset; - padding: unset; - position: unset; - width: unset; -} - -@mixin line-max { - max-width: 45em; -} diff --git a/static/styles/core/_variables.scss b/static/styles/core/_variables.scss deleted file mode 100644 index 79c0e759..00000000 --- a/static/styles/core/_variables.scss +++ /dev/null @@ -1,167 +0,0 @@ -/* - * AT-ST Variables - * =================================================== - */ - -$gap: 0.8rem; // 8px at 10px $em-base -$topbar-height: 4.8rem; -$icon-bar-width: 4.0rem; -$icon-size-small: 2.4rem; -$hover-transition-time: 0.2s; -$search-input-height: 4.4rem; -$search-button-width: 5.0rem; - -/* - * USWDS Variables - * @see https://github.com/uswds/uswds/blob/develop/src/stylesheets/core/_variables.scss - * =================================================== - */ - -// $em-base: 10px; This is not defaulted in USWDS, so we cant override it -$base-font-size: 1.7rem; -$small-font-size: 1.4rem; -$lead-font-size: 2rem; -$title-font-size: 5.2rem; -$h1-font-size: 4rem; -$h2-font-size: 3rem; -$h3-font-size: 2rem; -$h4-font-size: 1.7rem; -$h5-font-size: 1.5rem; -$h6-font-size: 1.3rem; -$base-line-height: 1.5; -$heading-line-height: 1.3; -$lead-line-height: 1.7; - -$font-sans: 'Source Sans Pro', sans-serif; -$font-serif: 'Merriweather', serif; - -$font-normal: 400; -$font-bold: 700; - -// Color -$color-blue: #0071bc; -$color-blue-darker: #205493; -$color-blue-darkest: #112e51; - -$color-aqua: #02bfe7; -$color-aqua-dark: #00a6d2; -$color-aqua-darkest: #046b99; -$color-aqua-light: #9bdaf1; -$color-aqua-lightest: #e1f3f8; - -$color-red: #e31c3d; -$color-red-dark: #cd2026; -$color-red-darkest: #981b1e; -$color-red-light: #e59393; -$color-red-lightest: #f9dede; - -$color-white: #ffffff; -$color-black: #000000; -$color-black-light: #212121; - -$color-gray-dark: #323a45; -$color-gray: #5b616b; -$color-gray-medium: #757575; -$color-gray-light: #aeb0b5; -$color-gray-lighter: #d6d7d9; -$color-gray-lightest: #f1f1f1; - -$color-gray-warm-dark: #494440; -$color-gray-warm-light: #e4e2e0; -$color-gray-cool-light: #dce4ef; - -$color-gold: #fdb81e; -$color-gold-light: #f9c642; -$color-gold-lighter: #fad980; -$color-gold-lightest: #fff1d2; - -$color-green: #2e8540; -$color-green-light: #4aa564; -$color-green-lighter: #94bfa2; -$color-green-lightest: #e7f4e4; - -$color-cool-blue: #205493; -$color-cool-blue-light: #4773aa; -$color-cool-blue-lighter: #8ba6ca; -$color-cool-blue-lightest: #dce4ef; - -$color-purple: #4c2c92; - -// Functional colors -$color-primary: $color-blue; -$color-primary-darker: $color-blue-darker; -$color-primary-darkest: $color-blue-darkest; - -$color-primary-alt: $color-aqua; -$color-primary-alt-dark: $color-aqua-dark; -$color-primary-alt-darkest: $color-aqua-darkest; -$color-primary-alt-light: $color-aqua-light; -$color-primary-alt-lightest: $color-aqua-lightest; - -$color-secondary: $color-red; -$color-secondary-dark: $color-red-dark; -$color-secondary-darkest: $color-red-darkest; -$color-secondary-light: $color-red-light; -$color-secondary-lightest: $color-red-lightest; - -$color-base: $color-black-light; -$color-focus: $color-gray-light; -$color-visited: $color-purple; - -$color-overlay: rgba(#000, 0.5); -$color-shadow: rgba(#000, 0.3); -$color-transparent: rgba(#000, 0); - -// Mobile First Breakpoints -$small-screen: 481px; -$medium-screen: 600px; -$large-screen: 800px; -$xlarge-screen: 1200px; - -// Grid column counts by screen size -$grid-columns-small: 1; -$grid-columns-medium: 6; -$grid-columns-large: 12; - -// @media single-keyword helpers -// $small: new-breakpoint(min-width $small-screen $grid-columns-small); -// $medium: new-breakpoint(min-width $medium-screen $grid-columns-medium); -// $large: new-breakpoint(min-width $large-screen $grid-columns-large); - -// Set the base path for assets (used for font and image paths below) -$asset-path: '../'; - -// Relative font and image file paths -$font-path: '#{$asset-path}fonts'; -$image-path: '#{$asset-path}img'; - -// Set $asset-pipeline to true if you're using the Rails Asset Pipeline -$asset-pipeline: false; - -// Magic Numbers -$text-max-width: 66ch; // 66 characters per line -$lead-max-width: 77rem; -$site-max-width: 1200px; // previously 1040px; -$site-margins: $gap; // previously 3rem; -$site-margins-mobile: $gap / 2; // previously 1.5rem; -$article-max-width: 600px; -$input-max-width: 46rem; -$label-border-radius: 2px; -$checkbox-border-radius: 2px; -$border-radius: 3px; -$button-border-radius: 5px; -$box-shadow: 0 0 2px $color-shadow; -$focus-outline: 2px dotted $color-gray-light; -$focus-spacing: 3px; -$nav-width: 300px; // previously 951px; -$sidenav-current-border-width: 0.4rem; // must be in rem for math - -// 44 x 44 pixels hit target following Apple iOS Human Interface -// Guidelines -$hit-area: 4.4rem; - -$spacing-x-small: 0.5rem; -$spacing-small: 1rem; -$spacing-md-small: 1.5rem; -$spacing-medium: 2rem; -$spacing-large: 3rem; diff --git a/static/styles/elements/_action_group.scss b/static/styles/elements/_action_group.scss deleted file mode 100644 index acf2c1fc..00000000 --- a/static/styles/elements/_action_group.scss +++ /dev/null @@ -1,19 +0,0 @@ -.action-group { - display: flex; - flex-direction: row-reverse; - align-items: center; - margin-top: $gap * 4; - - .usa-button, - a { - margin: 0 0 0 ($gap * 2); - - @include media($medium-screen) { - margin: 0 0 0 ($gap * 4); - } - } - - &:last-child { - margin-bottom: $gap * 3; - } -} diff --git a/static/styles/elements/_block_lists.scss b/static/styles/elements/_block_lists.scss deleted file mode 100644 index 6cb24d11..00000000 --- a/static/styles/elements/_block_lists.scss +++ /dev/null @@ -1,90 +0,0 @@ -@mixin block-list { - @include panel-margin; - - > ul { - list-style: none; - margin: 0; - padding: 0; - } -} - -@mixin block-list-header { - @include panel-base; - @include panel-theme-default; - padding: $gap * 2; - display: flex; - flex-direction: row; - justify-content: space-between; -} - -@mixin block-list__title { - @include h4; - margin: 0; -} - -@mixin block-list__footer { - @include panel-base; - @include panel-theme-default; - padding: $gap * 2; - display: flex; - flex-direction: row-reverse; - justify-content: space-between; - - .icon-link { - &:first-child { - margin-right: -$gap; - } - } -} - -@mixin block-list-item { - @include panel-base; - margin: 0; - padding: $gap * 2; - border-top: 0; - border-bottom: 1px dashed $color-gray-light; - - @at-root li#{&} { - &:last-child { - border-bottom-style: solid; - } - } -} - - -.block-list { - @include block-list; - - .icon-link { - margin: -$gap 0; - } - - .icon-link, - .label { - &:first-child { - margin-left: -$gap; - } - - &:last-child { - margin-right: -$gap; - } - - } -} - -.block-list__header { - @include block-list-header; -} - -.block-list__title { - @include block-list__title; -} - -.block-list__item { - @include block-list-item; -} - -.block-list__footer { - @include block-list__footer; - border-top: 0; -} diff --git a/static/styles/elements/_buttons.scss b/static/styles/elements/_buttons.scss deleted file mode 100644 index c4bf4337..00000000 --- a/static/styles/elements/_buttons.scss +++ /dev/null @@ -1,5 +0,0 @@ -/* - * Buttons - * @see https://designsystem.digital.gov/components/buttons/ - * @source https://github.com/uswds/uswds/blob/develop/src/stylesheets/elements/_buttons.scss - */ diff --git a/static/styles/elements/_diff.scss b/static/styles/elements/_diff.scss deleted file mode 100644 index 85ac4002..00000000 --- a/static/styles/elements/_diff.scss +++ /dev/null @@ -1,36 +0,0 @@ -[class*='diff--'] { - border-left-style: solid; - border-left-width: ($gap / 2); - padding-left: $gap / 2; - margin: ($gap / 2) 0; - - &::before { - font-weight: bold; - padding-right: $gap; - display: inline-block; - width: 1.8rem; - text-align: center; - } -} - -.diff--removed { - background-color: $color-red-lightest; - border-left-color: $color-red-dark; - text-decoration: line-through; - text-decoration-color: $color-overlay; - - &::before { - content: '-'; - color: $color-red-dark; - } -} - -.diff--added { - background-color: $color-aqua-lightest; - border-left-color: $color-aqua-dark; - - &::before { - content: '+'; - color: $color-aqua-dark; - } -} diff --git a/static/styles/elements/_icon_link.scss b/static/styles/elements/_icon_link.scss deleted file mode 100644 index 00daae3f..00000000 --- a/static/styles/elements/_icon_link.scss +++ /dev/null @@ -1,66 +0,0 @@ -@mixin icon-link-color($color: $color-blue, $hover-color: $color-aqua-lightest) { - color: $color; - - &:hover { - background-color: $hover-color; - color: $color; - } - - .icon { - @include icon-color($color); - } -} - -@mixin icon-link { - @include icon-link-color($color-primary); - @include h5; - display: inline-flex; - flex-direction: row; - align-items: center; - padding: $gap; - text-decoration: none; - background: none; - transition: background-color $hover-transition-time; - border-radius: $gap / 2; - - .icon { - @include icon-color($color-primary); - @include icon-size(12); - margin-right: $gap; - } -} - -@mixin icon-link-large { - @include h4; - font-weight: normal; - - .icon { - @include icon-size(16); - margin-right: $gap * 2; - } -} - -@mixin icon-link-vertical { - flex-direction: column; - - .icon { - margin: 0 $gap $gap; - } -} - -.icon-link { - @include icon-link; - @include icon-link-color($color-primary); - - &.icon-link--vertical { - @include icon-link-vertical; - } - - &.icon-link--large { - @include icon-link-large; - } - - &.icon-link--danger { - @include icon-link-color($color-red, $color-red-lightest); - } -} diff --git a/static/styles/elements/_icons.scss b/static/styles/elements/_icons.scss deleted file mode 100644 index 34b35a8c..00000000 --- a/static/styles/elements/_icons.scss +++ /dev/null @@ -1,52 +0,0 @@ -@mixin icon { - display: inline-flex; - - > svg { - width: 100%; - height: 100%; - * { - transition: fill $hover-transition-time; - } - } -} - -@mixin icon-size($size) { - $icon-size: $size * .1rem; - width: $icon-size; - height: auto; - margin: $icon-size / 4; -} - -@mixin icon-color($color) { - > svg * { - fill: $color; - } -} - -@mixin icon-style-default { - @include icon-color($color-black); -} - -@mixin icon-style-active { - @include icon-color($color-primary); -} - -@mixin icon-style-inverted { - > svg * { - fill: $color-white; - } -} - -.icon { - @include icon; - @include icon-size(16); - @include icon-style-default; - - &.icon--tiny { - @include icon-size(10); - } - - &.icon--large { - @include icon-size(24); - } -} diff --git a/static/styles/elements/_inputs.scss b/static/styles/elements/_inputs.scss deleted file mode 100644 index 459e907d..00000000 --- a/static/styles/elements/_inputs.scss +++ /dev/null @@ -1,241 +0,0 @@ -/* - * Inputs - * @see https://designsystem.digital.gov/components/form-controls/ - * @source https://github.com/uswds/uswds/blob/develop/src/stylesheets/elements/_inputs.scss - */ - -@mixin input-icon { - width: 1.6rem; - height: 1.6rem; - display: block; -} - -@mixin input-state($state) { - $border-width: 1px; - $state-color: $color-gray; - - @if $state == 'error' { - $border-width: 2px; - $state-color: $color-red; - - } @else if $state == 'warning' { - $border-width: 2px; - $state-color: $color-gold; - - } @else if $state == 'success' { - $border-width: 2px; - $state-color: $color-green; - } - - .icon { - @include icon-color($state-color); - } - - .usa-input__message { - color: $state-color; - } - - input, - textarea, - select { - border-color: $state-color; - border-width: $border-width; - } - - fieldset { - input[type='radio'] { - + label::before { - box-shadow: 0 0 0 1px $color-white, 0 0 0 3px $color-red; - } - } - - input[type='checkbox'] { - + label::before { - box-shadow: 0 0 0 2px $color-red; - } - } - } -} - -.usa-input { - margin: ($gap * 4) ($gap * 2) ($gap * 4) 0; - - @include media($medium-screen) { - margin: ($gap * 4) 0; - } - - label { - padding: 0 0 $gap 0; - margin: 0; - @include h4; - @include line-max; - position: relative; - - .usa-input__help { - display: block; - @include h5; - font-weight: normal; - padding-top: $gap / 2; - @include line-max; - } - - .icon { - position: absolute; - left: 100%; - top: 100%; - margin-top: 1.4rem; - margin-left: $gap; - } - } - - input, - textarea, - select { - @include line-max; - margin: 0; - } - - .usa-input__choices { // checkbox & radio sets - legend { - padding: 0 0 $gap 0; - @include h4; - - .icon { - vertical-align: middle; - } - } - - ul { - list-style: none; - margin: 0; - padding: 0; - - > li { - margin: 0; - - [type='radio'] + label, - [type='checkbox'] + label { - margin: 0; - } - } - } - - label { - font-weight: normal; - margin: 0; - } - - .usa-input__message { - display: block; - } - - &.usa-input__choices--inline { - label { - display: inline-block; - padding-right: $gap * 3; - } - } - } - - .usa-input__message { - @include h5; - display: inline-block; - padding-top: $gap; - } - - &.usa-input--error { - @include input-state('error'); - } - - &.usa-input--warning { - @include input-state('warning'); - } - - &.usa-input--success { - @include input-state('success'); - } -} - -select { - border-radius: 0; - -webkit-appearance: none; - -moz-appearance: none; -} - -.usa-date-input label { - margin-top: 0; -} - -.input-label { - margin-top: 1rem; -} - -.usa-fieldset-inputs { - margin-top: 2.25rem; - - label:first-child { - padding-bottom: 0.5rem; - } -} - -.usa-search { - padding-top: 2px; - margin-right: 2rem; - - input[type=search] { - height: 4.4rem; - font-size: 1.7rem; - color: $color-black; - } - - button { - min-height: 4.4rem; - } - -} - - -// Form Grid -.form-row { - margin: ($gap * 4) 0; - - .form-col { - flex-grow: 1; - - &:first-child .usa-input { - &:first-child { - margin-top: 0; - } - } - - &:last-child .usa-input { - &:first-child { - margin-top: 0; - } - } - } - - @include media($medium-screen) { - @include grid-row; - align-items: flex-start; - - .form-col { - .usa-input { - margin-left: ($gap * 4); - margin-right: ($gap * 4); - } - - &:first-child { - .usa-input { - margin-left: 0; - } - } - - &:last-child { - .usa-input { - margin-right: 0; - } - } - } - } -} diff --git a/static/styles/elements/_labels.scss b/static/styles/elements/_labels.scss deleted file mode 100644 index 104894e4..00000000 --- a/static/styles/elements/_labels.scss +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Labels - * @see https://designsystem.digital.gov/components/labels/ - * @source https://github.com/uswds/uswds/blob/develop/src/stylesheets/elements/_labels.scss - */ - -.label { - @include h5; - display: inline-block; - height: 2.4rem; - line-height: 2.4rem; - color: $color-white; - background-color: $color-gray; - vertical-align: middle; - margin: 0 $gap; - padding: 0 $gap; - border-radius: $gap / 2; - - &.label--info { - background-color: $color-primary; - } - - &.label--warning { - background-color: $color-gold; - } - - &.label--error { - background-color: $color-red; - } - - &.label--success { - background-color: $color-green; - } -} diff --git a/static/styles/elements/_panels.scss b/static/styles/elements/_panels.scss deleted file mode 100644 index af5decf4..00000000 --- a/static/styles/elements/_panels.scss +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Panels - * A generic block container - */ - - @mixin panel-base { - background-color: $color-white; - border-top-width: 1px; - border-bottom-width: 1px; - border-top-style: solid; - border-bottom-style: solid; - border-left: 0; - border-right: 0; -} - -@mixin panel-theme-default { - border-top-color: $color-black; - border-bottom-color: $color-gray-light; -} - -@mixin panel-margin { - margin-top: 0; - margin-left: 0; - margin-right: 0; - margin-bottom: $site-margins-mobile * 2; - - @include media($medium-screen) { - margin-bottom: $site-margins * 2; - } -} - -@mixin panel-actions { - padding: $gap; -} - -.panel { - @include panel-base; - @include panel-theme-default; - @include panel-margin; - - .panel__content { - margin: ($gap * 2) 0; - padding: 0 ($gap * 2); - - @include media($medium-screen) { - margin: ($gap * 4) 0; - padding: 0 ($gap * 4); - } - } - - .panel__heading { - margin: $gap * 2; - - @include media($medium-screen) { - margin: $gap * 4; - } - - h1, h2, h3, h4, h5, h6 { - margin: 0; - } - } -} - -.panel__actions { - @include panel-actions; -} - diff --git a/static/styles/elements/_sidenav.scss b/static/styles/elements/_sidenav.scss deleted file mode 100644 index d4c67366..00000000 --- a/static/styles/elements/_sidenav.scss +++ /dev/null @@ -1,87 +0,0 @@ -.sidenav { - ul { - list-style: none; - margin: 0; - padding: 0; - - li { - margin: 0; - display: block; - } - } - - .sidenav__link { - display: block; - border-top: 1px solid $color-black; - padding: $gap ($gap * 2); - color: $color-black; - text-decoration: none; - white-space: nowrap; - - .sidenav__link-icon { - margin-left: - ($gap * .5); - } - - &.sidenav__link--disabled { - color: $color-shadow; - pointer-events: none; - } - - &.sidenav__link--active { - @include h4; - background-color: $color-white; - color: $color-primary; - box-shadow: inset ($gap / 2) 0 0 0 $color-primary; - - .sidenav__link-icon { - @include icon-style-active; - } - - + ul { - background-color: $color-white; - - .sidenav__link { - &--active { - @include h5; - color: $color-primary; - box-shadow: none; - } - } - } - } - - + ul { - padding-bottom: $gap / 2; - - li { - .sidenav__link { - @include h5; - padding: $gap * .75; - padding-left: 4.5rem; - border: 0; - font-weight: normal; - - .sidenav__link-icon { - @include icon-size(12); - flex-shrink: 0; - margin-right: 1.5rem; - margin-left: -3rem - } - - .sidenav__link-label { - padding-left: 0; - } - } - } - } - - &:hover { - color: $color-primary; - - .sidenav__link-icon { - @include icon-style-active; - } - - } - } -} diff --git a/static/styles/elements/_tables.scss b/static/styles/elements/_tables.scss deleted file mode 100644 index e1602dfd..00000000 --- a/static/styles/elements/_tables.scss +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Tables - * @see https://designsystem.digital.gov/components/tables/ - * @source https://github.com/uswds/uswds/blob/develop/src/stylesheets/elements/_table.scss - */ - - table { - @include panel-margin; - min-width: 100%; - - tbody { - tr { - th, - td { - @include block-list-item; - display: table-cell; - white-space: nowrap; - border-bottom-style: dashed; - border-top: none; - - &:last-child { - border-bottom-style: dashed; - } - } - - &:last-child { - td, - th { - border-bottom-style: solid; - } - } - - .table-cell--align-right { - text-align: right; - } - - .table-cell--shrink { - width: 1%; - } - - .table-cell--expand { - width: 100%; - } - - .table-cell--hide-small { - display: none; - - @include media($medium-screen) { - display: table-cell; - } - } - } - } - - thead { - tr { - th { - @include block-list-header; - display: table-cell; - } - } - } - - @at-root .panel #{&} { - tr:last-child td { - border-bottom: 0; - } - - &:last-child { - margin-bottom: 0; - } - } -} - -.responsive-table-wrapper { - overflow-x: auto; - @include panel-margin; - - table { - margin-bottom: 0; - } - - @at-root .panel #{&} { - tr:last-child td { - border-bottom: 0; - } - - &:last-child { - margin-bottom: 0; - } - } -} diff --git a/static/styles/elements/_typography.scss b/static/styles/elements/_typography.scss deleted file mode 100644 index fcdc97d9..00000000 --- a/static/styles/elements/_typography.scss +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Typography - * @see https://designsystem.digital.gov/components/typography/ - * @source https://github.com/uswds/uswds/blob/develop/src/stylesheets/elements/_typography.scss - */ - - * { - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -p { - margin: 0 0 ($gap * 2) 0; - @include line-max; -} - -h1, h2, h3, h4, h5, h6 { - font-family: $font-sans; - margin: ($gap * 2) 0; - - + .subtitle * { - margin-top: 0; - } - -} - -.h1 { @include h1; } -.h2 { @include h2; } -.h3 { @include h3; } -.h4 { @include h4; } -.h5 { @include h5; } -.h6 { @include h6; } - -a, -a:hover { - transition: - background 0.2s, - border 0.2s, - box-shadow 0.2s, - color 0.2s; -} - -a:visited { - color: $color-blue; -} - -dl { - dt { - display: inline; - font-weight: bold; - } - dd { - -webkit-margin-start: 0; - } - - > div { - margin-bottom: $gap * 2; - } -} \ No newline at end of file diff --git a/static/styles/sections/_login.scss b/static/styles/sections/_login.scss deleted file mode 100644 index 030d09d5..00000000 --- a/static/styles/sections/_login.scss +++ /dev/null @@ -1,3 +0,0 @@ -.login-area { - text-align: center; -} \ No newline at end of file diff --git a/static/styles/sections/_member_edit.scss b/static/styles/sections/_member_edit.scss deleted file mode 100644 index aef2e042..00000000 --- a/static/styles/sections/_member_edit.scss +++ /dev/null @@ -1,41 +0,0 @@ -.member-card { - @include grid-row; - padding: $gap*2; - justify-content: space-between; - - dl { - margin: 0; - - > div { - margin-bottom: $gap; - } - } - - dt { - font-weight: normal; - color: $color-gray; - } - - dd { - display: inline; - } - - .member-card__header { - display: flex; - flex-direction: column; - justify-content: space-between; - } - - .member-card__heading { - margin: 0; - @include h2; - } - - .member-card__details { - text-align: right; - - .icon-link { - margin: 0 -$gap; - } - } -} \ No newline at end of file diff --git a/static/styles/sections/_project_edit.scss b/static/styles/sections/_project_edit.scss deleted file mode 100644 index 2222fd26..00000000 --- a/static/styles/sections/_project_edit.scss +++ /dev/null @@ -1,19 +0,0 @@ -.project-edit__env-list-item { - display: flex; - flex-direction: row; - align-items: flex-end; - - .usa-input { - margin: 0 ($gap * 4) 0 0; - flex-grow: 1; - } - - .project-edit__env-list-item__remover { - @include icon-link; - @include icon-link-vertical; - @include icon-link-color($color-red, $color-red-lightest); - - margin-bottom: -$gap; - margin-right: -$gap; - } -} diff --git a/static/styles/sections/_projects_list.scss b/static/styles/sections/_projects_list.scss deleted file mode 100644 index fe62b7a6..00000000 --- a/static/styles/sections/_projects_list.scss +++ /dev/null @@ -1,22 +0,0 @@ -.project-list-item { - .project-list-item__environment { - display: flex; - flex-direction: row; - justify-content: space-between; - - .project-list-item__environment__link { - @include icon-link; - @include icon-link-large; - } - - .project-list-item__environment__members { - display: flex; - flex-direction: row; - align-items: center; - - span { - @include h6; - } - } - } -} diff --git a/static/styles/sections/_request_approval.scss b/static/styles/sections/_request_approval.scss deleted file mode 100644 index 5769d5d9..00000000 --- a/static/styles/sections/_request_approval.scss +++ /dev/null @@ -1,97 +0,0 @@ -.request-approval { - .request-approval__heading { - display: flex; - flex-direction: row; - align-items: center; - } - - .request-approval__info-columns { - flex-wrap: wrap; - - .col { - flex-basis: 100%; - - @include media($medium-screen) { - flex-basis: 50%; - - &:first-child { - padding-right: $gap * 2; - } - &:last-child { - padding-left: $gap * 2; - } - } - } - } - - .request-approval__columns__heading { - &:first-child { - @include media($medium-screen) { - margin-top: 0; - } - } - } - - .approval-log { - ol { - list-style: none; - margin: 0; - padding: 0; - - li { - padding: $gap * 2; - border-top: 1px dashed $color-gray-light; - - &:first-child { - border-top-style: solid; - } - - @include media($medium-screen) { - padding: $gap * 4; - } - } - } - .approval-log__log-item { - display: flex; - flex-direction: column-reverse; - justify-content: flex-end; - - @include media($medium-screen) { - flex-direction: row-reverse; - } - - .approval-log__log-item__header { - @include h4; - margin: 0 0 $gap 0; - } - - .approval-log__log-item__timestamp { - @include h5; - margin-right: $gap * 2; - color: $color-gray; - flex-grow: 0; - - @include media($large-screen) { - margin-right: $gap * 4; - } - } - - .approval-log__behalfs { - display: flex; - flex-direction: row; - - .approval-log__behalf { - margin-right: $gap * 2; - - @include media($medium-screen) { - margin-right: $gap * 4; - } - - span { - display: block; - } - } - } - } - } -} From 29b2d58fcc8b786f561d8b92c2d020d35d8bd3cb Mon Sep 17 00:00:00 2001 From: Andrew Croce Date: Fri, 3 Aug 2018 09:10:51 -0400 Subject: [PATCH 110/332] compiled assets --- static/assets/.gitignore | 1 - .../angle-arrow-down-hover.9cc540eb.svg | 1 + .../angle-arrow-down-hover.baa52fa9.png | Bin 0 -> 209 bytes ...ngle-arrow-down-primary-hover.11d98d2a.svg | 1 + ...ngle-arrow-down-primary-hover.d936067e.png | Bin 0 -> 213 bytes .../angle-arrow-down-primary.1c0886c7.svg | 1 + .../angle-arrow-down-primary.ab8d4776.png | Bin 0 -> 214 bytes static/assets/angle-arrow-down.da471750.svg | 1 + static/assets/angle-arrow-down.eaf9b383.png | Bin 0 -> 231 bytes .../angle-arrow-up-primary-hover.656ab109.svg | 1 + .../angle-arrow-up-primary-hover.87ccb668.png | Bin 0 -> 222 bytes .../angle-arrow-up-primary.b38f7f9a.svg | 1 + .../angle-arrow-up-primary.fd1251b8.png | Bin 0 -> 213 bytes static/assets/arrow-both.40570b7e.svg | 1 + static/assets/arrow-both.4bb0bc24.png | Bin 0 -> 227 bytes static/assets/arrow-down.08222248.svg | 1 + static/assets/arrow-down.188ad70b.png | Bin 0 -> 296 bytes static/assets/arrow-right.8dc15dc6.svg | 1 + static/assets/arrow-right.c5e6e18a.png | Bin 0 -> 265 bytes static/assets/checkmark.13582669.svg | 1 + static/assets/close.34c66938.svg | 12 + static/assets/close.707c1f41.png | Bin 0 -> 215 bytes static/assets/correct8.4e87f243.svg | 1 + static/assets/correct8.a03d2fcf.png | Bin 0 -> 195 bytes static/assets/correct9.860cef73.png | Bin 0 -> 446 bytes static/assets/correct9.f5b58d71.svg | 1 + static/assets/error.77a47b7b.png | Bin 0 -> 4154 bytes static/assets/error.fed7fc9a.svg | 17 + .../external-link-alt-hover.720d3de5.svg | 1 + .../external-link-alt-hover.fe210d33.png | Bin 0 -> 663 bytes static/assets/external-link-alt.410f199e.png | Bin 0 -> 833 bytes static/assets/external-link-alt.f8c085df.svg | 1 + .../assets/external-link-hover.0007810e.png | Bin 0 -> 1099 bytes .../assets/external-link-hover.e82acbc1.svg | 1 + static/assets/external-link.0ba33f83.svg | 1 + static/assets/external-link.7cc7907a.png | Bin 0 -> 1036 bytes static/assets/facebook25.0247732a.svg | 1 + static/assets/facebook25.e89f66fb.png | Bin 0 -> 270 bytes static/assets/hero.1d4e1843.png | Bin 0 -> 689079 bytes static/assets/index.4338282b.js | 362 ++ static/assets/index.a89d87a5.js | 362 ++ static/assets/index.b72e3796.js | 362 ++ static/assets/index.css | 4995 +++++++++++++++++ static/assets/index.f4c03caa.css | 4995 +++++++++++++++++ static/assets/index.js | 362 ++ static/assets/index.map | 1 + static/assets/info.65032fa3.svg | 18 + static/assets/info.6946b1ae.png | Bin 0 -> 3622 bytes .../merriweather-bold-webfont.0391ff32.woff | Bin 0 -> 34148 bytes .../merriweather-bold-webfont.3f042de9.woff2 | Bin 0 -> 27028 bytes .../merriweather-bold-webfont.523a75f1.ttf | Bin 0 -> 60116 bytes .../merriweather-bold-webfont.7ab8fe39.eot | Bin 0 -> 30040 bytes ...merriweather-italic-webfont.6c56712c.woff2 | Bin 0 -> 25724 bytes .../merriweather-italic-webfont.c64f21d1.woff | Bin 0 -> 32640 bytes .../merriweather-italic-webfont.f3bdbf29.eot | Bin 0 -> 61196 bytes .../merriweather-italic-webfont.fc611bc9.ttf | Bin 0 -> 61088 bytes .../merriweather-light-webfont.1b1f32b7.woff2 | Bin 0 -> 27036 bytes .../merriweather-light-webfont.386fee9a.ttf | Bin 0 -> 61376 bytes .../merriweather-light-webfont.5bc7f0e8.eot | Bin 0 -> 29810 bytes .../merriweather-light-webfont.9845245a.woff | Bin 0 -> 33916 bytes .../merriweather-regular-webfont.3661478a.ttf | Bin 0 -> 60020 bytes ...merriweather-regular-webfont.8338beec.woff | Bin 0 -> 32056 bytes .../merriweather-regular-webfont.a80f8324.eot | Bin 0 -> 27962 bytes ...erriweather-regular-webfont.f71c61dd.woff2 | Bin 0 -> 25176 bytes static/assets/minus-alt.4aa24c1e.png | Bin 0 -> 147 bytes static/assets/minus-alt.a3fdb328.svg | 1 + static/assets/minus.30f190d9.svg | 1 + static/assets/minus.71f0755b.png | Bin 0 -> 142 bytes static/assets/plus-alt.3bdfe660.svg | 1 + static/assets/plus-alt.ce2ceab2.png | Bin 0 -> 249 bytes static/assets/plus.31113133.png | Bin 0 -> 241 bytes static/assets/plus.7ceba975.svg | 1 + static/assets/rss25.87d6c4ef.png | Bin 0 -> 502 bytes static/assets/rss25.f5125cc9.svg | 1 + static/assets/search-alt.3ad0b1db.svg | 1 + static/assets/search-alt.6266295c.png | Bin 0 -> 372 bytes static/assets/search.51c3965a.svg | 1 + static/assets/search.5416b9aa.png | Bin 0 -> 316 bytes static/assets/search.ea14b3f4.svg | 1 + .../sourcesanspro-bold-webfont.4c2fe9b5.eot | Bin 0 -> 28017 bytes .../sourcesanspro-bold-webfont.5faf684f.ttf | Bin 0 -> 65244 bytes .../sourcesanspro-bold-webfont.e3687139.woff | Bin 0 -> 29360 bytes .../sourcesanspro-bold-webfont.fe9344bb.woff2 | Bin 0 -> 23368 bytes ...ourcesanspro-italic-webfont.00ff8488.woff2 | Bin 0 -> 17472 bytes .../sourcesanspro-italic-webfont.34c9ce16.ttf | Bin 0 -> 44868 bytes .../sourcesanspro-italic-webfont.945b0b26.eot | Bin 0 -> 20839 bytes ...sourcesanspro-italic-webfont.d770ae84.woff | Bin 0 -> 22260 bytes .../sourcesanspro-light-webfont.134ae35c.eot | Bin 0 -> 28305 bytes .../sourcesanspro-light-webfont.18334c7e.ttf | Bin 0 -> 66008 bytes ...sourcesanspro-light-webfont.76235309.woff2 | Bin 0 -> 23608 bytes .../sourcesanspro-light-webfont.7c8bcb0b.woff | Bin 0 -> 29668 bytes ...urcesanspro-regular-webfont.4c124b38.woff2 | Bin 0 -> 23684 bytes ...sourcesanspro-regular-webfont.8b766abd.eot | Bin 0 -> 28337 bytes ...ourcesanspro-regular-webfont.b0120280.woff | Bin 0 -> 29724 bytes ...sourcesanspro-regular-webfont.db7160ab.ttf | Bin 0 -> 65672 bytes static/assets/success.4e032499.png | Bin 0 -> 4098 bytes static/assets/success.9ef06b70.svg | 12 + static/assets/twitter16.27cfc1cf.svg | 1 + static/assets/twitter16.33fbe6bc.png | Bin 0 -> 431 bytes static/assets/warning.9253aad8.png | Bin 0 -> 3159 bytes static/assets/warning.bde34fef.svg | 16 + static/assets/youtube15.8e97452a.png | Bin 0 -> 590 bytes static/assets/youtube15.e0b05878.svg | 1 + 103 files changed, 11541 insertions(+), 1 deletion(-) delete mode 100644 static/assets/.gitignore create mode 100644 static/assets/angle-arrow-down-hover.9cc540eb.svg create mode 100644 static/assets/angle-arrow-down-hover.baa52fa9.png create mode 100644 static/assets/angle-arrow-down-primary-hover.11d98d2a.svg create mode 100644 static/assets/angle-arrow-down-primary-hover.d936067e.png create mode 100644 static/assets/angle-arrow-down-primary.1c0886c7.svg create mode 100644 static/assets/angle-arrow-down-primary.ab8d4776.png create mode 100644 static/assets/angle-arrow-down.da471750.svg create mode 100644 static/assets/angle-arrow-down.eaf9b383.png create mode 100644 static/assets/angle-arrow-up-primary-hover.656ab109.svg create mode 100644 static/assets/angle-arrow-up-primary-hover.87ccb668.png create mode 100644 static/assets/angle-arrow-up-primary.b38f7f9a.svg create mode 100644 static/assets/angle-arrow-up-primary.fd1251b8.png create mode 100644 static/assets/arrow-both.40570b7e.svg create mode 100644 static/assets/arrow-both.4bb0bc24.png create mode 100644 static/assets/arrow-down.08222248.svg create mode 100644 static/assets/arrow-down.188ad70b.png create mode 100644 static/assets/arrow-right.8dc15dc6.svg create mode 100644 static/assets/arrow-right.c5e6e18a.png create mode 100644 static/assets/checkmark.13582669.svg create mode 100644 static/assets/close.34c66938.svg create mode 100644 static/assets/close.707c1f41.png create mode 100644 static/assets/correct8.4e87f243.svg create mode 100644 static/assets/correct8.a03d2fcf.png create mode 100644 static/assets/correct9.860cef73.png create mode 100644 static/assets/correct9.f5b58d71.svg create mode 100644 static/assets/error.77a47b7b.png create mode 100644 static/assets/error.fed7fc9a.svg create mode 100644 static/assets/external-link-alt-hover.720d3de5.svg create mode 100644 static/assets/external-link-alt-hover.fe210d33.png create mode 100644 static/assets/external-link-alt.410f199e.png create mode 100644 static/assets/external-link-alt.f8c085df.svg create mode 100644 static/assets/external-link-hover.0007810e.png create mode 100644 static/assets/external-link-hover.e82acbc1.svg create mode 100644 static/assets/external-link.0ba33f83.svg create mode 100644 static/assets/external-link.7cc7907a.png create mode 100644 static/assets/facebook25.0247732a.svg create mode 100644 static/assets/facebook25.e89f66fb.png create mode 100644 static/assets/hero.1d4e1843.png create mode 100644 static/assets/index.4338282b.js create mode 100644 static/assets/index.a89d87a5.js create mode 100644 static/assets/index.b72e3796.js create mode 100644 static/assets/index.css create mode 100644 static/assets/index.f4c03caa.css create mode 100644 static/assets/index.js create mode 100644 static/assets/index.map create mode 100644 static/assets/info.65032fa3.svg create mode 100644 static/assets/info.6946b1ae.png create mode 100644 static/assets/merriweather-bold-webfont.0391ff32.woff create mode 100644 static/assets/merriweather-bold-webfont.3f042de9.woff2 create mode 100644 static/assets/merriweather-bold-webfont.523a75f1.ttf create mode 100644 static/assets/merriweather-bold-webfont.7ab8fe39.eot create mode 100644 static/assets/merriweather-italic-webfont.6c56712c.woff2 create mode 100644 static/assets/merriweather-italic-webfont.c64f21d1.woff create mode 100644 static/assets/merriweather-italic-webfont.f3bdbf29.eot create mode 100644 static/assets/merriweather-italic-webfont.fc611bc9.ttf create mode 100644 static/assets/merriweather-light-webfont.1b1f32b7.woff2 create mode 100644 static/assets/merriweather-light-webfont.386fee9a.ttf create mode 100644 static/assets/merriweather-light-webfont.5bc7f0e8.eot create mode 100644 static/assets/merriweather-light-webfont.9845245a.woff create mode 100644 static/assets/merriweather-regular-webfont.3661478a.ttf create mode 100644 static/assets/merriweather-regular-webfont.8338beec.woff create mode 100644 static/assets/merriweather-regular-webfont.a80f8324.eot create mode 100644 static/assets/merriweather-regular-webfont.f71c61dd.woff2 create mode 100644 static/assets/minus-alt.4aa24c1e.png create mode 100644 static/assets/minus-alt.a3fdb328.svg create mode 100644 static/assets/minus.30f190d9.svg create mode 100644 static/assets/minus.71f0755b.png create mode 100644 static/assets/plus-alt.3bdfe660.svg create mode 100644 static/assets/plus-alt.ce2ceab2.png create mode 100644 static/assets/plus.31113133.png create mode 100644 static/assets/plus.7ceba975.svg create mode 100644 static/assets/rss25.87d6c4ef.png create mode 100644 static/assets/rss25.f5125cc9.svg create mode 100644 static/assets/search-alt.3ad0b1db.svg create mode 100644 static/assets/search-alt.6266295c.png create mode 100644 static/assets/search.51c3965a.svg create mode 100644 static/assets/search.5416b9aa.png create mode 100644 static/assets/search.ea14b3f4.svg create mode 100644 static/assets/sourcesanspro-bold-webfont.4c2fe9b5.eot create mode 100644 static/assets/sourcesanspro-bold-webfont.5faf684f.ttf create mode 100644 static/assets/sourcesanspro-bold-webfont.e3687139.woff create mode 100644 static/assets/sourcesanspro-bold-webfont.fe9344bb.woff2 create mode 100644 static/assets/sourcesanspro-italic-webfont.00ff8488.woff2 create mode 100644 static/assets/sourcesanspro-italic-webfont.34c9ce16.ttf create mode 100644 static/assets/sourcesanspro-italic-webfont.945b0b26.eot create mode 100644 static/assets/sourcesanspro-italic-webfont.d770ae84.woff create mode 100644 static/assets/sourcesanspro-light-webfont.134ae35c.eot create mode 100644 static/assets/sourcesanspro-light-webfont.18334c7e.ttf create mode 100644 static/assets/sourcesanspro-light-webfont.76235309.woff2 create mode 100644 static/assets/sourcesanspro-light-webfont.7c8bcb0b.woff create mode 100644 static/assets/sourcesanspro-regular-webfont.4c124b38.woff2 create mode 100644 static/assets/sourcesanspro-regular-webfont.8b766abd.eot create mode 100644 static/assets/sourcesanspro-regular-webfont.b0120280.woff create mode 100644 static/assets/sourcesanspro-regular-webfont.db7160ab.ttf create mode 100644 static/assets/success.4e032499.png create mode 100644 static/assets/success.9ef06b70.svg create mode 100644 static/assets/twitter16.27cfc1cf.svg create mode 100644 static/assets/twitter16.33fbe6bc.png create mode 100644 static/assets/warning.9253aad8.png create mode 100644 static/assets/warning.bde34fef.svg create mode 100644 static/assets/youtube15.8e97452a.png create mode 100644 static/assets/youtube15.e0b05878.svg diff --git a/static/assets/.gitignore b/static/assets/.gitignore deleted file mode 100644 index 72e8ffc0..00000000 --- a/static/assets/.gitignore +++ /dev/null @@ -1 +0,0 @@ -* diff --git a/static/assets/angle-arrow-down-hover.9cc540eb.svg b/static/assets/angle-arrow-down-hover.9cc540eb.svg new file mode 100644 index 00000000..63b09db8 --- /dev/null +++ b/static/assets/angle-arrow-down-hover.9cc540eb.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/assets/angle-arrow-down-hover.baa52fa9.png b/static/assets/angle-arrow-down-hover.baa52fa9.png new file mode 100644 index 0000000000000000000000000000000000000000..e611376d377781d15853148a978f89797ab02eb7 GIT binary patch literal 209 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=ffJ8J;eVAr-gY_HE>CFyLXioW{VG zz!}zX^U_8s=@f1&;btXog$%!CpFHm$nfNY9fJIht=B-cs^VY2U{a8yp`t}12dB5XF zZ^?H{h&|La?~+@kQ75QYAN18?``diMzE81t|6cwi`cNf)5~I=r8J7afjt50j2cOzB zovvh={+UDLxnRIK \ No newline at end of file diff --git a/static/assets/angle-arrow-down-primary-hover.d936067e.png b/static/assets/angle-arrow-down-primary-hover.d936067e.png new file mode 100644 index 0000000000000000000000000000000000000000..2ea698976daaf1df1acd60c4e138eab32f622715 GIT binary patch literal 213 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=ffJIi4<#Ar-gY_U-0ua1dbiUC&UQ zdq`{x!|Gi=Z_e<&Ipp)baW=;+p6o6BYCHJPnCy%>cm3?^gemeiuIrvZO`3BoZA;^) zZ)J0eex+V*eJpseX!)ze>kn0xg7nI4`;L7S6V$MO^3DHpxXXl^PxT5-ryW_QH*@GM z7mPWlykm}gfn|R~ksRYw8>SP1EYm-8=sgEX%$Vc;Wzor}MG4{wGgmH13i$K}=uQSt LS3j3^P6 \ No newline at end of file diff --git a/static/assets/angle-arrow-down-primary.ab8d4776.png b/static/assets/angle-arrow-down-primary.ab8d4776.png new file mode 100644 index 0000000000000000000000000000000000000000..ee7b9ed6009d3d3442ec3e0f622c4dd2d8511f03 GIT binary patch literal 214 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=ffJxt=bLAr-gY_U-0vFyLX$G-hDl zz@mM?YR$yH+8Ir}n^ \ No newline at end of file diff --git a/static/assets/angle-arrow-down.eaf9b383.png b/static/assets/angle-arrow-down.eaf9b383.png new file mode 100644 index 0000000000000000000000000000000000000000..31a819064f29cdaa0a8a8a3feecc39bf3cc60210 GIT binary patch literal 231 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dy>H$6>uK)l4k4nxB4K0jL%!Z)Q z#N6lv5IZU{CnhmFCLt>}B}Yj+xDTj>wu&( z7*cWT?x~%E4F)32fj9phOaK4Xh^43LDDMJ?lhJ=uHRr1=f9`$d_3iaiu33Wlj{O<0 z9yZCvChuBsUQt*4i|WFL#Xz_lOfKFa&-HuZg3TK?gSZ>&^Yi}}nlHV>I=#YY<{zMK N44$rjF6*2UngC;7T!#Pv literal 0 HcmV?d00001 diff --git a/static/assets/angle-arrow-up-primary-hover.656ab109.svg b/static/assets/angle-arrow-up-primary-hover.656ab109.svg new file mode 100644 index 00000000..05a4c041 --- /dev/null +++ b/static/assets/angle-arrow-up-primary-hover.656ab109.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/assets/angle-arrow-up-primary-hover.87ccb668.png b/static/assets/angle-arrow-up-primary-hover.87ccb668.png new file mode 100644 index 0000000000000000000000000000000000000000..a8af5709ba1b0fabe0d0796fa61d11819b46f6cd GIT binary patch literal 222 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=ffJrJgR1Ar-gYo-^cXb`WTNm|4tV zeNeQhEk^NWsa~q$i&saBnDZ0UKOH!B?3sJcvx5f?iQUiN7}2xlQ_SnUgOktCzw#_} z`S;i#%a{da*acp;nJu~| \ No newline at end of file diff --git a/static/assets/angle-arrow-up-primary.fd1251b8.png b/static/assets/angle-arrow-up-primary.fd1251b8.png new file mode 100644 index 0000000000000000000000000000000000000000..20fdf18ef5faeec1fdca435ab9137cea81f5f1d4 GIT binary patch literal 213 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=ffJIi4<#Ar-gYPTI)XU?AXn*{Xqg zM~n81R2P=z9@A4<0;Aarn741ZJm<)+-D&2(zBhbMpa`p>&(+O3U%Gj%ALr=( zRAm;7;Zxcn<5pnV|KL+Bo6>?kvfh#%4WBqV9ux^2e5%lNx{zi1XAZsRf-&cmckN^> z5>tFvAmiYt%*R;(B=7uY{^veV>rlO1;acDQqH3m(1g0<2m?*vY(-{%#rD;Ea?qu+E L^>bP0l+XkKs69`n literal 0 HcmV?d00001 diff --git a/static/assets/arrow-both.40570b7e.svg b/static/assets/arrow-both.40570b7e.svg new file mode 100644 index 00000000..4c7af72a --- /dev/null +++ b/static/assets/arrow-both.40570b7e.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/assets/arrow-both.4bb0bc24.png b/static/assets/arrow-both.4bb0bc24.png new file mode 100644 index 0000000000000000000000000000000000000000..075ffa9785ccaf1014b1fd0b55ae91abfc17dd4d GIT binary patch literal 227 zcmV<90382`P)`>cT3PBJWA#{!3zId?N)~okEe9S}3r`s|}!<}+>HoTXXgAW<3yc2G2@$*BX#k})SQGp6}V?Ydr* \ No newline at end of file diff --git a/static/assets/arrow-down.188ad70b.png b/static/assets/arrow-down.188ad70b.png new file mode 100644 index 0000000000000000000000000000000000000000..d6fc7100e60c625f59d13dd68d896ae066015c71 GIT binary patch literal 296 zcmV+@0oVSCP)q9LalXYX^cKTc`R^%GMC zn^L|*Ud&I~f=vdd$b>C%GR3$220e~#ktZ&Rb6vy{dcVbn@q7~xBrGlylVk~(oao5z zuwuC4Ny|2h1=0|;+@Bhr(-T-ST=2U&s0i0I`E1x7PujfAERcMk-QiVK`9jBS{>VVO zOe$jn3m+LjED)FM(q?TASCY799oK7?N16yGw}+8v*1hqTH`u#Gv-gN#?-Iep@4v$i u(6R@bsFdS6!=@u0#q!Z7Qkb)a{c{HLjK&@v*8G700000 \ No newline at end of file diff --git a/static/assets/arrow-right.c5e6e18a.png b/static/assets/arrow-right.c5e6e18a.png new file mode 100644 index 0000000000000000000000000000000000000000..5765f1b6d55b5d0e61fbc6178f96a3658a44bea0 GIT binary patch literal 265 zcmV+k0rvihP)JGd2`0H=eJ8tdX2Txa(^;6^+~oq9e \ No newline at end of file diff --git a/static/assets/close.34c66938.svg b/static/assets/close.34c66938.svg new file mode 100644 index 00000000..25f10873 --- /dev/null +++ b/static/assets/close.34c66938.svg @@ -0,0 +1,12 @@ + + + + Fill 15 Copy + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/static/assets/close.707c1f41.png b/static/assets/close.707c1f41.png new file mode 100644 index 0000000000000000000000000000000000000000..677ac8f47e65f65d2bbe39b113a06163dc2868ef GIT binary patch literal 215 zcmeAS@N?(olHy`uVBq!ia0vp^{28O&RnR z=ElPIGMT}W^~k|2hpa|MA7v}Hm(He=!vC2s{)lP2%)lgN$lU7E%fawTS#NpM5ywvk zTSadBOq{RDmD}}b<{}ZclOmlr^*udrD}2?M$*fV?IU|NOi2X7LgPujElU+yPexOSk NJYD@<);T3K0RS%5MiT%4 literal 0 HcmV?d00001 diff --git a/static/assets/correct8.4e87f243.svg b/static/assets/correct8.4e87f243.svg new file mode 100644 index 00000000..bd7b38b2 --- /dev/null +++ b/static/assets/correct8.4e87f243.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/assets/correct8.a03d2fcf.png b/static/assets/correct8.a03d2fcf.png new file mode 100644 index 0000000000000000000000000000000000000000..4b76107e65a4a15662ea1b90c348efde13f10040 GIT binary patch literal 195 zcmeAS@N?(olHy`uVBq!ia0vp^JV4CJ!2%@LY-GI;q`Ev^978G?ZO@xJx-kkcJUG0S zAtb>u>Vc03Z;V(;x?8tHuQ{?&6nafnMK?w9KPFc&=vAy)Aev vB_g~<^8AXZ-~7ubY6i=#ecrKu{yv69uPbb=GB%_DUB%$(>gTe~DWM4fy>U!$ literal 0 HcmV?d00001 diff --git a/static/assets/correct9.860cef73.png b/static/assets/correct9.860cef73.png new file mode 100644 index 0000000000000000000000000000000000000000..a83160a09868dbe603dbe719d40cc8604dcfdc9d GIT binary patch literal 446 zcmV;v0YUzWP)@*n!ph_1uFkl|o+#R;Lympvdm^Q@myVKBqtf1pW0hg~%<5rQmgz~5* zf^azl1o*-B0nNL5{%rh(W)RDcoIoW6q4o{!M+%r+qZ?f20}~6tMTrS78iXGGdJrbQ zNf|=wE;B5P?c`!`chG&QH}T?D1wnS4AjlLcAqciF1NpyaGx-2*hqx&|z`w1ac?V&l z%4EXitOsFX5GFUQ;+0JA(uxB7H1P^Gj2+4(I)n}grfs%qnEOdE zf*2)ra~UR+Xk}phARm=I5lnty`=oD2Y{s$^8`j_!cs4uF6a|e+LV~4A2s1xWzuZHM o%Q2NChABJ2URwWjAI%fjAHSg{#&zo4cK`qY07*qoM6N<$g4b%gv;Y7A literal 0 HcmV?d00001 diff --git a/static/assets/correct9.f5b58d71.svg b/static/assets/correct9.f5b58d71.svg new file mode 100644 index 00000000..485f42e5 --- /dev/null +++ b/static/assets/correct9.f5b58d71.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/assets/error.77a47b7b.png b/static/assets/error.77a47b7b.png new file mode 100644 index 0000000000000000000000000000000000000000..0d434975707922b1f01411da9cd1936e428f2974 GIT binary patch literal 4154 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 BX`285 literal 0 HcmV?d00001 diff --git a/static/assets/error.fed7fc9a.svg b/static/assets/error.fed7fc9a.svg new file mode 100644 index 00000000..20b8057a --- /dev/null +++ b/static/assets/error.fed7fc9a.svg @@ -0,0 +1,17 @@ + + + + + + diff --git a/static/assets/external-link-alt-hover.720d3de5.svg b/static/assets/external-link-alt-hover.720d3de5.svg new file mode 100644 index 00000000..2958691b --- /dev/null +++ b/static/assets/external-link-alt-hover.720d3de5.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/assets/external-link-alt-hover.fe210d33.png b/static/assets/external-link-alt-hover.fe210d33.png new file mode 100644 index 0000000000000000000000000000000000000000..bf0242ceb161af71968a5a515e65efda293c3150 GIT binary patch literal 663 zcmV;I0%-k-P)6vgrRvvyEMwQbvoYTJxc+eTO`tZg^0Z3ngS@U17e?(FT}-)2to35xl>bKZKr zFk!-kaUlr_2^r7@{Ue|kvbj{gI-Vnvd4u+@46p_oIpfLzv!N1K2FQg6>H~;Fv!Dq^ zU=2>;jIzTh_KlyXw8jWuJLrFm!5c&)lRXj55##}daTL+abWcQc1bN|?h<3($BAO$7 zykIh%#n%##i`atA%2pzWN3=(f1I&O-93~*O;b(_(hzm3TiXtBVyhaVGEQLMeye#{)_4IVt`}tXLrn(7X!S8KeJ=Lycj@cdJL35hzIru&?&zI$;Img z!viRkmoJv=51>$9j$nTPh4OL);{zy^|M3WCObwt_UW{R27165;}scXt4BD~JnF-pv8TIqeV^puC#{h_l)tE9P!ng!vp9?e}Hg+aDZ@td+=wm0|T^#OsU_!*iQI!!hr!M!=E=u_PZCG zA}@xVhRgqllkn$ckPEhk%mMsubb#TISsLVm>2MP=E0NAn@xL($ui;NTswq6G5{AJL zG(=wHj)KbQhlBW9W<_e@d2lV~Bl#6s3T%NZxr$&oo8h2nN xk8uEv{`8}7Ce%e=^pApO$ffbL941VdFo}6vl(KUIUts_M002ovPDHLkV1km6F$Mqt literal 0 HcmV?d00001 diff --git a/static/assets/external-link-alt.410f199e.png b/static/assets/external-link-alt.410f199e.png new file mode 100644 index 0000000000000000000000000000000000000000..7761c284d6ec2f88241efd5f3df5ecf1b374d188 GIT binary patch literal 833 zcmV-H1HSx;P)O=x!k$^~mi6G+hh};l>+9V!so}a(K7$RkoDz|80WO+Y@HRsqcXG5}X}$X)$g5P$)YDaF|Uu;tUjzXyV^QX!#`8@Y!N zxhEiB)L&R1hde+$lR|=0KmqedfSj9FXc-8GNbpojkQY9eZeSUQ+)F|yU4j&_XV0ET z0hx<9=(0oJ21pAX1`ARdAfD#j*4HI)(j`a%h%~g2otJ=uzFW3zc`C%E!?*r96B6Lu zmQVbvEOuM~2!0QF@pwOCFe%}8006a-8-apuM&T6#kjIOS$1*Z99yAND5RiB0Mp|JS zULoLu*f_#2yh1=>6%qUJw9Xfi_5~>55qW7w#{S1-J;AB~6}+r0DFoPuml6~L?88e5 z3IWF9OO`+i0rud9gnf5(iYf${f|v2NTt`&lMz^>^fL(YQg#hdD3IX=v6#~q|8xWv| zHz2?Yyh4C|c!dD_@CpGI;2rZnH^%$@-$@k^c6cKCP@dr~t2jt`N%+|o07vLj@ z-V6)SCoBRY0g-@6KydhuixE#SFm<*XNCC`WssuRXW#VE5VHe<#2gr%fexjFFz(9F1 z0C*#;@V*EIWG9~4shh)&sD`+h&)WFT`$GEacahJF7)(+N$ji%n7LfOWlt4Vq?+X$9 zeTdw?kQptP9nr690peR#W*-1`MBGv?KM39-qPNl=#4SGoQENb2SH#TH;YnFC13;tw z1&w8kXiw+` \ No newline at end of file diff --git a/static/assets/external-link-hover.0007810e.png b/static/assets/external-link-hover.0007810e.png new file mode 100644 index 0000000000000000000000000000000000000000..9df376d48e6209d28cb56b3ec81397aedd20f9b9 GIT binary patch literal 1099 zcmV-R1ho5!P)=OWc3H7rkX4_ntF_p6%oQ^L()ViXh0zj>UPB9Y>ZCJDTN% zEG!3WH6&MVsG6cfm7hc8yQ~ifel(z@V+KqJLvP?I1Wy2F~}%;6+~alsq`DSGmr6*icBb zKlodD&+-hgF0!SWDfqn`Qcw#fN_vXRgnxdF`_2gu+=pD-!@0CO2yM6HYGiv@t1H@d z=eOC<#02}@V zX_yM+#bn?Dh(-xsTv}f}W9kHc5v+}9%#(i%v%CWJ-^oIx;I!}?0HeSYCe zOT)@{zF_76b4N0Gv4?jMr0LXTASfLOfkpb#!o79@vc)|JCIleZY|s)2LFDqQ!g(<^ z9T<$JH;13EjSDv3H?PLP&4t})mYzibB378W_f4=rv zhD&z=tdx$HK)?Zp8rl(Oz^{VRVGx2+m)Z+uZ(VG+>%CC!mN9-Nz%({l5k_dUKaOh; zEebVJNe2|)*u#%$cTF;Mv1iI%L(f55tPyg+Remo_$4d+8;)0VvAhf%7k>N`{tnCCL z7~EvjSeLVr$ZiJyud4^7`LhNKH~UUC5L*-EZ!ubI7!h3;2muh#Z}hpN-^1ko)ip?eVD15^K9`@c&)-6b1iBP%TX+LYh6`fWmgX zi1(h!VHg29-CgTdw1=w%({4?s?Nd;HOxYg*s#-)aD&{JnPJxv9A^<(jrG1L)##Jcy zB-7@F^rnY5x-Ml8sND$ov4Z!|-vJ2jHmxdNtUh7V?HV=OhFyAOWv1^3m0FGDzC5*~bUfSE%i000ZK!yg{{ RJ5m4u002ovPDHLkV1m?^@_PUP literal 0 HcmV?d00001 diff --git a/static/assets/external-link-hover.e82acbc1.svg b/static/assets/external-link-hover.e82acbc1.svg new file mode 100644 index 00000000..98942ea9 --- /dev/null +++ b/static/assets/external-link-hover.e82acbc1.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/assets/external-link.0ba33f83.svg b/static/assets/external-link.0ba33f83.svg new file mode 100644 index 00000000..51b6cf20 --- /dev/null +++ b/static/assets/external-link.0ba33f83.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/assets/external-link.7cc7907a.png b/static/assets/external-link.7cc7907a.png new file mode 100644 index 0000000000000000000000000000000000000000..b98fd998654065a78c6e382ad06ee71dd57752b9 GIT binary patch literal 1036 zcmV+n1oQieP)tmHNjhNldoGNV{3Gjl5{iptDf+q-3EX69B{6qNUQ z(qm?3W@ZN83!rRE$!$kobaXjs`?1*fpvt}<+Njx;Z-LwKpy_M?YuN0a&gII8lo zWd1v@K;Z-5NB%vQbno4={?PmzJ<-Pr&{}!kSfCroM6M1|;ZsQSpQL!A*fp7xvKtE& zKBDWX(#4Uow^J&BGW;K45( zV0^tO?naOHD25@!KPC-h7fG;FJ7x0FcU^Xbt<+8;&C`%I&6`9w=Ywb-Nly)o>-0qu zVAReC@{8L6wiP88Lg+3hli|f#HUJU%zM90Yzdm&Z3r_E|Nq3>d# zYB#Yqgux#ki$Nk4f|Q3q)5}!FioK!jXnM$=fayd#;NKj|1;Q9aTOERwf>?lZcnHMj zar9vA$aJc9Cv9uVr13iJ5oDwgqy&VN1e;acG1#{0NWmaR*)9rtB7qo5>c0a6-{5SkOZy-QoE;5|{B(E- zG^XmFK-~T1PLwCkZHGAc&2~V7Oz`3WB3b8Sr56sV?$dYtV_fYf1d+*h%#T{<0OQI2prQeXa+o*n976Dbc81TcJ0x-mxy*uh&v zcxe8Oo*V99OJ*cLD@ns%l9P!LMA_e)0croN@r|4FPMDFXX^_pRv$3sjR(!M6f$~8t zN&}$c9^rZEk^G#W3Ir*kfJ^rczF7fczsp(e0Z2qo4~#*2Q)i2|$4J~|xZfClGV7&W zG4?K$CjNR-{3EF@M_?JH_fptq)%)vTc9U3V2*jXtvQ_}f_f`S<&$vn?J7Iz7U<7GP zqk*LC2r|4TyU{88P;>o<`v>l!>jCu4;8KdaQL=gG;L_Fd7(R?o|2s(A*U9j^^88Lq zYNEH(_ns4b4R%a0NyUPL2(|5eK{?ucNxB+PB{YcBq-+7$X-deIH~2UJ0000 diff --git a/static/assets/facebook25.e89f66fb.png b/static/assets/facebook25.e89f66fb.png new file mode 100644 index 0000000000000000000000000000000000000000..98d556985e071154454e65b1c2751e4ab8aaeebd GIT binary patch literal 270 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ʸzYHn@vOryu5h>Qc2RveKGND8~_)tay$568$rl86UMd??GLLjl#S3NSKY$ z*qR7j_&YzH4d7N8chJMXjf~5uCwI-NnZJ$b0)Or*yNAi&Obqlfvtf7kt4JeQoJJWB zf_?>Ob*AM!(IGK~Ei`Sv&NcihDW`>bFRZ?}({WbJ_KX){B7WK%|CP~pFLOWboEb^F zyymp4vG0KTY5n(m_^<9_VUQHRYX8 z4%0{jNVA!&Kf?J*p%lVS`b$Cv&8Hyapu0%IPv5_1@YZJ`F5kP0v(K$1Uo2FF#zz%J zvRCnWz8ZBPt@|coKbwmbhf3(^D*RAb-+sw)lNQ}Bl)p?=FfkuA;x(-trNK-O@r=%_ z59EO$In;P5rz?|3RVQ3s8NsIDT36eIxxyFHu9}3q6O^y(V~L_}S}UrIi6?pk;%B1P zg|C)s)Ltp&6LfCy7YWaAok^B{50uP6YPXb=tC*#nqdv-b`R%oiO%yRK1I|$v0l)y6 zcnJ>&wL%Izp{hsaF=_$c9M>>CsAS^1WMXja{dG^X%Wn5z+%lFl%!{#j9KVz0?0a1!Fwxy%G#xw;UeGQ2{~fwHtxKGwr&H&&GCq6gOup zn-5CE`aDTI8oi21cNn=Jiu~0Tp<%sT{n>pW^hycWw3-S8@WxZyB=hhuUw)d^eJ_d@ zDx3ZxR6=Li1HNNl{7ry)3VPY~*IFAmrwIvRLf70!F8nO?xjVU!vvSt$BSR85M@XIi z5!YzwhW=pMh`qnrJ*|n_!`ynGI`^ zOcMMK4qkr9Y21xkNpSKDl-qUqt^ZCVqkATzq-Y?ZYWwbQP9G;~;Z~Dha>F=f{{yb@NEjTL~z2*H+ z;+=j+Cj;yIj7)arpJF*Dh`OL>g7b7GyfW(y%^G{ZEQ+Bi=H1t9tUd;`rizkMPU`Ga zH@ve^vk&I!h6lDt=zv$WF0o|wop~XC7eDv|NP*9$r@iqp3TKFTtB-w_1q(#lDQ1Ut zxND;RjaLYdy7KKL5P6w#RY8di`|Z) zmu_s$-^Rm)`oQlTo}6jvrNmO5 zX2!$$qs97TV;~!{jp9U|bmXio`a48bPnvEc`=l*kNZv3tKtglP{$pdG=o3^2bU0^D z+Zg6P4c|Bn3^t& z-t|CJ_HhajjS(39dQV{=k@f!lQjp;;dmN|JGe1CeHs*Qx`0cA?3g9X9D5BRhknFf^ zjrNas_x15US3ff{C?B2W$u(Nj*_^<|tjpiLEME|59q-`Q z8lj!~jH+JjcwWVjZwU3Yfn<3Dg1L9m*eOP+Neq@!DGeCH3c_WPBV7k3nSibV@A3gL zROK8SHGn;_;X`ic2%u>33{x)mEEIf3CDk5;k;sQ3gb6s0rxaRyDAfR_)&{$2l5DeQ ztrYqtfC}{|QnPYSmS^ZYFy-3UDBy3A8I#*M3f(+d;{qyUHLl}sA2NdLM1_)zrHk1w z2L5sDn7q$fthW`ndz^;UEp)kM%j>7>UVrzlRGt@}8>@t^t!)&)F~xblyMK7oF7bJ8 zyveZ|%0)omy~oV~tZZAGu%D9iRQ>AQn`}yjY+#P>BzZmTvU*AAJES9(=cJiD+WdA@ zLh;~i8K&2JE~t)v!3}&=L!fTmqPc#f|Mdo%d1-DWv11L)SH7K#wewjLr~gY%h;%6o z=ysg=yEI)0(p)@+)vbompEUBdjQnI35%Zw@(&Nv#X;kuC^e)1IKxz=(3o_qV+gh|9E7f(mwec(v2Gl ztLl()tNfrjZ*Yo$x{A1K?@$;L2^0E(_vd8W&_~d#}PJru5+%hGtC3hJmw2vu#7-6vfbc%Mh^u7J-~z8poV)^ z@d@lfNGfTYYCzGf@OsW|B&~cfH`oq(!_iaL+cYR@1A~Fiuss!8kcV~P21oIDnAz9) z8(})3;n&cXdo;+jFu+;g^^2&8Bb>5^`W+8#3^2`>glsUCQEpXFlCKg+p7jaI^ypF| zskTEX44yCi$P;iN&=_ImKh%5Yq9bar5YGZJXuaK~eTI|T>b{!Kif{sPVD&q907F}r ziW5eORI^jfmolZFNzn()SocbyS$WN^r&={pFcdxFp5z?@xS<y*O*`zheD9xVGse$(H6blg&N)Fd^35uEemNboSu9-8tI8g(C9is}(s#}Vi zl3})Acw($;4o_rp_^40;a2t)M^OGjOaALjH(S@Qo1kBND9K^au48RbUf z@Q~Kq!XEP0O1_ehMTl;+v&Ge&4~iUI{-A-~U%G|MAkoXhnj06_RVmA_EUb3wV*pIw zsAn$F-UN~(#w6Ih0>35ibZ{Gn&ey~F#olUyu4>TkcxyyV4J_mnp*%u)2=u$p=kyLcX~vlE zjpQj*{_7gi|Eax-iQoq7?^;j+YraXrG(TozbN>xb%39yjR^`PnCDsE_rqd#NX(@~! zIj8+^m7*;g<*Xfr*uGe1OC3OpcSpEq{VVBv zX9Wv=9`a9!=KuRcPaeuQ9hs~30AD5mEfPFO;R7LQ&sh6bV_daN1)#U5sQoDl1QU+g zKJp=y43ay;gIZSmYFwf}(2i&U?io?3(U;QHnsRWI-wkcDhN5Rs2Ki&-m{P~RoqM!n zGmdmtPaj#Fnvp?MKKklEpJI=bqXv0YN!{X0xtm3I?AkH1Qohz+XT8p~A7>taUv~|J za-FIX3=nD>!;?>Q5~v>pIH%l?x>};%{-)INaRul2;ZOzJzhx7-{x-5N!cYcP1^Tuu z1I4L{L<+k)QC2e~hjaw+1cLNFdn9E-*$UfHIy=5fX)Vclg;)XC*9Db@j~b{A{$r<2 zGkKdIq+^~mQsZr}_vpj~v6l?5;J?3*(V$KxVW|Hg5f#rJp3{&-V>9_h-M>0c=f8nh z@Pmdw%}&7bn_AtAuXa9g8nk6zle0Q;)JyAhDkHRl<;U|y z#7fJ8m2fF)u1{f}Rj0ikV`E|UV_`XhsynUK*Y_B!!5RnDZ&Xo?)v6kv8}7i10n@FnfrzgRU2BmB0-ypLp}K8ezpo z2ey%%M4L44Z{}N;|2*_T@3j{joe2^z25Sc{bjcryAtFr&!TR@TI1?Sx#n6HXp1$97 zXCtW5R2^(Eqj(Iejf#HI5|F3c6gPzm_mG*fz-}Ur77Z&?t6Ddx{co}s1qH;Fh~|7B zp2xnG!<{XpL=e@ZJR(V<;Fo{#LNxA+LuB4j{O}LpIODnCCy3!#zqk=kxFYc_WYIjn z5ghJJ3a>m-x#PB&NCr4;Uyxq=d~$^jam2QTFDZJO;hlP*Yly*~&=*2aN{-jwoF^}r zx)OjiTMUhw)meZ=RGjROcr@bi`)lsDB1r22$|;$+ch*pTVAODVDL~1-KoK$W_P$3h zX9%zH(+)|ed%4-|_BK1ovNJk$3_dP9a`^vdgkzG53P)Ie1B9Vdx2%21sUx(Th&J~{ z@}CaUUp~*fOgAzP+P_o-9;f@2f05*f*=6&W{qWFLNi3DI-xH-#xAcaw;puFhyC*aI zh^s}+J0-~;=FZ#~Pkt0k9Yt7OQp#AhD+Pq-(d) z#YwOJ&9Xz$byXcac`xZvuazm3-@DEwUF`J!!EC5CABr+qW4^+qC@&7QjgTMz>4HEm zB_^$a<&gE)hor$OcVoVO2aX^lQbai&Cl7G0#%R{ zu*^*zFl?t8cC+nzUYneooHGy? z7I0-6Y?#M99RBK(H9`B_s)BFT+5b7_`oHgxkA|y~ zZCi%VqHo<`lE{2m_t(;-C~vWH+s8helrvAtJ$t$wVer{nIWN8MJo~RZt6_*6W&!sy zx>0x>-(7^Dk(_sZ>*V*CJ4%;Pq2%Xsh#pGgg(8!#-0YBLJTZV7zG#Yf{e1ZoK4>pOwI!lt^y?6TlK{NSxN|!H zJz>;S#7|e_9IjMpS%c;%EVC@`LDjc;wVt>-hL}$|%8SsSU!a>L@G(eUAUW-B-F@BPXi3*)#jDS0|e-oz~MQ zQ{Zx)&7O>nD;BU|Zgb<}e+A8@h?mS zg5`PxXNB7Q{4b>CLw4DK{NwSzDdj_MeY7q`^T{?2&v~b_5tZ?^@1*jaBA3qqKviH!yl)%m&qTL2E{F| z9pjn~swW>3$a4Y?23<{}KP!$ZNwgD!o$mY?ekC|IgeT@!PRcEM&4n23hReEqxyy_2 zCn7y8A8u+{kwrK*;w?f(D3_k06M^b~O~XvRYykcCx1h=S@2Tzrd&F8juU8a3mFjDc zwm5{sxcTKU%J|QLh-0%RY+CK`^L{L4Y2*8zv%<41$5G0#wq455bZZ$GPt#FRX$ejD zX9TRFe!;RNABJ3|O9FocX1CNvb}gMR{4Uv>O5$SpDEvtY%iovBv#nl_iv@US8B6{d zmx?iqT3}qCk=XDj$N_|>$|WTr9}sd%jf;x41(*SfuIuw#g;dsI1Wlut+_r)mze#YhP<&EKfOJjj*2o=SYRhIfY zb&?;Dy|H_j-zAM^AV%*jdJjG=dy|>Qj5Nl#%rT?g#7vGZo|z<`e@nWC!j8Ook$j_a zjXQfxLB|S0FaIU^6IN$Wo0iva=yA-pWPFtQQUC7Q%jT})L_izRtP*N~we*Q6 znHy50@Zms*1)Emd`ss(wlE-hQHCe@z8ff60Oc$pwY~T2+$aI7I%?HdxL(6ODtghJH zYzIZ2NEaV{gM(O^tqT)c+DPVjZi~7fnirnpI?OQLn!W2g3u91XJ#XH$F(N>OM0%Su zc-tGN!Xhq^e+;jb+vbLZYD%WGx8sd|Jgx@=t%_b}l?;KPb979n23Xb2&l zn?E*1Fb-jM36bE~xfO+_X^(~q5DZ{Jb(ezZ-st!E59@l1U576fxe*^eAqv1}g*{a1 zoce#N`W*J+TK{ADr*z-{UVkhaIE?pxbB{0OO;u;s8sAmW!9GR*W;`^xblEYhNO!CO@bX_tHEYu-6VnnZf|h6Qmd_)V!vOUezZ(WO#njK$ zfJU~wOemz4(({uWHafYGR-mn%t83-C1(6-YCKo6h5ha4kKUyL9GoK!bdMF#WO(G@& zM+AU(h+MULoV_DCaPhm$34eF>RiMoU_%VD*jQFF(YIpu? zQ@GWN8M}%FJ{rUZc#>$$Xz}tly?FG3%+=3CT-`-76Sr_BB{N_#5&%G`V-}G4ge4^h zop}F-9yp3&5RxYx{PE9ggPfq<#%ZyVfylQ+h9ObQc$1I!y@Rtp4?1pz@f6CnodE+e zJNTRZ$&)Yq{mz*|bfO_Dfy1!r6JpuOC7fxSXh3iu2U-Y2Fm#`aL8wn}eGiUg7K?~$ z5Cq(u`s=M`jO}l!w&RvQui0+bpStIku3#~_W`&!AVKmVAPxmmYT>ThO5++l@)MZ*5 z;8R`d;iKVD%1^2LG#emh0iL(QvjAD~sh3>KDbOMeRlbrtnD`CV9mZb7omMb4P%h^c z6zGCfAj1a+Ua6s-+uSl8j6UBGMSn~f*S`1)MI@5^fC){BgZw5#y2gkRhK>yEAh-+} zpTV~N+>LO3y3i8C_{MVK9=i5Gw6yD+Jx z8!bv_e4(5UQVoK8!-QFTRK1ey5L5Or_EtHx@x4Lq8iX8djc0u~P-VhAigVLK464Y6 z69d$kp3?ID;`05?{YdEb_kKW@M1wUv^jZW9id+j1J0M3i$g42%B4JBQ=xoS)&o0aR z0YLw+rBBej0AC8%Yx>7EtyDO(yx(rmnE(vb%6+2|g~pgxKvo>;m$Y``gc1R?`n8&TZkG8QFY{SvkF za|Q$T3@cx|Ji=8S;*GNaPHiBfXt;`;j;6c#E>0LBGD09oW2n6vUb4q^_1g#~3LJm> zF-EO2%mF?Sl65Bq2;b~>6dM-~8#PXEF-V|AZO)91%#T}OB|(dpbp zUU=ctildoV*&PtHNQzG7=xlHzy~!GS`g#Beo9=ovfi{($$Nh2~llnwePOm^>wGTP7YEu?S^K-SQ>HjpE>;UhF{XwJOG_I9 zc21ogwtMgu7XNhl*;L|(-ADSv=s7jm9?_Q@0ss-q5LwR^6_ly7@YQ5BXX zm{T&-pyBL|suOFPZ7(SF{3XRnV|B;`+_t{_t5jbGLQf4&Oe{ou+ z%uqNviauHkFoGO6;linr3p`qZ)wnREKA?4!nOkXqHIu#2V*&+aFi4m7K;M5K9*sKk z8tMU(NG3av9FR7D@*0bRN=>=lHc@8d0pib>Om{khAe5GkV1X&5M|2doFRw_*-?H<# z5EhiBee>fuon0tJ)QxH4)gv&M(=o$B)Tq5J65S`+JF|@cZi)CQNhk@wirAB!F1FAy z6z_Yg)Ll1ege?{WW~Mrz8%&e1*gu`1n%0pEc9$b@hx92?kGo$UbKKWixBt<+ zk&|P7`j?pD98Oova8~UlE57t07$i_yS3t&Bm->h?QgbshApZ>!M}?GI1=o^Nd)Y<) zs})_KsD4d%BIvo;rznc>#`&8uRMbOOd{E82o5j06kpM&GIO2-N0D9%ZWp-S+b@50f zp3Pok^HF6|u>M2Gv75%!fBTXRWt6X_NPzF7w?R+FV{N+^|HuQXz!y^hpyW7-pj&9v zBF;AIp}3lh_k4F-O|pIb!h{1Cm7*eWIt!8+O6Y77`tn^!;X_ZAKPO+k4X74z4EJ9sZGKrcqqyw`Epwq>A+m`hrK}DP6?g>L&KNdC+TG@R5A!G=GMbMg*LsH{|ey zNo8E{Rh{*zvT2E*oUIxu%y#crA~4}-`R=>%YqGv7WmovisKl>I0PK188?I1O3t#qv z*2Ez0dUuL29}|~LNS2w;pP@7^gOH)NEpEC)Ki&YB8dUSw=-Q~XnfEzS=dPu~*K6f` zd{8HR(RcLEXX=P|>JUI)6G_x_j`9p^xMe7a96Q|!P*yroDVCE~4|zj>K05dl)t@_0 z)Oma0K8WLCg!$PmKU0lGvdi7;(oy5?Z;pEwtyFH6#Zik z#Zk{U20a2v)7IbDZ~39Rcu`_9geh8t{c9;mL$v&+_{99) zzRU2?zzMHjFT!7qP&0~BV%EKK&IOa8ENBXTIuK3r6tbTHwDam4w;=|P^Q=%}a2!tj zH_nC9omc29LW!M^R0?-k#^b}lAyyXqBbpsE<59m9Zh`Lg9&Sjm;^EN-Or?r}T1i zksRM3tcW>dS_DrW+J^{=>@;?JV}p|tQi6-z8_YE6x)+g*c^+G2{9(-b+u-tt$*_dg zyfDSV0-l2SRrM*6NDD=7Z}Youq-_zTTuv`em1fR&^A&Xrh0$LZ7c;Efk{PAA$;fH5 z74852E&e;K+79dIzu>A;f1pS8$jm^Qlu3+NE1LmmO&Mg z`~f9#0eLaQ;5=Z|bsh}8&3pt8JccpV`e@odB^xtv!XSbLgKiH_6WUJeLeDS56rd<` zo9~TGu_y8gA3vhmfyj1|LKvXb{cHpl0R)3-Fc0oLhv(IWEB&9lgdI-kvB7Oha(mN~ zKd`J?N`;1>zaj>Fni?KUTu9$(={=M?;*~uhx(@K;%pT)YSe6hT|A0LHPZE2vm6n$L zP+bI(U<{P7;rDe5E&ThWY+}frMgv~hbJeH&vwOcrV5(0MJi&9OxlDYQ8?DN>VrIrl z9MZhBKV%Eh0gCDPaYRw6i|<=PJ_P&>Wpz@`yIc)-zoF+zNam$FA&cTO~gCR_!@v8{NMT5k~=gz(1iBD+mZ_lIVr2&i+sRScz3dlg|$RM6ETQv zl@sLd1L}os!rPU6X4(=7^_vI?JhNA>H;Dq(Vu-VVZIzu`r~5cxWxH~C$oKJ+moE-Z z_NxZj0kspOzg~a5Pk{!z{4fYAhc?F1*6b zxT!I-rSx$Ik4CY@stVYsw&7t442oH;4A3XTva-LYiFapL)PXZh)t`Hucf}MhRav=N zcX#gQ47C*h0qkoK%Ol(e>8oUhYXM}lgPhDdFoWM;&jGL&kyP-AE-cAuM>d1T0}7g@cg?|y`kDGfr}))(j;FSur+qtec`|UJ1|iBLVY>tZzaq6~LiCp|WrCR?on z`%N|d*`Aq(^5MD1r92^ALPz%O5K{5Z(dJ{yjitKB-=Dfu@sfrVD<0k|cW5HLsckKMH5%t9fuzhHpFKVk=P!T5urc>r zlsmY_z^Bt2yXd7&%DNR)RVve?+f?CWA4P@TuP(1spQ*B{8upT>qSFWln|3Xr>C27X z$^Q7#pX5YpKnBMeJPOn#W8fTMRlHNXX_vd&JE=a+^7W|uh?ymqD?hW1RJQQn$X)uM zR2<<@z)RaGiq)Ew#ncSYZp>7?Fa8{ag!zx*H)cY{aWU009c z8Edv;uXyEZn%=4aZ=S`Ee$B+F0;6G$=ViC?!10BfXV!6P!DI9jkbl&RBBp|j4qjS| zwYQ<~KW4Szzr9Pf4BaXW+iJ5$f8VPz1d0J45^Sa-&D>xAy&+{#7|j2xB7fF)QjNny~wIrPsTGnSm;6mmhZ~j<5 zq_M-d^=L`mK?Tz?2TfF6JO5e26l*OQkHNm~g=#D|E)1A}fUWHxrPH6Dt(g z+Vt+DDuniNTUXqxyOp~!5v}%#5=$Mv-Ew{f(FY!F;6G>{4ACn;!wz^~)O7qXb6KI7 zUt|GxdFI_;V9`P?kc5z*g3_VJbgTdTSpcPI9XZ9JMh}hIh6~j%GX@@xV8QE#cPZav zN4zvk^z!~0ixtk_yh{@3tBoYyLIBO>%hFI=gv+_$@9&=VCMR?)z8M!vWC)9xD>ye3 zkPS(S3o8UB>=ZrNS6^?n;gKP{Luf|wO-IKKCahnT;KHMKsYTC|Qv{rhBx;`oy+Q60 z%1c=6n)q0(;)~$|i9zjcfumiu1QnYsF$Zt%E2S zLI%W7h^c(Kw5ULVi!P0f?J>()K>ce0Tx9$;xIMr9_Iq^f{A4&VVSWFx-*1WxMBR$_ zP1%57d|Z7{fsIQEXq61JtKvh!XxYOP|KuMMKX zMQAzfkH=?CsbNDv&7be=*#It{mevWL{ug`ShU3z4PIyQ`Gkc#{KSzs~srZ_8Y)LiL z_XvWhja^tl^;QvQy#OuikTK)kDf)P%>;6CiEwPLXa=Ib{#X*aR2_gP<=RS6h1(=0O zV0=%D(R46C(~2UzQG6y#;2aACyV6@kw4UkoU^2LudZWwGBKMPbb3;2AhixGxh!}Ep zb{SU3i3kC>1q6$EV+`;ME3%}`DiHame(op()U3xe!lMIi9R?xg3 zhvmo@6nkW>#oWO~)@8LO->mcP*nk@aHFgRP1A#2k7^9!`mWCesh7>8koPGQBrWey* zd++})hwM7uF#in>SL_y*F38Vgt;fksMmyVhM0DSJG|MSNtzS=F#J=`;C?@C@jZ)qa zZ2gT~XZ_p7lX=@BpUn<$Ao(LG1OGVExovx@CMsB|5<)~kkluG-8jYO2ZK9MAGhZ{%49OBq2qeS z5G&6loL22*L2%&$Z56aseKw7(Wun<%a`n?bc?D(ao?A*}u}J=%b93rKwa*j0?h!tx zP&AeaW(HcG4%_koe;$IC^*FDOx__|)DOyaw41iD3G;mDI-}y1<%zvC?_%Z+tLN>Bz z+ufq(H2w7Yj+k}ppJGjXf+14x4Pe`vVC2lP7A0{EpwCt$)`yJ^m~)D^=C=sHc+6NH zn9}+-$P$LF3Ve%Z;itwxEq*1citb2^WGB*01TlT0P}D$~IW5s&oY5aM!bv7{ zZN9qIECTsCj~Zos@-Br5&JH{qqfDO5ADYB^N(Js~)uJaNMF`v^&ri6me;U3{wK!*4 z_9An_HLxp&mNpbrZE!ILETPJNDw z_3?$eIh|>n-M1n8Ug51YDGXt^3U>qO-pmS@$YP`Z!K--{-;U4RMKRzg?$0I#XZ=fon=@e>zS0Mf!@6Lhws!;{B8?DGLCg zC)8&Ci<};qQ?<}5+dcf*@_?(6yj>YFp_1Rskpi{e4mmN4;VZ!dEw=_;?BD6~pxZLG ze5n5J`FwUxVHos0nkIW<4$9ec-Y&cmH*&^pZ)@*9VG>FgGsCLi3GI;15te-y9)1z4 zQ~ok{^{_NGOgU8M;;pm5GYSypB`nJ9lPEXcSD1Yf5JHj6f<|RvW7Vd%D=uxDe?v9XBj;?mBZ3 zl47>El8285hP3!XW7|fyI=VFQ6q{R&uO&xG&%H1ZGf&>LuV0_{i?o0c)3vI_dR--d z(clyuxPxnLN6Q5PU{2FW+S-FsD1f~s{whzFzaiUxX$nPgIXrv#>UaEwhU8m}><)=y z(89d5x4QZsUBFv~uQb4d^CA1%W@m=hBu9AxPM6E^Bcamls_mYJV!X<&>^LySQwP+3 zui)9-adr@!7YAMB#qyIhnuWs<@=1SYtL-~FL_u+@CPW$f4uN?udrG|D1!;Uqdf7$) zQRG>kCiY~h_j_qnVh(X<;C((CGpb2sH3fm@Mw)qyH3?|EsG@$M$#x1}fUkeoI69nzU(jDU34lF8!6X3l%QE_p20M>)j&I%R0*U z?)fw%-U)>}U*A@>rfsIbF)F|S@^|sz!Ma#n%(TbMS zdNA6fX59a7@yk_1a_N_O%uwt$!es?*FZ8gPbc#<9a7nIYkxA^lmTk+>@W(^)|HaAT zS?CZN+>C*ulN&=znD@+A2;OTQ-)sDhn3KGY$_OTgm{$5$mEN~GG^LLcA9d7RRLcEV zo+wh%B<|x+Aduwe^WEi_8KwL#*t4pUSK4khg`$uvT)^UAVEbIH86oSz%+v)TikuXM zRqc3YbmPrvlXV^4U&rtzm1Z1lBG-oQXoQ4l1<~%kgz8e<;Jy@5oK_BqTHP^je&1P3 zAbi2maoO3Y|4E#3*kcb)%BG@r|IhyJO4FlD!at`w$dmA5w~$TV@7TH2x-N;}(d95v(t57) zh0MDX53!Y8Cae*S(z&$70-U{W4w8;Tvhx%e38IYE)@)CW2>l8P7*KW4eb^mNfm^(| z%mLfKF1o!>LdVFC5Uz55ly?1h>8IMD!LAcyN&VEB%07ugD((LDioy%hW;*_rP;5hs zFiU^=*xD@FhP&KTs-x((&&fJ5U_geE4u+sXq{*LW)HJhg>Vm$3gomnd0p?i;THD|L zI5nH&CT$Y*J@f7~j}Y0|HmlHx(g)n%Xh6R^!o?5*`=*hp0 zgZ{&L^l8}57Na1{^va#p+OF#f5X}L85#RNqmdMsOVHJ^1)5F#`Pz z9{`VPBFaELfN3oUJ9ZjKrDj)RfkOq?&Fegti;f)RB%!$7yFXc~r$B*I@kfCI)cgoB zFGi7eye#tZbrh#tuZq<)YA}X9x#0y0OWvn2%y!TE&xb0L96&oLzA4^^z`}MHoC`y+ zCOWd31#bV5{pQOC;JQe+GNsa&Te*h!4i?ulPB7L!?zx+Hv}?!u+`*o*ZS3)3LG09m zg4#Oy1-YeNzyu-<0;!jMRzx&*%S{rA`gIUX+j01T!%F)2Fj$8?*&Tb_v#gUSrKFqk zkRqFUW+g>~sO8_yQfil-d_9BFG7k+>n}Z$fbhFY@NKzt%MIdH>zXu{eKWD44iNZv5 zlJ4%nhXbbW+Y-|h)Hh<<-tuC>GH~kxZMT7t%DDzSByMs1fc>l#cCoOKobC zwWAk&66_o)ED33NKh`Fb$M@~ohYfQkkdsu6&ne*=`6PZ0FoCtgaHqv{`@-XdK5MHe z;HeHf3o`69n_X;z+;U!Gv}Lxne*I-o3{X)JX2QI{QQ`9lH1j1GEX+o5HOC-;>Kex7 ze0ki=nsT7IA(}EDFKaAaJ*LMB8NglAAaeUJ%9qP5)C?Bf9me99BV0|*!J1yVw|*+= zYs0egO_GQ1^)CGl{}UXRm6#rUt$_2V+o{H_M@?fhpdYj7|CY!u@oGQoLY}Hkgfq`< z#Gk)4hXl+Dh=xZmb7eqye|YYHhb_aJ(=C_gB>7I)4yQ-jlg{|}Lrk;d+WmNSfMdyw ziXhK`)46EDKL>k_f~F8`kFsioB6xELf=2E}!D#MkRwmx}w?i>N$XQb9oFlX2`^gE} zNL)a5MHzk}NWe=75-dDh_6_oMy#7$45SIGRJQs?m_vNSODvJy)>Aw8capcGOTEpICbAzeh{=SBxLf!+d z?88-W{PP2`D5cxgY>x!6-m(LVj1!73lWa8|SGA@w2=_#L~ubDWe86c%A9jqT< zbNTxomO5bwMKc4=^>!)C^j7i)5Cv0OjMJ167dXYg^Y4$z5#Jbp9dA!i{9 z12i8r92v3>JbRpf9r;s(QD=bjyOV&om|FFkLd8XcvS^+s)(MO(7w*DZRTOCp5c^x> zz57BOWWD`J?#%_t=f$_)@!QW+N+gKVbih8iWeP2q;rgZ9iqsRkN7b?cc%XQD>X$PH z(H#a%J+$sFPPZp~;%n&e5D$5~KGTVL^pH$l6Up$A;@nyM;B;u+!PsoBN%C1NsUdG_zETw;V1Xn&@gZyk1Eo3mXf@D|Xk+s)o< z%{lQkecb8+iflOp<@mw@-OBAIf^^@vjh2)2>%9Km?<1+Q)7>)q26w*=PV5+u;4;3m z9Q|Ff|7mYo4Ju7aG5~mAD1JuvK~lnSJaxd5M%0EtNM}9~WX`4n@QTr! z$G?~!57nF469-j1`uTTb={@)s=QrKGWSLh4l)^)M-wZ66rDXJ?gr~Qw6GM3Y=u&r& z14hNVkKb=Q5Na;&IreSHYNfmL#`*39 z2UsG|!6DcGB8e;yE!*#o=NYFs;cWn>-hB@Q6G|%stI*&zabyn$V5ox!{{#w!(;x*f zR!odS(}e+f9;pJMn830c780E$Wxr!3;qxRJfivVNT~wz5fjzVt2p%6zDUl=asF5Zc zINlCmI9}1&LjTtxum=WsqbOc#j6}6n^$CG8>-Eg%dyPgP zZNC>lQfbn`>7L{oxLWVeh62Jf6zm}~((lo(-L}X4}qi*M2wPGNBm&S;EudsyOcAq|+%i1Pc5|ey& zcOq5%f!3I3%!%#k9)_d?)XAGh$}r>{Mks+XID|hAV>u3M*sctnsGcdleobNU46h1? zcz#k4TJ*LXb(vvJbm#Q@32?8^@WYvp10qp%#4`>o!XWicwx=GaG+k!bT6I*0>c?0A zJ$;;-E!?Bt|7}IX8C|+o|1Qd^A@W!JA%MW%4vdk?in}V_6Su=?Xc{H;=EMB>Sl>*T zb}gn3)YXH!_*g+qjnKqQ=PhGbdN=Nzh3K&-tWv=cv*=T-N2o??PFm@^9pdbDU-+C_{@a3Kv~)PDXfcqJ_+*o>R3-%0$Y^8c9`T06rZ`li@^V$FZ-nZ;AO9z19}`?9I`! zeZw#w(ePV**435+neF4=!0&QdL6LLR$#!3BUt%Vz|CkW~FkEUBwE+9=8J^e}0UprZ z@<`v)OY~S<75U)*c;G0x!_t#~Nmals$ z5-K%jbkT<2^#rM}N!;q@9?YGCwN$a=Mg?#bQkzslgIC!@47MVk(^i-*OK>V2xG7Qt z^V0=RUp}iVsaMZWU<{L;;!|IEyu0HAEnr(XTM&wa_@I4n(YuAZ9_-usL0q)J{l5y< zB-A1#QsCnk-mZyfw*eY~@3GAnIQxHae>3yVed)MO--(m(r)L2lN!oW%l-?RYEnBlx~6UENJ)KN$QYm;MP=d~5KSJZ@Cx`q>|2wXev=5>wKluS*^wZKy1px; zXF|?a3eh9zuWXq76mpr$jugJx9*x!j+`topNR!9dMx=;(S_(Mkc`pJ3NdNz6m{!Hy zi@imxVSvYdsm(_Ist%nFUO2A{;$SU~GK7iX0$~?%*nk?S-OB;1h=~Qt zL=jw<0L)BvX{Wdwi{M?62?8n?maQ}|H#1}cApG3;SGntvnQTn@c(&N&*w*GrR^!%6 zjQY1@ql<3r3KAf|>4(%;rJA$%5)3pUWH&pbc4?~K1w>%MXF!P8IxctXeA-Clpvc*j^fD=jKIjHqJ`>?V(6wD`mkv2JiWZ1l zIUlHfF@jZ8aQO77Q#x5Ih&{>sS(|aGkHTlqfs6F-UYy-=#rVX(ah52?+*5}{$zJBioY?Gvi*1URjVxwjAusEkLd-5}KN4^UHhmzZtg(0cks96#7p~AqW}I%X zD1>?zc~g1W3KlZWj~FcKpxZ8>C3E|G>(S$Q6)uJ z8!&1KeTDZcOJDtSZ?Il-*Ssg}0$u5$C?CQ7TIrI+!`C-jIgj#tQtPsO&7OX_zrd)~ zW@n>lL$sRIp%9>p%?g^KzC2RZrQ_S=JPK;4lUbmU{ftKnO7PBi`1}J7SU<+o<24`v z$l)7f4O72T+h+8lcMKw%%?A&gxhIX!?r=Llx%GYfK6uLn@MciNPKwb*h&D55qT6kA zp|GOEf}jA0x_xzg$6CR}ZN*xZLgQ5bW$eN8vx^<2&g0sDdr!NncS?6JnZamNi=^T$ z9RX_#4iIs2atVmUsfV%RfGokbqLhM1e(!c49te-sX3KQC*`X!9M8{&Pn;GVJr_K|MZzMat%&-9aM(%x=A1a&h`vZm zQ%$6Fcb^upi)QbiL-TGpidh5$?R!wHazx$1iHwAG&?p@drk~UBfj{wImCj{Ch#u0x zh)PsO(e0n}x91&_@L?}u5%AvZpESIFLC{Z-cSVS^yogTK?G8kg{$C$+5TSfU4MWI{ zwqZtgN^ornvYxtJyBdYR&biFNgMzoljo$#{rET(rzG~+ zz~*CkVXL?fvvp}rIpDT$Zr73S-f6@T%X&_b; zh;gFCTJDdvKFjG_q)v`nAJDTVRL>h-qkXk@=xGKl#()@wBC4~nRb%}vjNCJGhg?o zs1WXz{1g8AL1}4gS?%YBatwE+-}z? z-f07d*(*bs8l7h?iwSJ0*EjX42PF?Bz}{J?##+27{BkYeL)DKZQXZ+JHNbog`m@#)#USG~e|fUT0SwIbWOHuvPoc#QE3)!3|cbDEt&V5u4OjkpaBKeiImW`YW^b0!{Ptt zfK$F;ejsTu15c5P#B41x7QAm#GHH&bqxm%mcv(d&?BoiZ>y;hB-YyPuQKz&VlAyIo zuE$Z2Xx{ny(G+auFb(O=-I94iIk3OQEm>$*UB2<5SZk>r&5^+c9rgazx^;m9({$24 zPeDrTdl7%#1W+sOEqWevm%VGvJ)rvytIi;^qoo7Bp8_)0R1)H=LgxoLtnuZyjU&73 z5dJ1L!AtbtV<4(tjR;hPOu@R8&pu}gF~%^a1@(?QussH#4-FM`6^fMid5QSZKPo?i zogEv%PhQB0+b|O;S-(dlKfK@e2cr!k)_Lsn_C4T@xsgPRI%9Drqpe?-ct3|f-O};h z4&bq{__4l;(ZgP#oVabs44dC{;|+gio>A79m(JnJqW>c9I8=^K?EEO#>+hleO|_ww^%&8ye5yOd$0W*S9)vpH`N8D4nU z6K$%{h65;(SqL&;iCQJfnLj<2iWo+J{SagSOY%R0&plV7t4`;KIJ>Sb3mtb$IE=x^ z9~rX%ZG5E34{`(;%(M`!+6+6kLlt6BB7J~75BPYHAA{(uAikT&q^hxaLBxeLEdzoO z4RjXJrSugbLZIYk~;xfl{9ouM- zS=iPmGT4%HgSveos001sSYxD!s2K`Nn>y$!F$3#7o}!$jU-srhFP#J48IpN<#D?Jw z!0=6n<)}ski=*-C=)KAh0Tc9+q(u<}GZyM$opC*vH@?C^bhCAN**&rI5OYWcMgecc z{qjK`h08G{*{LNDSNWLB5o85sbzJAp0xTu>LXl?UK1G8K?jlD!V^`amp-eS$VQD4k z(Nnh3l*t z2HQ=CBhyF_ZZi@n2ra^citZhG3vl;my@DYI*E813JKU6r#To;~bPdi!{RnD0f3Pro z1{gJDPhTYhe0XP1gdRQMFvk)ikoWcv*%w8`i0BU}no=SvY8qsLej5Wb1`d35i33KC zg`(edQf*deaC&U9bxqciOx_bCN}Tl0I~CP5WtoVtzVqGTJfhz%7$9(8eo~{Zq6c{z z&qN03%(YQu$c*;Ilf7wKTq1aDM1A22s$*s70>~1u8+XCtyj0WnB5$nne6idOSAmey{8uvv1BiJ8hRyf^H z?}m4`x6Hu`0uZE%T46aAPeygU4Nch^@(TUxz4mwZd-M=8gp}Wiva}zSH4hK%p=u`w zrN8Az2Wz^AP_4<^g^)l(|ZTR=X${tLH~SbDT- z$gnjOjltwoEmFq<9t_*s%g9A+Fkr|eYAWRR1DEkQ>B;CZE|WpIq!`9w3+OY$PMS-} z!?&3u)l)f-B=KU8^O=Fj#SAfKh3`7aEj_tpxGc`J@0z$`%qZ>cuid~X|J8yEZ?wO) zd`_z#$rRgH@|~Ax)-3|LtHql60r|oMWVKL;X1?|B-phh`AX~TZ{^- zf2jV&0`}irPwB>BGk3XwKVSPd_O36}grJ#P#9O^vkm*-*!`6og-!hDZJ)c^cy1X^a zhVT6!u``etP=+sE1uG@Z-6>ZaxIt zF4lcS%HOe12l)IA_wqXQx#znd(((kLpQ4c=_2%ePI&w{MNFp|YVLP-ie=v@YH9MGC50pC=DC#=+vqS8y zf{+#-($a@zUD`fZzL&9nQmmlm>7smB1-5oah`N7aZ;QGZDGNaX4#{lY?P!EI_UiV1 z`Z+=56!crocl+{Mczp49TWTR--R!+2S*%o0*6*lIAxa?TW6ge7NU9SdalSQ`+b5>1 z>O79E_%ZyVcUd*=ExAq>N^MMkM7eMFYaJlIQx8ek$O+E0cOSv}zw%2hcOBK~Eo5w- zX1z?JCbT#Dn@$EBxB3xsH)RXDqMF(J~|2x|1X{^_0 zr3`$KbsE7C(-ijrKLy(yeab}`sO$9SpFI~MW?qBl9x=W*bK0h% z+Y6Q)$O4?C+|}hRaq4d8nt}^Twsxd`Qx?sdeYi}csWB>;p3HhQMN0-oc?LhD=YQuJ zWBv0@{pO=~a?nfwLtO^XN172w=Or!&R_znMXr}xC`Q@8IzryLSOA%;U8qsxwm92`c zSJE~Iml^XD&WE=npGbEA2V-bCRa6FytC8cOM-b1i99J0gtG4=Mb- zoE>BudCK$Fdpi;>zHQ|BKZ?%7pX%?AR`!-rc2-9A$h=l&A->2K zGDA^hUStbNku7^~u66J4{{Dr}<8#mbocH_ndOpYe=3c*n)wCp$h!YG@LW@{%`nAaq zcI_GaHGrgC^wcht)=(w85cRXR`$YUSW^z{adH3d6oA$M96(ZHFV?WQvK0r~>$CRKMaid>JuRHx?0Q8pnUoAsMN-K47};>>vkg1^v}ukap-rX^Ri6cA z-fy>$^P7ZtZ5J@a=#xsEpC{nMZ`+Ij%T(tqPg4d#z;5I3E(?vPxmB#=iD@2A$ejev zbnRlR54YdalyiS(7qY`|lkYrG=Lk!>C_t|y-As#)KBI=-C-%0&r;xj7zPZykp-Mk@ zky!%`C0|x`$vF(;wBDS(4Lvq+t5YtKB8<*>ON9LG*lv{j+qC-pKgI)M?{S}6w&+id zn>Srtp&lO>+&_&NR}-OBL!JtKx{Yf)PRVwV^tSHj1cJqy4Us+ND^B)DYzpvnztQQ>>P3w^^Vo*V&sS7NU9E8W8cGL zffkw?IXN|Fn;Ca{a}8rHcVxQP`|Hlr`L)Z;f2s=6<8cBDX7qpdhFz~4pk689kQV#D zJ0NF6W4 z$WwAVS`N}&-FBxNJ;yH)npiA2*(uHtk+Txkp; zVmFvBEqq};o^(XjJ@k6x=uT65~5(kH}BIcWyTsCX1oD>Z%An!ItfqVeeew0OhS9x%j} zSv@|?v*$nNs<46_)GR)bc(y<+QNc2|u>FA+bPJI%RztlYNSpQkLpwc6 zknWcY%xV5LUdmiXChl7&f9qrb7BZ%X?aN$ijv#%v3uwM0rEQHC{)szjo#C2ruU8eXl3!|PK|C;)w!h}Bcm*Sk)n@oZ`Idc)N$|p#dgqp;o1j&g@uk%&d^;YQl-a- z3^O^y0zNu?G6Pt1LM1fNk*@f`Ga)xyXFl)RKMhSRbU5_$5&X?t4+Zdxda)LXGTg&Y zk04kZA$G5y4sKE~CI27uFJW}?49=p2p?Rjauh(Fe;VPX|w>Jm2=Y_uDhWcvfZ*_xL z0Jb+u&I+6ZGoX!714?N9gpu_z#)AOKLxE6F`HT+qc&(^X0$67bl@I7qnE0!3_MkvT zC+TH*Qx!;pvuXZ||9UE&HvKQ?TTgw*CCNuBWJkNZrrpM9XNWvhQt_n3-V{rcXXD?^ zXPj{AT9@R9HGku9tR`Kn+>HatB3l(Z&<{D?D)F`tvNjJ@pfCB1-BKQ!a*TtMYa4D_19{@`(4!zq3o9-6#q`-zt!S z&LlQIPHD&{M6HM7k^BVy>of@|jye6qjFtc9Jpb`{r}mCNKf28)9!F*uwNJgDa|_F* zUAHaXmr7zkju6p2rtEJWOWM!=s3W_~t+J3=d#z$`O^}hSn1Mg};NK@A`w1>D7Y^U* zm>3)aWVeaiOU*tjVtMXWs-bVyZwmEf`W;W_k`Jh9${7l~F1Ur5BhTl!`%>fCf&L3& z&r~JN!W^LStzRHv)_Smke2OgS{L{{0W1Ssq(JYkfV(PvTOjy0O@0MKaIA$%YL1KoP zoBC;C&$yBxiQg}s7#-;z-*HM}?O1!dosYOok_9u5MAgc2&?Z7_EbcqB$T`>lYLoup zPcSVlcgBos+fJ3&SVB;zFj}E!4U~!qcV3+xS#bf85iJ@IZ?wh!J3t5pnNu5r(uQ>`0}D9+FZbh9EcB6o{*-!vifu3zC#K zg=XE1{#LPvz$N=?_GslwoeB=Y8UIs=i{8ObDv2l&4G*b76NC)Ls)>k-=JbJmy=%NARL+dT+}Z$D##42f(}r26wzU zAe;7>`*;`4gPxo~`BB{#4-{mS%}rhSCo`4p_9g|sIbeo(d1-fX6*px$Yml^j`#)$! zjQ}qHDocA9c>UnQpX~u`>p{_zrKaq)*Mj%n1vzf|CH>8)zN+B24=!IL?iv; zoG|1v`?5C9lqzTw-ICe1+^d2LzEA2VeO_}|MztWiYkyb2c*#=h8wm_4ANA#{>|bIX zvpx=HHU|cF?5c>38EA?~Aw@KwrNI?B5uE7Kyf3Gza_FiQvKxcM}>D*C+rCUTwIdiMr%(6 zRBSsl1o~Fu8*RbsI1(QWykS0BpUw%3Dyu)Zd#DJrjg7Z&ZAk-pI%aK`c6xdW`_vHD z@FdVolYz^7tda-I0fOq#dY-w8TEBBR5XScM7y%4%ImQOixg!&^y;~IE;k6pGtQ6B( zkpkBy2k?6C9&j2mb%|ItjOUb{W0llu9POSK3dynhlurOS-FH9#BEAnfwHrgHow-VdNaNyK4!inK#kjbINf6?ezpaCc#21HA8FxD09S_*3kVWEQr zU5cq8-lEM?I00(KcVScQHjJxeqb^T|mk|CgwO`;%`U4WsM~rl&3XL05s9Lb>2B7s*fC%LQ6vqe^G?1AQ89zuRlZT{ItLR;iA|^vJHXjy>Nmk z83?SXm8lW6m_E>H-pE`dCuQ`anD|b6t9Jf?Kyy*|u$vBfyv^@D0&dSAUj_eaqE4zT z=eRe^~}vW^B;D^RgiGS3@u`YX0eDj z9T<74&-WPl{Uc(hs**Ydc9h^A>C1>S*C2)2yPvf;=yrDxMqkt1BjLIm9ER}gDpnws zNJD(gh;iLQm9T?m){0-oaL=QH-)#mz%(LTv)*gsT$I)#DHm3A9WYaU?N-sUcsS#+D zcXJ4tbGpo7q0|nL69+GZr{Dx zJrGH3=ihf&*D?TcGadec=fY~*k1r!+CrT5W4J&(pvMVd#hHFk5%H;I9MCcKeijNmO z(FNHCa8iUyGCQ=D5Glqv#0Q?a&TlFtUTKK@8(@gmPwt+4q45gS7*4IFU)EM`Z&rzC zMyom)NM6k2LBIR*83VWZvQDfML1`rWU5&%S2HL3!4UeV!kO9|6&-$!l>7%SWi~9>h z1*gp<(KzUDDz6bVBWw@~#SR`YXAC+RpofZDkW^wgA&7<@THInrq!5Mgu!JCunIu3t?114xbCT;$>t;L>RV0Hfn;w=(&Op*)q^*AG5@d&k8*>B0>uB0jZYy zn{rFhG}_XTE8!Qc02`oyG~Z(_-WV)+?P0wR$Ue^`2)eCwII~`)J0RV~`?YRX>>omH zUT{uCtpDf3;?qWO$f0u{u6#X0N8p}YdK@={5|PzrfMPXQd#y!I*&>sn@A=MRFuJN& zL9D>;G5 zL?lumtZ|NznU35d6}1~Z@03n4!Y(Ne-d;p^_e#Er<}at7xE06?{<(kBm`X$d;M4Q& z8K0hRzY#8CvAs`Bw;5A5RU<^ms8(}Y^G7>)D+qgVKLCaAWPV(mSeazX`cC1zZ}{9M zs2kNNH+&=C^)SQdzi%#*e<6~Q;`*Icf8^fea5zvL>YcyH(o*5Y#WIg0{&MG9T>RD2 zkHIHI>QaW=)Kl>u*2@1(+8`7Edhk3#e-7p%u}pzrzEUqZyYm>rrsVwa^_27cLJ0EN zk%^R{PRW#AF5~zsFWlwnwcpK*9|-`8Jc1xDn;-giW#GMO*;(y11r7xolQu_I^%bY! zGd5Fd^x|zNQ4iY}|H`9ys4dB_zD+1|1u^@ZYAX@6_dX58JO@~|*uatjhUpgh(%!Bh z?PYjDu?QIs#ETNS0Ap22?gpu4Q*W^jgs7WOq`ZWzKeCdIphIs@^f9)*CQl7)&hgt+ zvlb8eR>yqRs#NUWb8hZTxoz!+h@A)t<;tdPWcEVGT-Ho)#!rpk* zDRAL1I0@?tLKiHBmcS@*mrTn@tIZPCbI?_nr`u1P*qEd|&nncnAvJ55B%a4OyxcnN zIqVgVO~J}VYb=yC%<4BHhvW0q;+q8pv5Em%P1m~pK@FW#(M(s&Lu>;)XX6=##5T-i z0s@g0k4jlaAk*1qWJ#-=B<23k`?O?MmJ0cJ#W%w?atkQzRk;e;$63T!!ywR`1cBzK zsm^7zY^cJl{XmqCzS)Mr@H?Y+i-amMBN#H`=;g^+b6&U-H}G5w4kmcIqIY$g`bE)? z8pU+p#zLU+9-r|Gt1VS|e4Wu#LH4_&JFupT{yaeoN5hettt;!84_XWKPHwVaAPBR` z=GG*I07)M@t0#mS#$F;k+gGMifGelP9a$DxeT&C6zM&+FvB!njULK?=>YLQ84zAf# zJo(SxIg1bx5Q#^z5&Q0+x!an|iA`j7)Fi)Y$9sNJUEP|&Fg{c#bmC+Fvz#3oc^CH9 zxBtjyZk}@=H+c6^C30>tc%<7~!Fk^V7%TQXW%$m?!b)wqB(AyL&ZT3nhLKyDrrrNkP!l$Qf^sYP~{@)s`L#r95jLI@v0SNkWX zfCI-@&Y>mn8T457!-;5yWbtbL$RAI8ulO|5TFUf(Rj*{+c~T|%bKLs7JWa+B>xqR_ z0{@b|Svt<@t6&{=vj+mpd*Wv=%T;V&4SFl)@ONKXky3%hZtxa|_dmI#e{o(QHOK%| zFme*Y?-gOc&uIV>voQg|BV7uMWk58bk&0<}KwW-{E!^dw7~W6>u4_~xI2cXD83!)V z!^4_>NMJ73O-O}Q7e%D35yiJJZ~sBrhZolQ(og+-W+nEUi$^PD7%S1z4DW#HGg$?~cXIC=(qlO61Md#P z%Bo4^PF&c*1(ampC3N*S0+UDu*=GL_L3r;($~QZQ{ASDb|ErXh`s93R(_@pE9tx*V z{Am>Ku=XCyE8XLR@7O-f^eWaR^ngbXwv@UP|EyuZr+dINq`UC!JLhL8=FO)3u2=XI z?Vl^b#!j+5h1()(JRkweFNs*AQf8yW)iFLxg z<~;uSQD#4??}w}`g=C*XKUxu?mgusuNriebE&H7E&tlJv%%MWj#ui)6nKm4kT;2+_ z_S=t(9r5-8S1+}}cmNH@7JtFZD1WaEl=O3g1#ihG>dGnP1J4y7d$@bTWS#kapVekM zqaWsz_6t%?pFz+?3VJg|E(QrJ3d&4d=zICfU;F@RL3sOQ=M6eyWP?hMSa{IOJ?kFN z>C=wS@iE)xrvuC!$4D63V)@9mH{WVwGRv+C)qz6fIkwu?Xq2W=~&_KSTE)5g7wgq;LU#}8P6 z3fM;-dzrH;jQ#z4ngBMnV1%JeQvU|6bk&JTvS5?pdQ+XsE7RpTlYyK3_mX!a?4O}V z$#d^Zy;^)ACGnew!uSu*K`<50rNzSIb`=`5jnJ3)P1r~0*WOy37ecI9Ux87qpt->I zop@*eU}A`^JE+cfc#M0b$6j^o{)132a7;7v$v^qyBwX}G0mKqgWAI>U`D>O#kN>>3 zVeDvsW4&2>f9c&>Z@sb4;YRLdrbiVAl|jVJZ+#`hr|x^r>yB~bUA@zdftJiNbCJ}S zpamwn;!L}hH)oWxXihm?Z}fyFWgWl0-p+~P5iKIo)~cSq=NH{{7fqRhc!9M(vq{dU zd3g*wW!6>xg3lEN*B7=EAmS&VH?0tJ6xs)3+cbmsuAFc5dHU@D@~uEROMMA3gs{D% z+$`kwTlXq-q2xJ2@g4I&tXy(o(5~F`4p0UpXpe`RNX8!%3R_`TSV|g%$i&e%1(|PL5i} zb&}$E5g`U=tXG{)Soe`R$GH~3xU2YwwcLC8$S0MPD^E`M;BbJh@L&*w#Xz2YeM-pwrFZ{#)n`FPgjK=?}i`c>W0YGUhog%tX(JJkh* zfwo>#{n+GhnkV_h`Ke_%4W4*9s9$~+^&jE#-5_-dLIQ-S9EydZNQD$#arLGvH^`oy z8zk8Kkpx%@>VUkGM!WtI?%Q{)GA51=8=THm`Qt1{i)0kxe|V{2O)q;Mr(3YSH8mqU zN!PJ%sqxWZ-z59>awc=ld3H|Ppt<2 zkyJ>Ofa4V`5*xUGj@f39*{4TP&_KKk)L@AFHpoI`b@=eCf#M5$n)29z2C)|Z*NazL zg7&$^tTg*J5mqQq+5R-*S2JAqZ>rd*zyC+n@q^F|`q^CdsN(?zi0uj?is1Zp+(lnr zg014Xfw5^x7|6ih1n1j}?+1M?udxwzXJ&=k(&9ixSqPB0D!Vb2>c5NFB4g2ZHrzN2cSw=3@;o?GIU6P8Yy94C_oSxw(}vPDEs5~RLg?LMk9h5 zi+91!ynW|4Z02MOzGvd_^60+fpYsjLCNy1+^LOBj!rP&)ier5rK!7>h=Cm9!%Ya0! zJoB?cYL`TWrPGX;p(p_N<&o$HHdl)M{Fu4}It<4#o)PN`K>ZMtw2B?zC_(7i>sg?z z(n}krL0Uz+@hGF?<&(eP2$4)jZ?ch>W{c90<`a=AmD?BANgx}V4F;B7IDs`c`_&(x zU%H6>*bEN@NpL%Gpnf}dL4Ef6Nl#5^>7E`0B`*A}gAPSr+DaYCj`9AEQF1waMq+Hq zCdRW_4f+@qMMq;S=-}a};D-hjH5Dm!|@c8BAdp{#_pnG%jCdj=xYa#i&3C z7|}XkgAI^0R;nl`x+Rt3h)Zd+NzugJ}H7S|6`$Y=(m+GKHfr zW@ge_V%#_au7CEc+diK@vIw{~Ap*a&U6kO0g-*8zG%YpNGo3?Fxi5jvI%ft;^BFi4 zE}I6Qr!~zw04l*k^X(z?puTs0$2S+u;F|6ivT#dcgP)|@9||b5`Bm4rCshp8pUboD z_mnC$-oMKmY@RFwO)jmgVt1g>foSkwUdw&&vcw*@cACS&J9r6b zdD_krWAR9l{dkq7v_l&^JOd4GsI8RK-RSk?rm%gA#6m7IUz^S8blTw+*)%*`Zc`pe zF+06>p-MKJ7|R8$ldVGUIFaGD088Pobn@b_n7taCHqJa8soI&})mLf|&Qv2FDoY_9 zc)L8)oRJtIP86E|`!ShLM(bMz`KLe9{NH)>qtc=zdVN}j4z0+dTh4sY0+fh^mdjru zd5JLnfpeN_3Q)ydW2w_a;T#i?<;Pv|GfpxW>jG2FxomcUda+O#dFEe5Iz z+D7=bJs^1#bDnAHtDYP~qv?u|p|KpkX$dINTurl1ZU`x_Rcf<6s!vr0PzS3%2BW0g0w_3m|Eb@t*(vKWm>ZqhG ze!6Z>+_?Otb*1Hgu=0Yj_GfBE@sG(1XGoC-E(~GV8>k}I`B40H4kht7Q?u1OR^1nA zu-j%EPoPV9T@e7-6dnk?!DkPCeh}>K?X#qH+Mo04T!OYnH|cQ%PEKBJIQs0$DL#Pq zl56US;HUL7Cm%tW_uf?Fh=g=I)cLi>#}}# z#D{u4J?|2+3HS5$W|&z{i;%40BMO+eCs>{_H9;$ZW2TPeCTnUfM(N3GS?Qk>qVL7u<*)t60fT9_SPT!NIf zZLMh6>v+^J(Sb&14EQhLw&*jC){E*|qr&i^E;?A=jUNC+WemVUFJ#O`hRWq#)7a z0Ip@_NNq>#Z3~3P}5f>xAL$D})FnHJ@gM-uOKPk9(H0?~fzwv;Ax#87J-!q66U8;qs_msar zLY(jeEx%F_6cXgk28CO9kp5)~zc0oV9Wj5DOMNpX+NJfK(2m23?&ZGIP5!(($wi(PVaEdwd# z^hCdo-D$Vk@+3hqHPZ|0yDNT8M~fA`Zu8B?;VNRmr?J+nj+|da6VY~cXSm`56>zI$ zrEag2t@jGkMz=!f9?<5BzY%Zuo<>hsL^9~C6!=UgTpRDSK9^EWc;#D z2`ROJ-(@D>2SXYNTZ<18hWm)U*UVc++6k%O`;l<|d23;sC9X1jl?qlnqbYYqHCPp z>)h3UayxxJpz$?v=V=!{hQ&q{huO91kKt*3n0`y8=w0&gi<(LoG#R``kG5z@1JYLI zY?CkBY5!oM+8c!+y{Mgw6#YRIaIE+^IQ&IgERP;A-x!B3_-GVJu!^iVR;SO@9xnP4 zd|9cPllX61^R-*{n?4TW$;dIhF&++c>l|>YrKRC9FzjSXsMzxoYBVd9)D3fx%EkjY47EWCjj`ieak%)!{e}H7fti z*G>M!|0um7cAcL2+OJ6x;x*j)bmwywkL9P(7+JrU-;S6X!&CO@XQb&b77=1s<} zneOPwPxCNqb zE8y^DSmiX`C4f9PE`i?LvTy%Q*ApWr($Y;w=3hTU6y~sSK^`1{_GASCElr2$$@?vP z9cJTVT=UiqG=YI%Zb_6uV>?c1NL8;_dSX5yLf^?`m(PSwBYK5;1zTty@FM7bj#Gn~ z>)|8EEu6RxpdN2>uegh>PReZ|f_OcO%EG#9#|_Iymvd_HyB=+ks z+4zcz%)30Z)(H4XN(J+nHH{Q3 zYoDqT5EPtbZfQR~KED*Qgg9EO4)?O`wD0l!(JVPtd5fKE7lnMfnGj$b=zr*8{prYg zA%+f5boBV>g^{xtMKAyOL#IuA_0Nwkx`zS;PadC%)Vgm83}jBEs)f0B?A1Hpn1vL6 zd3E~4K{{o*xW7`?qXn_a$I=+}YBOFyF2F^a5@Al%MU;J$-=KD^HmYa)%>5B7_j(te zD1t2!f?dA`nbbEF^l@?^=aZhsQ9%%w_~>nEI9vNsAp!ak1SJE-;_|N*jrp0OhfS_H z^aRMUau|{oGC)aMKIJ~!*7g*TO(*|JN%8-&u!$CEV&7UW_ptj69P ziXZ}votK~CXNuKi(~jq8jLw9gTYJ9=V%c2D+#xBK!D6Q1bf0=Ml_$z&Xc>)p3YOM7 zn=LjE0#h$um)QfF(M{HUN<=G`Vbh1qClhx~h;V_zzp@8Mk-nZIC4k6GEHkE?O(t&I zhbcXLJ38P4`~GthhTO?<)Y)NPon9yfnkod{>SxLe%50$iT0)LtUji}SgW{0vp(jKZ zYs8PCe@?s}40)WN_Iok-@wOx*Hy;g>BU7=f+Zrv8{=|=6=_=fu$q$~85V02AQ5yHi znvVmF`Y`12C#RCj6sN5QuCT|NKtqcZ0=m-I@Bq`)g?(;!^Ui4GfuW5q03n$(7S|>G z^pWxg&T${$aKF4GkZASC8Hx-{!mYW9MKAcye6RHdz(RLlLXq@e&^X#P0W0xze%x5AJ8w0dH20z?zc!> z-UU~G)Q2MC^Mi>Xexawvni~qPbjCi(S8#JyOVK<+W$h0aE<(GH6n@J2%*y|;S!6nq z%w8OZG@}(BV;MH0k!gVUj{63C`xELtQ`Q=JNF&Z(we)OmL4yd>?B4Lkv@)~Xj)0V< zHIbl|A-@`1&`A0gU({T6^!m}rZv(v-Bd@PB22cK8Xg}z#O&JU&lb?Vgc<227%B$h= zr&x`wwWd!E`Zcxma%T6&x?SzmD%*)j$zCr?g@M?1bJyJertd!H;N!KG!1Z0A(sqwz z(ESawz3UblY5<&26k}HOG7?VL4)N8MLdU+Y&_Vs>@y-lQ1u%_ioDA`HtCXZ4( zJQu%vkeSf=d*))omYEWXB0rU=SG2oHff~?JLwHrQs3~B`N8o}MQ3|@T=lBlBS%n-S zaLXtS4E%6`_beYcv^k472-_zCu%&7yT|j}oGY|xuuwiqW+PXNQLQFJJgZO`EH(lPf z1iP_`G|HYV$;7Y7ZYpF!-&EVP8i9JV-io4?d*?YGXU51X}arR{j~x5eg-&A$@b{`lV~sYftLvcMv|t#R0NALxm2{Ob!m2JgOoI<2%5P2BXo(uFXX8^0hB^- zxh~LZmz=5z3YTI*`{}R_c;_@*8uRh`e9iZ?Jo#+7SI}85M!eIm=26fI#Rtw#e45S5 z?H?}!u2o0eKjQ3i3k&Pg8{I7wKVz100sY~cDiLd=}z&nxC4JqQjNl1>%=y%861eq;sl;ev58DI}d(uq=GJRf0r%M zRqz3&g~zX8CtlyR$N+kWlXuy;QTeW5Ay*45q(CVIY&Ef}Z-T>qQhHo)Stvpc=;2G4 z4tzj2BZ#H8A6|wO3Uq8`-xi2tY~<@SC=qdx-@)Fzky%IXsWguNkbX-&P3g>XV*MLbze zq^(efJu18}QZc8BpjDJoNQ7}FSGSj_(#-3l@)ML#YOjvy`uIj0Hav%XHgJL~B3 ziyo8=DIBbMqzs6Ks+#D_O`Mh%u1 zc4dX5=DwHhBdUK~ymgt9Y}~WJoLn^zJavPzq5@67=AUIWO55wj?)6XBloO}MA255k zHWuBjjvaW^`)UKS(|X|E!qKwXEftUyQ;Wyf1LU-=+|v{ba_4#I0=7Phf669_-MTZv z$|81r+q?e_yNK4EPtq>~8q}@R{rw^y(Y47qZFBbTm%{ zu=Y9P75#}v9ZnqT>lZK}KbMnmXMM64F#@NEQ-#ei8XT|p1H>@pktjt+j2-`}(}8eG zVtht&i_aybFZ~6bPL4%<#ec}^Tuo?&_DV!!M3-X0Z4)0P2KW&cF&|$#Klx>xtWUX= z3bp->8J+~$FjV(pp~wmrzaEVd*;Za`p+VZ+1mZ27*n>qFhPFZRxU27LhX}1NcwA=5>C&eCAaV6+^2# zaa~h;=vJwne^)Htf?>{z**TetlRM~5l%;g{ohczdixE%06rA7gr}mmm|IJr*{yN0F z%xCH4OJ}{$`b33$VS0B6GIrxl9r=Iz=?%OLk261r&Ep`#4%N>MT7}k$*mVrJu5S$2 z4x++mF6LO{Sqy&S575Gj!kJT|hHIW*oOKgpXlvSp8Em|M{Ho=Poup)`e(LdUom9Iz z?ubR<%*2iuC*&?7I8m~(&ViO1%i1=8jGG-+YiorZqveg@WCYGTsY|3qElNRWim!Z? zzvp5x*W}+T>7ekFC2J>sfoC1RDCAU&NpTxOM~&|fhI|Q-URYtc&|cSU`CWt|;|O;d zvI|WecoE+A?mIc1Evd3-zt#S=1~pYXH0VLTvpPf2i$vF45UdK;4_nl~On}*M_zQY25>mW{ zU^jRCw71^=)>yLu3&>lNTSVd?iCpdlK=I2)l^!c#wcZyJPIo)2)P{S zJ%DtD>2Ui5Wlp?fQ=sVJV~D>O6aL>>%0e;)g42K-D#{o6>s>J+(!ITUZ9z=JPOGAs zf31+={u9pTUHrdhuE?v(@9QgNinjse?ji=?3J@&kx__&}I<#jB!kHidy5w~)kBZ1F zBqj7jd<++f)Z|Arx@#Mj5kc0Gq{mWj&$NHn9CKv3*)8fuo-YVAlbpAH9MHcpQS?=1 zyvSfAKL`|OE?%(1L&p0|5fWe}dL|mb>x1-YaYe*x!`Z;}P4B)C`u1#ealvvtva{pd zmcxeuhuKn{b#m#ht*V$sZjk8bV^Xi+uvFrZQ?n(M90CVytHwp-SYZk*AZy|sz@lZl zQ`Bza_y7)sm1VrN2yVi{AIpfaBf(wd`u-`>?f89*?pn-EZy9si$XiF(niLCmi3Fcd zgpeWzTs-i~=)4Fkl6wPV<)K;;8>lLe1%f|CtcY#5^9mA$)#q|_N}qP4QUJXBpDvE? z^Y`3f^o_WmvyXw}o#5d{+ClleyMb1dpL51)f!U6H9OfLJZBag2pRs> zG{9?3-OXt?^We3EW$#0SQ08paM;51%n|0S3&yyc}bPq*r{Xq=2JtA5984C=EfD}Rn z%K8@r(+bnyzco)sSxL)K0at9_odkv`Q#4ytG(e1*;38!@uZa+An5!vSY(bDPIH$gx zdWX08`9YNIk7rbBQ~!;Q$1;0wz!_LBoT)o$#K#$fI$uQ56L-$oL0W zD2dA@d$q@W>?=m{&KvnkUPQZY_Q%_yjjWHlU}CwuZfbL82ZzZp|^prlaI`rxm+`rL_CrcBTiUgF{Lg(Q+%X3Juzk{ck=3K8a5pw|a zxZwUPaswfz#&{3nl$G;S`w{(?(AbAlS*S(Jf~vdq#JfbwfG?}D?3V2C$@T6=x@ZU< z`%_=V+J|S11)cT=c6aQm&pu8)yk|?@`r>Cf-Ou5_tE-L{75nFbzp{$1FQHHPbbSP3 zmVdtvppk!~+XMx%VkEg>lQrm(;OXxCLnW;Z!U9g#6iVu>m9E7 zllVn8>WHnu7zkWfW@v-|wxqbwZ#Y0gWvo^x_QDAAwfV;+6a2dM&o?&UHae?$p;%gEIIzH{SG3--cv-|_vmooGzR zCsr8hBiPk_;C>jw_P5~Zk;-c6PfZOfI}y+bpLM6-hDrS42X`lHXIofq7TX?c)SN?wMdi+2UV+ z4EXk9v4Y`e^^Xgg{qtG%q5doS1}?2Or5?67dou5+R~3JY@qf3}P5b=yeu?lS0|e5; z6rcG4FPil;<&EOPN!+8uNFOGUf5&7{SODVH_ThLbW4kL^P@F0oGC+*^x6ZM1*%v{N z%m64IjOWpA>t4c*E*A83*joxp@y20DgeTEq2U_!{F5(Ni4x@8)&j+MkRRS-sGiph2 ztC$RvgrF?h5f*?5SbzykVgew@`0`@Xd~p_vzJQ@kfhDn(9x@l|pr1epu_XiPz$P1{ zLJ)EcoQN9Gc52_PPm4P6oW~zHK7WH>Xz1jmu9#VOwe}r7);JMP&GQCKSj4gl_V^Lf zYu6J0Q3dZcv0|KCdUoJVns*0dp*+Hz&mZYSkUR!Kgo*R{3!BM9L$A>0f~iHz@MxP#^sH^eyRG6&y+?(~d5*ubNB;tAhV z{uZjJ7A}R2v!s)EGknnY7g0re*Xy|4!7oj@z1Q*X(Wsq*Xq|Z5i`u(+zjab(ii}-W zFSvXie|l_j{>N(Cx+L=SvW%9-_pni4wWVpBur>zBExQML9}RxQLn{M6 zQ8fT}5J85y*B1XFzL0HqzB3*FZHUj_(W~7`*ik*{wC>~fJ?{T;bk<=_xL+H8Hb!@Y zG}6+o)Fea%X$6rKq)P#57$qGN(l8JuL_k6s28h5HB&55g1V%S|_j~`|we7kV=Q+tqgxFPksrEcyRC#XmljXTC?fliDU=Fpx$KNB`PeY^5-3U>RRT%8F*prw= zkob%Tl!kg_%T1c~2FG+hMS&c=d>ZiQj4T^sylv57Hb{$G!GKe2jW4fP} zyyJUiE(gmFjfp4b+k|iT_$6J~UK^8|skRc0^vtN5Q)24&wq~aSQk{t;5dJHXJ&tzQ zUR#c*>f`ny!}nVcAH=0)6rRZXo0vY(gtB3y#1D+*AIqG)sY|TN?>|bs@Gn*Grx=AI z<|`aXstTX|UDXO7lQ7IJXr^gS?Tc-EapI?B;=n^;zvqsR5WHoHyp{7n@BzQ507S63 z00@3YglZ25y8CQo!}G!6OBNlHN)kW@`j&9}CGKN5X%u$NO@}8+3n99}c+db++&pKn zrv+H=Ly$;9b{Jqo+9ASX+jadZ5t^)4ZxKRaF|~t3rZfxIAUWQfu$i@k-btO|vsN_D zi5>1DJeZmXS?dP5IVw zRQ5Er1cn|q{}w^lfM*}uJT2je4994{Epo7M-kt6o@)E{7fuGG*L_bvDs8YG3Xeocw z)~#?rcE@NJkiWM?P}@WjUlKZdCAoJrlbk`ot`cpg z9K3$rh%Wzcfe1YOHn!gk8z!bTYV+2!nAhZ9I8rMAaK>7rRB)3<8-~3jW?%Y$;QZ%} zQYh&ewNAc2NhbL7Y_Gze^C-rGlz33daI-4z6YDnlZKWio?uG9!Ui-gQteQrMHo23k zg_Q0JT&mKIleAX+d2OVk7O6#NLX=GIaeMx|-6v%i{FnE#x9oTvlPFUp>4i-7Uu@EA zmvRijNmpLKgwXofKF&t(jKPrV58gRo6u&fafWb4npt#QR!zqDRNu_B}C1}_@gC)ZW z(=D}T@=eUza7Xaxn271MmE;n4tRwRNz3pnYtwv?(!kn7wO7FK@#e;R{qug~uB>P%UG*mmqB zLW%y-v6vq}L;B}De+3lCyJJgUX8>BclhwU-n&({zuXaOL2kK%sRLd{#*fLf*uK&J^ zBCN)5O^I4;=Cv0??}2T|7yM=$h<6@Ar=nF?Epx6o1y%g=SYHeUVE?J+kR3sCXx?_# z5&0X4uhuI&D&Zk6BX70G0$pIvP_)Ey@XeVZR`Q&$ex{Q_E~|JqNPw9>i>(^m#U;4* z7~*Zr!?7ntWHbTTEeVu?5D^QciJu?U<6bX@K{xLap`J)1EHRlVg}!VqQd1~))V0aA z7nmn2#{hvI*g-F#q^n8>fvRAo%j3(ib;~=+ky<=-dFN{<^K@b!4nT@&+irZ25RGSC z!(NLKe9e0g{E#>{I?qZP;!6YPBqL-u1ACVzWI>l(#Y2N^U(R#8q)+45Nv&xhvOT~5 zn8KQ93||jLQ|~}`ZEdb~iu82g@g^q}(Ba$1nrGK8N^n`gm|v5ov%G9G{hmTw?>? z2@{LLQB-GXmn6nwg;I!{W*(rkYsj>gnEX`LlV$^{xKQ70Pqs%9(x|-8ETRJgQobA0s*`d5 zSX3lK4=JDHxeMh=&YL{0j3`Yox30N&KdNTP@Xc4Mz+l3=6!iYDC_l#GFUR5aJZ@WS zUkoxsv_K#qFk-RX>lL$_$u} zY`>N+6L5}>%byr?6IO0!;9^ef*3fLDSvEgU&l!>*azn(<20~#tPd|I6Lq+L;3D`VQ z8bR+nAo3eYbzk=5ZAwsrVql6RD*#?x9>w!PmNt~WoezviK(e5)z287_WH&tMFAeOn z0|~BwFAf;qo;~A%1jma)bbE5M0WSMYjC93=`Gn+Q^D{t%IeOyc1t2VRS8Vp~D6pv2}R1h^;8o&~Y|6F1gh& zlPoWX4)4CJJ}UAV!($_=&I)_&!C}$r-CgL2V=grp;S&EjwVMT*uSqcy6LalJ=CrQe zqa#9`Jla*${AGCAuD_LY@uS=ep`YnOF4?w{mJL-4krJe@|LD++dMJY`*m*J`!s$j( zL-sm-Np`14`-xW2AAJh0!C~@GF>kD&O^PhMePS!ok3y|K&;KJEpu49+)3#xn-Bj8C zZCc@t=^HLZ$Z-a!y_v805a;#AOfMJ3?dJ;`sE#nd+3rgXt^V<~&>PAs6eBic&K=C-f^el(Kq)0f?IAXI^1ti=Zg|n{|Gz{FvRt4xO09| z@+(y2tkeh-N!o{~O!^2FWTjL9`D$G$*4#}c820-&=~(COH3#^v|Mp)-Njm470GE2d zl5WDebj_nPtw)+P$0X0O9qsoQDKE_=b_ggZl3}G()VXMahz)#Gi9@klohDT0hZV)D zS^XcoIlC{dxt#8%3v)s+)22-IzW?6HkfFnf2oOm&hh(*Q=JXtZI@=hxmAgV{<^EU~ zf|%2WrH<;);0`>SD+8MXGi>ekp|8_FV!pgdXpyVP1dp#SH^afoxD?HVKb2*U!DSCjm$UNs%QN( zl%Dcc^Sy7m!IY0mQ*5FeUl#FOmY&c1X8NZpRoeTH$Wj=8C_R#zi#yYyoo8c;=@2Gi&Dq}l2pTvuB9aO&aO;1gl(5D|h=@lldJv&LVQm-! z1JH(nc0Qns@IxEoiM~PD12G(Np-n2pA_u@0+x#jF`7KuHw1I^?kwVTF{IN)AgaPOb z{tf+@JV&q_I^-b(S+K-0>;mRS0?gm$mu!4?%O0Y*`T_~yMYmN@i*=4q&&d)5;^fW< zQBkR-TkYvXY>z0g@0@eaR=&e@MIB`9LXLx6umIhfTVG&9kUt?^pr}Be08MTH-hWr# z&38x3*@(7FZwQ-9)sveY1=QezF&;{j?MDB`Nf@GPu$L+I$xmAwa!F>dBli9GoXVku z3~E^wJ&64A1>VW^BQ)mxew;Pp(CMIlD}DRvtB_P%Hj!nSr=U!=1HV|I;KVthGWEgW zwOIbw4n`x`H(86CBwV}1z^p393(ASb2VuH6OKM78cua3gY8NMTn%Oo@8vXe}uwl2a z^6PKkA)?C2RaY+7PrBYY&yT1U)=g8(yfD3v3M;T4c(57Tf@#^748&561Sr&m2EBisX^%9X{dm&%(kpLrNew)&_S2;viZe z59^1)G7dkWq@j1T!q|b#y(jL^Bs>4B)r5Sxgp8r*PH95ch6za|9wOTNaXk*etWr?UInS_UwG|bK{kOCv^uKV?j>V~}! zAxkckBTu3pry%R!4J6cEFKi3dTP?;P9o?~UI8h3&jH&xCF#V_KXu1mf&_nXOQgLO( zogrfF8x+aLD zd_GNf{?BY4Ye#7}YN0Ltqndk=S}eg5a7X6KCdH(KQ3)HjCcJ#_BMggNQ4FecA7~i< zXd@u)7E$2!Y%4&>4oRh#l6&HS6z1Gw`E>SNk{?a}iGGQs{3-%seuM>raGtuD`t1tT zzQ!dLHY)kbLVi^qI`8V`m^D%d*)9J{7JTPQ@BAYA-B!a|??iH)LdWF6&x}WUuUv%2 z*`V&Fg>76sO$oY$A!GM0vWj6rP{=UahXC}5BE7PMrAVtr9hMmu*zgmxbzWCU>EtJ9qhrxt_Lv1n56xa30|FpEL)cGTYvrRJfG=l!=dp{6aODf{ExCET+fz|xJu8?YXNn<*uqO@qU+nY3 zQP_Z9p@%~re^>|+{8;-}toJ!BA!b&6jh%V$`3e5JXE{L?e`lCH_H@-RpY`=k-$zN) zu@X~!wZK&udM=SZ`SE_(Tc2OPm^_iEIV!m?R~%~iwu9|7`L##P!Vx%|hvl@z}c6crZ4Ys%;5W`&zx(R(ybQ9LljYqK$`LB>|ur5V^g z=3vLmGK-M|{U5+jCx;Y=HPcr;mYweoH&@0pSwG@7S|2|_YpRKfP67sHH4u=?HFpd2sYC@*iA~I{bepjc)1?|{^I<2UM9w9EQQ5ytgp)dVaWDV zdeiN{VVDXWcCOc5ymR^+F|GFqx6rr+0YlfV$D;(?b&XQQmFp>;Iu1|~UFWr|xc1x- zsk&PCDH!sKV8FZA?_5q%gSEh04bO5TiBRi{iAFrDA(B*^H00K zpsyAvq&YG>gjV|f?l|MqN~EZ;Bcx6dvZCDUJi9U*H%zcb$vyn*l>ABVP1{Nq>#wk} zNg096{7FAEG&$94<${+$71;NQ-QHd7Nu-D2_l_Je^tHPOClbJO!*|TJf0Czs&yP8j zq$<~I`tX8O@WT^#QQmLE0sLOErT$~uB|CC&=#-{mN{bqp7b; zKQUGTiaC)ffe1=i!ZATeh@mGb7K~5UrKA}w9Cy15r8w6K_(X$Pbb?agB}t=nG;#Ps zYeK<4qFyID@Er9GATUpX(1;2cgYjW^NV?=LjpxT}OQn;mE?%u&q#>y*nLw6jRbe+1 zO=CH6W#&N#A?nr9E+Yi1dmcVdp|V(_*3jH?C8H;m@|8$%<~{2oMx?S9e#!RluTz8n zRDuHwX(+OO7c(_6ni1*zMKGAGf6)aMijS<47l#tbzxOwJJAsK) zF)wE@_l|QbVNNcpo;)6$6fw^~_fFObgw_9okC!eEym%k9mF|fJqu!dXwVoBQ=wo0o zWZ{+gwW+Nt1!601q@7??VqvrUU48Cdhd&n^0m96=5ui&oK?P4=V4(hPz3#+TXd_z{ ze!id&#Y-21Iv#(^=!xPhA)ZqcwOJeb#`^&XtI)9-hbjvVyg9tSowuE1J8=#D1aJm* znT1Lz6^p1cOO3t1T^HAq-C>@MA!)t2nH?z?a=`;M=Yt;p=@Zn57=um@>(T-b1#N40j-|V<1X#E)es;ux3#c=h#!I0A z2YrqbqxgE!)FRvWwMxmcVd-C=0>_NVAEu9rDmR(sJ>*BmQ}d*5cgTVr*{Y)NVfYX0 z2HG|38C@-~cWrBb!Yf_ejp=2)!+VgyZr@2{KYCgIH35r$V-q4 zP}c$V9#8Xkfdw3t04)ChAMKhwhitJMyatg^(Ux#&Oxm(K@D z=HE~g7ERn?JIsN)h=o#CZuz#6$HY1XyTVAh(;w$Q<0@+H*_flBOv>KRm@hdBy>gzy zP-ixO3loH4?C&0tv2L!nf7D+`HCB)^K0Shbt*>f2RMq~=Ktu%#7>DwR15{qI@1y+?LX?)7@xJJK6WkhWyb}Q@O43EYwq>*Lq5~_@ zr#=OoC2Z9uugX!BC?EhkQlVlnKPLJQ z^zSuxv^^B%|0E@o@{;*!9lO#&Op+%Ja#&sLhjlVeUvgGeB-L&^H!3SrsFdV$M<91T zoOqm8L6;nd8n-xU-0LI@e(L1iSECW8ekk{)DOaI61TbJ&)-Wu}K|Q@-7@+wI4nC*v0k7voQblmxFa(e3(_$THBVYjX!Z z%WpMu*?vol&!-v*0>YtHel~?KrmZ~PL^Ou-74GhGLlNX?Z3RHC_g~E+o@B_=J&7?@ z{BynKcBf$~$mh6irccD$JkYAl;2661rk_K`h5Nj9unLD(6L{X~JqyQ13;N5v-ny%T zNJfbxhQP00Zv%e{@FulBVfJf=HR&w2Y4UR7{fW*D-RGy%m$-X!{H2nt|J7x+LSiZ0 zyhhP(gnj(uowzCri1Gb-?*^E!|}!CgHM(#m_pui|dm!oJvf6O9fom9IcsL@c{l*Km97 zHkk*!{xu7@Q##i2J3;#K~$yzk!mB+WB{UghWozX)dg(0qt82V(IX-)P+&w0 zPXK{Ywu<>(k;+TYngxat^!F^iPojlvvT_fy{&{wMl7Jcxdz|(^>Ig1B-<7w)V~@N^ zRMeo$t%gW{MSg8_1lzgQHPIUgo7e=^?_ww9yB<@ z#owla-8&eyz#o439E$J|+M|$-mqm{q-7J$A(O;_ONypxX4HMcLP;%SKy{Y(c6mUr}EH1ZbJEi z&X?M#NZ5Ur?f=3SW~>S1rMs`$w@~HN{3Lnfm9}p>88J~7b9ifM3~MuNeNBd2jhm8E zVhYukc>|%&*W1e%Fz?G?riqPkay_rid)sRFPf3D*G~4`Dnu+r<&e3o>(IC<})?vh# z6$jIp2ng)99h+}E*Z15Vl;M~Bmk2{oPJtFocV#dsj_BXSH=D33tXvCq#vU|=nY-f% z#zXiZ$p2R}1wVtq&wZY=qKLd9aj>QDA2Ef%9JlJs_iBF({*fQu&J6Y%AwtFG zii4#UH)^mrUEM;6pzK|?t-^scILR`iZMlHj`;7p)5>yDt_(tdY5R@slWnWQ8+@4_i znW^Y8QA?J-EORUV&mbk(zDo|abiKPhA_hSjEh$3KGKVzbwJH9vr4E`~RlD6li^shi z{bJ)&D!mNx4Hl~vb-MO{&hgn|fb)O9E|%dyKar8!PV`j;@xKh`TaSsZWDd~usdF6T z#!3-SYuc;>j_o}%f9lGm>Oq2RFYonw4X(qVPY0CEW7qK_Uo;%dYq7uNHYf7-^LRFo z2@2l0Bjb64T1?2JkJSqX-zvj>tr>x_Fm@u2YB5N?lM zAtD525_gMPC`?gM<8A$j=06A&or<3gOtoR`&k-+Wc0Y%6z>s?~kdi7lFzB7Glm8<+ z&x^2f<35@KfiAf*Z~Z7k4cVl@U8G^8SIxz-8^1>l=nY~)?<;#5N!}>jIpwEw(@3`y zHliW{#rC0Uu^BN(S?g>CuibEz1l;4^L4KnRVzrI{F-u*=H03w5n1`NYb5*B6YKnfn zB1wsNGW@F6xM+7B4csNv0|)ClM3~-FUz2 zwb-%IP<5ziqetGEmKAf9-|oT}{<*{OE(5u%cLF~M;VT8rp97cujZbADx<8H{vizOv z?vrr%coaQ>nh{-*@8r4I~0mRq01gYCc|9$AuYZqr(IpTEEOkDvgLZp&k`w&1bP-?5J~E|cu_(p`w6}e zS$D7(=SV`0Ty2)D#N|;tPVmS?vewVxZE*@M+_~e6m+Nz! z%aucbIx|;l8vT%waZRj?u23cC!qd-KR^M`b;sz@ZUd%{(;k7#Zx}Sr_8JNMBw|}FbiAqc%!vQU)eUg ziCH4d2qI0-_NK!s?3<6PP#6ablX3#p~5aZuVc)Az5fP zAfPS#kh5%$E_LA4i;N}ZJ{v8ne_csIv>dEZM*tU~CY*dB$DQ$hp-M37eKQ? z?PvJhd*gB9(E(6acyu(hBUJ0B)p7ihn;YJ%pK&t0L!WP29zMDCC4XkHROuz9;Wm6E zQS+Um<#)cgvr5Y!sC&EbZB?DOOzDb&)wg^(#dE=MFa+Ku_ zhJRDLMSRh6`dlvvF@T}BPw^>1D8?3?y#-3bbjZg<>{hr-#T1D4r%YIE|3?rsac+T) zMnhwD6Vp%?@Qe2jHDI~?AOS=HA)r9SV3sRyBQaLb*Mm0n-%{IYL-+<&KpDWI91DZg zs1c2iP~1#=#|mhSAUBrtD**BF)R!HVLX>u8ziO%+#;7Y1Ep4_J8l_dmek{NxaFI&U z^_vldH+=f!9z&#QX1jd^t`{JE}s{nj-Su@7;lknGDW(ZB&|s72dJ& zTWU*li=KqUM0Tm9AiEZ^S<<@*yNg3yv<~-tR34hIxO^C5!mV3+W8rAfH^rsyz{86__gM~m873bQ+w*Qaa)Y^PWMm$ zg#TR#^s>_%#%JJ}YgqL}hU7`HY;foyN5|Lb^@-pSuG5#ejjcPoYocW=x-n+VII;P{ z(ew#FM1uUbe9H;p5lkmuHCO31eLrq4=4S`y>3H~qB_Jra`~XO^#1b(t_TGuxV*9F6 z{^?iyrtLSbvt+|{L9Q>R`t<6yk&m6CicLR_eRWSH)lh$|TpxJ(>;)-QB!jQE1afXE9?L%paIF(PrC+Dkqrk~0@ zA}q@t=~LB>pDQelX7EP`AvK*HrY&CISy-#X8DwSZGC0^kMv1?E-D9w7F_iqDkUhi+ zbA9LF`)m?Kj$T}4GS8GKUx<*vT08gFVrJIDR!k-hry=Q5#8d_cvG?8N9nS*H@-^*p zhEVj6t69mISRgnvkBjnRKcQ~*`Zw~YM;F6KYS|5k@Cuj)(B{rq zxfu2#Og<<+0u0n(5TZ5Gc&-clA(=3H9^L;1$P|GVw`>B&G4I=2wS85~TSz*Kg=bDb!& zp9-1c0Hy;&Jliw?tTSQEX!0H*ctG2DFOqZ+72E?6ALNBD`S~{!#&D_HU>6_#Cx2?y zp>-=tE10S;7<_9ku%Oe57_p(KK76-~Q5l*TpI4AKqTeGBRo?dViPhiG=Rb#&IEE0S z1}67Y2#n+f-hUy zE2=zT_r6V{g?V-HjPUQ`v0L&|_MPfqOFcikYoF}L5_cH5WhLG9q{ORpdN#uIEmfnt zS97Z`OYMP9waI+_yXF5358Z4w<*N-KE`o%R&03V`J882oZ@>H67>-)TmwjQ!70s8! zCzFhh(6z3wWwK0zv5I$VA0RdK23PsV=fri&Ia1R6x1Up=XV3Zt&E8WPxP((qZa3mom?6~fO48Q^N z$arEp3s)AqIrjPiiVL&UVT`c2$z7*c-SI3n-<)*Bq({z zaKPX#awZ6|3BLT_1bE`-?-S;|t@?d7|LDf7wd{Km6#(rq*ah4--?h=y^g72lfqLqHj_28Mk3}gpOb9MCY*q8}_c0N7Y z_5VmW={T3))Q2>W_i~>_EzFE37dSAzyj_VU_j^^7!hER;st4UYD1CofUtRd_eyW@B;UWSmJl3?PEo+OMZ^NVwL~AaW-uk zK?bP7x}vT*X+X@U{f!iXA(O_FuGX`1ty}OqoBf-b+P#(f$Xw#T z_l&ga{O{8c`Ta0if}96V zHEGY?SKc|i3nqSG zw=v9;1AXc;Q*d*y>@9^7><}!qJMk~ZMShfQ`RjY!NAA3{gFb9;i);E7Eb<=<8u}7< zTt)|%l>okskqNr(b_+UU!g9db&MP$+j~^q$lQ1`z|53+70sZ&8QTV`u20MLvilsif zQ6cJ;%;YbR&lCe+2HT9|>C(V4!fqtng^)_A6$?f$HBD^TvhKwHte~qDh@=Pdm>rF# z!5p=P#))$!zoidKjdE<)A5Tsg7Du{lSsPjwmCE;BB{jn`A;MHx{H81JAp~}Sbypis z23M}jz4andQD90~&L0s+eVhiiv36YQr`fR|}Q zZ-%@>;c6%EXv)5J8m;Ezr<%T0XRD1*B|8rp8@Te7qN*zc`3s6h_wphkxTV|#vvWOV zUC$gZg(Lo)?|Agi#5a$!eiMbf4O*H>60SxGowC_iV)oRu-T^yBmv72Ayp*+R-zMHj zOceON=?|B7uQ!h16#}bRdL#DclRNUjAK9K!Gk8%-q>I-{(tPig$8Xb(PKYVfVk@2w z@ntALdzLRz zqEI_4O)B@b0Qxa#k;G4Hcw$U9Dn+~J)9fliv)5cULlx7}{=uuUa-;cydjmqc^IxXxdf?zR}F8B73|Akq!xo2noCbHr)T zGCcG3>-Q6ro$UL=7g%y$0YK4$@|&JN@>STl$$EVu07J%uG5p7bsLH1RdU^T9sSohs z!&y+hz#b3VG`$bz2u@Iq4b}uaU{Qb=M9?6LZuv0=IZ6U-?LEPlI&6V=aHeBpo` zqWSNTjQP93n*&rsB%e-+5uzc6+K@T9oZ=w+>mJA34o08Vz^CWI+MX2_BS8@A_f6s` z^Ph;k^zYZHZ#x?xm$6MTjZha)1;DKS^GEJjRW^g)m;qqUm^b<{5W3X$S$o<52GMG7lIXh;Zjq zkXMKkBMJJUSMpz1FvGJzW_?7`2Swe(c(Jp6h?SWpN-txlsw}&lcaa@PP$HgDBT_npQH(knQqWe3hNgew%DE=EFa7A= zZ;N$2S4C}MPTQ5F-y;ULt*LPuIJ4UZtCFY2Y+Cx?iLYBIb-PqCAb4OI_(d7oSK?39 zaT=;)OZR?wvwk6{JLjcNkPrPa{2ZRHPb7{jnj6kYSVR@NAO*90cCamW?gm|Q#oZ>C zf2db+vnL~ZAjXI`?&Nh4WmoUgEV&ZeGWf{v`eWc6hWVlOx=7!7S!n0p8RZn8`$t!{ z7B%v36-T>!`s^kKUNN%rY8OV?pLt>RD=y-dbJe^Na~s1Kg~r<@~JZ?TM3(L~-^ z{4MLBWD}xHf>H@T8Jp8l=Y&}%enYVBURWf20C5^_9~(27#&!aG*i{GOk5WSOY2%Cp zg^7Eo9XY{=JIwEH4lWlP$a~49tZWo|+T8JHefYh{b|dp{ux_Z)Ugpz5SRs?nD^vEDm2;9B7 z!S|w-+&rl0+3oholkarb7JG^XCHrrLXvSdfu23{L{@xiU_z%=RN1J@AdI|{qaVLZQ z|AT6DGsS?-nE1ah)DQ7A(Mr7DZicef4=D749-6X_S$}TTOJ&Apga0b>7kR(Bj;Zq= z3_7NLK-qI1Nr*C{xeH;p6E&osGSf{b_q}_9w|-kn$T{#vwW%~#B(JFkzvWreJtD-_ z-apq8%e|2jfKG4haIKLR!*~D7PLXF9;eAfnv-u}3{3L(?(WUykD_sZ}_7dvLa3s0l z9UyWyZ2)xho7XG93DT*ws;ml{r7LJ1lY;x z!Chg+&|-r&K}zLl=*Od-Sl{gIe{YD*_Z04-SiA+N6d+@?%UQpw6Cb!^LsEp{L`eq> zE-ts07S-_EQVRE;gze&gs#d=MPF3S#vy^wkd$M5~^%8{AtI*S3+lRcXC!Tng$NnS; zYzaxn9v4O<@$3G_q@o4vjPICkG%@chK~B=OCILJlmSvN6`3}J!yQ&Wc=QNnDM>&b| zLenfML$5KBI+nE3%viyoztn zUMeWq^qaKIM;XQ852!yf3%LtHcIx!zm51!vTn@Y@0*SQKCdRwI22lUoL(Ot;>#OAM zi{!seqYRSePeJv-7b5u47`7xhUS{FAjDN)*o@%%^c{ z1<868803Y-tVL=`_jd+!f#;9OZU43Hx?^gu4h{#@V-3U*v}h$#A@+7Z`LAM)B*)Z`VgPO(!$YS&r04uMygM=*lfpP2NM zQl%M3ukFXp6#+QR-Y18+b0SIKQIl@Bv)nG94>swhH!oY=2=ah=sk^?Eyq13A*h2&T z=mFLC=RPoYZ?hdj0Ov#GBZ*_1Hizn|OMfIMJ|xAZYhZPH9j{p-DyPYxezp6Vbi$#d z^_Sz3MdL(d0tErePneC~f#)6`34J6oW6CmP{A$aDowZAJGL8Rp@cgv<;btN8$q;At zWaLi=p5ObGM5)4=L7L-drH2Fp;uMdje!bWIU#O9X^41j>Bn~rYSyqL@K5^rJCwHhKn)^LqhYMmreoRAwnCUEi@whU)R!n+lH%Nu-owUVQtq(6i zOO4JHt)(`jWyJ2T^OoFxLCAYgzQP2@jN6p&AGV0%n1JbE`0%O6E6`yzyUM7h#~}LY zmFIVhurKbPdrf0GOA9<=&T3WON~Nd0HD{PM>fy6{WTqb4D$?=-&E~d0L%LN~`+SP+ z$nf6uvsV5>61>{KG{W=0Hzre+>vO^$CsoPL4Q?ooUz@i^LUOoFH3i@2e!gUy4^i&R zR8LnsH!{XwG9hQfO7Zs5PdAjeCJy8!hhEjGRgzv-pL=g~S8qV<25WW$GKIYauj}jc zhf+*02asX%4=TtZB*-zG-21h$kyx|k*~{?X0j9y~Ut5#qHNS;9Vr{SBg=Nh-Ca$so zpZ$CvZFu|WwHJkt;E>2u&u>z19tFCf7h zf0bk*3wqa>&4YgO_8Yg`>*mF)&6HRpI_yC?jEC+cgThO9UfnhQZ%y8EH9<*a2*M80 zy$J0|+~dUj(&G`Y>>|A$c78sg zA?}tM7<>ZG)#)x0IVO>8X`aI)*%yA)2oX%kLTn8wYzd;oqn|DpCPyar1;P$WJ+K>s z%&#ZD<(LZUJ+4hj2-r~C;-Izkk@|7R>xjXko;B%ku0hy83+x0#pCnr|26W!fg&(H{ zils`3^uE?oCmsjC|1Ga+4{C3JCLR8z9rnlFp6qzY`ZURtEAKY+!k`Z2qSH4`)g$du zkmEM)VR|i)sGo!Tu<%RWVLt~bwp5t#Ht!P%SL$s)k?(C}?P*$o`jQ&F|2s;P#w3ya zxWefI*Z$-Dp5ghBL>E4h$hQ%HNVy(DizW3plIb|*X%DsCKhYM>-l><>!@1_^i*%5N zz*|+PO}P9f^FRE5A~oM#eX7`}wD}7w9sojX1b8VYro)D;&f&fz^g)$#*YIqbNn4kAk z=KzlGk~Y64_0q{8!_-wo^^e*qAU^TFGq%yOp$j8sAMXCd@jKqYc0}jaF;s=aqBA==uMNUy2^p)%QC#qa>2|4QCs=JC&4<%*U1 zxkdL%%#wSJx2xZTy1-vkoH>}KaWO9X1=~BaCDP{Sua^>?2}(XkZ)A(U<=1u;*!(cT z7Hu(>zk=VC$0Cr}2~%BuRhn5`$oz(N-MWdOW+ky}rC@JDJoF(a$IIeU7L$<&O!Npg zE(%C8K@<#&wK#)pyKWE^4YZ&6ofVdTR)NUSVF?fvz8XRcp@ zaDQ+;hLH#yJ|Lw8i9ntjf`A10y}9b}Za>;3H*Z@S8h{~{iT$}TleH(PRMR##=#p~M z0QRdrDB?qi1G_x`{1u;&ISTE=<}o?*BeGq=7fUsStSz4$?hB>Hdz)WQG1-JRljG{F z%?a_}nQa%ex@FSIIN!Kdo@yrvp&0%s!c#$ z>W4!YJus*?gf3j@!2i~ou+v%i>BAzd{%j!Ouyj}K$#n4PT5-mjLAu*azxCGg4_kFD&TxI>gMAAPK{VmvDZr4}zt&A`! z_;?RN)1z8BQ%&T~e6o>GLGo$g;Jf*tm!o%FAr_eFlPD3QjMilJtE-U58sgI=GlN%XNDDPF7e`6xNW? z&K!}kRO9Sr)>>2V#}Wc)KWo~8dFNyc#{j%qMYL-P5$_3Y9N-FeLqzk8?N%~&Ey3dN zK^Et~&GtuR$@{g)?=8MwioAxuzm7qsfOrN*_1y>wtr)H@%xUx?&_xmD@@d^7-ubp4q4GZy5GMX zuKQDe-k_5tEbWz}r>Cia@oy((TH}>ph>x2{51hJnhClY2-97c^0RM*jW`~U)A9snq zoq_1clb2~T@)Z!r;k(9sev57WTP$Ep`&s~c)hJE}(Sjif9!5l?Ag9#wnZa>T1feDL zS{>`qPa=fB1u|@b`(Y-SMFy3{@cAg;{r;<`UxRlj@VECRrJ<{k%@x*S0 zTs9vXWRch&H+$O<@J7Lp)*{g5{hY&0#k%sTgnu|w^ zZJ$YI$sxoyuwUUUSUY~XORg9!T>J?ERj!0*BLfSqqUEgm?FVYUON20LsJq<`(N7t^EAx69LJrF{k^k z$QGQsPPeY~$z3x@Z;I*bKKEZkbeWJJ`=eF(2#>-v21N!$!g;<G5}@Z6`K^O=1sOxH(~nh|%Pu6a5Yd^M|_Zix^#?( ziJp&~AIVbz{Fk0&mUUTpR?mu-S$I*uZSy-_)`BPYg(0vXjkIDqXWI!Oyc7Y*_!SO7 zyWX#aYSQx&J$n0D?_Zz-2Lidb7#OXR_a*~Y>_dHi^ILC2Un%M#Pjo`%cht|loWXeoAZ?`7@R5GTG;BY?|5 z0(ho)@!cP{M}nU)R7Sbb`HTMm7la0K{qiNr$8~Y&43LASod#pdj5jkW?fkB}Pei z*Y@r`j(y&z?XKT-ou?Ac3tW zt@{u)FHM`>J3;+#vxM71^0MZ{`3jUtw&%Cd;&ODL z=mJ3)AV*SGC7u=~zS>#df91?gJz4_3aQ-kxfJ%P1Hr+=FtacW}Il1VeW^0mUA-!dt zE2|NfWI*L;vzh*f4j*ddA5i0ukQf@ojJ!}qD&)g^Jy^|ScDP=?zt`Ju`}eA?NNYNv zjvgm?HLoeXXz8-xYmu8i2KEVcZVE|UvHeOpVQpp%_m78hY-k4lCLORLlw?a)iN&(;t3=^ zq+9GhMn*>gME{LOh=K=!H<;L;UGkk><%gS;%}~h0@+L*$_9tvX+soiojYTJ=z{h4Rgd!~ zUcqp-I9^te!T@2U(P_+!%jV*{^NC!yypk3@#eTh@c0H*AS3k1SRIqvgGQ&+=&Ez@9 zy^T)=xDcu>uo>99>}?ZwDkSTj?udA@Dj<${xc+6ubFue7nI;LL=zIDS-_QCSxi8ik zsi0+9t}Nvt8R{J!RPRR%t8xGgu&Mf4@rw{Wp`Jsr z-uX%zp8C)$kK&Gdl2XK`k1J53X2(*VP@fq2(`tx932;W=e-Qfif{}lX1KR@ofPLu+ zJ0BxLrpNvrIvyi7M$~<_TlW(nd3jYC9A)-s>j0fE z4Jn#&+<^93p(@k%SKX&sD2W}#ss~`07MV%PD~ge6QQnegeMOVte@yQAo6TAJFBp5-GtN_{X|ZQ17nlnqIJu^_0sc&>V)jrFiss#wX}|0PVC{4JS^q zm7DsQxE#MA>a8OX{=Ma==tqgB7z!ww2OV;Cx`SP@P6xx}E#o%ufe;Le=Qe4UpfJ3M zvrEsbQWOxF7M%bsoY<5xw*;8oq*XcP_B<;l=vFs!Kv`8k_@gy83f1uQ|V7pR(zw{e89V|k*QMc_7 ztcxw|R@8m_4~TXBTv2i1Nk_RR^~?EJ!ZQCeTDrIpG=8aa0`iw zE;maORO;Q?OI41O+4kVpuT&}2BQLC&T1?^RzV&6bgMNJ95uSF4e~I>C^LF}J-KSXv z$I*QIXi$1;P@C=F8{Mjal0&%3;ME8&2scpABurm;@qc?3w2(sqMU2p*M(Jgdl2T;d z0y%aJ7yavsJjg(RuL#(@>aYbLCLMKFG%e~vY`keYw^WFLfV(*L~O@+C>Uz|B9*KNV}DK-cbe_|Mj5 z2(aQIZ(ocM@p5*Qv?TqI!JR9@G2+Dh|LGa2ybO0?MeyHvG%^|eH{#)>JDj^*!n2?5 z@A;`Nev?POrRA5gO&6B4hzR&%QTB{^i2$tZw5Q@(Z0L0PUD(y1QmYNB+ZOO;P*Y~#lc&_k z28<3BY({U_;#Ys&(%gSbZeEboLkK^6Kyt#+a-@jibOodp_@E#&hk-fn_Vwr*yYmL zJX`_8fwMayl*y2zP52-gJW43iOA2|^$qnd1DM^5NT>VJmnD_Jna~3A~a^$)oD=%!1 z9k`{$&gltuKC>*V#ID&H^iEVfHvRq-z!4SAkoAl4;37e&r57bN{G zFk2MdE*SV_3Cu%c#^ucgTI+<2?Dwd9MZf z=k>gNKCg*Dw_Hz7Or3>O;BM-cJa?okNvq}$lMc?F(#{ZIuV7YoW1<3t7&ur%ozES&FN!1KJ z!f*~3Jf30)$`tIR0H(v)@u5l?maoKS+EbRN{GlH|TOVBcli(G`vx4E=ptjfz+fek+ z>GQ|Ju1K?G!5|^tww}ag0-7lw?0tNoYP;i+^Gn|-j81f(E`H#@)V{khGgOGkA%4HR z#MwkZGFjcPl!BD^A=5;P6?1SCHPL`;v)Xw)J2ws(l@YY)oSX>uTQG` zLRZwDBEE6_ayLo+kpS}~iQ<2;2=70=aR%h2_kM+GgI@=rIq@adOyn!P`Vws3|6?vn zs4pt|EW|OlR|?qFPA~%ZK|${eF71AfQCrpK0x4h^x3w=2E-nD*fKI>Q$kzOT1acWg ze4uwza+i$NloWv?f0R9>eL-Z?>wa4FH}raQMbE19a&!IS8v%N<$f|{t)*!iBnmRH2R-`{Zq|!^C`li=Tar%6)MD*^-^$ zfBBbA;1nFhy$g#2)c23>lid~+HvQ=S(S^vhqu1YA{!WO@1yzd4Kx{@NmiK5ONJmfiP}#f+JG4KEJ0jM3 zAj+kgE?}Ft&FI(PSMo95H6r&k0ldOny@$8^KTkMXDhRzZs6isTtp@GXU|OYcP&J0g zqf#9V+dLy>mz~cmBH`1JD&56=%~yZgdjI&yT(vwn2k^VH{d+GJT)2EErn(ufH6;_S zXIL@X+gc=5kw3s;krWSpdL`gelic!nJkH?081a*LTG6hnh;JRfI;5R+o(aJ{*QHnP zvk=95xSD}1DO$tUSgr3#Jq|Pb8OZoOTeLEI)%$9!xhSb^uSZfL?dNnQ@vor2Yze?- zKKD0#K|}+6d)@1*vR-nCjoDnl&3yTpc=(Ez`kxzoEK$E@M|T;+LXmel)tjAeFnpZs z-ZB-xFmPyb-vMm%$u?h4(RY7I2(;MG5Ji&02fX|8!x7&1Jel)#ePDs9*)Q&wycU0L^8_#ph0V89&NRk77Acdk_J3 z0Q4aJVpdQAZ~Zf?GdZPs3jz9U^?5=5)$@$3ZE5l^pH?9@o>H*~_ob24+dat|5g}Vc zs{M>*Yk}lF)90OU0c7P12JBVS%$jCDPku0*(qZ=jhiM&!T_U zqbQdqLXemJBHucQxS)F8W60QXgmK6QTBiERj8n_GL~ar3;4U`r0j*4wzB zQ$3Ef(G&S7J2JH}P{Zf(&)_2u9-TuS6OI3U+nAhgZ?Qv3Oj+SMvOx~dZEjGI!85%` zCV`z_>n&eO6Z;qa@euP%WuO6n-MHj#J}r$xqOc)VD=$2nKZOL+ddQX-{`XUoAr3q=$i*3BZT3SC3dk zcw>A%?8y`1<)Z5vn@_`w{xT8==Ikp{ZMK!@{$axh84|-UM~DU*{cUAp-`w4`%?vK0q~h5P>wrb-<4B)E4L^UXuFqOfGPIqg}62 z9vK)VJasnOU}X1u?w*0-Bg`7(vx2r$O|!Y?>9f4WUk*_vhPN-oedKd$m3;BU9^qXR zo8ef$g!`G8Pa{bI(y>Kwj`wI<>YSNkMOBTn50~VdGoplkxX}zg{EiY}8N+*SZvU^+ zD#3c7&X^icg!4l+EeHgI0a3tV6b)kg-pag!1CV5y@yGwtFyCOBC$&tay59RTckt18S&&KNdHn8 zd}xq}H)WsTL}9mD$ah;wRjuwxiSz-@$&rT2j@M4tBi|j$dkHD#1umiPz?Ur_2$4}N z{O^K|<!m_%4BysoQ#}}O#y@!$TrRKq+YL8#HLtS1On>6+ zYG+{GV`BJcF4U>fXBrCH1kaCy3ID!-JYs&#M04AL+<_)XJM z`PA_{i$8}8eD`{#8){z4-UovVPoG%U(tDjkvdL0>CCTle_NsYAf!YU??$*_byhB%& zg2jS`Xue-6M5$9O%|!N<8$>xhs#$jK^(mTF0m{wKw+?+v9Mw?tkS*F6@;FT3x? zR!&e05T3)frRWEWOAtQY{&IehDR@%T@*^^4 z_uYAq-Nb}~)9XHFUa!BZ;t6p4Wul#!K|3ebi*nDN#S$On!enj+!Lgtx&!~UyTF{0a z@DC&y()k(H;bX*&iUX?555zOw*bl2e!R%iRy}k!V2aa~l$*#ue79WND6J^DlPYB5P ziyBMmibL1}h=`y`68*j?GNi|2#WAUZh{$PD0ThR!Ll@@Yl{x~n=J zk^NEqn`}U#Th~rJ6o<^*G|ni-QBS9oK(M1fuHeMqMh}E}z=wt~Ngm+*nrMh1u|xvt zDFxM_Mrxky9B(MzywU*&D}&IHO-_UZQZitS(dNi=wBm^E?M9YD6a<1*mD*mCO83zx zMyJ}`tQ6d)CA{fJ9QPxR?he9Ca9EYl#t+DstUDe3&!`T~z$h&ONFlMA?s4ql%~&}D zA$*<6dOine%c*_MA??6Je;-jPYr6gT?Xf59Z|?2L%^=wh`2@NUJTIF^wyUJG%p%c< zN>Dvl90HimAfelpuRIg%N~j*^i&hunm9e$c%rkjg7EzNW;wS%6zxI~sOaqDSwMW@5 ze3hVh!$K$Wo^0dA!8o>MH{yvJB5ud=Z*Ev0NrU*ie_utZrHqRuv)$4RKhDzf8l_B& zo0B-~hQHH%xQaDbv)mHk0CKKd$G%xNz<6;mUb8`Ax2sAeA#DuwyASl@=iFZCD^S@X z6jSy7tFdRgfb?{^-?L|^vMB#Leoj36o#kgX4@AE5>f4kYEL4iC>*xMlP=z#2f+!lcko%ImD|JfNgMXn zg7ucH7@T;h&ur(_L&$#l;=UU%A#k`)oD+uiIF{xoGhjU23>Q}dR5GAj&={MR zqYv+hg%Ke!^D?;B*C(Hg;X4f>yoxZ9+o9BYY*w$-x$KO6`Qh*gfhOuxx%Re?CV1_0 z|6>6WPdR79NM?V-ybe2X%D9TB1eqZBe@UV{XV5P%qt`|m#~_8=z&}7_lYX7$?MC;P zpx1@Ip~x(J*lqvE1E&M5nHuU0JKed-gfs?@^+YFul#^>0-lZb7k2H;V*pp@;36 zY)gyZP@dt#$BP@sYzujAyW9}CCE$tNb;HyzZ&v!k`-`3`=9C`H3(}vXgD)SKdsaYJ)w7!tb}m&IXp&3SmQ?4HT>nYY8OofrnM2KcZ_tz1w#(K zjdo@;sdP8>@6>gLEA{Xj3nEFY60-i3{mZQvgMBQR@{oq?4i4_L+jW#OyM22s$CIA0 zBICR8bX{6lCC-&PNM~Plsf5%k?n`AW*2t4BI`;mkr}Knj>(s;by`KWJAMM0*|5irb zZR4J%;|cX^^$QjT1t1P`b z9e_I6xjXzS^nc5)arZC{kI$2J8rv+m#1&c{37C-b#Zs0OzKLnS{qOBTpCko=zSWe+ zce;KrUz0j>m{CwReQMi9kQVL%a!gfb0uPK`VjC;CsRj#y0SvaTBOHUF zR|RM~adcdtK`eiG#()Vr{x&>69311d#D(Vl4|scx?p(>_!5#e(sh6b~1omdB(iX`U zZlY0H`s<+c7IWd*i5-W)FYpfN6Ik)>GynQJ09O2_`j>jta0h@j&5Ox~A_0&Y216+oNw7#4qdrlZ_~&{?xC znxP5^wZ+4YYp&JK=X1H$*iJly2@lNui!Ks(-n>xlLhaC>uYw4s=1;N)u0y{hp zEAk^8>IeZZvT;W)n0LEzXHWrj?qH0KKrr^pAcC3GU%kGbkgj7}rdJ}19I5NF6wIA}seUT>lK zzKUQx#asG255N8O?f*hk^zwK1)4Ir;kFHVCjHU9{XI_kHq?&!xI54vyX$sK|VAGK9 zKMM@}acy@7Bi~YN8xEm%d;)&Y1hw{qGwI_BB9AFE=4}>fxSG(Tl*6+qJZ!fOE7zRK z0b|Tl1==y;KM)k5E9tAZLPamcVE))*kPta%6K5#w>--H#8@V+LF9ghJdZCy4!p9cD zMogfkouPcKc8r{6lT)1DiepQxcah7?|8$WFG4u~ReEM-5{-iVX4e$w=!JD~cBOPuG zId8jiaRlA2Z@e72xf;;|F3*I+Pjaof@oY8^ekB=U9r!41S&;INheXYAT3A9L5&IMW zc07@w_Wv6LANiruA=cmy8~**KlVV?rI`HbQ1-qr*SOlm73eI3ud?Q*h3Y`lK;Ojp^ zx`N%oqwm+hF}0_yChB4X2!|ew(k`Ah5&7su0X5RA(4EefKM0q>`_E#hB`r55mv#A#Px5X3 zR5l-XK5rJ$8AFy{4Rdl!t z;bB1>2AE1#Y`(+o#QC?aFTwiH0}IJ+{r{QQL#e<6l~~#gc3g@ecD6}0jXPA0L)_p} z(;iQf;4R5@FF4Z_+6N8nE_uoRfIQLIh~nV!ktj zRhG6EWRFA;X}}DpEr}5)Sx{u%)c!=zgVw(OUt+Ht;%$7tH)nb%RZAy5Ky69fxdzjx@gGWwY$&L1Z&35*b|Zm_%(gm*c+l++_z#ykZLCKF*p!J05$Svx@|nWO)nSnHbWT| z>_;R<#vGe$-uQ#P?W=XvzF`>h%QMB-ovk#;yY(Jss#k>)!+(dgLx-*JMj!2Rc(A`k8x>a?c9})X1scHNpglphtGo63Qj) zk9&KIl7aKv05`y(cQ^Sp{n?Tj>f#~32ARGL{0uL&lQ6Pq4q%7y0Lih8m1o9pA%&4l zDA|V`QQO747&l*!Y|TqC!faX-Nm>25ParDx z)L3u9PExu=&2My|%&5`J>CMIU*D$4@AYBOR4C$l_oZhbqI0@oXEL^HLX`qzRqB`iR zoveHVl&j#zlSKEB+^pQpWDhlhGmZE7I{)JMydpu<^A;qaSULC{onT@A0Sth5(%n@I zn)hARR^+G~ZCSsMBiZ?>tj1`?b4?gd2_#u`O3|F?k)jr!E74776dnxkpVn_v7rrFYM|}GPN!kf_eqw&_#&5)2e;F5O0%#__O2bKkPx~Kb zcmJg&D_}0q9sg=`a2i@LGh8SX6KM-x8KM_SVX$3Nlsyl+C!&neg33j)WpDrdh48|6 zU=*FgNMP?ZGer#%GwFYSOsr?o_RjC4C_?qY%uUV1;}4IcfJ@f9d$FnXlj0zet#mf+ z*i%6UwBy0J(i%-5>RM<}O6BsNaw*%E0Xx7o!q^C!L2@a3mX8JtgR82D{wUF}QIcZ6 zvc~xlVs!xbX9itm9O*h83WT#69mVi!=3yR0`M!d}|BmP>rl zi;5({8-Wqu%EE?E__$YVDB20fy-Mf~-@@{PoCR%aL8@)Y$U6(a zXyB6QH!u#3zdx!+cC9Pz^@A8yfY~Zgz!h<%7zl?*$YtH>t&L%gFcvY&{Gpg~0bB-{d`tq&uJ8WM|obN)^=c;df{ol6U_^ znQCX%@`B)$5km^^u+I&Fpc~_EFhB5-Uyn!VBp2~i4I=GB_51fWkDEl`k29FW2ZjhQ6nC$6%1oJjD^$xK)^SSlvHE_iZw zGDO9~gy?Lxg%$umq{nX@D>ExbeU$y}G^9&T!Z+Jh{Mi7ghz!vo^*XFE~>L7;s_G@^K9TY(tgbDO#4@p(K*T~0z9 z=oyZ>V-dRBy+Dy73xwBHOy1Mv-2J#`ew@X7N}pqJ^_mYYerBB0>om+j->pTtRDT2P zX7Af1z5o~E!QS3MCZCj-)|Wgv>F@jVi$TQK2-<7t8oi&1gGONML!jxp2||6M(;Od9E37hu{l2xsW73 z)uxOi1XJ~@(WSuuD^fY6w2v|t9Q#c6m3xd!2lS31%44FxVmC3ZeOmF1dLx^!-RfVG zS$^5UZ$GE~n+~VrrM-~QvyU3B3u&1u&pw&}PYd-AZWexf#{z4B#&`fBj2E17$)=G9 z{92Uj8-Mxrak>xeN|AGY z<_v0Qefm;g3V=Dzzy{s^&aO6~p z-&uRwB}D=Z8`)Dk)l)dq^GY(a=tO(KPdbcRDu>O$fx*#8DhflsqLT# zpA+WI^~(nS9YgDj`m*w+`Wc0PlAx%!zn@mxJushl={~b>e^lKl&$t55TuI2NPW;Qv zNnjJKAV+mkP~@Ows2d9FUantIYKT zf!zaIwwu$R+k~3H-KXRFgtJ%F1hTJ1?h{`)&zDk%h?Y*Tc@AjC28@ftX$?dY3%o(j zTOLb;giar+H*bZtHG1jj>{(+J6^k$p?snRB$&$0Y-{Zi5lHsAj5yARddi-SM8C`w5 z)e|;$G8-bkh%UU4yE_VBrot0U=*`S&0S57~NJ)_ey5>eD+K!DOK#BqgCvrF;urGow zp+Jd)5{%%DchhrK^srzW6ENf^lNP={IKkWVS6tgGAo6T=f#9I+W-)}V?F7ASuJ_yw z?i8&Je|41>ffyqLa@G*`sp$|DZnV)2vf-fPn|}bvts~~-w}Xc#93JQdWpA;8kiWvI zM;ewAJk;rjlhO~15wRPJ6O(aYgU??2cC~iSf%IFnDmx#0*Oe6Sf7H69+H+jdY%H5^ z(NuclEvfNI!}+H)9JX;1=g+VI-zX#T>Me9g#ZgyG8!Ni{mcX=(X!k7)e`>m)s}`a5$AIF(XZ7U%iFRd2D^NKMo(6I`(w<&ov|IEu z;TnwOi!$(GwEJU_@_r^EildJXN!BH?h6u`5HLzo(av}zJJ5x!#o5g1wRD+(^P0n_U z8)>a=2C{Jcda=w6Tt*2nHBUG9rA)<&5eB{gK0eE2a3@f)xqYWz?2yxFF6DZtl~6jd zZbAEC8SDqlun%LM70iw_LGhuzT`ymzb3#91P|EQ`@6FGFOQ%t}C_9c6DDujhg!kko z+n0-}_DJgTdEv59OTcb6;vwE;U<>-mXf}v1-?b;j^WD2YZ!AwFmANfozq8z`o>Kw$ zAshGh7Fv4mFdLIV}hXfW{V%&{mP96@$ z7QI&txp%=2z*N^k4BO4O(|^VM2YJrN1y<6TI{~=pRCmMd*jC%=_p~ z?x%_61&_u?dl1_(IG&FPFmPp@2!j?tQVsT`*ebaNn7}XC^c| zO|j!eF~I0Gsz-Lj6aGoDD}QM`mLprvnb! zPjIRZgq|*vH}1K>_u&W#Ai5=$wU&(R;CNyLKF(hvS`o zdsIcUninGhzZns8hBR{pum0}b{qzfze~{$o_qy}Z$@wa~&wHuI3;(`!YAeGPLU_`^ z22B4^RnY$}clBEOKn#WZiBdC24KStEU6AZ2OT#%%gSKdfVtphi`nH)|5LJ2(Sw({aJxOAc~m{yS^HL8K4LQ<%DP<2UG%3Kwtz`6Y_A(_zt_tI zK~b8--y8ZcKKgRS-8tnD&PM|b+ZX@-q(HdAaPvjGv6iJ@h-s+A4Vac4YL zOHBE0>E=J-OQZ;d39cX8-gmwjh_Hj)bwH6C2pybSSfP|K5JZk` z7?R}%ZMJIQ$5U1o7M|AQN1tWGsppkJ$bHL@Q0}{)Wf0oXO9xx0Rw z;ppRuenJvlW>^ju!w#=^mz< zPDH7&*egQdK|S${C4OYXMNsY4f#p}=@XR0`JcoyD6}3YWXn;fp3VBqMAXSzCeGK5m ziTr8ldlz+ck&3>+3%xt+qS)t{J?NrfYs3DgSiHepEQK7XAGBfdE`gQ>B|ux!c3EnM zB~mvO20@zR?l?151go1mP^Evjlpeb?=C>>cMXhj;5%euVv}|Sblp~u9%4)%I zCk;~^Sn?ky5wga-a{+R2+OPgwt8)gbKj&Yq9DDreX+qM$pYQ0f4RL35Is|^x?RrRI z38fiV!$;Sjr}fUo)8uj8(E!?a)K|$*uTc=>565GMwd8{dFuZJG4Dy1pH9ujq@dx9> zUJe3>e{7jx80t{1@^6v)aGKJU=*xULMVX+ZTYLE5ovZ`xwv{)8%fY%7fQ#STXT$*V z*4kIcj^*uEco_}A_46G-iQQ<@kW6J^OVgO0;MELOoAs$s5dMJG6 zz3+W0z?U8PrwO(Z@{#m8kBF*}{C7+3DPSSgVrtGAH2ez>)_==1SjCVhn8MBcQ&0V| zIlU=>@>`VH5}Wp>qvnzn75Rf{)Z0$~l8}{B?zpYm@1%?E{ zUC}9^z%W$s;Qfu7S$ol!v`PSD$|YfOcG8Vq~LVvOwto9tarim=R%y zRe(P{XH_}m_;d3{~Hh|u!Ru&K0RQgFkT5Wox{pXfi~9pfiJ)jKvW79Lz| z5aC)ti4n3!eN#Q6CpEjjiZbVWPiEYIJ&kpZb0aYvB}$(Bu#hdowEvg{?y5oI^au?f#C zE`Izp$so+MdF9Szz0K3{M%A{X_Dq?=h~r4uDZd9kp>HZWpVqw6zMnj-vsHvRxpj7QEcKYw7& z%z{(tMT>H=YrGqYxoQ!$Bv9dc`Ql3fQ`mpb5|=7FQbSl)>kp>HV*>hQph-FXeNw3h z3f2k6r|!#~^qtDU@d%0_YWhp8ysz7?E-C)dhm(fcfj%ibb6xNs(l@~Z0IDQnKlmDN zJz@KwSHTnNox-9)ABj&kmYow06K2Lg0w(b#L#qTsPpM~id~;?920*|cZ{6RXJ=**o zoJB4poL)*us`FRfAfJzkGdxamuPOy|2eJ5;7C-X~CX5+hxW#M6W(7}t{$ zM7h)4KLZb|y4kz1`Gc~jT`Jj@J9plASG4lnF28Sytmv>V>M{($x{rLDvzq!YNXKQ3>Qvse^Wk4#WoULHk8oz+xOE zh05k!aq1uvi~VE038Kw z^Z$LchFk5Tfc8(Kp%WTl*qL=_Y|NHiE!^G6hx@~d+rc?!(geuHz6ObO5>z}Kx2x48 zTX3;zU9$?e9>mVN>g{v)-&Q}ZcpIsVvG@}=l5XdGnP42Uz$%hBl~$ymy7@p|L>K*L z#C%V$dqqIgN9g*Nm%)6KRe|>EKunF3)0&+5rC0OKRJ;$Y=Sc-S#GitJP+t?#u>Pi~ zxV8aN%%##n0)tZe7F=Zr-mG#%P$YpsY^kWlscgj1@~X8GDcngVZ*M+`Ed0tx+Ajp% z?N}5&im)E+xY8cr#pZlT7w=$5>{ZC>mw!A55 z2e*-}kM-+6ahP4V_@S|CNEE?*DrelffcKgVIYn&h$64-DZ9)jRmh#mGJOs^}g3<45 z02As{EgE3Pa1I`QE$@EMCK)$WY2Lg?q-=(l%0w`*Kg*ohz%h#)`5CU0E-k96@7C%q zEeH!{89PwqoiNV>99sV-CWWF4y?b6W*Q>e4f4Ibxi0xUexz>(WDLwPc0|WXP;%0YA z!zEvSGO6F3T)^65;qcFw#5BN05vnEv{cdnrpVmW%KkCW0^wy|3@^i%-$~&vGgU?*H zHG)u}V0whnzr|eh>DD(*lrDi*Qp8`X+E`H<0IRJtZ9_0%rncYwrYOQLRR2*Cpu(L; zjdRJF*DclD(~H0B*Jc8%<(x3hob`s38W(?Laz6O$pxg`mNglw8HBa_%zjcuvXqGfk zzg&|3yWKcXA+i_laTs=<7p*?P`1NU12IlBY;tlY#v+MALeyUX)*80pK#D=!$Riq3M zoKM5x@bEzGQ27y|q4Vdz0WD1z6Y3K$C4f{{*Qz6QmO(<8 zW>KQ_F(EJ=I?hkCZ)uEQ`h7=#_`fqHtyLxdnfo=E!S1ZUwB~gIT53D|%8>7)wCD&+ z(WJ_zsi(l^)=4t&sUWkrh{I>CKK}cvBlTd%azINJkRQ(D` zCC;sTog3n(g-$-ietW5Psl&=wTCHL*7a@P7UNu-LVUjU<^gI4K2m1P<_XX1ebR)2@ z)V26w-;u09&P6N#sdOS!8&4fodKlfK^5;a=#SJ~zH%g%Rd}s@h!)=|#L%bYk=hl^* z0@N++tcCg5hP;vJCI6ajnV3!Ty2NOeh~PB4)(k#E6%?OzWvETZ`#$%&>bYKeQS%ML zRw@Pi5coX#j3S#hIGcQf<4Wwm`_1nP#f2&+IpHs?UjB%0A`@RZ-(!(Tp4Vm(Ycud0lk3w)v}uO&3x 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

    rdBc2OW9Y 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%0A?r|>vSpBWHiyrO?p@5^|i~d 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

    nQ=Uuxan<@&y_+Zd&)4LB>FmsMis>i}g7QM}T<% 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 Bl) z=)Y<}Pn9fgbVpN4g5C0R*X5)DrC5iu0BfxNF1@jf13ZhPW?$2h$qu_gjb8|9Pj?G` zxNoJS^I+j|jN4*}6B$r*$j_N_0bB8`)j>fe3#%t^-m##c{zXV&1m#u%SgbIi_{kYV zrwD_)1a>)N=K4rPQ+~LJm@x916#Fw=9p*jxW;`!vCcIO0q#va>1V5E{hi#kBzINuY z$mOKt5x??KnBfk@x^jTfW&-f8oZlHCz=1x2)>OY>c_Qlq#v?-%xHOEtks9;Mb~a;q z!`x%UO7_b4Ut$rck1|(1w_zRLZo9Jx5)BY(ld+xDmsr?ecGKg;ic)R_TYL0E#zU`=@NPIg(P+7g`4!pV;zlZuwu}_u~ zF<#F&8;S>uHA&kW-^dQe42`df7QPx=sQ}JzZ~lc5&uDvCrbDB_94{!ZOl3(O$`3fdp*kl24*^ZAW%}qT=%<&5buo=PlZA(ySege zu^p_;=Wkom|LLo}U}4PqCW_ecP}0#S^AI*3=? zU$I$ZJGBqxu4%ef_6c=GBDZ^^?IkCb;z4&&hL+F#&B{Lb^=89i8&T%1Y$nl$I(Vad z#M`UMu>fGXp`eh2yAK^Cz?-C_R1C#umQon2KS%H9SicDNc}bxhzEl)8&P69~r*iin zq)K^s3bWMy!`WvAR?BfHzoTFU5n|=#)*r}_j<-6)qQ}_7%mfs15c+R*qp)AZ4 zo11AuNap@CxhGFMs9dHAwX=Cm6IT0-03?*L(6gqjznwcZVUM70ogRDW)c{%Dcqy&Q z{QB{aSi}9e4_}UL?`-;lp>vjUHVAIX5)699+2RB>3zO%*>Es)`dn^A{M;2hud@ae+ zs7Z_3yseS_537BC-Y?yX?%pg6?bR%0o~W%f4GMIL7hb+Qev_Y%ZBys@r6ajd%*krS z0f7ao^W-bzJc>M`1a`K`!lSiz5HLcPO7nUaW9>N3PQpi)bDV+LU$&LVDk%%FS__Gm z<+~r9cd_9n_Gp34!A}TFLT118x(m@}ny{Lv-bkGs&u%!m#Jm7hMns5!si`e!`b(o+ z{}-gJdD+c1N60^jh~`+-{9d~5>HAX7yGWnYb$agMrxmYHu1%E`yVGBs`q<{(%NyUK zY!ui>w?OK3^!8$+A(AjzIjV#a$_s!>?40_1SunduL?CUYF02U)Z*=}Ca`uQ#>-n(z zP>`DI?BMpNi9@?ilnB3J7~P)xKKPjo`jwyi>1MfC0Q3hc%^K}&?BCZr@<9X)40ME{ zk%CNa^Wzt~t6cu+yI$jqx*ar5-MY}Lw1Bq)&Q0$L0FiT+fYaL7mJ33ceM${z(iHz5 zX=${#Y0W!h-pJE)&$rzj>>)9+-zDChk+_L-PCY$qkZ)u&W=cmdVsy*#7C!Tkhg{Pi za}^2@J*uW~{Bf_dk!!=S6fs6@aKhV{vK+yYG6t z{xtZ^nbtpXgVaZ-O5b?d<)u#PAouvTodiTf=6@#?=1$@THe6#FeN@xYq)l-+h3AWIk-SWXu(3x#Vqd#FAy8QQ+|m zMYXe~zI-@)>^U)VaK`<5Y?B;|1_qRoCFr5J-^XA*qkZApBl=60(g=!+GtSFLF;NUOyO9tENDGxD(*Tu zS)=1bSqnENWg%w&f1CMJ@Bee1e2ytBOf1{))%(x!eLzhHO0U<2*SbzWswFxGAS=74VsrUWCWKAU(@ zczrjE`+vD*LUoDB2}= zg@Fi%h%OdPWU<6k6Ea{NsrQP=coOGC}GbO`7~z)Bbjk z8j8xx)T6cktf~4?`QgI5(iegoV^`qOe)+dIphfY}QQ9-ojeIZ1LhfgI0tfNI)-CY# z!tys|MI{AAucPI`SX|s3xTC3Z{JPq(M>VJDFNU*wCz{KTnT0C|^JY1Ruaxh))YHE= zSdDj18vpE+7iXNdfcH$H81_oQiZHw!ehEZWWSAOp5_8oi zs1e?#MEf6gg&){vYNm?tVfpp1p_IdnB2ey`DKk)@LXisOO8!bRS7s;^)-`fUq6RY^ zHz%K1oTA1|xZu2pZ!2U7Q*3geQPQS1LZGUIbZjhXzR+q^x?vqLmM#NNNFVc*0-KK= zj22;%i2`I^b%10LY3$sz(v0~K`-nKE3BT*KETDpi)@$P3hJRI_ib&QISK+^o-A^Wn zv4ojgc&Vq(p_rFqBLk(YU3O0ZQLhD8GeYAw%*T!~hy-fr7Zf>;UJNB*^fC3$`5msl2JTt682=VywI%OFeYL<(jU*`{jGF%Fxx{ak_xgn^6%csgfu0;Dr(eF##7yG^nBvH=1B+G@K?l*F1C~CbNJnl$5teK{ zS7~+iNRIdqQP1K6E;iqaEXF^J-XQNJUA+Yi;SuW7=) zZS%!cI2#&p8@-j2s+|`ruAF^4XU84^@;$%>gz%w$sqoX_$wMs~_D#-lkaR8avsQ6;+%tbuRp`$G%n>pi-&U5&`CP$Imh z8=fzJz1+2;UHvkZZ3bu*4f@m&PO~Rd*Yh5$k!b3pqVA$a5Wy1+FJ-zBm5kRPJ^5Y3N^vIPD-)$NT zS@UO1HiZ7_I_;}jXO2c|cb4}$VWy@Zaieoh*1SI{<>_$y;tB`+WaWeO&sO3-_uWfQ z6^|FJFI~srrY%0rfE0V^x{kggtwkLy6%9- z2#Fy2AJ%dMsDH>XfS)a=RY&_9 z-hSF$54(g2SNbFw3%pO#gdg6D+YcRlqpos@%17!6@(QTP09%3pUZXtHL(?bX=Yp2F zKt)gQm@V+L4XJ!>SW0N&OnfA|M=)Ofa@3);UL4_d13qVwkMPRDHqCwG@$*k&hxgsm zEXRrY`i|-D4Jozd$?t&sAODxT7%Yk#?el~C66hejRc2kqXHh|e;DUz?FZ|`y=(u?- z_By^%%`A3!;PbC|bA>ZKs-DKonpkbx@Z`4&jiWR<|GSMSDuEG1M5!!P!H88|VTxex zfx}*XD5o20+j>~n+MHU?`d;W}yA}dHbGM5zZ_N(orGW|HT@YdOL1 zxF!o_AF{)*nQd`JB)J4~YO4TZuD}G+{%(vqc?t-#;@3w?FTCiik zfGI`Li6$q=)TgleP1eGOePVF7d9?LM!@R3gCb6G$$qh^*)n#zb``gjLWs~|65Ez?T z5%bQHx_8tfj*|U8T9+{SCx!QlADTn7JAYUgW0C#6<|4}Q*mm*}5Cu!XfVzns)&e=4 zEm?XIJ#4k>X!idZ`fjjtAPtTak2$}8>%31Cf|gSc-bXLRn5h?8+@z-qAfQ|uT(R;G z)_L`u??O_{WN7_Obd7CJTH#M6_7OJu-u*^e0ZDK(yiN(2cXp0yDAi(NNk||^_@1w` z^++S{op5tg*3p(tM^Y%W)JQRiSS~PeNPZ1W0f(vNG_aAUb6J?%r zsS)R({G*WS8-$cS}>sW2e5U??^gQeRYO3Suy!1yT>|^nl?an zB-^wRAisz6GsL%B55G%?Vv5*v;+mWkL~uVacvM0QB2rTy{UBOj2%gY?>!lk;Aix%B`aN##-AbnfmYbj zF1a!Ak;DXXYPd4({647C$}l$ca<6ZejlcwzF3qwBd!qH8^Q-2&dMpD1L9kD>cDOVbVR0Z)&H$oUv6IIVgFw4vW==hYoJGd+;l2%+IA_swCk-v&*Fj7c;Ee4h6ZG@OjM8&mr89Nk% zh&vxYE_~KGdpfkBVCLhRLvtopi4X2%V?|Jpc?vF5BMsXY3>X!bccmZ# zHNwe~V|@%Mq6eZ^-hcryRk&V+0>vje{x1_30Z|;cWFvUV5aBe4)|WvtO^iSFY+{`h zAwgqH@n7l4;7lYWT_^ahAH?6b?6DZwQxNWQH|M+*OXZu+VggOlA+$xy4P%e$n9-#2 zlsh75nAj8fismS<(}zKA_2OG!WOUswR1`yy7a-M5`iNPC^Gj!K6T{Xnbi&w z)w6cU4!QC+$U?-1LWCMre94O*y54&EqBFKboR4w>A{bO&5o0CrjREJ)UQ?l0+^(BK zNzA@+(?hjKFg|%xj5PxXXgnwQJ9`NP!#(6sbO05yeg)~E$~~UHgfEY(vQ>=9MgFxF zA#Hx68YMZ8c#RppiCZOZX(O&uV2=?6E1@#z5NHwgGvcsGj_>D;Ne!odyTm}W%Zs_k zj-WrC*q|U3AwsNz%u4!F+Jmh}rZ`=C5;(96;OBND_FDLSGW+4LU;AFt7wJOay2AXVHdB&zh-hNU>s!V~_HoxNk-w*y>c200`7Vc#ow1|W z{XOox&f1b!^Hz%R6bE|PJ5`S8HcKN?5A++{$Z+5~5f@(3M}e8k$vwm1pZ=)y)BV^g zolPR*1z1Vg-d|8559(;5nV&jT8h=xd>~||*z`dqot@&r9QHEUm+8OM3YT;SoBZtI4 zl$J)iZO|+eJb&*g&bl*>K=*w_2R-IF(i-V08Yz(IRvHe)Sg7QZf}NpCr8wt>bidIO zZuexkM0`uAotQDfcd!G<@mSv(xxQ;i+s%pidYxszuF{Bd?K8cu;g%wD9Tc7GSW$oe?l5QnJ%LA zLY(RMyh_do=K>gy+_sgclud0qny?mg#nK+4?jYl_zuT+NF=`&P9SMA3X*bK(7m`?_ z+CER-mmhyHIg>up^eXl$XDwtbv&SQz{**|9J=xC-DX~4#2e27%*p3V3b7ph&z_@B@_E=H$jQKlrS$oeq`nx1ZMqq>GeCV&l=Pyai0-^ zuF4?%l_{C z&*vB;Y{v0YVg@zsiNEwn+s+4~O)sllC0z45#c&?)(vaNa$+fT4hAcl0yFL58y#oy> z3Uq3lO=sTjot2!BHsd{PxyP#3niR|IitrV-D&0ky-<$6k&*N&ksk|uMTO>#l+6W7e z{&!ab=h+)IEA%wP4=Q4nueyU@jy7BtLHqnZXevRZAEAkb9r=h9_N8wO7bZw>i-+DD z#s~kR!tSSjXZPw0rR+_pRiI2R0@YfK#e~_}t=rQ^g8S!kACRMB80!!S!H<_aY?&-# zR(gprF}yMFN6Wh{?vB|a|8sQS@l^eP9Dkp4r@b;VuaOi*Q53l+Dh)-GO5BtZi8O5Y zsEkt4MAmK6q$QPc8&a7~%DPb~vg2C!{662`KRq4|;X3#8d5_oY`C`CC?3eRROybt( zQvGyVu0EUsVWH=qjVR;lm;oTo78>Rv)a1=JGzko(b!&|WFKUY|-M4bgYWxJu3n3uC z_S9?0*y98m)}G@dXNBkIL--$KHB9)4RG|*JVWc!%*q6yqOg|(!gP4Sl^F*7+dQGJu z`M*)h6?xKAH5NK(kfHJ-BL#2JN zYid4dBaCrK(~GjpU3wEGFJICa$QP{t`;6WO(NS(%`&6P0G}ek&*vG!*Zdh~<<_Ekq z;{20XH1)6t_$GMr9-(c}JnGLXC$FZGHcy;*B`x_e7dQ}6d^d)Zo z$rH(-=66AqrfBFoX|+kRBRFU;!x;t62Xz6cp&)E2u#fYag9rj4UoHK5Z1$?G;oiS- z;qtrH02e?cIf}bZRTQj4+WJx-FFKebKin(%?mfA&InD>hT9$JiA{Q-6VO?|eH+glk zRKL4y;p`C1`m<3TwGya;5pt0oqyl+Lm{xiO_M~otpA$ zXVNWf6yIxvKg8hs_ra%Ct5Oz;W%DmO&dyp!CxQ52jFVrmxpeTqHz!b~@woB1r(xVb z6U86CrN>4oz(BC}_(k%i(sz}&N6-tbL9ms9EkM^sms+kwFYkcbLi~)wOP4#_C0AI` zxJMdPFZeq?#ZK6!xXs_h1ou2}J#6ZaDmTIPW6I=pxU&JbV32B!r6`-w^v`Zbxg&Gt z(W|q8__UBvfN4DuCtB2Hv=;q*zY5>NOnoG0wVGC|0e9d3wMn0^#5pYW`BbKqtHq!N znLl#-07$`GOmH;EbRI(>e7=CcSBmWn0=EeU2E{0;6C>p_K*Z*VH?9OlIWso#yX6S8 zVn+73edHyO` zq42a9rC2KMDagMfb?h8lw1gbt{;p|c;er4RN7u;0ozhS_596_UPJPsrAusO0*ZY6d z{nX9xxq;B@FU?dNrOa3q;0AVzz`Kw7Xi-r>Q0WKiz~wZz8+(N*rcfjeHV^hmW@F?w zqnK@pJ>SDp50S~}kqu>tvZbIBZybK@A_WWmYU3vlZM%f}H@#rErXXB9jeKH)EeGTr zHFUWwpDf8fL>@48XNH#B155+6dn)8gG`NUFFFzJkwn1155Q%m~rk^ljMI3fr(z3>P z8rQ4U2wLbiXBYyc2WhJbovFQjw!S94bkeb(@+e*bJVSCh_>J#IpyuJ8FYjXPbZ*ci zpmr`uVcn+bx=?v0LLpF@)Cu7I_lejDxmH~CyQ3OWP3 zTB^I|v*1OjSX+)A#M>C~iiyL*art(06$l@29J(4H4~6S)U%XyCqh@b}hPmRpZ$0NK zyBrrrpHK-OeazjWfG7JOr2k&9KJ;XrVw3M51x%pjxfKD6Uqt?)?Yc_)eR|U}g*AtU z{&`KqWQTI{JiB}s&1eao)s%*?X755+=d5{f@102JC z;*HM-J_rJ~2h%2_lp$#4A2jo8{k7}lv{#=ORU*}ftRQLqWXkRpTe5DlS|w5Mbx;3j zoTE~2Oe;4MD$f`r$qkPbBz85-b5Jv=DMLPt8VwW zgNn#GI~SW;Ev*j;$C(1U&}Ajwr;oJ!_dW-aUW`(i&1J2s4svVhHup3^O4RB!`TMi7 zJ~_*MEox$FJx7*8HHS*1xRHCy&lr|x*%Z-xvW4#vFGm!!4ibt1g-P1rf<-TM79s0` z)q+hS-QKVTtqKcQsbC)tita59`CA`78zqYurX$;C1Apc@a(hp_Gg74-p9wCxI05x5 zp#Fw3OmI(@137C0sM#B4lI<5#?kn|`Fl4d5W$W>T1wbcD(LxEE5V7u0<*41?QAm|p zmy{d9g`Pb~btw4~zk%hdyFJzG&;}bR(y2%bj=iU?wuxkbFbZI=GGv*r z#``3C_6I4$GvL4!#<1ZQ8q_Y=;W#7n4L$MMo|fn3$W>Hy$&hX)4eiZx47)YXH0a~a z)5PmnNeO}1-1zJnfeun#dEhV>otDnf$%l? z!{92^zsgLbw7v~K`S&A>P6 z3X445J(;L(zdB;*1B3Nwv=oGa!Csr3|NB|qJm1ug5h@+CuHLJ%D^dXWfNakrx7$X5 zlebY$h>^-dKYh4!6F{ClO`Bj@#E;H zDac4CF5#{yYuRd75bt3?%Hi!z6Z~$G#=?0)fqvrb@%2OehFYqI4O zR>+2rlckPj2pEA25ZocoWl3}v3iC3{J53m4NWX&P8@xnzK`=Ka^K2^tBE-18XX7m217PB?O4*UIHu9CS1rgU}+yw^=7+x);K>9^CV1G85HG zFu||HM0NrbaOZLw`BP9xb`A(HJP(7wR4Qk+8ul^+S2Wut6N;W#1eys&kHA|?JWvrr zhgXM2izRw85ZO!4fcx@_i91Lq<9X!dxV#NRv_cN!wQa@L(Zoy#@b;t$exL55D`wh` zY?~&)$-&Vj$3jKT=WpnfxeFTg^$`}9EmHD*G#K<{ncmCJyG!>L+*;}x+stb_JuKc62vBuvjLofYUpifkqU_3(yB|3TPX4%#`4O0Bp zBt73_&ncWONMn;~gck=y?s7*W9F0FW_M_ zey?rqsz}2VnmIVl!i{b-KKy0Sn1$VQ9noXrYcObsx$^l}qKzKKA667K!1?+|byRal z4bRdEdyAdA$mCp&p0pDvC#v9;Cr7TGKBLwAWu#(JaLmKucXNqF`?9}%HC824Y3|AC zW*<$G$GDT+R;0?xC^L`#=t6higl9e3N5p{DyWUI-riPQHqR`gOewP|JMhIan+*5Vu zfgNnR1x;Yy^zH+xUNw8QvT(PyBJYTOQ&izA1I1$oLM^tXD=t)cJ+I`1Lga}ftCxWN zgyeB#_zWo$Eld=pcv{+xmywBSL?Ljx)FeCpsQ)ojkQpqy}%oI z+m03EgkFW}ll5#upU6BgSBkS78V++U^)`crjVN|7t zy)H_G8FIREIw%Gtz&eHy#Y`Y1GDnK^(D9irLLnL2!0YpI3{3bB0fsEi z{f1*yX+anou-^L;Jrw_+EnEX~7a&TQ>|%A?^&7{|RvfNJV?RBz78k7#Q}96oEzL#w z0}5L}FKV#Lnm^H=j+*iI5DboU$U!RNErNA&up2O@NNN;R;ze3-jG&P>(tUX(XZxql z$}jXaSx263qWZ5zWVv7oyC>INEx^__7q+3xyE{h(izWr@q zF4ddAJ;;fRL2smT*|E&9-*V(oX*AQ|K^k_RO4?_H+yUTc9dhu7TFde3(@8CZ;;fFq zwPjw)l6;jb;02hwuIR2$)xCGJo9N(0S3ENEXn|j_V2TJMo^1H>_sd@?IdIv1BD)=X zvntGn_qk^kozQhV@QrF6e|j7g4|gm#6s6Jxo7sM+UTB@Zwl(_R&*YpOthZuz4&=aUq34E=~j4Xxzpsf8JrLe9}ZI6t?{*WbaND+o`(As zwYEO~?lY3pqe8E*G7}zJ3GoI<#$_a<*puyN-!&@V7WZC~-R<#2o1Y_R>gPWiuZ21+ zbV4)10q)5Qr+xo++7ZV1O(#a1BiG_Q!n@(w?sl5h;lD@5GfT(co_^KzA9q{QfKzqf!%MgkQClF2}wW7lTj!awuxD6vxnW`yaM#gvE4iFw_(p7TyFDhGJuo45TeasDc@r!G`?clbami!-06i zeU-`^6f;V$GV^pc6tdd3RKNlm#5wrOJgF$0IaKIw7jiM-iGP~#RAA4>lbF#u_%dua zB>Z#fMdUNSw_`7f5q_alqR+4K#5gT9M_sQuJ6R{M9W>^w5v`5XE6CfITa{zYWSb2A zbUF`y4|SS4Z7Vz%S)gF6nZy*mH*5K69@yGr4sKmjUn@wzUC^Va+=naAI96H(TbEiwYT{cY{{X0HX!;Pi)SWeUMB z+jbN19_-3 zCs1XY=PqB72^J|&o*IDrDDvzU+A;_XOiy8*h3%e?6*2a&u&8Vjmm&Oo zWG2WnKPc6W34|hQ&Z7>?RkS|3$b9VnVIWRnJzi|ld#M25w@JGtEp2j`fXnawI8MN- zi+3EiHl0E`f6!ub-ZT?IKU|$D9Vy6L<9{KO`;2 zTf$EFph-ZYI9i=me|0}PD|Fi*P65=Qd(|x@G=B0Mv(SFb3hq?>ZCmzGrCSZDR4Aot zEl7R(@ZQP%Ic8S9)R|ZP=-y3|V>G{7p`JJctGp$1yJ0iabvG_ttbhn{{z&zuX;JsY zWFzDcaVEw%=~#{vMR7{kL-+G#C44PcN+)V%?%|#ez4Sq!;Sk_q25*%dhTG? zSh95&m~d(yA|I7&LFI}BXczA((Qw@+70VxSwpYG_ESa?qkSq3|hT3Kh4%MytQi{3d z<VzDh*l` zmVb#Zb^FdDz80?DQ5viZ>fin?(+(QPLERV=d2fKim~ppBsz^*30Uf~<&~t0mE_rd? z+k}IpjG}?N!$}J9-v}GS=??S2m{mf3C_E`~sN<&LK?`tVdK|V}CbL^PQeRm(u1qKQ z%p#EW5*6pNWVtft>Nrg}TKiE$?Kwsd&u6nRff_)??90;m@@O;$r@5ijllmd!or8LY zKqxwmHCKJrEVO-%hIBe=2JDYt?M{g(y+Q zsUYA0^wn5`@bP#-!0usg6Cz$Y>`qnI0!K=U)V%WNSA?|XI_f`8Yl^1vID;XC96O5}X%fV5ESt2D7@%!<%O z7tCiW0z`=n@Qg$MYv^#N-dbEd9KDdMCAHUpL`2&2=#L|e{@e4*;WmJ%ooHwK{@*7+ zHp{o8$Et$VI&x^_<_O*I<80?;IF1e54b*z?!svg$0`DFMZpS!YQcp)Nf74n<2aEm4 zNh_Lbeyza{u9d%b*IzCJ$*b$0xNR&~3sgqBC}Jj$L!OD*vSf7dacA4n0OO;*7mBL? zIW`lf&%|e7OLhMI{Kwa8t$Ekstkhcz_{fspRv$I;Gom-sZ-(Hy#hv;OCw?CBpf);}v)aqvB#c z`zm^_6j>!vO+}k8DAc{A%oUW#UsphgR8pMtSkXOXM-W9|i^_#@iD8OA4SW;2P1%~QZ;CyuAgP{sFM z$+JgOxh2Pu;e+YBdm|o{Mpq6+$FAoM957L57k5mJEke5!S*&P$qzsVY>m>WNH*gli zQyT1h$^aM%Obe?IPxGqUBMyI&m$TBNB=6sdwxD;#2jStzqd}Pn-mWDl(fe-|6tZbS zX<=K4H6}=taHrxN@#g?kRb9ed{gA_fdX@J?4#i@B|FwOA?uDD<8Y8!hvF~wArv?*T zcK%KRnvy5xjHeujb)C~kC$H9@mY1Ke`VGaHqu7(rQ$rDJWv8v}78_jS-I3V+{k@^P z_?^a)1M4#`-XbCoY4^?^I+fs)x-C@t06xb&mz;7$674}*pOlXO+#!I2$N|n(J~DaB zX;{am-tL>YhDK&yae8|F>6`zu5c6*~^Iq;x#|cDexglvWMeA#sb11`W->Yp`(Y<;A zhvjY=ez!3;Vsy>9jSJ^@D{(fkQVlbQI;lmF+pq2NB&l5~Wya5jAH7RaoNoXDGn|iIEDw6V#4JAD(CAr`SudNmU?PWbTkNlOgrw0{&k-rW(b|z ztlbyf9!68`u!+)hlTAxF@yy`U?FbZf6jxsi`ziHTk0qlIcmKZSB2Y+1&Vsih!yixX zs*q!RT*$aJVSovol9thzER)d`9@3~5xl3_g!@Z1Hbm&j79gRrsQIOZrGd&hbm{2>M zS#+kT(<~uo$N2V>xFVeWLf&U3Ut+`bdOC5kL1CZ86s4l#uQN;#en>)fm-T!9otr;x z3Mj(fwtcD7K_^^6?{w6=pDdc4zG`H;nqkJg=Z6>Ei76&8whf>Xasxs<3%CDe`hrl- zIVsZGGtgck|B<>t`0jE*LwyOU<_MHDh@Y-UsVzId>U=*Pau!KKwK+eSIhL=x_!TJR zEhGvYrg1JOu=H8rh${W%c+r8LaNn#`4|Sg+91r3Mgj&6U5-If66F^K*Ew!VAy57J) z`mZJW0}yN>@^$wg?C|(qq$`8DOA9NcVckHELf^NUsK?oBkeqeFaKtin3vaQPzdj%l z?}ra{ivej6Pt|PIAglCG%5YXr^5}qpjg^IfP##zP~y74&q(wHZ%4;$Qm zv=%+FKDDm|WdlVYE0%meQ8`!BqxH3Q)!G}9gNF~kdbZGV z>AT4*E$Z3#?(q^XQ2E}ABO|PprTjjnoze;Vw>uYGz6iY5r~AjO_{tf?wmg4X%e^VB zQJv|qe{o1OPr!}1c!0Hb#`z8n!!;)E1yj+sO`yK%>0z~%o|#VqFP<66pbar@U=P$p zYHP72D9enzNVC|chr0O6``@5{{{l5WDkQfgU>4S{e#kJoS5q<5pk8<#gbk(;kbFl{8W1NB&7+CqF5cvN(0Fo_r-<5y8)qUG39A;Oyp<{%`S;`B zaZkc8`}R~p&-Cg8zc8|nx`ftcq}fExL8@(ta_;2v+f-&kifG&KcXvZd5-~9cMW|e% z2erQ0T`9c*2k@ozszz0Cn@RZv4&B|VK=E9(fIS3>qh2(&jn4gL1u*W!jT`(aDwuswwrq zTPmGSYNhOCi+q|7E)!_#hNjJ${P9_34wTgTgWZpFs3KAUal6G%urU4U#6@G@%YHg! z9=&ff9D$lJNO(n}{!UXA_(L+(6p>yQVx(L8S%K!l;^;P4GD<4$2%neN zd`kb6?S+G{is-)XTFC)@y`a5C3SHGD&T2QGZ@E^kzLo}9?)Ep?Cz;Zx?S4=#Plxmo zU4hi{`Y$%C!_n6vmS5uht=-I0ZtTRr^Qen_gjVIsm?54Je|;qW_;@_USIP=5Kl`ie zdc}7?o5?L;dVys9M(h!C`{ezp`9&TMU4tlUk_BCfK zlX~o(%HWO4I<_+DM=hMfJ|Xm?nk6622z5MkYO}WW-VIo7ca-!{9K+n@E^P@-uL>6) zDow=R7V>R>D*SjDrN-N!pn;Ps=wxfPbt!eKBP-9fH>Vi#iFrw1U}!QT-vW35S1AR$ z2+261?%eD~)3ls6pU z+Nz?f7UL~4g~~rSWbxsiY^ZhjO57v#cWqDEZB5C2?6Pi=>T*FOysoOg`$Z?^GJN&k z8m>(J>nKA+=DjGjz9!w|0HeoiWj4KmsaUOfn?=jyNWRN+OJAwVx*rR|UjO?rM?l+# zZ~qK)yY1rgviCA)L@zB_-A9#W3~5vws&kHp34yd5;%B-RDoyl%Ic=4xaPpLIU}7+L zvKS|8FvaJw--)!Y+0*Uc-`d}X&bOgRIhmKN>e#x28K2xHF%-U0vKi+J6Xq&C~lkcWrV+cl5$xUrla>1_C z?a`s72rgZI2B#r)p}T(Nn05x;KhggEnYH((L8z4@XX{Q4jqU4rEs^f1uyV zwI0z;GdzldfE-z+N?NFi3+;?G34q^Nq%H_ExC>OTpzc=VyRtw9>B6kRVaq1dAwGt_=27tV*BS2aAiOg+WK@0+)xfuo`&BuH}{1=gYcF z;i3R3xo9m^hBIbR(;;`ev{0q*bRTuV^z|PRb#wD9g~K@}F!EecXv_dbWJVhzr6PI@1%N&x?RHxL8XZt%4uHlYQxmQ45;vtS|j3PoIysZ?>0LcEv5e z5nIIXAD7&w<(nbllMzM^&&5PO7}-MYS{@U55qLc=t1w4HyS>ArH?d>f`2(SJvUrI4 z&PK$)c~Y4BRMG_WqdX!D2S414&9mwWIh|con`L^7{<*g8)6mT9T|F%+>YA#Z&4c5* zFFLNQ&=ueac2VD~3i+3&k{T?liYru+ULSDgkVjQ-Ykj1tq<*tryTqG64-{G_t3cFH>-T^?oVa&aU#}g^6pMm&NHyRN@cGP8Nbv}M@M`b zvJPW|CnnNVB9}+@UCcs;7po5rU+rc4!VX}cM{FOeuPLCLAl>+HjMH8I+hfHPo9)h$wO%5U{`87+RuJgmv92~2YDDv7v55#EUH`<9FmXZx8l*!j<27gw1`G0GFv>2Xv zdO+ju{=;UAZ$#v8HoeB=#g0+Gm?-KHzAj~m7z)se3J*bb%QrXWwlH5Nlv~O1K2nZ2 zk1h1Ulp){A6eD$VX$c^jiJg@e`XeFiEja9eg{`=SQsQz@yrT)YTt1HOJKNq!-+h*) z(%CJ1m%hml6sk9#l$y)|T*#LKQ7{~;_+^emHbaBMsp>4-|-8JZJ~zF+V%&m8Eg9&BH3AU||BRwmyIP@1ja-aK-vr0NgA@ zM85!5Qu$XrrjcO;8TPR5)5vrN_+%_%y|0_{X=&Pr`4MsxrRT>wlsZu1ws!_xvt7(e z69o^Nsl9yS=;F1O4eH`OalOxN=j!+04w=G;8=ZI@Ez3BsMAFI6If$IOinn*%vMCvi z6nM!%1ZiA5B~lGODThms?lq;8Jr$umcZ_GZsNS@W+Vd5zsDF5?crws+uf~x)a<$r| zwG0-D5ffa-90qyG_wu=uH_l80Ucucji~WCc@34_BbqVyvfD`kwVKQo%0Ww?ThC8YK zn_A_i4(!05-umcUh!g3{%<|_dT{*kyloajgo=TT3M?H{6^xv0LRZqU2zug#Yyv1Z+igwXVWR?nK5eD@CtdWnyXB5aJg;{^`u= zUQqRBI838QeEn=R|I&S7dtX?}JU1qwV_#hsq~kz;B5#b_xJd0Q?jh#j z@RNYW^xBJHF^zPb+uwfIV(M~Dtk0ccCF zfL#5I#h75!jA;5^b-jK1Ib^{o?}&<#CMxmQaYlU)f82KC4<}tm{%YYWIIbZ~jMFL# zh(~nmx)<}PRrNvgoIs}y7;h>tNL#mR|BL=vN4=gXl5Viqm;<7%{C`f!Sx6Ts_E}SU z{*>mlLs2;quLcK7>Ymj#8$ZIHX?eWc8l^9qVfF6d>-C0m`0t}ToKJp8m?dR$PBFVZ-;yu$rre2s9IM7qU7{Q>87E>dIdx?yoG}atY7( zIr9z?>i{P=VpsZNGs%P0^S*;_!2^20>#)KLcSoK-M?M;;sir=BbV;gF@UoI|ii;+P zxEA4ODEAw{3p1R^{;_zI+^N$UzotgJ?a;l^xK^9!e}WPE<#ygR$L2VUY_@P%up4S^ z_uj<1>DoHW-qrg`G#sG5&+8-UCABPzcl46f%%_!es-Bz0$ZC799=aaQoQ8tD(7)nkY#5GIBc zS9OB2LEAp*DhLf87|H|i(9A{0UWF2L8fkykaX`y(9-ZeConn7feAXLEt?0x8`(^!> zOcA|Lmrd>-NM*?8)))>X*>0Nbh{4zc{Z!de^?@k1v}{qfY>z4)bcm}c)SevlQgV!( z$2tFpCKeq4Vcr)Tu~v! zhLP9nw(DCA@%LW7y5gpRFjrc%8ucyk79Q~H(p#GE`x>%E)A>vBO4W5%Sylsv~ac5HpcA4n5Xf-@k1)ajK7*$%Qjo1;LP+DHbwA8ROX~lvZ@6TNSb`R21e|%s^Cj~Pd%hpvn8ePw{Gj=eT6UC{5lKGsy!7Q+mTN4?Z2VY zkRcN)YO0-!8<8vsngT(4b3NA9v>2T|?L%jVe~@PXQ&YzC+Y&av6Kl+lw2NapkZ9UN ziva{XjC$H_;d)hzc6=*(l&a?S@8;=j_hMmN2A$z;URjeF!p1JLIl6Vthap~l3B{ylK*se$%8o0)z1Pv)kv@aShrI9nKz||-f`m+?&0d!*SyI$y~ zQ70c$XMtzDO+~&|6^T|%cj2x3$wQVjqKF+D{#kF#a2qszIOo@r7k!USR`0JtO8tL7 z%A&`p6&aFO6!&Rm2KBC@w4gRj852DGNZmwChXB+-FD!9DG755^If`!}Pq8g=r#6uxqIaeU%o3uzDwH$uxMvXQ#%0a|24B3AHJomxFJh`-4?EV98Z`qRrSPliAdy7lUk(b~f9 zqy``v7c7O>*m3#d(a)y?g5Kn0N0)VHmfX>VXC+O_={dU5%|nfdk|Gv4DnyUGVCjYR zy+BB=o~IpId`X!)U(%k=jgmZNm5xjQ<8UQOl(?lx)?(-AMvDZ!wiWPL_Lu>244s19 zuwTy=iVMP2X!@*?rW>)L%`768O|FsjyP`V`y-U9^c>wurN?BDaQ zoQkpBu=gX+&$LN(8}HMST}=XMg(u7o;wkKxPOQ5R%^l# z8umT}XpkPN@XF9#x>L6$;LamVpSV^Jg8I6|A+VvJ)9jAJdOiPvp z__Vcs+q74mkQ0TLfq-w|_Vz-IlIi!#{;g{j;FM4Q`pe#j?P>6PHhlFG>EF97BlP5l zRlHH}bBn7VTB(3tTmQD-n6x+@&w49GI5ovS!Ew>nW9$2c=t?CZLTp`P0N%5C$i03VpYI?z>#I!6W^KDf8~SZ!-l~72)2ZrQfb_SaAOAYb6M? z-?vep%-b{5LK#+vB*piY{<;{H@Hg9fPu4#ESqa)>DHBte?1HRdiHSsSlsjGWMwupd zT$KJza?@lWukIEm@&GhotCUoU(!O!apVVZ&DT>VancXU$(8q+=&wZ`ky>cncc3X|- z&kz=T(t6>RGyVx`R>%}dX^^L~Ijcd`sbz3KkSPS7Wh*Hv+ z$ljwwq({`;lqco@N0@ft;`3BBTH#3%R}BjqSewe}{LI@%SQ87UcO(u z)#Fp`w@Y4oePAU$R1q9}Gsllu8yb+$uRl~2hcFB_R>G)`_(Nbvv;7! zH+}f~ic(E%zq^(JR8`5zAoW$jy4=8$qRbVrLJ8hL)>CUhMxGM%rfnZD>Nw|Eq#HiG zEJJ6fEC^n*neyKZZ_;H=$HW9|!t(xe5l{N~dF&6dmDbL8j zb+s>O*84^j$?Tt~KhZkvjPFGRT`%SxW61SWPQDI3PiDifzZ==);Nimgj*`$XU3lvz zd%NLpgc$S&-*y;miexoDome%gv@i9CXz!J2aX9?(WoY+&a8nNjy_QVOXcv@VATid#{3e47a&B)!`kdEDiIKzI;U0%#=o- z5`KDd*&U3ypK6W@^7+cUep6}QraW>o;gtW^qeeD^J>KY3zb(2L^J1>>7*;~QghbhH zk0J4CIykU-J~J&Ff2G3}eB$Su-Jd4E)eSGim;Cvv59Bi}ttanlQl7&`vfFD9V;e`? zP$+aVu~PwIKON5InK@7LoWXsg_49qBO%;B374qZ!u{;OhU7Y=}l9EH>@$(beE5j*w z*Vr9^Oi<)3s7Nj7|Hdy|p+8hJ?ks5bey=6U$yc&0z@&oZRn$S%ZZ6rjuQR`0cdwmdG9eJ*eGP&udmyh0@OPDa=JzN9P z2o9g|482(_P{bnT5P%6zM_O27#CAnq0+`iL|Kx^{S6@(#mp>mcaEU7sR|WQb9}aC~ z5>RVK_C}{D!93h~DLQf#et0K&^8daIXqayw-L}4EG_luypmES#GSR`M%GGan=v^zR zcsNnV2`}0>O>y=7(t_WYSATXa+>zWopc*)^x@e@f*u!avjf>-(#pC=T15hG5r)D58 zmO9dm;!;pFFxhMWC~fEBM}=V#HY|C%Vs}d$KQpFT{qIM%t%R?0ihdzDD={`n?LfybDpxn7QeMtyy3Exb?vwuD z>em3O2bfT-61&|De|vd-&}vf3Nw=j=>5OT{^p74=c zUuL5m4Eu!?J12qSN9seWgLJ9GqKPvN*#0-AA5keco8f+ZBQr={I@LH(KKGQ{fs_ivB_YKF-;Mrja_T)_C>KUN^NJ z_FsY_K^ZPm@#$Nl;o?|-c}M5noFCM=lc)OPtD$t{Op`EAwo-&I$$ zCI`s72p-d4y73yYZ|mc=cMdxkDGiG)L>ds(XGI*8)T}ZZKW5*nPyTn`xXO29Ffm?w z4qPWFTQy8lF*^8baL2DH@Do6rwpaZLf5zB;d#Pk4NZ6q`JZpmzoHY#Md#qC;8M$b; z)p*!x^#exKui;ZkWlB)UeF*An}(N%^q`>mOrD zcHSznUJbH;uTpJH&9K9R{&_DZ7h^I2m7lrKr?UQ#FJ2Uje=7up2lW0hq<$fktMkT5 zG*!n$u?O`~cZ}pIlmc3%vLjcW#KQ+~&N5w3C*nI))t{j(Cs9lt>smRyqxK)9oFsZF zy^$SptWCzyx7v+Ob)C_&zS}HUs)=AZ`SBaX@844T5yvbyB$rierB6==a+@rWTc64b znBIFvGLu(ADBADVfnfJNs|_N0^tISk7DKwZcj;8!9sZ?~YwFK5r9kD?whS711e-6l zbvjysZKEHTjTirOnH#B~r%~;FqlQ&Vutk%oq#oHEdF_G>dE)wq59?}}*Cy87|Gt}J z8(xy!%ROucLiYvMJe{|VQ*5%99>><>dnHcKd8g;W^~l2q3zNOhc|E*QKEYp&-QUfG z@Uh=im*w5!+a237_u*5(dCm)U4H*vXZJ3FAxkcx1hhf4E{n01{^?Q|`Exi7CTN7K7 z+@}ma%*xHk-T-$lg;d!Al$oDt-;|h;jFbB|Dr{kscUrxE9bol692Mv?7o-=*{Y#kG zF`jO52i zJSfza;5KiTg5o9W*2I5Su)JTXQ?ZF3C-qkNLA5(Wc%E0rrnbh5-nAv%G(^q7vdtw+ z!F~-5%(w5p*MUHCFxes{TBIzzPQV|AtPiBTBEYA`JPJP=H=?knef&;vib{+eLqm>O z#7U%~)Ys_Wbb+04nlZMwFbN+M7ie}*?_aOCgCU$+iR14h@!xKeRQ0GC$2({kiR7e5 zHy@_u?Fn#i{HOqLr)a4?d6GA0(5q2sTWGV?u%!;q3D`D%=r)zTr6T(8EYnT-bO?6$ zq4QSIVf&q+1Te~xB(*YcPUHMx-U;S+vI;-N=O8u-w%&hah(8d4mV%@VHixCC4+ti} zJpoHTP@(#Q3QPIlY+>_mSGw>erKV7bXKlb7a%sn? zhf1!{XPJjjK?_EUztrwL?s$N>mX?G;NmQ?K#=|yin}eN-(Wj1%qx_Ja-(`ynHZzl2 z{(RfrFW-V=X71#Zk-ud!vWne?AktApMRDKjm`Nu|S7Kl>?F@Riii@yphOi?vWmbIm z%+QWmAl#Z@XVKl)o*q~to@j9C4ITY;AqE=TFQB>apau)oV*~C@VRY2A?W2YB3V@9A z!GII^>p+ zmAcRV8Ie>== z#B`;bY~R$Miz3NQLE~nAl|pi|7wz8=4&ha(oOAzFW3ssGQbG5nyt>utc+i(e+n`9F zmcPI2t9o~D;Ba?n@=4$vgT}<$vi48Q<@EaN?Q{ug_L6;#I*;-COeXvAkM2;_8z7GV zWJ>Rw+yTi5Hw=R*9Yw7)5wZ@ z&t)E8f8q`hMIPjP>g#aO=z+gO#T1&T&BI(hx&`%qJ>{^J)Lj~K_CA6SFXwy95}Z25 zx0$Uop>HQahsEoYUR7Z9Tg8(u3i!m-NiW-fW9PBAitK}9HH$%9N-vtQX{B=bQQHTe zoIB@?@m`;%krR4e$xQN-y=-#MaPmfsH>4LMtRDF?m4l1RSRC@^-xmiv&oRM~=vlF0 z{NKMT!+PZtiZxV3GP;TCQ-!hvY*zxN8CJ)@OEY+c-%=rW{#Y&1+o94|-eLbLCzW0( z%aB!Mi)1j9i9n$|YT+K7+YCZ)AZl9I0O9C=|Iq#e{-$TK%01TB2Va(5@U#ZsNxy)o zqToqnfj2;LU_#0fZ3D=q8 z`xs?yp94%rM2kW^{HGNKA|9iVD!UjF)5*Aj^!T}T&_zc=e)TZj!^r`g}Ql)Nvg z6H!PFxKr=t)<|@mREcO4H@s=Lw}~o7><^gN^9GxbjwektHQeA&1X6!9LxNuF9cCSi zp@k|31OI9(p9KtaktDEm@T-gGz#f}5aBFbt)zAP=Wcqkd6s+iR(}n|&lS1)lx;rhsMOp(UFcyT_772K)Rs{>=zge22s7Syl$b9+ZLD{8x=c7CXRY%3Jnc>B zJL=)L?(W@GmQza1fX#>ar0J*a2YvcKrkr$;0L8Y)krkp%3O6-3nd9CgtoPB;fxAz4 zyu7i@#S-||iH-^N9vZfv+P0{^{@RXOnE2<$R+UUrC3v`lJa4Hj4m%jSgAd4u&RR!q zE-msZRL`350e(G0ATqfvi9a!F_JQAZS-uaY@@1XfvmTXw6?}=vy{s5>tn^`u)(`g_ znS7%_eimC*yGsgODyqNQ;-r5tX?*>)aWU_&F*2jD$FE-;SvXnN0AwEn!l>6P|3zH@ zUyWlk>GXmc4v}comZMgu(49|s-Ew+(CtX@3Pi?@6Ez?Y}Qesc)ACA!KJZNk6h?=au z((xcXii&KLcIgFJ^f`GgYp?Km$`{TM6&gIWX>QwI5mhn!C1P`PmVq9u0fAI(2A%Nx zZH(m`@suYsCyxKx(8Gv_%}mwh;vU20Cu%Z0pEVZ z{HQWS>Eb`#ZmR}Njc<X3LPoUo14f$OqSYF^AQwl3wCe==%8o!;6b-rIp!;8;$;aKk{olqWe6G=$ zbT%M&`8o(r>YA~Q^Guv6oBUd&L(HfG`Pl5Q<#XzdhSQji&2h{s>1Sn)wHPNYv9f>J zbk+GF`w0GO=^UClAtyMLyTKFP7Qqpe#sg~P$T?-SZ1sTR*{}5%Kfov)A6a+>H_WV}6m&o(hhjS7}Vy0;3vR~}= z{hrHfiQ$=Cvj4x7CE@GDR86|jaGy7kxM4wI?Ils6o&>lNw`0$woYCt&JQUI2Bjn2J zgXF7}#apAK`#gWQ0Ul9Cy}Wy3c(2o7CpygxREH)E6S48U@@y`1X=Z@>`9O2eRJIj*X8opUX+af{(UocEbz&&>4fUY2@zA->Yx() zj#F>dyN=q8VsHRp#hh$J?!R12R9=vWp&s`cakqPo_AR+=&wnG0rQIP9g0wV%2$wfq(vh&2B zG_N@G1Q#*BJ)BgnOTS1)AmjN<{tlbCrIZSfjTwru?u_rWh#QXB4XU5yD$#x>SJLKS zE(LsGNHD~;17sx<4>WHX#S)?s2R1x(UsgLV9e*!9!0k{~M%%Ec=oV7TAAI%ni*E zgd#8n=)#NYwTn{Lsc;I8?ltjZL+y8*15a)EGD}@jNzLhxV z6$qY!&BRT_q+5vGuPRc@x{nCwx!;$i!`+l}s8wHw&T(bkH z?(e)rzFUOD&qeTV;cgT59Bk3Wen_1|gq9g#T!uhGIQ#dCHR=BR_IW>$d?y(Ak=s?w z*i&Ws)@fTG!3!HHGku&3bx%w8SYzA;7(d#qUetgB6gIRk7DJ6apUTn$sY{ivu}@?{ z8z&|^#S-s3+p_E7yR_{MVuE2n!AvFT6J-G~vHi^lQQPsDsn2^e zBfotc3{k|QG$4PH)McR!{WEIKh&~48f_WI>1l%DyvJ@a~N@amq-fx-TmppUye{XCH zsAMxyP20@h+RUQQk(Z4IWQTC`?Dm1HMULV;M!UqBh(&6Pgl7<61Sfto2^JxGu(#MA zhk1RpZx#(=1I>9R3~IwT{vrKv$-a{NwR;=lGk?teH2v8&M=r!vrcX;fECooZQ__%~ zJf4WQprCMjfAP%xrfqu;zkkx?S#k;l)-b5YnX)bT+xWCubc#;Gfgbsqp!xGkYQH=y zoHVlqCb=r+IL>N$b^G3x0H0axlvK-W-kO~28@(K;#Q7R9a=vQolN4Qi{cYFfWi{9_`q6=)KB=ysB^P({)$pLWcGB9^Us~kHk{Fs?^9P3BYl`S^54tPIp5j z!89yd&B7WxDJdG>t=+W0EB%i1Ox&xipQ03}_7@ko)AVpb=YHgsB``9?K|7=$SniXK zai9r*45-x0qII7J%AOhGEa#aSVHtBe{_i3MQWr9#ha{eh>K~ZAp*GS@Uw(Ruu*iLJ zK>ANVvWKi#xJEONzdUK}0Q(tBYu3xq@;AnGt$;Zzy8e?)wI;0N($Z*GaI2-w={=Q; z+0C|uMy&m27!6ov*LnM67f!xy^I!^mPE$o~8Xu)JXX{_AWy(lm z$X1FD1%(QrY~pX?8@PYvLld2Xw)!4)o1v-F+d_4C=S(C2SRzMuWcEyLc_BsGLk?bV z!=@p=IDZ=_19uvCyRf3LlGcuhYo;O(Dpm?7{W(=2?o^t;0Cdhf55MX6~D8Yr8AzKh)i2 zK9fkbP2YN7{Z!{aKv3WpISt^5d(g8LqSkB`y+@&U(F_QF*&+-1Je)HN_ekn5>L2)@ znd~u8-5SxEte=Rc%zrlUrcC#Wha61papYhXioEG@+oOX|#l2#`M@~By+qz;d9TYE4 z5A~Zyg}fd5)c7nACjvCIkoILGooMl~ob-}&za%<$b^8zP1IH#VeZT$3Yp!ry8RZr2 zm0pW|8`{?wsrTN=lQ2mb*PP|~{e*SAGzex@gBv}Vha@fG>m|Wn3Ib6@^elSv)l{JQ zQrBP2FVbq3ow+G$OPIJoPUX^%HR&%RJvb6iftl5*@WKUk|0{6S7f+(w2UQDc<9mwJ ziVoKUdHkfvTbQ)NyTG5G`pRi)(FZv&z4W&wc%*XtyX6v+jjv&@JZNaDnQ3Vg6H^fJ z#{mg7=ZekwPny*xYjy^?9_7E1JH$J%CCn?=CludPk|-IVreS!6w&I+ms)~zBBlfUm zLsGa5YAOkn(t(lrYyk2(;-IRDz4lA@OiyV#G<-DyY_yYp3M0SFcsWGx5*s)MZOSgR zc|dHHr4ti>GSfXopDSmRN6tAxhj;vId8_)HOn%E)2rlR|A<20%k%Ouy*L@@ z*sTg`4dO}{du&~=%*2p`;*Uc%^89TZJ9rIC%kQ>QT8xNLw?kt4!(*qo_QPQ!5(GDSOtPhvryn!!bJ+SEW>nQs&R3e1a==mHItY-K~G(`mSa} z)jwsD;2a0W;=u`O;iH(x3Ce^g5mb21_S9&i1?hDuAP!U)6UDLLv*%#tC zcwj^%$5M7IRwypMr2pgeD>!El>T_~!I0*<*L;RS2q?hC1oSaOFMEmp47TbNwRJRgktZr}mC{|5QQNh@r#R#zwEAT{wRTN)WY{!E*Cz8&;|T zf$yi;0t1`Xe68z~rjmv`#hCO6HxxKK+hF>IMBOP6&T_|A-XvBbA2O8s04}JZLd*r1 z{omz)bX=1NcTgOd4Tpw6AdFluHKtAUI2_oD@J2X<>EWai2Q48=7cp$te1h%E_0mjm zQi(ng9rnpbQw~8MygLv!Mukq;I#ZcP`~IhKVlo zaYwz5c9(ST6!!F{3jty<5wA$EGe=dLR?&hN zqi1^iE+(h(5@5e8u%@ZCQx2}%_YXc8y<#7jf9rkpYEhZg<54a(Z}3Xl(mRfZoy<~) zh`gWKZ@(UvQXfIh;H%Q|YV#jU+T}}|c5xP-d_S~AYbLG|h>!mLM^~+sU3X?ttlasd zjk^P|RDew%2k-q)`cI2n!qHQ`)4E*F!>otfsavOPK7=RddZc-$a}ETC?e@1a`?y{E z-mo1^wLH2bBZmzLbsWI+$j_r2f?6MVf~Ncg^cOhYsV048D+{ugsj(K zvGMF!B?W|fNoBnc-R9|tmO?t)!S-?ufdWOYbIQ2LIiMW5$N$-1bD!j?vdC(6#r2QH ziSs;`_FDv9H7zJvJHtE6aBp=qGO!@_H~d2%;6c z&S?G;EJ6#+ehJ5Fz{H}m>423a{Z7;P`)+E9X+;q!QWbfeko`_GBj>!J;NlmJ#0(B_=BkHt|BLS z_DRHSUw_$JNV|`+1qsM^hI}LvTM*1!f!Qkv=B!02+vFaYUpcw&(-YCq6IDs( zxC)(#3GM)djiNHX*;Yt(NmI7d-ww!G@A;q)#XT*x{4q9)ugJzXJLp*1plH__H}URY zDGtF@-0~+XL7i^ z$+cr$S1N~>E$#ieMrD(Ip7j-~Q=o2GH+Vu^0#mHkZ+#R|2)mNmwpZ<5n$|>=VuToe zb-e-y%ba)6r|yU0<~N6*H&sqhTc=%~7G-ot~uQek5 zT=V51&8OKLA0Up%oS|MzL`l({4^BrHtEzolR*R7>&`x>Fqc_#GWd%yGahCvN?FGDG zv7{y}Qr;#dkUEzIyQb$txAPD)_W4$%CMK(oG}Zg4^dAb%kjwZb3Xy?4QKfFdczJ)` z;;^1i_PaEXAXdoKPExVh3Qt`JcUn62s4gu};%(?`QsUal^o1D$Y8A$3!oNKpp~Kb025i9X%PEu= z7}4=K-+*Yd9|oQpQ}F5M5<^S2L)1FpFvyquzx3ByC#j36+|%9{ zvjSMcATLV>{9QvYSgMEfKh00xe%DTi{40yDAs0H=`z+3c;D`-LU=AL#g!={H$Oyl>+ZOpLy2-nJFD5KM=tkCljzg?apJ+g4JT3Lf+% zCIUp(rqU3CFcSRu`u~V+xE4NfO%Lvx+k6k7^ePwD-?h2+Zg@9grqbQ}P`vK9f`BUS;Cs1fU_|)g zZ-={{C@v{!vVhG+sDWKg_XxyV`r7^H4N-q!Mn^fQH8vKH6qh`Sg+2J7hDqnI2tJqR z9CU$N;+-L*A#{-D{6dqIT`|S?o6e&92|+%=-Z$jpMAFKy6Eq%2YgG+(?Gq^EqFmhz zMxCc+JQiX(OO*~D5pGJY%~S2)#)#j?n0Oa_Z)iw`vHpapBK z1WqaA4U^P|F@xs{XQr*9%MRa-rT)Vb`fzX#anM9-a`I{p=fiR?}p50Nl zZC=*~?dc>z&L7Sb;gTnZmY|4PaWX_}>KHXF(p*2VZh%@nVY>@eDVLR0*Px@zWm#%H z9QP)MBE?|~cID-%sL3UVX0|I4Kxjp!FX$%?tPvS+#u4ZE@Lc3T*2S8uJs%tR3SzWz z9@}7nsNb$o0WDHwWRU&B1;xbKI-x^EKr@mjTkO8ZBK77KE63leyW}}GpAlbp33wD2 zmX+-(zb0B&x&D5yWlK|@BcfEHxhv0d4)!{&o`iki0zhYdg-uBM1D@8iT)~MBsdBWF z^I`S_Y}NYi#2gGN*ldf^->{KBP+|mxa{nT5Q74zcAlT3Bc%|+_kC=S|5SIfT4X=Zk z#3>XVEe|gn)6Eglgk`+4@$pQo20$#7u1C5oP6_dY3M$R}UDl=jbi5_S{4X+wVqaCYR z<@ra&erh6pjY-LH<;2Wmi&c8!?o3Jkj<_-n8l>1xn)iYg4y|MNTLNE1TmGfCp(w_` z-cqg&EXd%^!Z;6X(x7s^ia`tW%KOWd&s>g=Zp{#BWk@plOLz5z`?u9}D&)v;lG)~5 zRXduu{dTNtc=MyzUM20;beFpWX^zglYnkk-2GS>K>M>%`)p?m-Ba8NE==sp}h~175 z^XXEd{ienD&Hb;wax#x+Nf56k?Yv=YLTURVf7-x8L`6x$jx$Vd{wuoG>gpxchNEXR z&V&{jGWf%XJ*)DV5Y-~jb~TU?H@7*i%F((pIH9vjM*4{Jf|(O-^S;ygYiMaP$4e}I zg*6)y%Bd~Toz&e2B(HqO9-D(eNBoL}q7Z!uK7Vc*mLoLz4jGGileQ?jo5)LDQEvC_ z(d4lD6|ciXJvl~%(UA~4H$(0nJz7jB>lM`r9LH#3`;&c+c)iY5rltWkBdVR_JYMnJ zjX}f-bxgVABUGnOB?_YF&p1KqXPdhY1Gq1Ue|-7y%sgbqJ`wZBRQG#2`Z#EQ&KV9iAPwWsT7 z2#>^wip$JCo!3In8F~b5`b;BYSp>hA%K-pXzqgjp#)Btb6>Y>-Z-Z#+e)?|88Rcq_ zSEtJwX<7PE&}0NI^3aIIthPVs^}T>4(>$2XO_b-F6LFcSMzoQ2gx}j-j_I68Oe?!F)4Ad7X~|jFx;GGMyg*d?jNDXX zA>QD!ImqDe@>Z(p%l=qu*U=@w9qbtGy=>VOUg$yRrXbK@C$RhF?ll~6p?B99NkiZx zbqJshDH1vGIhw%1@En%l$E!{p-B!HzJQkrrK3fWZzJDGJ5<_!YftTnf&rH!DNBqLoqB z3XydhN}cdJQ?})xI0|&1M7+gF?#JjB<<_7IHoU_kURRIFSBqn&n@v*218f^{G*QI3 z`!^9XQaHLR9<1b?$84%m!zD;Ez&s36RcCBWFTea0=Z=z=Wq_Q8MpZOW#wRuoP&=PT zyv+=Z?64*_!NBaiKGX`xVfkW$m>Qu^)w*pMqkB5_74xi<#SlY5iq1Oz%I?>3+O?t8 z=kJ8e@EIJ`)0sj9fyW1Q&gS1X)2HWai8j2@#5e;yC*qb&aM$lU)keQ}v4lMM@L|cM zt6Fl*iBP${N0%`B$9=cnPdVNlu}StcnX>0ylbUlxHKVXiNzW` z`&_XepSFN_k#_rI`y-6=^ggl!eFe9K1N899U=p8J5kIaYNVzk>`~ z!KZlkcdw_@eUbrf1r}Q31BM(n5qSr;cw2e}$iyti$Z5t)G^`8msVTwGzQ|o6K>&A~ z!3{@gQ~}K)V%{sYqMzn^ZMCdvF`K;^i=?yH(PRT4GhP$&ba8$(0<~9spek#R)vL3Z z98t7v79!<%AfwC!eh2GZMUBi1CkrB@b|+Xz^JBM+(6qbUH~I@R(}>egGv~s9+H+*Pj>A%EQx->+QQTLS)rg5$?(=4r99m}&-x(1Zh$6=c zp|jN(&j}R7i+vBDt~SyAOYs{0j23KrZM^&WaBNm~253joj|%@c#uNRgc~OK=?qX)v zoa3FE^vXcSEU@AQM+RLzDoL&-rM!u$jIoSZ?+#&j(p+kzgiZn6D%rQ^3IT;Q1;9ScAQDh zc#NHv-H@HIo#>MWmak^XbmBsezx;mVb05Bzo%ICMlZw{K)@J?(c1HMwJwDr8!?8|N z(l{CZu;fGto@26ceyQIL8863VfyI^nqQaS7V*6hDW7WD@8*tV6p`M(ohbd=##n#pt zo?D?8pL{*hK69q~ zn(Me(=W5QCDn9BaaNptAQW^|6#WI#wL#Tdw5baplv3?sXb0Z8e!NZ@CU$nThhU@e+GO#(C_HlyW znZ>hSdIUpCH6*VG-GIL9hi4JWcn&jFWel^oku}|ljg->RlCUYT;K&ZfISb-Yp6Ant zh)3vmv^aID%UQ7c+e2A)qE8Iz`MXB}u7vH&NU?_kUM*%SMoRKPpZ$fh@me;@H6L5fxrN$(lzx}D zb!Uo%QEsB+^UZr24u8L~ghJ8`+z*KWaU%B?>MBvxboo~;=s z^!)7M{q$TB>yr1Pt;35kPMNwZlEY|0_&1*QP0OYaD>cX`6An3a{xk95L?gIv8UF2< zv}nLlsQ<<7ZrJv7V71WjC*MyBDA?b82eIv+DYg^TRnqg(iS83ikdV(w-@!w+l z4&4I1ln(s#rDa_~6>oHu=bCPma9xcneTl(2vfxr)+)jrI8?r7&p1kcsLR!GZI4Z6FJYc-K7BOa1OI5BIQKM>m_L<9$Cb)a+f}=4S1c z^neL@%S{|ndCb=&K;LjF%3b#TtkwJb*G?J8#uNm@xJ&_B*j(Y^f1u_6s44?^{_w53 z0ii^Pg<^?kYN(02+f^Uwg5SWgK5x_5quX}yb;efFjDurh$;>+m!t_s-gYfLrh#jH_ z4u@pP_g=<)+8H-_I9~sBUy~}gBTOz(VThMkF+E`xY+Z}Y$P%n@;>NT2vk=U*R}rc7 zW(UA&?D!Khf7&Z}QpZGd#!?CO`&W+3)AXHr!UM{fwD$`YU(AOMhjE%XhlZe|Yt&;| zpqv^vIRBa)n1k1?<7J8&;|Kw0648O24H%Je?4mf*hj6C~sFcrkM9hf9HSRoa>60U7 z!2LXRM)ZNvJH6!UbR9kaR%kSB*SO4^f59dGjh=gl_gj3mS{pLAx1sFxB505&3~aTmwK*&|oG{ zQ5`PHdlBAvwdJm#9JfJ_2q=`z&={{79sXVQ=*t?FO7QtQk*T4*dJBHqyIQ-!`bxhe zlP|YD;{IU&pEr;0cpn$+dntfpP)*eQxVQN_mfldOgs!Il z`J}R|l94Y>*n^XEu>U}?^2PH5RcQ~hWmq9;Oq8u*Ek=9|lVmUA745beU=k%^2JGxU*Uouk6$^;lZt-1*RdEME-Fieh$d`V_Iu4c@8!S0l^0Yhh=5|G$1j zay2rD8my8apRCD2#i08V*gg{`ciVZim6{0^byq8ZeI8qL6}AYZjhKQPy}F`WwTKaF zHg2l6{9iF((476~_aewXRl69fF%M}N3u+~plaB}cU+(>?m}^1q*2_PL(1U@u``oaD zbVCHgmTM}$wdF>C;O)0hL-8gOk-TIs*DNtbRs)MPYg0_862iYtRh8asI+dp zAchteJvAt(`E%RHU67A_qx8UUEms8Z=w?mMnP@Cm1X{Bb(0LahM;^O$^fP`@n4f_esVuMq1=Tw^P`UZk1* z6$)m7U=B`V*F>GwQZr>ct%byvL>LGkDo#gTd917WU`Oblb2l5t!@ zoWf~De;oQEQ>Hb7wy8S*lFQEI?NNxXXx#%8eG`JzG2B>=oCDbDY;>Bo7xR8z(cuu)hSh5e(#x;0 ze~3S-tTgnhS+;Wr1Gp19KzPKb`pjmr!35%nO2B{S-IC1@(A|BTu+QO_Wk6EscwIYltUxzogX8iHbb>fb#Zt|7pfx)OIZO!RG#V6xxQ zxV0_g>s}%?Ep^n)3htG^+7B1e$cOBmiGC+%1gq%Y3d9TJ;VRl1M_8T0u@KLHYg1uI z@@W^X;sBw`muWldX5>ym9kckY9@uVDA&RhUNtQ3uY&4m}n$dZkROKy^Dl37mYhrVb z44VyX!Nc_by~*lNRDbMOW9%6kFL*3Bae1M~*$TJDvmv8q3PeNV5ovTwoMf`=AzRi( zBNhcyznI*cuH1VO&)zLxSHqm@8m(>2xQF>x* zp!XK3qz@(>V5r!^gQ(+iXj%bte;vAl6$tybmpr35wC=ku8L~B;@draPg}(xM4Wq0 zj4wo1?(8iy?|^;VR$Z0<%mF0#$s6HdoqGm*xuNqUXCJbLKS^ziha7YT(m_TT39gRp znKSYIBS(P{+MWR+O6E-HorP7{pn-bFVopNSzEO*xUG-Pxc!P;)5jWhs5id7)F_~6p zaO$*L(@~XHI_*smX6-lvr-lP=2s;1Nhl#LgNEz&fJ0wU=MdC ze+;NW<%AUo_ln{wQ}!6)YLiWy?sHlQ^=>$5oB@3*s&7lk>$Y0WTOWBH;rnfxlErn^CuYd`Ssj?IteY-y@FDgr3CGuaU zVoZaB`{Bp>tS^HWd~*i+{|eS8>~gmKJF^RCTeQ_CNjExEodjt0rb+5FD# ztbQ2+igO=?$Xv7I5U2?-Ke?b3!L@#4wTC#Xw04^>VtZ+8?EIXzV9&4zEERuv5Sfbg z`m5P~LV-sF3-8u&B)Lk-&dUgA=%Xyd{p&UP_f0&21FWb5b-2L-rOaL_;1B4Xww*9F zw%trUXk2793kz#NYy!cbvcl3p=S`n~zwEc(1dgKG-ui`{l_OmSKl>2>ev3R2p(bBu z>*By1Sl^3nrVHkWE@MmtI>Uv)SUSvVg2ZOq<8i`FYtUZ=$G1hEjvCPGHoi04-MCk|aAdrwBeflYdaq6$eh@_7wOz!O`-K$_hs+g54YnQ{ z)y4&ry!Y$vC-mtMj<1j><}2bk4xG&Fg*ZA+b`rfO zk((7APQXCPd>OpkYL^7mVrYs%t=9eLl+uXeHop{Y$)XM%8DSE0uzaSV@k?pM%7cma z;}eBdfzRz;5gRTywRyLt7lHe6;h>2De9R+F8;FSf_3xZ?tp%p^j7!*%6|)hNCd-P997{hWeUW$ zKbvk6+H*1g=xx%$oeM8fDtDa6|2j)LcBN_@;k#-ECrW9595_-LE2-!br(b6J5|Qu! z)L+BLsX8$>-W*c({-13v4Zej?0dn82OB3C5eq;P;@qni{VXyXUz3-ZrMEp58r^Qrz zs~(Sdzh?4NvEKA~e=qrJ=`$C<%vFe3s(=0ouU%NSf|?7vxwStx&KY*9aq-dEg%akb z>}r1;nMFtkJEa}oubi4mxd*o|yK=jCXDIK5;$pzDt!1~4agJUr-GP!u%7lF-U5(+jueyXQ zyfR0+?v^YCQ=Ik2;0HS4p-t1nQUy&+i|;6VNi+EE?$HLoX{MjcqaIf_`M`wHS}+E| z`N@zVn><%H4qLUXua`1}i4&IVZD;Ik4&7D&Vd2!36ns@+>d|7Ia#FNwvz&(kb;)qk zkCdCScAMJX0Ax)faVi=na>WxCo<3uNsue!Khz3qpp=Q9_jD>zVpEhyaBJSR6Ape(^ zOkJRpo`U1dv$KIkUceKiOO-HDcLPUY4Hf27RbqR^_QPrTcuNF!%IsIdK^OQf*>pr$sM05U1jgLIo`Yk^u znzk6|#OQ(XW)}gPqBQ+#Y?w>E+`l05{Z1TNDC8k=_%3l&Y9ZT0CT67zM9w|PGWoUs z`??n1oA;JrTAkl_;vFT_l3?2rZ9CQA(fjEIG!(2={TzVltjV%%??YtL;OzS)y5IW$o2MOI zP<%?eyLD6EEG-+7xfcei=g1Ux(A5<#fj=8);z zrc(krLPCLw=$;w&JGAGI`fe+;S@_tmI#QDFQvM*ev~ut{Mgp&{dBSjPmNJQ5tY{c` z#ss#_N*dXiY+@i!BwOxBaaHT~gYZ^c-vA+<+DAYAL!Ril2|r2mue5&V%ku|u?jh~d z2cI4kb9pn~8!C?*OJxoOlnqP6kNAmz%AoEa|EpkRKitvbp3kPJ_O5;CY?W1x+DWkU!-JiDA-Xiyz-x{JJU+#HfH-9um zn9`uz`mM}mR~PQe+rH5F)$t^d28d2xqMOFz;thRi{t3zYh;xH@{SftLzKjR(jW|-+ zm6dA5B&8Pd;KU-{EOPZ9`qaR!y^MwN&LB&R^iqoo9Cpy)1J_i}2F z;MTInk9+H|(_z&vVn5Us+rCymjaIlehHy0(R{1Q<6~|I{!9{Hxfwi0i50$Q>x9*F> zncnS9OBi(*f%8JNAbx-LQB(0|45?rAkn(7Mf~iz-4pWdsBM!p3?a#ZYd%#{uTZe2$ znH(TkG;$61pK%yE&D5{0+7D6lxnHT#?cG%o{{nFN@0)2Em*}~NINO+h$pjGm$sWW& zXnQKPYU~5#Xp4ss8X&3)mR6>ZJD|Q#+U{W0DFC zfl|!&A0T_MI^O`Rm&tx&7a{k+;Uw_oxJxj>5sa|F{tSKaDjOZ?Y%+KfE{gz?KavWN z!(@M43z$6T3cWZ4F+u5MN7>z&nEtPFzfulJgG+HJWQQOlmH|U^slnd}>eI0Ul2H+) zbP@u6BUk52A=Cr6~4$14fMJ2ev%d+Vwu^cPJZ8^mhw7LD$ZJS z%cn$7!KY%eA?3x6*;!Uf{pr)4%4qU1$M&0$*Kx|l+u+UN|Cf* zmDn!1?23u+fMvn1b0!&Vae8;x%}@kn(AaEr{+176b3|F09r}r+c{DnjZ$FXhpn>bpfe|vzM{8l{RgYAHEHnk zOQi9|L2(A2y+;^zBuW0w_dOj`n{ikTLy1-e%%8#g%Smj1U^1HIVQ zJ=`gw&a?CXp%7zPmaNxdoLs-2xYrft1nl_7(Y%~E+r0%gKb!VJc9D<89y!O$QSSyq zvOA@W1jDg*3vY#K!tPfpty70`wD|5g_-b@N<< z@Gc#N{t*F_WfJm4r+-dX67*=o5Sq{`Vx+q~O2M)X%#T7-4CM@6q!Y(xA0oeIxj6s5Dff*j7u_r0|G85Y$gl|}#@Bbb*e+(~lLgWe=$eszy&dyoz4oBfo?GMyE@SCyP!N@$GM`3v9I_1q z{tY00{1i)Z)?r8=`l`$c{@*KvCK}NOR+2%tgpP9O4*tU8W7p~0awB(`Ma*a&{^tGN zB%oy_SlNqA$me z-j>F?wQ{8jwN@Y^!T>-uv`u}NS=+zSuoWZJz-H)kM~|pXUfkyFjMG2Qhf(B=VA9aO zx3B+c%;PA{^XbTnN!h*A=G(mAL6SfB3-9Yg#Mz{T19Zs6Nd8{YOlx?Xlq|Sm=uX3Y*7S2eHKB=1<`Pus zE`)GyfS3Y75}4_@xzc`c-=}P@{|)#0>dI= z3qGi@Hfo`US`cTre8us0A8}YJqJjBWxE*tnt(krrO|R<)wO^n8QMMAgceJ(1g5h#w zf6q2aAP-^3sH1cU8#ZVy;F(}9GF&%0=O&>tS01t*<%xO=LdR4djSN$=xjl7PnPBhjEf;=J~{31kHfT( z4#qM-EIVYg_-!aW&TBcwMu+qH-R6SW0vRR>Ns2f%$m@Bi5%ddi<29brn?-H zzNg$fa67@BBat3IiF?&;5Cmz_;FfCgKN2Yiimy2mYX{Aa)8AjXTB5kL?p14Mdb(id zEm^4&em~a>Q&=$90QO3Wfl|a#{oWV>wRb8%Z}+Z)(xQ~)qg&{8mN_xJ6%uPI!vddK zda*IZp^G+~TJn>Jx66X6_7zP>Y2xP0rLT);6LR7SwVelM;bg;0I!Dy)RCV%zWb&8S zbJ(;F)}#$^e7T6Qlf3iM$-Ka4Zt?05|IjeL53M0x>q)jl{Qo(+?s%&DKmIxA4%fb9 z&udgxNXT}PXpl-Yj9V%mA#DlwsL-Yony!X~qDkhhgfwU&^BP4F%AV)Sy zZ|pvua7#JgchvRJ+(*8cgmjVUO<(V5Uq?BszrP%g*w#fmifsTCThiY1R5|r>TrGL| zkD=)q@fMapOTNp!9nT+$G&4d87?1q2C;5f13 zm^-BBNYync6X=r*E4DH=pV{sV&r~NSE}wk1`{{Vz?r$x~eDb8MP$2*|H)GJZduxEy{47LGXxj(W-1R_2qLE z7Ku7ajQnUk6~3${ob_);2^ZzaF&GMR z^+LxVI_|x16!YI5;2g1{4Q)iFYR|>@LD-h;@ukw$0Z=U!b z=hVZ;Lz?bhZ@H9*rQfn906?1F&=MT9GQS?rH43+?b^cFeFrMT~A!N zVcUNsR%v+hS;t{-r_n=^A2t0X6^YC(VfXYPnY4yRY@IMlSXor;XG>!wY_!u(O4u+w z`$||$prpl)&?&!^xq0fQTFj>6+wHfMAln>|8{APaWbkFoS(W=y@<7}(k{710d{!ST zS?w|PxMosBFmA(;&3GtnCURXKBIG$6sYxrbYsjVNJLv2T=A!)d=oJ0*k;V~BlaR0s z)ajfZ#6qdLz|(EJ9RP(O@TJ)j*uc-HzQi?Z(&Jcm;oD<)e5CzNa{UY)DN9^EsXTZ7 zs+kv&)25i9E8C9EWb04~_bW2u7Kd8e?AlVvU?U|M+oK@(v2EuYMzM@Q=u-b=^9GAA69C&dwc8D*N8PQ zZW$~07Ht^}Z@pVAAeoo|L*3GA`3(3pYJM$!PIC7RPFyHv$~+J|LM1RjBb>hrvT=gzSoNB7 z0pOtwj#%N{ZZa`J0f0{#$-G@=^Y!oDN|Pe{2QNnZE+#~&93`=eCpsRdj|w(V{kVO~ z0?)6;h)2r_XSBEBK9TlLOUK`kw}wzZaPN%22C>N6+iwGRY1A`*X%xfl(aVLqw{WW- zhuYpff2LvJuV2ngxeoLy@1&w&*sW`{U$QjfRw)m^lMYYGKZxJF%N?2!Qooj#X0tmE zSVaA~#J1=H?$P2HTRNX2#k-H5?8{#y74q_L+NX9fI*Y54By{{oHa;va7j74NoFGME zk0T4F=|Q#jFbnJa1?}SLq8dZK~J}l0>T1V_rwJ?z?z5N=tVgxONACJcOw(BwctVW=cxU;G`I8i(F^DsSks67PZB^xn z!Jsn|DG(RpkT#a-2rZ(yR_v9iAA~=DSq~BcepM68>P^4+?4mC;jth$^9494LbC$E) zKiU`0&I6P{eGxqt93;2;8!%y~O-hQ!awZ#fj&Iq#^`nND*7b^8UACc@=g`uzbpMmx z|1OH4!QE2uq`y**=YEC~jLyR{DfriN5CB7l=(!U?cf?COp35GTCa*!|vDgRH*(#UT zq(TKXzY1WgbwPeND3{P+p%_X{BEyVn9NtN8#bpL(eVvcdx9zwf4dzshn$VC*1l8Us{v zPJ!b%D=x1gVN?T0dZKi`4Dl*rN%z$6d?eTe)uAFc274cb3(%XSb2+~t=I@t=Lzic} zeo3JfYMQ%QV_1^f_`{dDfox;G(o4g(E}BerJn;Os%Z=%Te!-y#TN!LftK^Q%l`lW0 zJ2`Q(L%z<7GDOjT+w@L(&)Vo86giAbyTNZ*&VCJkR zh5eLVbDt^$)pMn?OryTp>=oFH=XVcM*1E+)BUzw_5uVa~t>F)_2iVtV8`7?R@VaSD zgQ>84?Xx91;Lv@)_m9a1G*E#kQ4d#4fVNb`?V{Hw{4p?{ zE}rbV6a3Tn((EQ3)&_?0Mbc$4aIclnejd)A#~+5Z609rqce}RtUpP|GenI`>4V~lO zffu+ZQ?dF;aikIN*`##3G=&bgPC@d@&p*Ht#DXP=n$GoiNnNmb-NCh(Ol81NCO^<* z+i@^FEDL@Q_plk*wTUyu#NvCYz}o>76^t-f9>Doxd<_bm`J4Zmpj^JiJ%Ropd{4&% z5`yg}B12S+kOmGX7C{ocI}W;Wj~p3;GDrR@nu1DW-N#3VYvVg#(soTZZ}~rwbRCFC zb06ZvXqze6yG}ih5ZL9OL#~awPD>Qc0ljAtEJA#7SCg#iJGH8ak)%O*e}?>?lM7Mt zND_5Og?|Y+PwFNsC7l>NJz*x3ZU0@|VYw@YA|xuWXCV}7!kDuFdm^2tLF|6NQjZj) zXqP4(hX zjOcA0;LHs+Wl;LMaB5puA?3=DrhE{9_4LTeHB{wq!r-IC3@s(SMyGru6IeYqT%kwo3XZ5 zS;Zwx-k;N#aSEzeJ?d`{X!KkteYRT#MjNkR@&m} znB=F6!NTyxSUMHGx7?zSWij&CZ8aD3W}(F7{5~y$`v`RSYS+HsV!{$4A!Hr)3!^Vq43dVrSKEkp5ABgs z97op(f*U^|6U&eaS!iirp*1dtyoDYp55e4AJ3~Bgx515GF1c)QS!Uy-pZxf_l=pq+ zBSwu+ip!A$@o=PRH7#=Ey$L*k}co5|-EghC!s@yAUkK z|J~l|ZwcuXg|A?O=gYP!BZ6;c|1b6U$$1$FR2-E6=D86iNulFmm_D6<=@$I1-n{_o zRCvY=9U3f+mm!{FA)8hLyO$p60O%`mBThi09$WQb+xm;1+fcf1NV%FxG-YGkTWosu zORXe7y+*+WgC%2^3|JX?76iv3wqqKl$57$o8w0k11j@Y4~zGyf&ooQd%dCIkBg(zO~$-W;wKgTLD`_9@Wu zV0$oRsCS$oKhR0o6SRx{am+4pF7$9dzM3q|URt*zxI&hG_&v>60R zvm_%UUIY0K1ir!%mNfW^5rP>jcW0>dz!4vAL-C-CRhSVgF|oNyl)!`yE!nP{OF5cG zK|`~9H1Wj}H6>sbrYvb<{|Z`U_|W)9*NMvv{yONNeYK2pZ8AU}GG(?44J-V76UlD= zmsrMEalqJmLVQGvOYsA##Q4uYJuz|i)cfk_YRGSwx;)1r{n`pKYEu5$OVp#P{Ndl% zkC^9HnFz%D~JA75;qDs~DIeHL?;v?=?o`Ee15j-&P{zqSE!3 zp;z)c`0Hzic^<(3vM*1f#tRvAlBqbu5*0Lg?2%%>nnwpEA)VJ$h*Ll2Z?Yd#b4R+a zoy%b(g?ErICyAYau(FGRX=0{FhWvl*@MO6ZrCgfRM29JzbgIVc$lt5i>k?Hs@bpn3 znr}AQeD}v3fLy#sT>9oogQ?nHOpTyDS;AfcjP|t0fZWjI1+j!5BZwM%Db`LMoEf|A zNbhXiQ;QeIz*zs)0)NAL4Z;`IFg-}__rJ&Wb3^yT(y-D$52r0QvUI0kl^&XNsu@`L zJ%*`=34;|oLpw?Na^R5ztif4p9i@4W*jFI7x=FyA1yY0%1IE`M%BS*`RKtavGH$i_ zH~C$puITX(F)%eZGuz8o`x^h9kk`GIp1MGhl2)B~?$yV&hwY0p?I~_&KJIOf%(&s# zZ>GA=p7jflRK(MCz7a7BMV%??YPM5vC66R5Un~u4W7|68*VxyvIuirqPHHZ{)YV${ zX>#xLFY#~qv&VYg9*b_&h|0FuR3j$^I^UZr4Hxtzwg$)?fi!E5@ynP;kD#xE{IocW z`~LN=vhMjH6X?+25}!t{(uKytpdQ=5T)#dQNVz*77+3nt)At?(;^kOGu^x>jC+KIl zi|M=umJ|%>owYO=7ggV`q|rp*SZo4p-y%AzLd7Q|jAK|*aO7LWY_?ShcnK4;Ds#-4 z#^Q+59W=u>Dr*>lV7_>Mq@g*6vfb}+Bh73^gm{webkFbPhQCe4rwhM$*LJ5?$HjIg zuVr*xV@=xIB`FC7X?rYsUa%zIPUR~$HLW5eD@n;5FD8pi=zNo{!HJ6;Ug1O*>JXc> z?;_by|8J&`BlnCRfM9C!hh;!4-7uEGh0qoLrSoH)PS{XG~ukj)gF;%;$Nk>4jz7L&S<(yol&2d zBUsKg^ujxr%)ai5w%ujYh^m_Ti$tx*x65@^lq&+E%@%zk=S+xRL3on52^@<1L{`u3 z!7v?a9U|b6P=sAye$FKktLP)P&+XY%c1{U9zNLwb)_}5}=i4U}3vfE{cVWO1!&z8_ z7V!(Bv4=74!2*^OOxxmw9Y1<#YYOBupuvOQn5)fiD0}p&3f`@nbMw^UFU0e%mChDf zhiwo8`Ifij!yR5g>GHv7yOZDpJ+oA;FJ|pt9cCPyPW4f-w*BH*h4kO*ha^t%HYTdl2NmuGIbS zynpboJjnJ-xp9HQ4!vJZ9Dt)(I?i*6>gUQY6O+Af2?F_bQamJM;71dy^2lEWVFAK| zbx3~$Tl|QddTenl@=bzT?Qv@zw}@H zIWKQ--R9MwF!f;xHR-o=|3gV%Ya4D}zGC?8`~?)eSNGcM>5YcfE8Ai)zPcR>qrnyO zl9}54pOyi0mxkloVy<1D>G+&D#T5kw!;pyaR`Gc~Zx7EfOjQEZb$`Ul#~+E*e{^Q* zk1Xv}F@AAFMTo_1a^DvZ<+8@OMcc{2J2jp_F2EC8oDR~v|C zG2rcIch2omB#`tBo`-DEXLBIhP>h;|6VGd!jw}QrDr4an@#@shS$02uEfDfAl*!a$ zbyUaHnezV>tLR@2b=}(MBn;X$K}D|({h*pMYoCp@;o4v!6#lJnCEQdZe~K|{r}vz$ z|LC8XJvNJ}(@5{Sxl{WhFXj#H_McUChM%c7Yq+*we2e1S{a!ktimZ*tqxlqw%$3jS zb|zBDMD&CK;y}B>xEjp|5T=_~VMYfx9B|Ztb)xIQOB;6DQ&di~Y9)T0$?v&FT?YJ3 zcGhH5AuSx=16Qd@Z#5s+FG=eZT(T={bK|F?iOdhJzn9*3?jmovA14>n6z&ea|BaMKGp^#_ zA^bFOR`^hOGW;)gd~IqtC$R?|-s#0sbxz<#XH6~_{JeNL`@_2coaaYF&!?k4YXLU% zcqtyQNeq+69S~tH_%%0ZU&obr;ED?pB9sL;;;)A7R7T&+uJLEb8H6N76Kfff{kAI0 zr;GHJVkV7$d3)09!_?nJ7Jn9^Gv7_(DEA_B)~Ucj2j?_(C=Tx%oxZ$i_(C>z`%bZ3 zliPf#nN?>XIll}mOjH&VSnyxHS;=a&(UuXgStrc!UP?p&X%#hF=ll5#k z+Yx2HbLriW`~aFKjrB4yhFEbgt^d5y@)qi{Y?QNOHA+w^uvCHw~KanBSsxoby5DCO{;;PO^Q$RljI(hL$_PND zB3hQ~8YJe%lPLTRf0LX{_ZTDPm5V0uMw?7|awiZ@#_svCU5@Y8@W#iJ+S~fkWN{?( z)u${974xXX{&E#+##F}_MY2q>m$MmF2-MZKj-8J|Y5F0L)gb!$F+qbPhg}Yr5xYgv zOH!!*p_qq$tbk0AP!=_&b5M$UGqmyFab%Ez|0pS>p+uY|Lhhlr(`h)gIuDZp&mB-l zbEPuDc<;7T@_M@I{^@C@6xbd4@glS-vmm@(Qqog;;Y3?l+h+M5j~F`EMtsp?1VHSf^oi{fh3!X4cT-kF3i@4J%tK!Q-^z&M9zF4qB)A> zEuPT==3?jlJ=s@q=64M=d95Y#mj5NekK7&2Sh`lYTZ=5yy* z%4_jm9j(R6%&GR)6~Mps!|iuy>!`tZ@mo+H0_@L;y8u0g8BDAWx%J>&hS<>A2xa!| zd$}b8XomkJ10_?xp0~dmMLapi(?j`A6f%0V1k~QtB$9R!pDx0<0Y?O)iPg~mbUAwi zehML7jbF}u{#AUmoNX0*J&=YK2CLcn{A}9PuvO7wf5M6$(mEMkAnbyUzZROX=1+nW z=J}QEQj){y!;*ivK8u1_NJ`VF!(IsUMZYk@k?PPHZN_hw@uMSJfny)cq@jFu=5b9z z-gIY=UOJU1Mm`d6Gt3I}uoJNm!}({Q6}OJh#LJ0%dv>_I#8w;Ie|PzktuOi!`uTUy z{+~ytJlR6TZz*7-+|zCdZyu!sg2BbGWhP`p?8~0u%EGKQ4E_bHu;Hy8>hYLEtJbSy zrHzd0x15uMH$NXPe5$UOvT@X#enZV{w{ltYP~skV0Fs* zRwMsq-!_h)dP0gK`-0Kfe*;Xjb7!3FvKAaPS$-8#+pQ`xzhR&L(C!Gr&lz0mSn4D{eQ3`{@lo)ycFQO$v>BFhu@3T3y2bdTiO z^^DWmB+>R`+2x0_PTMt&dNoudSk2XQ!k;PDP$;w)H?#D zY*O>ETkKtQh4#=u19)!8@O=#(5D2#cq6R)~AkyzK>K0%EyRUTqc-DG@>c=<9Rp_2r z45FA1nj$5Lqhzx-#LqofN{Y4E#%`0N-dZ2QYdGz4h{S{ zhjgy=-WcSn&PdLX<|*IC!X$4QtP1#g$Tow-Xh~;6{`o38GlW z|4jYjc;k2g0vA94g7uK0jZEZ#@e~0Lm{9V)Lm_#R+!>F;{qnn0I7^4$y^InAX{^KY z-B0)JWM1)r)nqwp*yIQc%xg)lxmqT_tG(#*Tzc5=$FJ=4+Ni7TC21f`&38>=^476E zkSi-&uJK9gFmV#Avl0R(aRASE@^FU#AnDI7QGu!$C93CofnTIz=(JAL8VU@SunpfK z880JnE`!Quu*VzbqfW@=0ogYNjPmP4!LVa4`t^N1uyicBjvDzi2 z%y{hJ+nX%A`A=~3ZcD7S<2ydC}Uo3-(olAX~7VczpG_h3K%FuIp%`TC^4$>_y z7h_vd^UKQ1Z#6E&^R0-?ziBIg2rmG3F>h$x9U5IB;^&>a={v;*&wiUoF1=wjh~Ez4 z7w-FW*=Cc-Gebyfp59XErEBrH#J>&oCfB;s@1gvU#?%^x2oVGjIXxx zmc)*4nHxBo$c_3U=Jtdo-R`s_H z5iWcW8H`~z6-jiw$FSR9YCrD&aS`!#QLXla@#@`q?8xVOxQ829EXyIZrW5P2#IqTa zK(4pt##n5?P#Ewkh*tr+3fKg=)6gj`jG}i=E=5@g($E$l#bLn*$_zo}7)52;I)r=_ z?ju6f1T6Q_pQDG}NoAEMt^A9Vc63^jQuP`!_YrRRe2DM|W&_r#+~tyrclCEq7R}C^)n3u%8lWN7+|{pj~!iO(wQUmV?@r!8B~{g=DD+KLDY5 z3|X)sAd1PivIxLY=KF{Y-_Gxebk@9^qFk*T_FCVZRLMN@H2uKu)ZJ)p&+|FdiZUs~ z&xh7gk|gov!u-+pN9M2)rj~98UM51`9JN?^K)fH*xIQx+4!y#0m;59@ofx2@J0s|*GCcL5T3$mD{+CNtuAevI}>|7 zV*~e&%+$hgbSu$UpMSF|^4D&+(qGL~nf%Oc5TUUQS&kQ@QGA{d)*^y$EL!pbT#e9- z=exQ&tbEt#qleNWF^^>>$bhvM&UQI$;yY*SHkf}*_%?S2M#MH0tqz!s5$VI07g@&M zy>LArfX=w?X4(=EcT{Ko@%f)m?K>1OJ*T3na0k`_hsr!eS^gIKyl&PaOWc-u0Of_2)5&pIi&SFN;#Pl&`v|Xju77 z^gOj_qUaHMPmaBaBC+|o9vz~~e~Ga@`vaF`8pg{bu}O<_FY7Q44QN%IRh%Vf6oA(c z;ePXB|4bo0X+C^G&acKXmAuQZ%=$Y6m0?!hJ3{}xnHz+Sn~Mo%|3mJE3FhgenRI-~ zyYzHZF^-T&EfrleND*%PY=J^tu^h?_9!F!f=0rJ#uefa5zEa(h3Wur0jl^~z2Xfz) z+0*TYR7@}<)3)s?XXl?Q_1mW179BabG`GFArR;9$k3q>frF7Z6D=w9uBrxkqk&GV^(?A%jY+B5a>ch)Y`8SYW0|ngl+!mz@A@t z(x*`3A!j7zM_$5+O2fTJWTaigmX5p^@7m{f=8AHx02LKfF8jaxqkSsn>#n_T7ax9q zM?ok=y}`L~ZAtUq)@zRgMW4S|(M&TnIrU53KsQ70-B7?%w(_BA6Ix@lwMF*x;x5Xp zjQO9$@Gt5Np7F=in*5gvwd9{q7B9y!sQja%*R|!Zdhw~L^v9+5T}4O4U%nCTNwAt5 z`nc9m>}T3`#htEkvW@=!SnJN5pCRqt14Y%#6f&Xg+>^(O-9tmCWWPoA zO-W>1tkp|gFS3>0Rr1x}>E5c(JGJ`Z{~P&RgB(_>o1hKj-?uvlLr=5A$Q>Bk(28w@ zn4W(w!CtQGEn@BY!Bb9q!Op!_IN~W zP=q;G8h8;{XQ%y}bSX#{Vv7qD#uj&$UnyvF__`s&uwcjd++`*!B|Ww(1Grxi`oy-+ z3@+j!CgA+}uES4D7V|0aF`wfiUV1r#8@f?gp@EzXNPUk93^+R={&N74t%(Gy3^R1t zJ;k6FX-j6(f9T;BH)^mfT}chNaqpJl(7X-!W(|Q*)O;B%Ts$9xc|a+x#9Zk^VfbM8 zUfYn?`Izf}FcD&f`B+tzEi=V3k;F-q28BVw#+EGIy@H)+qgEO|Zt7rP6SG8oX~DB+ zrn$RAgW8V??8krso6!yML(V9|1+&}ML zjm5AM67}yIEE!GdEBpK1T8fe{LM+;u1jHR(V2krdmx{pAd&4l@aKis9qTGAR`EG$qa-J4Ocq#;&LhRUg{Iy;#UyM?2vi z^W^RFmxb5km53mf{6H+3ipmePae|-#_+)vk(QT+a`yi}f*-uB{zD{4K;lliLtgau? zMaX434dM`X0yw(pp8&J8{fPk#D10|oQ2OM(6Ep|D|Mim2@87PtaD9GL#>vl=TV0n# zD8nsv{z|Hb-QhoOsHZLaWwbN|_)o1)zya|*M31tHxxy7QIuu+^RX5ZSgR15Pd(P?k^u9;|PlelW6 z)19sIspy2h>}B+BUb%s_d=JgllAwal^_$)pf3=UGM9S}~IVEYR_eb8A4OFls9-3gB z2n$0j9O~8=Ex_Q0;wi{Ld-xH=2+?@U*~?mwk@`YIE7IOgYmAc$7`sey;?>3cu=`Xm zanK~^8AqE_$3|~1BG98xE|VOfFEE*1t>P(3vH9r??$C4YmQ}}-MWz=z8L;176E&8v zlEmH3gaw!ELi9F8eQv7%5I_1`{CDxy^Ao$50$+S#;crWnNwIBkn=s)%7`z*^r3#QJVF)DwSV2W7*pEoFPtJ#6 z$`>7Ee-aWi+y8P-5j(-;mChH&qDF80y6|{p$v5UN*j=uwL0IP%BkgTd?JA?+jlBy= ztG1ofglmeuhkZx{omB3AvQrkD z5J549s2fiTkC?q*z76=-)Lm>U&n_EEH7c2TZRES}sS&j)PITZV@-Tx1(j6Uz6XZOK zoNwRHsl!7tuCJ4|?^SgE-kDfRF*d-{u81ql*w+!6j6VX@@+R`%X;ZL~b4IAnA%oHz zKzO-nqx%U8>&83CW=CH(`Be?WK;HhvFVCk}>#|Gx>*S zCYGIaTDRB5es&}%(_`mVQ;9gWsBJelR+~KtqQdsa`juwXjlbyF_Fgh*w(qr9z(=~K z#KhTesf}js>yT=7(!Lw=7h}Zlar7&%qv?!SIm_@U1Ka2)Fyv+nZyryO^^uvCT$+fu z_V#K~%o#M93*jl&c@iOD$Px9{0ni`alGr%4!nJR^w-z=0z4O)0+GImb28V1<)5A_+ zY$|cALYk1xsd6zE%CdSpm`x{4F(g5e_zHq}WtYA@DxCkqMW<}8rEhp{JDiA7RXOkr zm6e^7fb+qnbWVv10zhl*_fc7NFrs{^X!+-7wh$*rRftbuo*`NE?xuY`wwXaJh889+ z$Z~%tG^7dIG@)Et{=)Qt-{ruQ*T;@nD&*f6>SDhT3y-0|8-(%|D#1`rv>2qhBU0xp zoS;m|{9&Akm!#D{lsh(_cnneu90tk{M+fe+*264l7H>i+uo<xg%q9FYIc%MW=ddV{IkbtIpISI%%U4eofT1a0u5&HP~2E)s=+k0$T zvH3!EtNqtQpP3A^lgUb?X4xCxkn^#ZU2+2Brz+%#b8g9FL2@2S5LUc<+8yUdBRRn) z7n{kdg?o-a>(A}5kGtf!Re|iip?Y0~T@%`Q)O}drcGg0F@Kp-mQ9|#M{;M6P^u{4y z^ML~j80%M_0*Dt0^k zn@3Sb&9Q6ks^}huoE4u!)b1UP+N0x5kWOa<X((3^6YCBEF zct=(758qb{_yQ7Xm(XQrGb?fhkm(84P7PN%sP(VO*dvKYh_idg8=^f%Jkk%Ka5F2; zML#qSO?AxdC6&a7`rMHSC73LtfusCKM}rtk&i#i-qlLn3fM5Mu8uVEf_89wbTKT}I zVqz1edIQl)B@Qp4K(t-R_ZMcNQ}VM9&rK<~*XA7fxc<+_ZhwsJD+}*FJ6t;Xu%jzx z0i4j$iWeupNx+*!Cl-|-T;9{L>l7H%jFncREGkY=wkXqtRKNWn9mTG(bri1&#o4ic zQ$#F57UTQQ_xPqH=S`~YjvI^V%&3t1)Q_Ttvv#J~I*T~d!`?Gp95BWBCtX#~)KA~w4q}YE z!+xLd>R^c%e$Z;BUs*YLVaqk(>XN7l#`>AQ8|)VU>p(}asbB{p!&Hnhf%@F3ZASbr z+c+jK5{*TO^&Q{uj&Ofdhb-BCc=gqm_Hzpkai>Vi_>0l`%i+iK@nN0=aSeQOEbTK! z%b$5A4($xKV5%QJ#M>s6dE407fN~|6(x`y$92S_PM3AXP));Kzhn$~WG8C#og!)k? zUXC3paw+nDuOIk${!HH%Los&`r$>_y)hvF+Z_7BdcLuMWt97&)tn{T#Pl{ouO5;vd z4xOT;VG8fvhuma^`M>|0^9YY=Xlxw1BEB3-?+gd@lULs{Abz;?bwK)9*J8EN(I3sH zLV-}j*j>icvb@Ka7Ha~x;e2IOJOjEF>~es8kAE;WYRkcpNj>$)`JRP<>T(v9U=U@OV{9mpMZWsRRX{^Kdu_M6$ea;O3~$L7 z$yZjhThy6XHSo8nAfeEA)7q_UA9}<`iI1*+_v}(g&XIhRGm0o#C|`=1UO^MNJjchD ze4P>%-DZjS;r$nPDo|QNU(NTR81FPAkn+|+0$7m6WAO9VL%7wG_tSRZXM;FKq=}qM zyqbx*oF!05vcym+@}B*tmK2ACz#%fs({mwm^3NzqbPHydUp_pY-24RjB=jTO8;_$1vAU> zs4P8#CYpC~O@|i^|NIuh3KsLXJiCiVU8C7*mEILM=A80X-SAHr?Ausw*y_&7M^P&( z!^SX%&O*(Yx}!LY+8`v#00oN2Le{?n(vdg!;x5L{#%J`q zVSl!vy)3E@dUk}tZlVhV&q5eF)|5rZeA*(H0=FBcEIVT@zBjJ8_{XG`^PhPbM?WN8inzZfK(@{tV@EngnF#B2Pe;#`OBBXm zE8iq>RI$BjfR+X{o_55|!P`j4ie}@XpTE|^LU$I0zd7Dt7(;P>GV{$?GkPI( z-p~aNcIQmThnaFz@=$hlbN%2z%WN>^Lz6HpLi&RUO4zPPzE8J)ZhGp6vmxsWo}7&h z#qohK78c~2K=M+2`9SRvpX_dBtarL@9%FU+pDy)W>-<3u0*eD+B@W=I&M%LU5agg^ zw4samyo1=!ZKttukGmZh&X-nLFs<|k41d!fG5JU1n*)nKB6Vnmjsd;Q5F=ERzS+wv zKo41%@h`Ecn!#EIxvy)3Q9EA(t{D^z_6l~ZP;p3*E-xSZp>B@v`BA=z)@{I2uv?w3 zg>9gnFxtj|>qK9@swR4!u*SJU^2zuGObl29)DhIk_0LKcuL;k~>#@qY@*sJWx5105 zE=eEEo=lgtsm&|4dOT5dBzV?&>Fkh{rM>#}vPdbfC>_D8#!lgLXf-d-QB{)ZTJ^}*|+p+5tuj<;E$X6}C;38C_W1RNj z!6jYb>j=VxAljf6&0E4$ra97J{?MSH$3Q&vRO2iRutnU=jvoBL^(2|W5<=?M}aGlw>Pjk z^*?oq6%+!~LX<6lACA)2B2+!HC^EorGIF?mj14{_$4v;y{?m>OB97=4=iBkxlfcl2 zKct>ZI{dabU0jVa_bHpseSdTtGAZLDapY+q$OE=!5tEKB z2f_R3GD+i2zxNrn3sX6FW;-5>$Osky;rJ6YX;h$_J&__FCLhoSuW1Jsc3W&Bpir;c z5vDQtOBN)JCk(C+7Gg`WgVotZRL+sFrYt=@d_OK|r8N6h_L~iJYi|TGn0YGn6Iau_ zhef_+)Za+B3F9%`3%S&MYkwhR0kTLKUCu@^66}j;{e6eEB$h8)0EJ@w(RD$4P07IY zu1^Lg(-znL%+~28$1gsTYrF!(jO)~auUle!3n%(n4aYECuPb6}$vxsae^!&wbQfF6 z%%*}(NR9qW`*YeJnTNEhW(-}b!!{o>&nXaQl=qI3Zq){%xdeQNd4O97~KXMOaB4 z)dENOrFcS^Guqk$2gYA-XpMD7`K^vX{8<_~Rlbr+EN>A)YHz7D=tMZXie z-rXm*+Bsb!`yLlgJivnP42(YTOT0RFk>?Oj?x(X(4S1)|G<=(Hv&Zdnxth@A#epp3 z665K@t$*+06JD5)hd3+O-ZT)D=-+)v~jPjop2*M`=z)lhJ+AYsfI>FlX6 zI435Gtp}b4KYZFo8K*xNh3`Z#QmYV9A|-HAr)xvF?-dL_Xamn2n(Rg8RbZl3r>(2D zQ3E!X99eT@c%W6Z+4?+<0mNE@fwq!survDAO2AP+?dU&@s2WKvUK;QZAX*Md)0++t ze_V_;DU*4nK6GgLI!e-h z6_wSR=tC9l6N@i1L0nsL@(x!M*r;lH_8=-ZuRu1Mvs*$J|L($JH&yI2?75nac{cg0 z5LMcQJ_TIxD^!@!7Upk*G#W8}agICBf_;&WE}~+I(oh&mLF#3)O9aq2$7IK6v*7-^ zl}quU`S~vBf1Vv-Z=_tXmDX31vkr(YB9Lh{i$JK!!#(wbFTDi!QV|NZbf-N39SnK) zQo>$4MVW4e%2!RR(aerq{^M zyE48qR8dYy?(q&Ahhxy9Vt>CNG(rLDzU)Xb@#;Lf_u7>w;_0vRJJi;>JQQ!2v6t*S zZK8axqj+1P@yJ@2gO+o+mgOx}$Dh}Cl$FqU$a$LpBC?~x|fTSikA=mIKl4|~Er)viiX z3sy^L_9iNV#aKRtw=j`VCXE`dDnB_35-7K9*>!?<))b36*!iXE#hfaZMqxpOGUw5x zkdP_mZ=x=oz(Jk&Vd>|lGk>|jc3Oo*A`L(2jS)@(s>2UHU9X1f(a#9G@RY-@F9Lqa$@)?4)dda?C(!67!PC0P^HH5QNalQpx22ILrvu7N+a28=fXKsyO zsuIuSzo7l7SS1(cB?Yhl(iv+u&SMmWgw5@XSY?n-Q>evxb##T5Xvk(WSgz-LWne;w z?f0|aj+%7yPIKuR+;~39Sh8a;N52e@!Y_Me-j9;Ce|M`djk<8n!I&cfh^LnHqGa9Y z--J7O+tjLl3Q;!U7I)l<%3cgA*FbxiERRBlT<&cV zFAPQ@|GkrtaDVx$HYG_vo$pA-zQ9)wZT#!4wiwuTl0a}<^(XC8dR6SdTCaWN5c6vO zjZCc%iDf=d{;tuzHDUjYT&u);RQ~aqhYWFObyj_?ml#y)eG|JrwQ&z~Wbv7}m$$w} zNsX0fSQrO?hwuGxQ@Z?{gfEh_@O;Y*Y)kpq2H`yzDr?)%-a)*o} z@@}snTKD*{a;buSJ!0wx+h4NS=2*B8S9MXlotzF^^myl5LT4=R`l0tW6*qh0hqgqeJ$yL0;d-(EOn}v{2E*c_2fcG`-QIE3oc#+g4-T*NeO>&e zuA}f*`T|wIKZeBVFjB2E@s#*%8vZ&cjF)40YNpT2jPXB;&O92bKMdpVorSRv5m`qi zl28;1GnP_RXcZNePzouLZLUfwi4sX+N<|S`lw_GoXhjm0GDx=U+c0MC@B91DnRCo> zoO{2^^FGh#=_xZJxk&ONcahWH!|a9M^T=oy=19U}9p1b>Bw*BN&f!{oCJ1sLSjcei zs6a*C0gM}Xxu==#wTWn4$GxTA4=W@XS#OBE7%i;}@P7bkmo_D6y6Ub8{}^}dpj2!-mKHh_9pt=_Ub-!qG=phs`AB^aqWW0*8|dtWi{lO?^-PKN?)Z ze0oIJpLjs*|E|waH%QTX4gb*mp}y;A%0ONEwk4z>zz^}4sV6TZZ6?93eGM4?N*N`l zXt`^-Yo<`@VIgKo=JYW&SBS9|KuCLgTWdHSQPGy+6feV>=?+DF4l8`vIc~w3Zp7xHa9lBr#5X^z{#P5hId7Kw z7i2akgf3|HJ5@IA%-}p=YKGMKhC3?KZs5a}mydUOmir2Q>vv8?w|3_K+**fAj{i%# z`CHsV%dg$D@9tN+?XF#U+xrZQi5k>J{$h`lt|(_dG%X=_ZkFHigUH5W9up|0(|Xov zYb%BRzc2HZ2@ysC5&Ce3*^F#@M%ylp8T`R4k zf=@U<(^jpoj)pVCAhzcEF&3!%&c~e%Gt5O6|2%^!tex2odT#l&7%E@NpMuYNE(L`w zCBa;y!Ch^wzkjzPckZTIRZ_ags%Fz`J4z1)G!JX7ssIK8D^M7}#kh1l2W;oE?#^nG zh83Z(32kUZo}jq&L`KT9?3e*@J!%*_A5j>ANR&a_WlH@jLO}>i}-{8~xUL%cQ3$9ms9mlls5OFl540AcVW*a$w{-4$PG?Mev=OZ?^?-f!1!dvb$a?6gU|e{jnNNEy>utCB1F z@buX}50?=)cKcw&Kc>cP)@^~&TWZbSNVL$szfigbczX(m!?!KO_vG10!Z63t=bJX! zWn>jg-A4>Jmg4#nrLDw>$5+oc+u)fjz4Gxrh3W3sG?pFy=iJJrdF5g+p>h8?iTM>| zGzG>RKTMvyJFY4#4W`?wbHu?XSY)_5D3UxFG$M#ssC20wI-!v^-(FCDUn?|;nd@#B z=ixqb!e)Dav&HtbUo|;1BBaS(60-?^!_@vM2gcc@5~yw|ZZJ`rrT2ds!HUI*w7n?_ z{BHWbUdZ`+{H8v5X)&k*UnLG1pTq55ufaQ)N^wCPKPo=9XS*cNtVPVy)O4=|T)K`=sE-K0 zb^wq6>G4P?=MQtA&^b?DA@K@VtL~0D-ITU%Oa^sMF#6!@axXsnDP4t9q-N1&bx|~= zjpj`F1+;hADzGjf9NNkF-+9jJmR?)><+$0Cn875obZ|JYp9)vbp#q;U#co8s+l&zE zux0C^bqz$hI?_6kB^qO+5cU6p z!KJIM%r2tD)!Z7%=Di}pv&K|ypY`e>k|X2By*t)wrem9hP_R{~H5g_xA`9GDTlcwF z#XumlEvr@?Da6i?B+)c7ez5WrKmu^*6=LI~YmL<-)Lc7?p1dUeG+eg-cj%#E+mm6O z(4^$?C3kK9G{%>cYai}dyTeV!>(|@YRrBJU*y68f^==+UQDxbI^H*Oi6Z$Py>i~M+ zgx9AT^^URgME|DZlNU#vuYUI5M+C`JIB{0StgV+dGzNrkax}`jYoy*@>WC$YrhDJ1 zVprSE7NB6CHkT&pt-HJ^yvTMsUrF63es-SP@*}a;)e0%-Z&k!tBt%_2vEj9Fp7DzT z(cStCZDdF09D5!IR|N7_H}^NYP=>Q~QdT1eOI5E&Rv-fs&($_mISd!=g-IP`F4_q?H=9eWgw8-B9 z4nk0me?|#b61MBCBH28qSV+O!WXJh*uL6o@)wq@+S@ZCRpHC!6+!P7k>Ao25@U+uS z5nFY+7;Qan;vOh1;b(o*utNUqRX)_|_)Cyf zCD$1+$9hV&ocQEBP@-&RedeO#pm6ee;LIjlxX~_LH%EOw@SOdR%!%xu~#InA0f>#M)J^MO-eJ;|2-WkV3=7lwt|n;+#xjs z>0`lilIc>jzP7dpQH{;!XFEpNTcyI|yiUtQH6_og=%%kR)*IfNoh=-mX>c{5n7bRq zIL{;=lRoM(CtQYMpYVlb^v-6ev@P7VS>MK0b;56^BVqH}>QKcM8QExciHRjlvbSo25CY zHAa>vUfr-tso6PW!YQD8aA41PVa^VnIC_-Jf*29vb%h?-c#Iuo9H0{y)mB5iKn>!~ z7+*J##EDj0j;?>Gmrule#%NVq07qq6$8bY`MUHJBYPsH07(%+~O+!!+h(X4ltXao3 z_yeJXI>QW?#9RN+6PVZRwtzV4^3=gPQ(t)q*duOkCBc0_7VYXa%|;{q$YAx@sP-E? z)$@gYONBOfWv;)?csLLrYW8MQ109LHLVe$K#1}=!NqPDRPYx3Rx2U*soHp*`jOmG^ zt$~EkhdxT&Dy)kz-`<2#_E#7EC>DIvh-rCNoxByeA_sx9Hi^CiV~FGXxQBqRnu^(f zz!wIR@s47K$ z@3d~+m|5L6{dr0Sdi=!kcrZ16kH$!#*#?Ci`y7N;gY~;=?}ib zH*C;drdwV8%{+G9ef5_^AF?eKNBzpqJ$k-Vj^MkUKR@ZZs6((x!#80tR{n@!g{RT8 zgiEe8zkQ>h8KtogweT@^aXQ<)IhoHMqNEJnGHw-r{eT!tmvhl`Z_xZj{0e1SmEJP@ zFp~Ry|4>E5;n7H}n~|Ii$rXqO@=up?>|!Fmu}CG!cfrFbm!HEWBw34DQQXS$xx+cy zl|Yt!_@eq+=%6i?`*~^T;g@wetB21L7jvmz65RIy>o1n1rjtNpyu@*|1K?5WMsaAP zDE_{PAQg@u#yZjI=!?h*(HE5@SjDuNzmu#AOhsN2 zK7U+Em#gpJm^W0tw#Q3&nRqjPP_Vt(SAQ5$;E4i0U8}T+*Q@!;zPlKLx))3K&t_FlaiJmltF4M0^c?(V>VMv=5(nmiy-V$1aTg z-3COABDG>{o}2JoBgT8PWRUXOkvEmtIotMrjy4s^UFIR1Q_eh^uAy*>PBmkSKRxzN zstC_>Wfpj?QdW7LiHpenXu3@J<#55lp|6qcbl zYE6gC*{aN_8?yT;^_Lf_? z@3`VpixWBy$ndZkrcs3Ka&ZQ@D0vnC-BxM(A^rXFNh4D3H_w15)fvrQ!W8?!5BSMN zvU^SIi2XAXMmB*Xlahvk<)bUdEdxr~BPXq*(}Hkr3_#>a{S$E)x9LT8aPW}@%zyPr zd3bN6XQZ>eFzcLv_~*-Z68@V|&Ju|BKOyGKW_@9K>B6pmlGlkEdHBvO2u@r&&UQ=y z1#!_5Iz3}1V%)Qa-X99XgUn)7LRN^`7@mbamu&wx0b(2(m?Sbx(abRDC)(^YT!FRq zjWsu6mv~uxwY$nZBO&1@Xf%G_x8#@Fpz~0Z)~~%qBUMe2kyqqolYL)aye{1mD{f#X zt*uQ~JfXLNe3n)F^`LB3N&bs5Ecmtd#+hC1?++eZ4jNa+98(|Nx}g8^ALII!tp`%p zY(8MDP0onc`YqT)6hBLSW?x))-04Szzkl;rjYwj0rcisE-?y)C)S4o_zMgubbyb@3fANeDE#zpU%d2&*pko_|Ltaktq8u@99PS#0-bHGR2Gw%b3kl{66jV2<1MTC*Mkq@N1zw;R9u z;%zW`%>9w{eCw09Z3th)#ouTr z#?*!XEPd;8?E4l^p_ba<^x0{=m3Q$w!Y})kiNUebwQ&4U(ph1KK)iBF9vmyyHp9xD zrC#TVpQyl_dk(Hz@-_6dFm5|lih0y}0qA3h)z@_EJu@AO{8Hv%jC88>+@8xy_;yLw zOQFfPIy=qWe}9>LW}7P5KZ?%!<1l3{HR4EII>cti>$PKe^)FX-71{kxv*CYYL&J|w z&4)t;5z69tdKbK&&AW&?nTN=xYk;*eI*pp2f$!~+?g^zrznH-Yv48KkOnYEKFgBm! z^L`|HdtF&AckgICj~oYf1!b7VoxnuiA5-K!#o=V5r4vS*p#yD=GmR;vX3 z%7tj3Fd)8Km^?+7!|HPt1sDtwzlB8m&oub|?LXHK!SLvxe<*vAr&r*^9{N~owBT2RD(sfQjvV|L+10cTL*1DU zpiaR}xlY4jJ?WIWQ}p{aoD9qI%2bEKtc%{fDP_8I&Vydk#~W5ch2F1QC8dMPETV0% zroI*&@4Uljhdj7gTz2}Le#kTPy}F|CVfOvH(}c4A7MgKOZuABP-YTm(n69_JmudoW zwoW~4ptxC9TIa(SnFo97V(jnrZ;Kq;FfVGo-IjV$ zZBX}^jJK%HS%uUitg>B%{n(lLRq_8Jhoo^^vqq-q&Rw{0Q?O-kM8|%m-LJ`h)|t_1 za+hv%*g11QpCLa9s~c)0tr^)S`1Z~%nwi+Ty7t*$(O|~n3$u;WzV*9+m8p$~KYS>| z`V#V^rt1vu9GYn_(@KKa#^#H$(i)`3fuq!X+FC7|K{$ogAXXguzD zJ#__fa35=aLOpxlvKZ4{>nw5;FQY(x+Lb->?O@< zv(dEKJHd>sjX%4GUB0#T!d&pe5B&6N`@kbU> zK(SOFidU$<)FW}6ATqe|fVm6cR?42UACHlMUh~be3s@4YYK&ODCz`=ILHhA>Y{^j) z*JFasoa2UZ=VF7irrW`7btrQ-Yo99G+n=(BG!Kde5usPJ2 ziuU)hXiFvFu#Z;vpU}--f!8Ea zIl$cn0W!QRdCmVD`VmM0<4$1rdI-MM-|;_^UHY>s8^_-7Ke$LxpFi(L^RPwE@S-j& zci~-VM~Eo#j=blbzY>L@o&)2%ST&_#G!c=z&U)0r9V z9h^N`Y4*Ks-=ZI+6>K@FI4Tz}lzW_uGLa0Mo1B)aqZL<{T$4ZX@j%k!uvhmi0it64 zh}hTP9(tIhO*NVrZnEQXLl4Z_ig5R5a!rsTrrJsj~Y)<253GUZ**?1(H?2{ zRSvr=ouYQE#)cD;%Z~2Go^F6W556V(Iwh+so;l)jwbS>@NiNy+!0NkSlx8QfH%s-t zKj#AHTIEV7EGip>i#3<5BOj}~!92(83zvhHqUTYPj0n+|mi8_m?1@wo2`?q^aW`UNrLD<9i-pDVm$d{lTUr2Gm!$O5$q2tv)mx^}k4ZSJZN| z29ZONKy#cuK>9}pYblq2Yf3N~G$$Q9q~jHIUF-QG(!jru18+69nDp<|BnO3fyr$pwXB~J~NymRM@5IB) zW}_F2WZ_p33*#M?fiNPJLdW2?ppP)Rko83Lc|I&U2bJ~rqskmTCRuy)9D=vgaA|Ha z`CYHzuXE<~{W}=t*IRS$F~3qEbmv)4)iI|R39}^SarRl!2ljMBXvK7wQx?~pGe(28 z@Ix+X`SY(UpqTv-+e-KXUOa6N0~CJqdneO=KWSVX21c^yKt``a)`;!uFT=>1mucMI z9ND9-;D`{x;6V->pIjr2g@H@^Za*^4?7QWB#8Gj%!ORVV1vQs+B6ZI8*-`gAC=exf z;WlR)pPWov-Z8VGv`~(cm-6N1;nN4Frbm}88Vw3=u6??2GE3Dt#r$Pq>e=BTK+EEKB_G4(EnX}t~Yl=_2snmRM(+|W%;%nx|2)V_3r38 z*Zq8Mm~!PMdo5wIle1oK$adN(!%@jm+HB#WTc=$fZuZ`Y>FsX}QQkdqec-3El`6m& z%XvMc15U1#i*c10Y}rm(RCmX{G<3P8SWZ1hb~ZKe1QDNdm7Q@sm5I!4vI1S&>c9LE=DRh z6UwF&+&?wdE#-5jXnti0_S`exWUplEJa5NTLEGg@WhJtLxhcgs__*mGEj<{Pq2cTl zY2sjws-}N^2Y*@5!_FE~Bd_E1-G}{C>$)qCJPq_F?TMV8xsm$N^Vy)~x?u3hm@{1| z4z5c`=$Upy;HRQcX7=RjUFav)z{NtW$_~Qp{ttOr^?l3wE~ibCgRs7Wj0LiA5sJ`& zvYyVmN-k>u{Bl(){3(~F+%W}SBWf^=pu)H8sy*qVBMXp!ChZq%KmvlO81L|z57z6! zWvu3GpC;xNq;;s6H{t|})_;|r9r-1yjB{E*O3Kl2fzYl{g~FF52V8ffTaLoB%718 z0eadiGlpMR=9n(eBmUP!5t@l6N$o+B}&eR>#=x|7C5rRp$ff_{au_nrobw)BwW z3f&_H78wlgco6qxM|;`DFLrjV#zf^_QQfKX=s)E5ahddTrq1)wTFiSTyY#a;yQ`&V z9q^mwwyEZXwJ-FadVGIv%KIrT{ImDv!L8QOf9h{tmK4wOmRkQ*EA95L=0h7s>%4TB z*cUwQWtLI>OOu4PFWgkG2Y6qJbu{#-iTZmp#7(R=;Oyh`JduFn=<+m4mI^0#6VA$K z)7;Fj=3Vk6?l1XPuq#pr8Bnj32%7J0>knlP*G~G^HC2xsq7|%x%Cpl~9L#Tf zE{N_^-`P#--*`er`J*1_k~USEYy_1Xstd&K)I9!IW|2A{?jVgpa{ihk{>%-nD5TPL z`C|tC5HB2JbAaOy3*{%tJ|Wq*7m8<7nBwgB9yPb`Vfp8zxj|2_ww9mUh&PjgE~-2z ze0y!^_hjwNf#!_R-)+N{v16Za2%irCXE1Bn0xzYoETCmSY9oR|H&xyy%hNwvD@`O= zY8dmw_2=43flLJ1wtbAr633bP!r z1A?}T|0=K2{u9?kAOXaLQeTZFzdK9VP#W~UcRKDMahg3uSsE@3{QG0du(yW^BNc14LUlrd zW>?WQ6Ti&Pm zjlbp)W`(B0(~2RV-pMuFn-LXFT3v4tj-i4C0e{73Eu3_}MpxwWO%{iFjT`NeLUHaM z)Ip;)7k|43W|Oqv$&RDy3jENF{*l=n1UPmif$ZX^*i|LS5*n?D9_72eb9gjd>9u3( zhA5V31nveOqiV%)E3jYt+4;v$;d@_A;II5m#rwp7oY5x@sLTHQd-n|B(z&ZYlAf*y zO+ZS_k&}1SjY;raEGWs@A2FJEY#li4CdN645A1|WWKW*Kp3!(qX= z>x9mCAJ?XfSBb>yd;S9SRo-b!i@cmAP>n6GoP; zVwg}#h4pe+$3)F<&BXz~N^jm}@B6(@Eb`CgBOeSsEB~DulmDSZy2;M|0|mqK(D?ZC zLVPZic>%Y~>Jd8u(6=^&_dM>0HlfF%%qqxy`zNZ`OG{r80~$XW(5CS>Q8|+aT%qnF z3aGveJ>PjO`+_g#lHm`lHCb~w6a5%0Kj&*E!Q!r!@G>GPkkH;cdHBvoe3{@h+4-$ePc3Hh5{Zi*xPR=Kt~$AiKxRr_7)XJ?(^zi+$N zz1c%4n#+a8jpue+Z~I~O0c#?btoxlj-{yqGW(teKcqOathH|W_4(1=@U#vYRn|SHq z9_FvIv-*~LMi6xGOYZjHmaM2V6{lZ(p$C4Bw}%quSK~1)<)$rBZ|talXvS+@ujl*3 zciAtuGQ9tnoUB%VYR{Lt7W{4N->r^oA@u?*ZfRf4-btlCokJA2VT2= zE4rRO3rRX9a+T{^;(}|uN zx0SVU{2lw((l)KJ+p=Rjy0a|)B{M-<2!yOX`1?!xf??g~ZY_vD3` zF@?SWF#LXRutIMoRX^E_>SbY-;q_YPJ@!E&U&gzESvDl2fUm)d?s{vXN)}^B%ExbPwtqwyeq5mf2VKL<^9bX()C`al!J;ayTJ5Ps(2C-Q}2vg`ov7L6<6$dNwfR9A^` zw?x{};l~&^_4?q9ufWXt3-MO;az6L@QWCnvt7m-PGYeAL9QU2bYvnJ51)x;X zCms|wa^lW}u)i|e;RsP#>G*C3Mn5jk`T!I~T!MzRUR1S4)gHJch4+FL&xfrNM076OTeq0;1OYQe{Kdu>f>ml-Lgbd9==?Vp?GPa zGw2u?rqBWNibxYvTqQOG_y(+6o#$cp=aB;Q?JD+}QGuW6ODt1oi7>TFSCkl8T5axp z(Ro|aCauT(oq^96r*Jo#(@F1j<%`H)KluZHgn*+*J@DrK?v!W{i~hmWvkJH{)bp3+BdCi5R8 z3l?&BrHGOF>shJ#!Ey(Qul-%KO7U}zZVznPtb4Nm_FLN3TOYnoE(v)0k?lFVu};nc zB5hmtKD6oncjN26mpVUR9a!4EN3+u&vQOp8CrOCa8I1s^g#$qui0CyvvK4tWroFS5 zVg^Z^SRd`DaFQBl&6;Vg>3 z^oUY4zlr?sh#pk^1iljfxRsiWhLkmS`MYlXeJvC!z`*Wi@VlM#@!JIA!(-9e@$gT4 z9r)eFj8_l+y8q~PeT)e`=eXjt+uy`!N#D~y9@*p_WLkY5u5Vb6;WV`3oO_TW!C8uN z)zTz405>pJTv0mHnHEv|gR;Pk9;%p5<1&||``6y`cBr3;nA*6G@Vs=8r9vv|=$QCm zRC(;!%<;7G;NR2bS?){Ch}Qc49Tc4&ku{ZLB7ukCxoQ3wcS#I*6)BLC5VeQG(^R{# zWB+`$!_*RSq+IF1U3_o=mq3@IJJ4S$=0d8cbD1&lb@J!9T^V1e@RXc^nAc96n8?!EG~77!>jNF1shl9!>*29r zD(=!uyy#N#nn2>fMdh#li{WY$LK`y5w#n6Ke#!WV#jOy%IlIc?C9HZ2JPA2?el7;T z7A(ObL)@~_CP&w zao$SN!%`1+DYNaXS?7nD#$;B^*3!5QRbuH1O-aXm27Io^8(Ulw*`@T|$ChQB-MW+$ z3QkhTBw?%eBkzV2t<#<_GzPUs3FU`W8D5Z}NqKrTIaWUNELHS; z0ktS<^HJ}P*>|I#|9P5S^^gq8Iw=^khk)ELC&rcRISb&ROW;OHa1*aBz<1Awq2;9E z8*~!O6o>lDMxjMZK)pEzM>me%TGrxM`~PLcL*bizIaRDad0s@;gG)y=C>*Jm*DmB2 zEKXrzI_koR$hz`SbD0r-;ggu{2`m~Fx!m0%b#NwN6?aJQU^v&CX}H98 zb2oiy+!;;sO;o2JT`%%Ylm`3_WI=U~?sdiGkM_xRW1D~7z|g4z8TBEb zToxu28jFg=f{=vdgVB+C+%op@$;;+Fr-RMUI5KRxb7yuovk*wgUgJ5@7NBvTr~z1g z9>QX!N{$L=v<)Y=d=_pql&h!l-fD4sh~BI{Lfx72#gEz1*S1r*WG*v%UVUQp==T~l z_MGk`0_HLLqz<r={OTTD2K; z^cdeBKOINT{j3h^I8+IBt9ASI^EZ2!=wD8+a^bG6Fx{0ObQerrlAoEp68WDzq4#>| zsQbrz6)C61&VEQ(&!YHHWL80oAr!?a;kSSn{A|PP@6NkT+CE$;opk;D<7d~Gk$)F@ zR%yJNGtt?&4R1-0iQf0)4j6l4+(OL7@*SNO6eTGx24i!Bnv&0!TyFp8_dbw+*^t7y zDX*Z^eH?Z3>O?5Q%`&3!YI&xuJYpgJTYcn0fGA_%BQ}Xu^RKP;&j>$Fz>ZVXogkiI zuz9UC9FG;(LNSUqz8`L+F#P3zx=}z`*f&8X89zXRFJkMqC7_8>Y8P_e4b6kHsH%t9 z@wM>VM;1@_H-k7^um`tgwh%aj)Xz`EujBjmo7s?T@fm;ZgdUp>w4tFl$Mn8mt#127 zO0fP*JiZ%g#c~UWEI?5GBm_ju<;^~BEff)RPiv^tK3e1HuDR@GiLyG^w5jy~I)Oh8 zEBKk8?k9NI%5qbWr5dCx;~D~Z#}VmM-6!nel4U#LfX`2{&s4semo zOX!g94IB`}$5my&;qk?4Cz5U5f@Aoxd(~kt>gO z{ca}fpbWfZhmz#KGi>eMGNMFk*m`r-rOwT|WcU-b#HIGzrp&WRMLP`IE8p*Hchm7a zNB%n2)zF!uZy;2>F~-|W8G4lOVsM_Nyqxb4>-a``xt!_#q6=-}=T2^?ntnJx8&-NV zU~9bZ%u$&X=Z%?oXfE+&oyE1huVR~Q`415x;d?cu!fr*(Bd)Lg=@+H|Zf6#;=(B8# zVDD$01CwiZ%r1QiE-EyYlxR6)-jD?2udv}$NKF#nld5(uJST9U5}rVwgrf6u0mEy= zU}mQ}43GW5V9*)N(LwhXh8r%Z(j~dc0((CR-*bAYp#&5y5`#PsO1%VF-6*Ks%Q(c> zx@{a;EB1Qrr?zfk-rtBRW&{|^!{^O2$?kVGHDT^?Dw;`-m>d-|4iU#WQNMt*Rv>o_ zM{S}t&#hS~kq{0Zb8(C-pnwO)d$I=Hsl$6s>GkQ@4Z@?4@sMlhYW)PBDjJVdsL zwRP{lek&cgtR+CI7rS9{g8EW_C5&muVl}ofJVkYuRsSC zZ%sxp8uD(a#oWRh8^=#p(iq~8bnpy~lXwJrrc?x#d=WtZkOPfJB>}PMp80KQuZcB5 z1+m`XQ?){hrO(r;Va6vyE~@ zulO+g@U%8NEk)KgSJ9Lpd?@I>$j4^Q@)6y?9M@YS#<}eysE|aj&wO?3@iVEg>c!-{ zT!>4DwVRW7?40sMOrXQe?NI;s_2cP3y3BdPOS3X4CiTDD$nZtz$mAwKOTl=3&bMvp z>&BVOEMljB>%O^dJ?r_F&a4@Gcc;?v{{jEy$)o!X0-^$V30 zUA|s()ZRk(yR4scY(a`@rNzs!qF6VjPi(Iy#nrMS(WlDA?+kO&KK|)1yWxDRLFKme z90qQGkiWq&QE%~W`M3AQeB`FK-Fd`bB~k5V)Et#OZ5ljpSSa~vv0H+dgg7SW%hzam zuIC|13Cg|F#_DgYh#Mqo7o3`vYh_RG%ZFVnrdr)l4GA%}kixz8qf!@_U9ZI+T)cLs zS5WpLHB`~L%6n1e`A1W=>D?h~VXJCcvkI4G52jkESrJW)T8(vGsCUrm4*!4tzB?#m zh58?3M(NAc=|E-5@Ce(gW2GYICdrkUVC(L~9Xmx0U$sh^O+KSDn~!xDnDB>|;mTP@ zBzXA=|H@Z%>&CF zu#^>);h!r3-}NdIUV-H7-lW!f+yY<=aXM0(dk)KOzAj7a9eSHp@Lgs|cyuO_ee)h+ z(!^{PY}p{Lu7d(p7cpt^ndF}VuV;v0{$v1fH%3hDnYCTKJNwond2YV{5h@x_q>j`h zfCLS%mOq2wDl{lMJ*o{$s9Q<((a>7b!(6Gq@$(qqg@_t@7XA#j0g~)CoY}+uNdr$; z1cI1XNG{UykuFjO{15vKP~e+C4Ja%~T7i5f1*Pk%Kib%Wip=eHST9`^1_4AbVU4)a zhvkt;=2W4Hu#S#Lx4ocnE;zuC0D*8MKHw(TXdN(TwNdwHN9XWqewWc@#P~O0EkFgU zXhcRhBBmoxJaFJwhfvFyMT!e3-2L9NtgQp-IZ2=y@x>kds4RoS%bE7r?S0nYbNRBr zWsmK6@iN-z2!`g@3EMF=dp7;wYH&tp@T>}E3?&*i0VHl)r~$Ta=bK`+&7YQU|Dv1s zX@A#2nI3;T_Rh!MuG^MF{I++Jxy~z`{3<16wBHvV6zw`v^MKb9=JwfY{nY2|4Xl9a zaD|QIV)>?iu*;j38?*PJVmhhaZ4uwwrAn@{?dH$YkYn>RSl77c?X}+p*cWz>?h;?e zIS$pHdF_AMCC0y6TFq`Aros4uG2QNl;6)8LRDQu_`I~C1?@P`3h^ZKE)#VW%nH!`q zX`j(znfR8eK*55amj#vk)B;qVSq;AyCK^P03)XCC?vd`To{K%Ls9Xa42kel|7n=S1 z+l~gDq0V3Ow|Y(2E06^8kJ7d}@|VE8hhQqk%_J;U=)f)Yt;OO152m-zW&z%|scm$Q z@Or#KYOq(PyPHk5o^W*T_fA!AdmiSI%Z zFFAzp+y)s(uHTau><}|9K0r~REYzmAX}&HM`;;}9D6TXplrV6Y(aRmh8WmU27=>@> z%2Y>>seoh)R%`3i$U3X3$Z+Rn%=2rxW!HAMELjZnl^v6h_)JfRe+Ql6k{5|bI!@hQs`$I}^cA@1y7>1i! zKV*RB50+kjc1dCsd=~Gp+8g(aw6U$hmSspXmKoMH%T`F5gKaHX z%uBBLUZDVMD6}X0HKT6tNY-84M&sTw6CMw+Z2I&`6!N7K=|GFZJB_g~{u-cn+s}wa z#$Bikc^p*_(n%#NR555DNJKS=A(#63t(jA-it@$oXf(<0?U=V-)d~C zs1}Sqz(Fu|aq94J8?beTxG1&*FGd6CFF^3U6}82d<0pQoteSYZ(q8y zF0SwB&!QqG<~pQqDltj?F10p8m_~m~Prk zG3IDnq$|WburF_4#gJPn?Psk%1nzfX16-8RS<3*GxL!)FWyd(bsc#OcA z6m_Uw2z<5`nhcN_C@rXWEJWSg_%FtJa&V7>F5~hEk}=Wjw00?lt8`Mj^L#8i8s8K% zwW@Y+^U-;8yz-HOT42Wpu}~2MK@k~yYKmVOziT^(*#|4OGUM`thL^6NnlonB*{s06 zN~)jjsyqF9Xl&(i`)+FAR@Q^7tyFiv1Z%I zcnJ1)-U!h$pG($8GXA$(D&)GUG7bQD>6FiGJ~r%+&hxXjRJ=lt7$6ePLC}UFA_~!U zX!wouG9R)er>2hp{eFs=%0}w9Xx8dXH1k-1Swc?tKGZ?`?^i!~^%fTyZrtx#TPtxq z^W7=Tc}76+gr#GHbqUUBzaGAK(`;ZFseXSn{UId@T7^ur!Y>m?*2684EQzNqY?NcO zNcdGaOu`WHzhdt}w5Smio_7?6bv-Kvv^8kFJH=oqh08fnlGcD2SdYEixt+33didC! zQyZVJ7#Wa+(tksDujL+}Zu>;}Hk4n<=>p!h4h7VSK!=i$2mn))V0p-3MCzRWyQS03 zs?htA$$ifsf~JF_jUNS6RToKk_haFi$YxvFSmhg8kj6hpfx&06O^u~9>OHhj+a zXcfD-`LCpHq08ouq^4nZ=ivrvzX_dU!&U*0i34+NozS<%;M9{C& z>wrIEv)kHM@qPybN_e(p8R&%A6XLfgqV+3^hC*%)oDAB&>gNf3u)A7<;Z3blAUcLh z9}4QGnk7Rr%4vwLlD}qzO~o&Wfg;#im#u{s>2<2uI+o`#@UVfI1IR_>^pD|B^&W!+ zc}2LR1~S|2VAcR|I_s{)-Vmc}t2asOaY90qLq$r4`~&X~n2PK1)Wj<%X}oM$r2e>- zXLMr7d8k>3=uFS!T$Vho_E#WPUuHB$`W1$6RzSSkl7n)MQvnLlQtms(uU>jP)}vtO zMnFvzC5s_4s8Hm*W(*%Z4xD+jS7oSccV*T2jc7y|=|JW^tx$0&sgOeH9R|j_r9Aw2 zx2ME9?c0KL=csVF;Z-b9%ulq=n-4!rM(esnzer&ITTOIZBjS-*(Wra*$rM$1Pv?>_ zy~K#JU&QM9(01tr1%hw{8xzMVe>?Mtq|G*AWqc{GQ!|xPz$kGhabB-J{BDjl1)o6w zv>i6UH&9&~mx!MExbv)ZG44?oF>16BuG5Z3811mOZohjTeoLk->9}TM8|g-oi*kwzaHUsU zH7z2O)x;;;BNlEBNjG(u9DnpJFwQRgk%7xb&S25Urc>*q&qRnS{@nrA_2)!b#q}Ej zrb(g3vp@XT-yyp0C>*3{tgl;`*X6yqaf44@^5a47&bQRoc+-Zj=4W7(gxEq?s}gCy zC||xC#7mnM5zN*587j{rrZQK{Gj~;n){(DyqGFb2wQ3AZ{w)9=zm2nHC6-ob4rxyl zQHjGbyB7=_ryH~Rzb(jQO(+RPJ$6SAgYk1JbQhDs4wl=sETxzOx263>G?i<;yJjy8 zM=!^XM4sQTQ&@@>Ha-$JI!QAJZ=a* z%00j4yQrzF-*ZpKhaas}Ew(uQ?nwXh(a*%a^8RbP%Q6j$rZRt-JuGA8Uo7=&a+HI9 zbfg&~|g2%T&RF~(O?X=8_4fyS70rS zC)-bqxQf_^H8}k&hB4}^IW6~-!CVp5G#1_#_!f&4+rwJNTnnvz^QzD(u!iK0>M8Xw zz@mruJuTrO^a^lMejSS(`Jy|0PP8#n9)b_zsZLcY>mdNrY`@*cSUT*!sy}Y?S~BJ> z0F?RA)VLgRA^TGw8me3+<6EyR0U=5V@YW?`xC#_WF%Op*xZ;`p^uJaz)w!4C=y2$} zNukZHoOKFIX-+)2{*4Sh4)eU&KKpJq%)Dm^wS1T}nybk@&kr8FKka-%SNsA=h ziqbSHD(jX?Ly;0?-9+}@T=)Fm-^cII9{T5=^FHtQ>;0UNYn-dEXZ<|fq=ndZC6-F; zrD8Xd=0&j1@uvTxRF91mt()=0o&`^5Sw^%S`94%0J?tLyB?d)BW|Fp#Wx?XdTwx}1 zj5&;NpDqbvDGNk;Y|eP!`+X4*cU;U_6y!cowo(N{`tnn;qAZM92Sn^GdL0GKu>*Rn z5V>#s5+7T#J5@q;TTG}Vk{Zrcz6ai`O0D1NuavFdmWKp?kKMu@z&P=~4<#)6-f8yD zEvdXwHi_!x5KfFdZ!jBtZ|avf;t~^ZA{Q9&>MrmEB+C8YE3s4{Mib784{1X6N)bnu z9WsG5CUxXbvl7l+vJH=op8P3 zp*?X1QMDd2WVcYXD;<5BK>s51KoAQqD*kI^fahK@ZsMxs z!T4%jPJG<9G`UWVCkP!qPa%_`j%@e*SZVdYPg(6?880p6s!u z?2Ty+3wgDhvoz0T>vZP*&0PY5h5YN+uO|45D!+Aj^eN}f6&xnt{$#;*%@pN_KQ&i6 znOa8v>Z&;#dm6&J+oGq2UJ5bGK5PUtXT+#qeMc^EX%@WWWC7&l=X ztDYXl;kEy&Y?})#DObGBmmi}&2X^k)BI|ZCx%ug}lK2BiAYhipEB{!%pIOWbL+`O% z{3$#TyFx)o&WDJiRc&u=Q-R&Spbf-}TO!!Z3Rb&t-D7l(h`9~c`>3oNSWMDJaCt}} zSm2Y?w^O0l|A%$j=6&y16+U$RD9aG@5-{9Oy;$g#topT(pJ=P>Wgv3o7Buv$on82Q zKaiC9Nh&6$^uFEdKHjZ8v4kGKqD{@}YMFn3aj;w3;IH!FT1z))&)BZBlX@lj?!_@( zG-b(49`r9azQ~~8?eb)r)O{Z3fpM-BF$fAQ5-hN7gcv0@4MznCO&=5Y{VUzbitGKJ z8-Ey>D14*h46yA%deiW!&*N^c25cGZg+9wPnp3S3KImWH{@+);?66Vj)CF*9QQ))7 zjmipQRtne18RP7I#g3A!gvG=~gck`8gpmbOUXq|VyskPt%V=($9QCrU z!VrIpv`@Bh9KF>VN?rE*z=8|FRW8DjOM)cj#cBMnX`zjm2;D|$V^yq9fsn(k<~|z8 z8~Tp4FUH@W*8T9OHKpHCtgFl^a>;60)AkM%@{^b8TY!$L?Nfdd^S~+%}-`KRRM@zFp=YZwPp3aX)hR)B#7oAW(?R(#`Z&eF$vloeYGq&Y%U#&t^*yw`AK zc}2GB8DRz2H`yDUe)y{#WxjWgIrs#hKT}Z}-tyAFx-EE93^2FC{D~D*HkI9++FhFI zS{8ILy@A)ff5=S1OT{5X2LAOWsajc>JMO*4IjUB_f-@^$46G0K7$*T@yw$ghg(m$L z?Kv(8!Ibq^?iHY<%WYJzFJ|}gx~}-c@dsFc`IqJ&o-yyQ9MS)=vNzey{O-OXJSh6x z3D=D{~Bz$gEuFN98fI z;XH}(t{bx=dr6UieckKTyc$fRcqZS3&yn*othfOUsBL?h_63odS%>xDxA=?6HBiSR-2p>q<`p?>7vVIkI;swk;bWt1P- zX-6G?YFfnJa#Ar<=oIRqV@gvzn<}FlR#OqlB>c|-<+UehQC`TxJw+S1L1B9kCrYBz z7n)J_K}v>d4+DXi#<7;K89--SilyvFyE3PGTiNk!3RFnaS;)hq2{9YxI42!WhjSv| zOJhebWKK6dK-baC$56@ly^cR~RK~_>v*8?#)|WP{)d8O;hXsJ2DIxD-giz4X0i_dPcq`|?d{Zg{j9+3_*LcHO570KNP*Jxz82 z;yc#is%aoDcUOUw*Zweib}taAk|X+ySRo4|wFbHv+pc1Fk2#Apy3kwKF7=dOodA8k zEym!r%9VyB!@b;JRon7#MU>vODFuLBpp^!^L{*t>CzrRJ1UHy3IpkLmYr zUX)ZBWbpjC1D#kTkddM%Hyopy2s?qs^otFzpdW9e+QA5*EwBfqdM@W9w1P(kF^Jd zt&cOc)xe93Pivm1{0u&;0Wx|Z3mSi}hA3buCafM`JLuy(KI>CUp5ES)nGpG_dIuai zB9f&jpfKaf7U4g*xR^kZXcw@7&HUwx|LsP8V}VuQgV@KuNwIVh_o?P32xcOV&gfb) zvt>I*Xd+1}GTI+wDd7qiY@p0^dIOZbcg9Vq9PNcf8#)UWJK9F5@>KoqE;zr}l4LJ! zwJP|$cN^RN&wo|*)UeY_ehln4^il@yjviXrgy~mu1H_!o(Hf2Yr>sbgq!Km{G zi4fJ>TE>+yj(%ZXPwt64)+pW~B?R3w&V~2?7(T*++@jWm$!>2p<0RCjwmm_9wRTt0 zq(nn(y&6;D*-U8$?X6C(jzMU$+si$&4wMxz@&#tPR!RKT0T&IX)kWYg{s$~4ff-Gl zMaNH_VR=RkY`|ITwAq2Qk(6XK4E++lei$*`EkVaM-6Xkq(2>V&PEZ>x2(9U_)Dl1Q zwAf3e(TQs@GzTqu)8r373{=Yx%{ysfFBZdDzmv|PZ>;N_iek@hpW5U)F_=bY-9JK4 zK1oFo7U4c;bCSyW#<_6h)^M2T-UpJr%GBCPF{j)e3s=wVQE8o5Ut?7J?a#GC`xW@s z?sgigJ3spu-9P;wPjHtCaTWs=%X1kPXghu*?FB^0v`@%+G4Y9XE7mIFVK>7NKO#u(M$6X zV3T^VzH$vt%nx0KlUi7x3UkgP5OWuV)m4vij&^v|?fHy_z=6t#v)QPZMt8&}O^#!z z=~%M7hWcB<0B5U%>fqtyvcM~k)mJh0SjCz|Mmq7d4rgIU3D7<_hq+*T3& z%jE5ye<6D(;(y8k=U(b=0U{Y@MyzwqX+$gI9!7_%Gl8g8IeySGN;nOpL?UN; z0J<}Br{mB5M8hFh!bva>`ERHNS>QE=#0~$*ZHwVQ4Gem=TF{VLOcJ7|Xb58oFA(Kw ze9>PHE%x&W+{blUMqqLycsiX0N z(4q@r*6p(R+#$}3-qOQSZjVhZxF&&4Ys2`FeYa=L4Q+mFfh!zeO1Tr4=n) znKX%tGNpm`!;kgqA1K5TeCyVR1kiT;FS2{e`{U`R2bYAv^M9R>x6TMME0!eE~FpL z&j>Bmf9tcG54(KeGcQ3eYPVX8iiQ&|Y!x zV(34IQD-mI0~b18D|{4AgCzDrIVS8`S=4l!dFU(uTFVdE=AqW&pkCR};lq0>Zu|4) zguZ$=mukHwrDNVA< z?PN1K-2P0_IP2;U?1&)IWxjX()mXbC6r^)}FXqiNJtHiqAK9Vep*?ZJPcNhk5D!>o zUB2F99}dq?x4-Q8y+_2LhfYB(x%fX!W;M*nTOfW;%v!2IQ!<4*a$Nw^7vYBY9q6aji20Vw z>_~l*-)0$a72$!zH+O;~w36n8XbBZ3GXb^B0`h;L?Ocapg(>BoyJzw#yC1h}fbU z(%#3XgS;w6QJ^6238x#57-9h>@u$IN5g`cYq(`I-s6?IQ%&O2w!j**{>c|{mx(krHH(VbaZdOQ)X-Mo1Qp)$a_#=~G!Iu)Tc3L_cDKF9 z?3AzW2R|8-<%t^Sh~6R;Hf?FVJ*Z0meR8_U&8STae86s~MZEGX9 z&gx)6CpV!`3x1^t-HUR31wP_a7RHh9Ohkvk{x>aey;1u1%+8_Yc>c5;c;%}D&dDZ6 z1fL*)J)ex+JCpyr2heq1{zT*a`i^(X{8rVPfatvodl zUl_k0W6@w{*3^2Qf!ZkZY0pqzH$lf3=7?^kzL>n#W^fRazBv5QXBE!R_VHrcJ>pyn zY8lU_E$S6c>{Fsz96PTb%X1nb(XMU-UQ%8;bw9agN+ob&52~y|#UK7UFxw+xv0Dm+3K8WgzdM~zKEhb;B z>G@h051raO^}J|~bX2#WZoK#4_&S3`Bl{m}p6R-onC*^pf`^bb9slq9JNL;S`{}L_ zFq=GdddcRme&a{$&uSU&l71JCD;Rq4dL7zhnl`P3C1-=*hO+Fo+gdOSYp1evc5DZC}m8U-Qy4%9RSOKd6f;fmU-gZv&1j0h3gj8`mBwigN4CMP2!>oE56Z*OI7(M@w~soi$&_BIn_Alv}}Hi z{cH0Af!(25-yv_%vMIf z*=rL-ezYKrZn2XueXl%-&@MPoROj=dSmYyNrZBUtA2^TiLPu8)g!x<-_;5iRt106R zziZ|qtzM_J3gXoTKsi5c~F;p@!trq!nByFZ&ek@y?6DiO(-S;?2w z2D%=K^d37s^BNX%-Ls~KPpP6JxdpZNkGD-9ToR*{i!*UYKYtd^Iev&9zSZhwr}?}!Iem@l-p8ND>so%`W18QQm~5#B${5shIln%2`%B-WQq%koYdI|TW(AG9 z#0eW;1II^59r@9nwcZA%-T5Davlj;ZL-{M@u!@lcqnM#hB`xuzyW0g{XdY_zQ}L=< zSZSDV-r66XxyUQ+s0aiVfprM)V7GPm>6atdU%u`#aCMXzjP7q7D^^vbquDLx!)-}| z=8kiX^k(s`GfMKIY|?GR$*vW@SzdwEJV`QdF4PY|W%Qj7%403E&h4pfpN}Z-Z8V5z z{lnzPspqQZPZAabhTY`X`N=I!?*WjBd7zU>_oHal?xGT6hUn@vtcf#Br~M!2e}}{QT>9me)A4TzN8ZY_l~nh z;#wap^xx8>xp*Am!(jv*tNyyrY z;uQ^pN0KA^UZ#1rmG8z_xf=$zQsH+@*-U=3qn9=~Q9)X~Vd|)dmBr>hGK#Df%yJ)f zF1^Q{k@11Zzd#f@vGyc+tV&rz=wqCz2GSBkL(6c?XvjtCDc`@ez>*!TGZc%dI$JI1 zTki1TOXcGE$Zz1(-yDnVFy?fV1!XDyFk0nb8UfI-sQp1hqENdMSJ-2QHVOJln@EvKDNFQ_feQLd?-jd zsGKGS+|J+f41PYa9ID3+fHPds$)YA{dD?~%4G+B;j6x9+Ok(ACOK1Jv6~{)0ETcnz zm-s%Qmkr07H-?ahkEdo9PgGw`-*6Q z1Rfv_Di30)UfqS(K4Qdv!iwqzgcf)rs}@U-rBrE^H-yAuotlIl2vf3rqmR*MFD0{1*ls z$}rjV!iFUQ|Ar99U3Jp!Lu`{toT79N`~g-q7AQ>M=+ZYt0ry_u9<&ky34;ySmIw4* z=p&_{1MI{(_YW>@@Ba32c#JK50o1R|s(#X)O`$NGdrcXkB!z(GcE8+c>dG%e*Yu{y+}ZRvt&41HN;8!jMtINupr`MxDnh;>Ngh!kD_<-E8WVUZ|~w44YYTp1@l^r*LQ{T&36_UYX( zJaW4xitR4`b<5;(zJvPi6vL#2)I9Hlr$~*f-;MYC{%hC`j*nH2oitrYT)Q?g<*K!c z$@s=DE-7lTqh89I^9GagVrHuNnzBXP-b`;lNhJiX8Tlz+d2T1ygW>FrHn8x{Jv|-% zUTyIm6&XK9u;M;m`*B-unWZ9=Ag_2#r5~OlZ(R_F7~D$*Lc9dHOUnY%t_VQp`*vA) zlX|EMX9j<nl@=^+%BTKoJyDNswCM$>d2(!ytumGf8nz`*=4y|qu z_?VgU>PS(y*y=6Lu>QvX`7KZdVnXacBLTPl2Or38lHc3Z-Y2WK z>v4tm$KTI4r9J*F-(e#Xo$p#+9|f-#L-}N*hx=Nzfk!iuo{Hgk8F+Twk-0(!YjcHa ztrFHM%Om%rUO&jAB%$xX=nIrmI1kMCPVJ@L*z*I5=X^m0Zfh1vR zo)w)?Y5Iz-ztipDSP995A6Qgn_uW!N8&)={o9bIEt{FN>w@piUX%_#i3AQQ(-dw6RAQ>_K(+ zn>EC<5gg60BCXZmEWXYxUIatQmLl_gd6V*>Frat3G-z3qBYz#)cs}~cbBS#WGOO7i zoc1!H%o$^!G3lPTWa_t)f2VO9@1D|7?aw}`S^s?X)P9{`?wfDZlgyc?Q`$b+!vy4w zy4`#o1~>OvXrw>-8Eu??GoEp6)2Ct6AMMUHIZC&_85i%!d}G@DtW!8(@b`0PCl`jx zeA9*TZTBQEBu)dj#rhL&(KXzyli6%Odbl-$Mnvkc25ZdK-p5ifa788N9t>}4dTJ#>N}e^cTKwgmEQ%sGE+aE?UXM&gd3 zB+fb3D9X6l-sx@ahW{(DHFqcz`3o6l%$}M4#96W20^=+?Qv-7pw1fb$6Z^=~h@W&q zoOBivrVBdqsw9$gqKSJ7yIuwulWO#z(xe`md+p*S=-#g@PZOt$fk}g14qxvN3+)1hIIBp!tQhfEU%PHfsT$O6Oq@3r)D5+Q8fvR=q{9A@;@oG{2JCxE8kxmH1M(d21wD79^xH z{_DN;vU2dvg0<%-2#oY!05RBuY=5)oX8z6Nfb=emg_{XrUENWMJ{cFvi-A#t zdSOmCW_Iwd-Bl5m<*0AyRjg+paDN$|oBQt38EG{%(0wkq-@`g9YX4h&)x>jB0Dh~v z{H5|{cjwGFHqtreS|9L zt|BAe%RRr44|A`~G-0f4U_HHj;_q#7rXsL+FOAdU$Nv+Z+I7P@=;x7Nl|S{z9;FUR zFI)S`X*K5z^k~-U>(u)wFx($-wRUWpxUh3PX@l1{^>gpB`>H>*r5tC@$w=Q^$!%48 zkeu&UKKIGq+5KokgR^_=WCQcKUjBhi*t2g#YH5_Dd(W_u@HYEksN20NNhU+)t=MJq zKSOqCZC6^2>~y#&XVW85u7DfWi;glMGSDsW0z9L0Qenp{VXyY&b?<31Pcg@&7kjtV zD$zh#u;7@7h)bbODgIUy?Twtx<@3=`ovRz~q=!t5nlQK-;`a;3yPQdLS?gMU<>2uB zkU$u3S*wHhoKbXT+N`TE6XJ-ZtOGiE=dBzD9vBlg9|e|lZJz9iLhT}-MNH|x?y5|C z=%Hg}i_z3Bs2-?DwWF(pMUE7tUSMz%+jx z9LA7*u^qgs^>`k8ejV&StK2O}?a`nSIu`KaVaTPmosZyfHc2I3(qvcfh%j8F%C-4}1bjiIW3tuo6DmCg50!g-3oT1J>_Qta$Dhe?QkDty<~Gl-JN1?{=?yr_cW4ZtPB%G0#G#?CX%ar>`b)-6;ByKc?S z9zU+=jBF?Of9$hUa?;n$6LT{HkEDkxRLB+jdp3EDrdRrb zmrpfZKc3n{TG2S?LWb_)hr6F*sQjAu=&5u{TeL)wyK%gs)f=1D%T0|wf(V;9# zO)B6_FoqFvAR>6OZ^`u5?{+cbLRe6fYu=8c-Ev{8&JVmcouD#IFdG>bWiE7Ks+PnXMZ6KcB%7iQA25iqQhVhm4`LDdc39qp5c;ESB=fnJpzOxORLS2%`MvYhF zC4mUnA%&12=jMFvdZbE}0WW0Bq+;RrtC3h0=A93>Z&+BRDj2pHR&eRSAG>G0pm-Dt z8E9|@h`&hTyfy!vEv`va{rqKR8pU`>OL;<|>EDv!B^Y0P8ikTY96(J61tL(_%6E&K z%E5{8nBTD}gYOn*iGYu5tSGFnG>s8N*#1-wo~1zDW)=lLm{Jbt5S}h529KrAm9L!X ziin{y576w$w0*=9>RTlO2np=SU5ZPh_12ASxndyx*wd@`s6tCly8=v{mcKYCGT?1= zqf!?qbbbSCd-EDJXVu_Zz|}Zq&_jws=bsPsk$WcYxWZ@I+`{Y|l~LAdlV=mouAs14 zpeTZi7Ke{={XC{Z^s+O*~zSH+XWvsxNBdsaod|Aa73!oAYS>4d(EMM zOC_Wk%Ib_-Axdc<-cuGk+Li1c*T1@ZxTS*ei8W+=u1Glwm4*`z6 zPKIA%_5uAEp-)Rn!>H7x-`HtC0YjWg4P!`SsN(ZMm0IU6B6b}CM zqQKg-FUKhm_TAoLY6@w?9!SFUz6EtTt^!j4igAvP=ZYvn%1?~dse_f}QAbWHV0O7! zOm`_()|4tZ(@uf1JYZ{pog_S@%)IdnqD`D3S>3j7c?F(?>V}&%>Ui}NG1!MNf#%5g zcG>HVj(^TgG&y1B8#p#ApK3tl5^-pvLyIZ}&EC~dw!CiKwz`(V^3$b|wbVOmp+Da8 zY?oO+=oR^O|JCz`{M;~Sv0q;-8+)F&i!W3v&Bkjdyexa5yK#ICwqJ@>&H(nM+VYRl z@tq5qvw7CeUPt#7D?K0!>OJ4?++zb(n%h^pM66t{wV6qzq#x+KVn45>`g{J z`5V$cWijWHpDey~sCMf{!97+OQMn$9B+1KE5|>`wkB}>nA)@8$P&{W|5?Y_C8+r zCS(pe^|1;?$jNqME2{4nofj<7H?C?pzVEKD$ilj#vaHGD+Bh9aJNdT}SWc=((?_EQ zMd(yE|4pKd^b$&d0!Lf8JZ=dETwdXyoq+Ju8>xK%9EjDo&b1B%ZY%0|PfEjoMrmmw zmhhq^6Gjd(K?GhPn0?4?3;T#*=ar7*ad#yNv@wt9G|gxGYOx(Cr(^&{*ay7ZzKhDG zzz!MO$nX7!v2Y>O7m0znCf-!LeSUg~frzVXmY=_>L(Ma~mn0DyzjGi0?Vl7z8QL7Z-t@Nvw{jKS0jhUPW<{NiR{f>I4?C$)N`|60__T0f;=L?dKMTK-hj4 z9D#s>3*?;G?2Tu=8LYOiE{k1tWpyXR(j=y9J9DmxuYBwDs#mCg#Mz;XJHH~1r<1&s zL;cx2o=Uc_&miUN&A3LQB0U?f`BBw2^8AFD&h`SH)^t$f_1tk%+A!<-R&qkzGF#C? z`Yg_L_kK;h{LWhP2WKp-(Wb`zx;A0C`u*%>P4zAgDps9s*B{9o)^J# zip(Sm%-X6l&>@nBR129ZF`>K`f)Mko{tew4ysoXl%P zhz26h?}<_0$SeN$A@{e~2OHoWGY;y+-n?(06Qe*p^~lx3^%Mo6w@c{UAkILOLR)vy zcE7dK)j7-9TL#6JfwOp0o0TNSHRXLSeMRLQSbKwXJHStQPQ7jAxGdxkoqKdWzr*HO zL&J4=ap;$cG3?R%Hh-k+sPf|fqQ73w-Az*v8XD>#Gt4ojN}m#EOARIFwI61aN-21_ z9IyK(Mhp+&`b3&WT~TnRLGlq^DC0U{US87l?repOn{noQplMZgYs28c{y2)L0{ ziF9)9v_ObX^Q>!K$jq8~a=xkbPKUUkYklhC+Zi2AE@C-4jy^h z1ZPk==UR#N5E(#)&^-%&pLu8S3Q4U%eUVyFj$3XbF(Re)N>j-34cSD%lfnC$C+I+LmHk29 z+Fi^v<<~JhTT%~gpNLc^4qlw>YK^Tuy*t>$!ywCZ1F0q@`}zLCK>DUkme3knR>oSQ zf@reB*suNKuFtPqzx=Cfvo%Jn)iqT(gwKhrerT#-W?QKi^lt<7wkU29Q+TvPdHaN-E?+-@gr=QQ;(1QGYVMREwKP`UZrZS+Hy38%mlutncwD&?QW>Ygl`ER~N zAfRmjGROQ!BI6fO=Je5n5lBVy8p z>#^&ae2Jsu@fH1Y)AwGLT1j+_bw_qi`wx?2o5Di{yp~~454GCvMLLS*z^UHHKT0FA z%yRYMI}T4!wLH@J-L`^fTlZnN_awU#0GULwK;ZH5XMTc5_!fPI6zgaRb4XbH`fB8Oy$n%A5tO0sZ#%m5ooB`Mvd z0T*_f*NntcIiH0w-;yi*P+%eJKC4|#6ZC}x5Rr4SOMc=j9UO##fQqxqWPaQ=qoA@L zUdtF~9qf30%Rqa?LbQDvc8r#*QSAcPZRQj~9Fh`RE!CrjAr7YtyA1l0DZpL^Ln>$@ zAwuJZmb>BD$jU1k^V12J-CfV`A{R6W`^j<{;gO=9@~VA>65`M1sP?m@zBYHKiscg5 zGntzpI~OfxM2&`cqKDZ=uA*QP2Cpku1$;j2%|6~`J`?|>h3$7pH!LsPwA^qF@y5kR z;JYp3*ThpF26kRq%Mc6FSH8;dfFBN-f?(dt~2&_v$ zc*f$=iFURx=T5gahx>?eFE!VR&HQrXR^@1KrbOEALE$`*4%Gx;u(ESOQ=9U=<#Wkjb_>IT%m2Ed>nx6{)Tu89 zo$%WIleMq=5Z9E3FxYL2m`|#z4DdY3L>}G}qBh6a`k3mtrY3t=wxY6+h|!T*-NYEq zW(9`U8Cchra-W=tj6o&ftZIq|m4Q>&8)&^o;`6ohRer0w9(n$i>09`3W5B63Vga2! ze|)_sAILu3RnJQ^aw|Oa>yv$R+LPTS#I|3q&L4#dHPWHK`tX2cY6%2Yq=6> zv~^{Z+A8Zy%A%%2N9MHNkE;aTzK?)N)5zQBjax_wzpzUO7QMlX z#@apeey$cb&TP8*G1$J%=1!`u29`CG=zmzudT_^M_f>5w54Vmu6C>MGypxpU&KR9f zqkxKnA^WNEzSAMm+|=5(@XrPjEn}_bs%IA{R@vIgvU^_o9Bu`_D)YE=z!@857re_Y z3wp9=@Sfmms1qyctN6-4b}v+xf0&NkW<8BU?!aov^z=VBcle*d`9Aoy&2i~#0|@w) ztqB$7sSoMrDR#Sy_I`Yh(l2&n`sN9_X6qbp=XuQe} zU&Id_fwiHJ%aV?xHc^>GMG!>5`-{W*o$ZWhXQ0d#B z{73(k?YjZpBN*{9-~DCGyN$khPaS@LgN%A3c3i9rSaH`xrgPWXkC z&G`sGgPG-f;uJTdDuc7ZBH6#gFA0L@mwj`cK4IzeVQE4JZE?Rk-qo+YCOT3!TiK7H zPMyd67-6RAkz;~zHS1Q4C?sC>q&VW-W$jC0iBC*>8ZMxYk9>BK2WyEDPa7#ttCIjL za~**2k-5t62~Jeb7AlO7_NCZQS;9!uI_LzW)f2$6^`v+W?-L+urI2zvG8COIk`RQl zb%OZ9XCn_*-Ka+5(#Wr6S zdH1g@rJtPFd;ZZ_HiT=pNE07Z(2o&#J^x0bIcxFRD%&ebr*XnAVl&((ZGC*!^S2{8tzf~s(w2Ued7oJFd_Z9%$qZv0=ia!B&+=EhGusYI?`8Y0%wsy;IMV0C@^ zWJ|-Qzrf0FERAp8wrsxo`#Ok`W1|2tI$;7bU#MJ7ly!=7wj2(wV<{Z}BZA7!^08;g zldzn^nqEQ}(K@9wG7-}SRD{P7ZSNWX6M%WP9+d`m#6F1Z`L-#fd||4zgi^5C4z62y z7AkSR(upqem#hCYqc{c$Rv+?a7@x^M=c#PZ%~0UPK{SC6!mIRw_53pA$fgJq7a8Ed z`!cJojr!73Kwr>n$`uGSl`Jfc+m{%Ax&He${P?h-OvQa14#O+pUcEvp(M8d=YebZ(eXVA8^m# z-}&^;mYD)^s@2ZV6i9iU$Y9;C*;p3yL@hV=-&my0eXB*n?wh&N?`bdkBzAtc$2sY~ zs)vtLg?#BO15dL$&&{b}$=R}?;GjwU=+qVC(}J-Cwjcis1-y>W^6exol3XMq4XR`$ za9&$&*DI)%ZzvwA-Sp4t)ovoV=beb_F1CDo-(2OD_cRO0LxzINGw!dWd4|9`)Jr9% zb|QVp!l|@VqAUiOz!F!Xg3H#uctO1!ZA2IfLcY^(U^CVt@YpU^<@?!}ml8k84+Qfn zsZfr%$O!*~f34?zFt+Ag?cvCz-BY#ivH+xmaN|}K?gwxVCI52|!!voNMFWKu$VA%% z@l*VQD#_eT-REa1->_xdVqyXxLG9wwZH)(s?{(K*EZwj>ujD7eL^1DjS9G|XPXZKvB7&)z2wiyW-V{3HnI zo9c}t^Br&|wghqgoNP2XMW&Wa-k{W30+-I+Pgk}Wjzakh18+90L&HgU+p%DMoDn?R zF?F*R5o3?@3LL@F<06w&WhKP<74P32UrA+4f~x&l;`KeO$Cn$4vaBLHvA9ZmxPh_2 zOTq#z{PTds_JGwx_VDYS-IC1A%_t5I_^Tz+ZAQEDBp&Cuyw^;FANR5_wC z7p!<<-?T-+mS<94AC-R6dv49>vv(P>fcW>n$yqK+*LAa`fkU>PI1`72AE&O8caCKp zsdea9yq0|`rzqdSe7^I6#a|of$g?>4<>O|Oxf;99jy)B4|KEp8mug%lf1LS#`%1$R z;ls2N4XW|=jD5eB3r{Owo)+w-vrmcB47CoVN*nLG7HiO2dx-N#w3H0JYz$cqJIKI~ zV>@o=Tf2Sz=^%0Q@;1AqGZ%g9kJWF8)5F+C)hb|7J$IS{GJzNT^yECl$Ga;YzM6K& zIr|$0Bl$JJ?w<=$TS;S|qE02uBeb$kW|5~_uUYFzZsI{0p>nc)p2i&%x=a~75i9al z8Yl9->njgjlq50)A7vzoy=XXj6bHFZ9l<6WA`BhTn>x*!P+pb4?c`Do!kC|Ib2Mv$ zVu8*DKQUri@iKw=Uy?6A3bR}VnBpsJeK?!jm8k>^9?|OT!Bh_EEAGr}Q!A=UUbu1h z&Z4RO)xs&-c*WL29p=#`=^n>u>?6J5PjCQ*Tfbi#c(d-adQU1kcGaXV1E!EM-HXoM z4&*mytQhBO46K;0%^6Zl7(Ld6Yzb|;&{U5q?snP}E_8@w0c(zYXb0LTt0W_Y#zxnr zN|d$rCHYo)GVgoC11igtwL!=$o~19GH$DD;6rFb$T;K2aGv4pld)>`; z*HTi^A<>-udd=eT@vM;-yv5X+0Qhi=h`Z(f#cPYJ5pz3Oig0{z1QavD+5huNT?A?U zl6I2BA}-20?sbX^#$wOYZvV5*YKe$t_MO(XXO+b=?v5x^pVW-@4KPEor$r zi;r)_T;lF@-sr3KFrp=a-{F9(gKhOaqF0r#DmS^dPPX0OGLQH;OEns{|Cy;Av%rWG z2#dXgn&WXWuasNksLWOTeyCySNPlKQPmI|iFfWzSI5Z$Z9bY0qFbZj!t+vJQ1-gjXQv62i~EN4iF z_*;m;&nu5G8LTuee-8wo#fV2U+uBMpGYk~wcSJQPW?dfEQ>hyKZkse>sTR{GE84uz zMoJqhRs9oks;JrnfBwZWtp7;B6ZsR7h1qZBUMHz$3y!)EBGtDLoBcv zg1f3>1fE4&U2r$pBf}g)E3w{g>F=XGXVo`nd4-c6$O@cacpAQG!y34(9F-t79U;dF zM9NLLP5wZWBtZl_{ylt?M5yieWKSxDRxiV?b#G#)!AA>ok--?Pocz0<Sc9q$G2%+IU93(^c{E6aNS&_!{4Z{6`wKj6$`W3?sA zX;RXVMDw;~82$fU7!fnoNAVmQ*v^jmqu_3W!!d+lFm%ulRnHFo7c>pjva`$& z>3c6#czY9L_;594vB8*x7l(Echn}~67^~X1>J%bJixtas6;*5v!v-JGyc-Zw%M|NzP0 zF#GPmiMM@?%62~iHZUD@AWn+CVm+!jSJ>dNfyUV%t;Ja_j=lE83~?fT5jLQBEl(@w zIptQ1#C|F@RPPyngWnSt{|c7uRc_>Gljhzed=NY?US4+hhV2F20J6&2=DgvwSJA&`Az|S#4a8IE8Rn_zjK!Py? zE#hwy>K8DZ=zz7bjGV5ClXZG{>lx7^G`i3kI+J>P9)v?=Ek<05ScXS_umhFlExQ@s z6ylcC|6&vogk?yEP#>v5Y^ezQ6nk6@);fS_nU$t$6&e6n5A%Y8(877mn|UQDb&M>N zwu^vJr4|g)sF`TGCk31-6sU!#tg!DWc!b0WQ5BYlb{k!6yz{6P46~)lgclCKSb=$o znfog;^aP-V#?bL5s^98=zv#ye6oOq@Eqf@H0vCQB+OucRgvVV=C)_-(pio`Xb2jtX z!40c2!SF-avoGxYr;-09c`G?@G+JX4Jm&#|j$gfNZ1z91~6 zxPa36#~7pYVfafYFKBTS8t|v>m!msSXtoJADy=BcA3t3C5BV z1JAN^(&XPH411(_SeR3{eS&=ciM-zX$#I(bs%yoA9s*HV7+4;>tTr#=PCA%zc&Cuw!yoaQj4f}M_#@L%O zx&u5#q}G9{6y&FgdI%Pl>#hY)v-wE7n+OX^u3Sv`Bks++kpXOAnEdL7gm#fX>m6ge z2A_qlE{Ic?I2JZ_t1`Rt-NzR=n5_U#&_2kC9I(PlC~O;KM(2tUQ`m{CXmIEJL=xms zIEn@80q90xj=IS2@UJD9{e@9~R*RU?W*?fOSZhCqdtKME-bz8njrpXHtRG{JOE^YW z*y^Xv=db)YMJ~biugF2s_CLC`8gTQqFq5Jj`;&hMBBmuj+mEX*L(^J;Ci>CrIr^{ypm{`CYztumvd4<4a7bSHL=0ljsGwH7LP{ilz`CgO?kj+SzT9TSBY zn!^7O90gnjLg(j^km(Ono8GD;jb#}^VBLZ`7Ae3n z1WBOXL$W-8bV^Qby7${U#s?AhI0Mp0nrB&&C^91!LUYrR3+XlHF36l~KH4$jiTzuv z22}>RY-9ryLrL>zM6g%|)}nT4_BlR0w|5T#X3BR0p}!$-W=T#wqK}RwubbB&;pDRO=W(VD#pPXiNDYN@YfIj*wFrJ^v1uK6a3^T zM!;awKI`=tE?iz?2nGM%m;c|~-uWh=ZtYq~gIiP{58y|5$M`j!1SQP;C5_STQM7f{ zvAGFz_U_{2$_ZWFHPz!xC^gW0hukx~|!`_cucZw`+hl+0}s)sz`2O8FLX` z#aD=?>Gd@BY_$=AB)w0hN6Yna;yTNbI}SNt1JxSKe>@CyfHH=?7H(p7r>*HdiUIe`=NR-iQVXpX7_;WO3w zz}O;Bh=ST1$5hyN21dI-!RT>cgqmlI{I7q@s!-}c(`YWHli>4)qk)5K(`5@z(sr_U zzXBuw-7m&ruzC5Et>=Yx2dp6W8zNfLP6~4k6W}SB2ouf~rCTlvx+a>f1r)y$syDL! zaO0Kb{VN$CF*>!7HzuEM;8P^^Vem+SxAHo8Im1$^IxCeEokSVkR!x(lK!-@@Bo-Op z)buziCeJ|1^!4#b&792GAh4_xFwQhl3EqgLMTV@mW*x z=+j>alVrcovG{6%gQn+A6EngSdGjH!&faen-gaH?Gp4* zqh2mJT2aisTb95f$79B{em1Mstbe)2(ia&UUsleGoIO25x(>J0@K3JKXe%GE%}V>t zQbu4A%?dJT~J#S!fCr7^x!E#`RufgX!3V~Is3!! z#RRF^xQm3Kcd8M)D&PUP@$vwvc@ad?1TkVEbx2_4mSN49%Ic7F7SP~X{LQ@~J@NC| zR9%&00FD>8rnb^@uQ;Ke+K}PsyVkLL@`d6O_%_v!%u60W#7*z;H8Do+-K1W4z30B= z5nh>v{O3xm7M<{j@JQ>vXLER?b7DLUUGU+u@-fKoc_RpysI&;wkJwez2+TcjlK|UJ zdiLn(m+)5Jo4x#?-0Z&QWtNZfITt-_W$_d|l(+LbF6BrDm9g%d6N_b5ncdhv=*~0f z>Y9I0^*S-*N)F^UHAb{N5#A7xL% zWW&xU&q+h*Bd}E3kczUHLsNjrL3Qs3&ScD%w@VNB&^C5x2A`4(Q{r4--8udu+0>mm z>05^tpdmjLPUvTJoDX_O?&59%demsX?-oW8EM5<$GLfn%68RAx+2oGp_V(23{H2`} zuhr>68yR-1<^UNvw}7zyx2he3me+5+tLKVmx$nd{<>(Rg3@40ST*l!dZND^;DTd`$ zNMC6~s+_<3Sb+`O0rK#?A8{5tv#E3%{Y}ynmfJP&8jUr@{$MCn7R;S ziW3M_px}$-Q74Ju4QXxLiVvM@R4rM|`h4j%x$O@be=;(9X7q#KCMu_21kP`Kj-&zf z|0nZnGo(SRR}0Q{Jgrp#HQNh6D(*XFvt8I>I={w4kZE6K)gsJqr{>nN9}B?cyiD`7 zEWCV1B;#1cio{?ibgK<3^=@~tkK6fK8ee@BysU3gp`c-wbJ2>8mLIi0%Et3k zC;-f=)%#1E4#rv|n%!Q>u79Jim_))z?1AS$N*BXBbq1eHypBD1*UgH5#`CDNU-6n~ z|GqA*$D?mn&+n+5H~V*f8P@WxHwqbn)(OKA?^uwgx2oOcc(zs_wpLnN^YWgO$M*FtCxSN>w%H5X zu8GtB70l}qKW_TmRP}`!es!_1;Zs&H4RtTXxR(e_WC_7hY~T{bPyr)eq$d|(oRghv z88*W3R|_7gaoW|>AVETNj<`Lqgyo*w`yuf5yIbhq)Sk3O#Y!P~;W8AFoZ~k3Fq-pn zKU-(3Z~X#7a_>^Z(_%4FmF?>wozyHgc-gOc_%YMhAVdebw^ym>XlPGyvvIci ztp(S8M(rNVJSQ7ZJZMa!(IuLvt=&F5AT3gk7Qx#hP80x5HTLZjGuB7Sj0r){lhA_! z6}F}vn2XS!C;OMs*sbb=XcxXX;l*>=3}xL;4IIO*Ew$6Eay{EMX;v8u|;1tXrltmgE3a_gAI4jfPYRxwvs& zG^@bbqv8YcOq?kL)lwyV>$9E=YhgqR-0ujMGUn*r)qJ_t=3rKqrV$n?w}kI|=5cCy z98(tor5ZBJJ<5jPHGI#ka=4%-?sD|FmwXGV9ZQ{$AdO9oGUw+y$&H%qHyXD7zBax+ zAFU%f4|42}SH>B7Wk2E-sB?QhRmota*gh(qV-{9(P&EuNFzue6&bpXe95Nu~CSCcldR zedsKxG5MUesoCP9u%PRj{*A?(&5~*ZHIg9J#8q#5pwW4z_4xn-2>zZj^rXv1UftSw z<$IFp6*^(1Q8jX?arCJa+Llkb$wvz#$o&LW!?%`_18E+>9^c4AlD8qD23S92^S zT5 z^!;j-pscwNTgxw~vpM;DQ2zV!!LXzKe@In~NaiiCoHN#$?|3Y;J3-8=+z5Oh9`pIb zUyc)_iaMx0suC$&CNO$coI=N+sbCeFLdXgAcmb3Sp+@_S1=)%A+VXZ-i}#MVTR^VM>?$GpfFMmc~i{yAO#Y0JbOxn(Q%`` z!ISzskZ2X?JG;>B2{!t(G5sWkLpCB;i$}@P4-O5`GQc0JZ~OP4$yGy|yVPXrJBES&z$SXgv zBH@GerhlLG^^4+!oBO}MhT~r11A;Kbzc1sPa1IK)FF0!qT&DA=RHE~^4EvFF<2=dY zH7QmrQ9$IACfD{HCF+tya;dErcn!yPY5sZXrV4S)qaz;{s|~c(&ODh0dVfqhtiy)I zDTVDi^A9DUMITjhbGGdgkX<9ikYdaBH+@}sA#3)&?xSL1@vi>6=R@4M)t*gh`-jKO z!|v=1L0?Lp5-=q+uZ$~QvsAtW+iGcGex}52aiJ6NZKIZYU;owY=+|55V*gVk8YHr7 zzE@&!R1jo0e!?W4e$sp(cyfYu>}TSGe+@A*zNx#Y^jE*wH4Z>H{ALgOF)lnfF!}no z?EQxU6L86QN%E(UB{FZ(>Zx%=AU{ri3sGPb)pOwg%i~m5)i_mPC%_m+ zNX$XIPnQ2#48fh%m34g_%3oR$bFrj;o0|Vsn+(e{a{L{CX=V=8JJwcH|Y*&iA^E zhCjwrqT@d7Q=e@XzgvU7T^<2BOCVn?rFAKza&~&R7(07>1t=}Y7^z@BCuwzN6&fgU z&~(^s#2q+|OKj-5vWUzk0@csg0ouS2)sh%f@e(@r9NtB;(KBMiMDg*CHBf2^Y@K8R zmM1%45B?qy4^>vBG#F-h1<%S%mNm!nld==4=I@JJpipSs8RaHs%d%c6{zN074@(l_c5>q9Cd{v8F7;{0=NvROuna{4r; zc3rfl!m+jgKK3Z#P!d_)6wU3B)R2eV5RE$v@K98@VDJo>w~#sC z{QHpY=$4`zLj}L|Q}2HeS7Ke8v5gaJxMzEoeez3nxcZ$ax210kMJ1j^&HPAcDps}b zBLqN+bHFQ0%!1e%iqtrhgcE5lV<&chO zqR`>vahO|<5f^0LgrS8@Lt{CHuRZ+aVQ^*VdI;r@43q5^?X%y5`M;GbSf^DZf?q5e zpPXCr;Mx(P@)!wndLuYx0%O<6ZUN*q7^>iEqh2)$##NvNZ8xwRT1XGV$-ol!Swx}_ zhHDPTLU&c(j-qSeElTWvItdc$v&%3}X2ihcd!y&q?wzA@_R!CYFzx6ss17#Fe>#)o z89)w46fXxM8iD6&mujkAnFMoGdm&aa( z=$m|O_Ei#yHM$AtpT7aVh;_;mb5*FVR+XoW;%Om*j92Q%Kd(Xh-O7B7+BHHY&Yo>I z(1RQ6XecJa#t$PZaVS;LltOE!n4i<#Ekyf~lk*CAMdXS;zf7O|KRz~;BWG~&NT$Jq*o*Bc6O?C=Y) z^i6WYBD9W-Lj{U{{zo}GpE>;r=TVXzE7FvPst3}96UkW7ItUA=eI(<|{7WaL0cPX{R{A-_+By(T%^YJLJX zjs031ci^F?)#8g|VVVaIA3)pNwpE)(`cbZsuGOVsw1XKJUHT&;*Yyn07jL5$ZEwO( zg=%JL!LN+jLjlxIM!nP^RcEMYn`8eaucX*rLv&A?g2P52RtmgD-g;Lw=ylEaeMv@2 z$nUtEq75s9W|l?>+T{>1>LVCHZ8-3>`bN+v=^*nh1&)IBKJh7OaM%&EcpG#^rTi4b znC#POgPJ?eP07=Vd5v-M)N~+~fia;qnl;W!v$ROw4Rq(gt*R4@?eeT z)OQiNFq~+j|61o!RGKvg5PjX20cXOz-)Ivt&cpd>@=)atD2QOwq$DsSNEFj5!o0p+ zHNQuOAq3`{lhb?~sg`v)r-P5p|KZK$`w6pjvL6m>L0abID&fsTCXostrM=EL99QBr z3hTOZJ0ChCI)y3GrX?g*FkPBTV~6xe!!^N)U^z@_GMotfmHC(WEEs9Y^gA$Ta93zk=P(g+&E`yPa@ zs3iIGBjn0(lJd0rDz1_u8jK0Y{B|s1&_ozr=O<#8tQ~E2tk)noeVtWvmvUekPbiWr zD;asxS&n_Y&Cy`vj&4VD#sKL{PNtJ{bk83Hj$B|q+-QMwkE&+{w=}{jF z063d^KV_M(y^f^XYGLJRjl>L{GV#O)zB% z!q5KtPl{k3exg#qe!a1LUSsyXz_c(M-?i2@Uzyr*8m}hAH+@`lKkFSG z%UO!poGOTxMcc!__omx$M{jq$yU(0oK%k(AD09%%zV7xom$k+IL;gnqr z{XQ&^Z(H&$mzOks#2ILNiKjCxjjSf}aqZ!R{_%6EjdDXro1Ghcoc}269vQy&h&Pd^ zYJX>>eJXlcM$32dmD?}p+TEzQHXHXpt%NS+vr+H+VN8Ah<`Hkt-cJde-Ay6dP@ntkGGFrx zm)(9lulitQVkGCaB=-b*ft+Pv_#E=E2{O`Qbd<_?k^Fphw_h5@{t6(E>=<(qK`_eg zx{j73h20oV7|$uw*zst?GLwg~lUd6GO(+a18#os;CQZ%o$3a`(R6^lT$^kxM7PVXyJaX z!#K(qdoNPiR61C&xAVPo-}n@X!OzFUE1|h-cX{h2oN6VaXSEET6ytB3cKe+&^nE3? z3?l2-!%E>6jQuyMq-#zJhgnzo)ng6zChC{Mo$J5x^SuG)Mm~#~FyR`N#2!YUKJ%m4baA{6l44!Gl13-vWh%Cb8R*lDqG- z2>6)#u>H|0lg+J-66%D=_J%egY=a8>`noC11?uY{XQj8j|IH2z8lLRF>+p@>Ih(d# zv-wB9?;~f|2Drq3wpTJMjhY>H_Kj106J^IgkV=I(0`RJ(rv1XA4W8!f?XaA3sJ=Xu&E4J%_xKO$4_`Ee( z{c%mdcIxtSBts1g;dbqK+VWY5-Zy59GuHHhYc0R4dqEC*K9>t2TI5KMVP=Gwl_{??6{rZ>Ylfw~q>6T>< zlA&BekV+aSbP07-OBCxePyB?BaSvXnQg0o_B9`X%g|Ql5)_V2 zT-njFbeD9FAROIheW$;1)heIwwW7I`az{OBC`8qA4O;&h;x3i9?o~GyvM(Ik07~u1 zJHWG;AL){V((@QwQyxA&W?gM<5OuIrn3H9)lTyeD zUr=Qc(Gchm<$5Z9ym)Jv|pSoW~+%(=6*qXW*BX0J2 zc%O3PpMlHz2b4<#jJ#j__X>9A7^-26t_hFscgOh-MFlJ4uP)f9cDq_S5fdE~U0Bq9 zXm-V>#Y#5Jm+t9fs~in{-p!KFlEuWlrm(1RhDB%5R)IU&# zQ>wj)T+tPN7Chcn_wu^i58b@Z^OuH)s!%ABgOFDkTJ!o+TP{-AG>`^_-|HBfS@T7Z z*!SBGK8bg}g$s@n3@Ugdf6A=@K%A8=-w0b3*SbM*#c@UrO9fkplUj}OCX>daPsmk0mj{VpReRSQymdt;EX zKaZ98JYOTks)WvID)%9rzq441P$&gF)G0sMZZ_it&)>*Gp}jCOO=*=8zf^=s&&L^^ z#)5=1=daA{{VHN5;6SC(OM}mA`*-zQd z3j6r>@bBBseQ?%_9xuwS;r`=a8`0|Fi2B9>Yuwm3y1N%`uZI2UfEFbu#VKsrKFI(o zN4INc2z}$5yl#9G9{x>U#-Nx@A>6i}&aoLH{V;Z>TgP<5H*+XF0|BonL>l(v=M@<4 zkzwzCM~NHy6DCl}x_{;`MBs=am%}=>4t8=1 zVdPDl+9D}8>|ywgoI2H1q^&sjHv8f22^Zk7UDj!XcCT=3!t`&O04bNX+jc*^sDCTb zz}Q@;09c-FkLWhICJ}{=TgqD6D3K^{=(v3IZQ+|eRR@Zix1=Huge$U3-3 z#V`u<7kNz>?SdEgr~-9Qm2t-MD=5IM!w2OQFd=6+SzNO^#2@TMBm&vCw2+w}SFi<7 zT^IMi@SpgC<7hNP@+t;C`%k4p zZh3VQ#DckFSMj^&d17b<5ycDQJ?k(Mr(DGe4(5TV1VgV2@^K9!t;{3g! zm3wAb`|p`qU)GY!o&UO=Nlbim?A6BWQQyquMQ#}-QzsB$a{eZ$1$cMGp~2PrvVoW~+!2l6Bar%u_@(6`{RtA70-0 z$cexnn3aKRokG2RJ zUYADN<8kK_6n|EIclh*sAU`+GPVT6G$^CXzNaP>SheDJVUH?1olDvmJ6hIv6-iZR+ zt}#^^4=He!()meHPXn7#$2gR(w)G>)-sW8tLW+2fi)@4oK(D5;A24PDs?XCnN^P*@ z^J|Zc<-Qm1kVCFlO1STY7Kj&0x(l8^emEp%PwP$iBnp?7GEm_B3cKp$b%>zjwSdAE zOfIpxd{=xg)Eg28St>6}RvERMoAjTyP>lWarT9_$Qw63)=fvy0BOQd`Wq3UkV)T8Z z*4<<){Tszs*}(}&4Kcsl3pbosoK>?uC~{{7WK(nVh`Q*pUJQQRYEQB=VZzslt*P!PaE>nU?7YN$^m%+I0c^!KL7mNm0Vmsm1q*Q&fVwt7~eoK zzJ?(~n_(#|+pR#%#GK(9Pc+lepYa;{b+%2;7-P;vt|>}4xLDxwZ$XySd)rX>#=oXG zRZWP0*HBfvBp5eUlI{q2mN(y|M&=LBX!sji+FjO3Dg$v$PU`HO890 zw3byIqvjHs&?fro{+7AyAPNU#tG7;>Pz_%gKi6#fhv1F_?PhQB!#B~ZDa09x(Il*% z$#cH5BIXySe~YugIR74Pr9<6d%W2yqH^9)4ICHFwitDX>_gQtnK+H4ZcloUt<^1=1 z$G4U@E!ioRBQI$FfFiI)gR#P__B8QPIFR%DfoE0R&k1lr%LaL5lnnh*D8=afr-!nc zH?hhV9fRV-rt0>T_7s^7kh|g-J$t>19XeqF#O#7El)Fa$Pq)SIS(sh0vX;EL6DfXu zZ`>n`dZk`d^sbf4PdTrO3RZ*ArDz_~j<@bY5_)Oa-)$?-%KXL;@sQb$2S0U!)*&;1l5#v} zssPv}SA}B!3XDg`0uyWGo`Wyr+_10m!1upXjQMwHclJ}>ZIV+>)3bc%-J`gV8?$;v zPYI8)p2}{=X7({yX=ae?_9Pu=FFp{iQ0R<`pkz<1)dqtQ4D2_cH)o|}%U&$dn6Z(f zw0*urijanOPb!C+-Ez!B7E30FSMi;GI~ZSozo%`}Tyw()!fsz)tJo}IZhwk?T}`B~ zO9W#-HK7tqZTDd~=m}$2N%HPy)PGzUb>CyjP$K=PY@xH9^RI5VH^fqo6j=1%sIL5@ z&owyO>wvS_c|mSkcD1IAK>nY(=#xh~eI(_C?92&+xoR|YKZFn>L@U?bAAhweRuLR{ zz9=q1`l+M~QeLzH6$~jJQP8vUxd=KAg0Li_<28`KEre0=n>=wwfTG;A?H_;Xpc zHkc|dv8uOP1Hp?k1F0jdYnXU&sQ}I-i~0-epY)VvW5T6b?7_&ze$Wz!vz-@sA#-ud z0!9TYckZDa-&qC5x0=S1Tu;UQ>8yu3hfa*W8D;%XF|>{~raKCp;y&4R+yKe~wF*f&#y}tun5!1sM9|nBgN6bFQ4pkda2l!=+W}?rE7SRCM*>#&gic0;A z7~e?r3ktSW9UnLNxR4N4^g+y=kr8{T!Aem~woLSpbz$z0L~EPn<1R zJlbI`u2%LnMqMa(7%jx9@EFT=5(1?o2*nu^LP4O0ALk#!RjQ$kC{~eQaPqPaI8k4p z6aff}^c7|+zUPb#v6^fcmDZRbD!vfcqg?bKstQkZuq3? zvKW>JH#PH49;WwG)Ts0QdoM2(u`3S}z?gj6AKUq*9;aDiS^DBaq0)rvx3LkHpyJ>< zCXOT1g$8P`S|(W(qS>2g{!P89N?`nB%!KcStDF)Si7<@e4*Ry5iV@PRqBu#|X@8S| zzTZgn+y2J>`P|>o*4K_vf7yysGGHiyifoxKA-F5I#h9Z2@2YMJ;(G3(gEyL&~jO_f6GL`Pi^M_lR-iK9SzNL8Se=B-*#l$mIG_G%;h`fID?qAd=dnD2uM~Sw=Xd=X zFtb=c&y7HWUxTV2+ZZ2jz4=NO3&MEqKv|9ApR0@{q+FWHH142UZh_7cP6Y$PcHu;w zxEjn@Gd2wKJ0|iz6Aa?Ut{pk=@LMR?7jPn;Ck*B{+Yu?4DMO62f-=8KPjzJK_f;Pv zvxT8tcW(UgkGCu?jmQ`A-M5Z5Br>q9%IrtgOwS_hSu-U|bqVE{{AD5Hv;uZii147I z0pT-gu$tUmbs@j^(edl$r;$ID?Wai@?Ij#w1~;Y5s4uh~Fr#6v_uID8%(n}h&7b3@ zH&E{&%+%$l#HNNQY_KgJP84a{j16aZ^QGLmUVY?E6M;*$Jq%faA|GCLiQ#&T7b1a6y%s6bF@xP*}#YM zl?DI$FH%6ie1rY?C3J?(hr5vZ1auetuX3Gap&D??dRfzm8#Yn;D6+RH^Myv~-!@Mn zSRa!yrAcELBl@=pL@c}BgR%1*r?S^J&sLL`Iv(|jN=+VQvfkIH{O) zcemE{z=25mcAf0sqI};C?j{)2Oh0(ws`Aj)MdFkL|FDnB$dMBnbGW4AND;&}Hj zbWu%b25lqyp99eYud))GF_-t(cDxlDYaQGx`{q=xD3~H#>8z!L8ux+9;?TcDzrCed zB8(=4su_lNFGaAzCX^w)LYO^kTN{BIl)_!Yz=%gKJ49qSuz3j;-TPZ53Zv95v87@B zf^A_jmE<`$HI~&jC1%}5+Yh?lUxnXSv~UVUk3r3V6^$-}3SMt3Y#YrvdjPeV(#&c1 z#R`}TY${%c)r$})yXqXAGC~osE%FdsT#PF{Im?(}wr{v93}};0<4_tXG49AOmK_9s zXS83=D$l)jg2z}GFy6z%C33+cKnm)S2&Ei^9IAp>VD#(`{h=ER~@V z{o4X(^9}+%2+rVW{ZS;3MMm*1?HG>*FbH0}@48TIrrjZBDb8CxQZpeY)cN~CzY{MX zSCw0)Vmnt7LUZ_F*l-ZHc!GXV-BYx7X zRnP8_^g+4(+M#QuQJ)tf1;e2bx&-57d=^!B_oAwaKbv*2zQ!DBG@$g3U0nk%} zJB`@pieI*UZsi!Rq>=?oWL-DRl;LTc7HyPh*!QJQWU~r3kv7W9*>gPLC7YO7kRfq? z3Ao-jI?0{xtsl6G0$oIpuMUmyNtZ%Oh*NOd@miSYE860)`D1^JDgKvc1*r~()cPA1 zE_o|C+_N$mF|3in>y8d^T7&Z?K}kdZUW1Z@WJ7oKl@Oia1%IUyRoec(6!6VG+a6?;YqNdeD=V^>i<#Th49# zvYUSEgFs7|!=ys_n88h!6!C2+>32{nuD<^OjX6#{(Q&=}cGarckFDYz-mJ%wHaT+L zxwHLC(=N7OVE&#}p}9=IQLWnk?^ROzi>pNaO~M&#*~R#GmT(FrJ;{Xj0Kxk#?xV~X zR2bIB(ddyc1srD$;CHG+Fb*vp;l@RgC>$F@Ds>Tww5A>^r2Pc1;ZD&&3+Nyi0Ar?dQgePO&PW(4Yz&?j@&8Q_>ZjF`jT6nrO&Z+6E}adZ{%_x z9_(;%83uas1nwseL~81!ClGtW^&?Jyc+rvUwnrTNqUT-yrnd~3%B~M6Z>;b>%OxP zGdZ}0`oCIfw-&ey~Plox)(o3g~=&nQfvP+KfbEng%;wnh^D5u`(fv?g?gM&bNKb{;oFT zxS+Z?Oj+L5i&a%5K!}!Eys#vSKJ8FYcy=M`!THFo`;A&e_M$=1_6{SqDX^`2PgZ+w z49q;;DOj%!S13vX@FQ^@a#b>v=@>jF^``MJ$019 zI!gngkxJw9ix?hIzdLE3G{Q8M*qy9+9wz$!0ksG(QkuSvkZ8gv3$=nYwS(5d5zhPw zf6F$wI5y%2HgdNW@s!`y`aGQrfpUyf)&E>pq&FP=ULI~-A2z#>Mn2kE7S&dl)RKvS z@X{{D3iLZuT85lU6fKL!w$qe!ul;NX8XFS?X?*4yd+bDHi&iHoaqrQJZM-z!@5RUh zC&D+VB(-4%UDB4Qh?zJLt)JCr_R0lB?#4yi#+FeC_Y`W5$XP;$l7n^=Q+X4J+R^E6 z`)}HpbYATMV))KuBj1<8H>daygxvEXAy~1xWyp6^R#TJNC&e?m$9{3MYKh2h57T8I zdjH8iLgqa?dJbnt#c22i$&XxVM3Zu0q&ZbYy-F*A{ z4ltgRD4cj0vW0xDW-dId;PoPcJdyE z%9fIE6Hij%@S00=wjK!WeoRcS?)ga8!H5Jk_Ghkcg*&fW7SO!>`k|_oW++>?ad(vf z#2hAk`rrBNs$o4@Pwbati<>ox+iqgfos-0%={VWL*Icn+4ftGeBTxp;#mtDB$&258 z6*ntm+8?+y>EPan zt$S>kchAk(exSShJ#6F?NRSLOAHWpoIIF zZ=bRm7g+_rj!)nHwaWGI;PZnMWN)KPAwPUP{mk`*?fl$s$x01iJMSM}dGx+jnn36} z;&|HXq*>dk$*;k!yBK}ELy)qpt9C+U*gk@LF8KBS$z&E+1Z|e~6p~UnZ6g}+-Vo>% zhea)-k<-gZ`2IJ2|HcH8wGxo^`QJprdAMcG5JUyxfIw+QkObXy8Tm$I%77Ny5L?m} zJ@S3$RQfsFOq!lm;u0|5eB1qNKc+>ONg@271rc+V2*L#NeZr&0$NrtED{!Ppb)^Cb zbJd*VVYBovt#mBzt=oxKM$2Z(Eh@y#r5gAkw>rm82v){DANOO@KVpB5Ibtq@&+8iE z1egjKQ=v_8nGi9{nweI4v~=IxhuM^M`&}8zNN}YGqh~HvF2qg;5a~3SS-?)%A{bc! zz^^{sZZem=;@hDfdk@>N6EE|Bq;9^FTczzq4Y*ZtnbZmOxp<8oxzQ2cezk4){a8z} zW1l{7lRAE%N&Y13W!Xlog{-FyoA}xo=Y7rUydUQm!vT9MR<7g<*mC|h`86KcOo=C3 z`zTlDUQRb@Z=@&1@DEgZF1}R*BSX&G?3zQMtL3KaHou=7@VhL+@5=3yNWLO%(;3yA z8S#o7sp8rHBR_NRU#p!Eg!#V1{f8k^Gw$vDlOsn>!c*1Pr=3V0n*jECZ?*q8I`ep_ z-ZqTi=gbUaA3}Cxi&Cg;MP?$=hDxOfZPJEHQIk>KJ;u8?a`l9X$|N#kF_CIwnF9RtWj1am=@gK@w$VyN# zm6d?==@aa7VJ319 ze}gN>6+j;9noRY#?%O}NUUVa|^6oNVYmP->GI(4VFusB0>rcjO(PdtQZ*u|juJYhK zVZ)sfsZ{s#GZ*v8pmCpOQ6Lg@uO2(32~TKgv!y}sOZ7jKg3miN zr$h)DjQ4oHL1+caGbU5H{~6q9gh%VC`W05fP8gvGqnzB*#IAc2#})YluLj4LVBRy9 z9m;Cm7fXChN~ET|OL4Fji*0FRyxC^{$6J_UfgdNuo*;wATP9da?K6CW9goG zVcjI_@N>Mg46OuGErRewm1Cv2=Fq-769nBpHalwfBEw*Cl zn``NGP^!}EPwYXPxUw!vs0y;#72#~~)aNs>!rr^e4q0UR=)X7H1GbcfEC&7RMPpL#*J|Opb zcYJ(L+M@%;8%lGJUY}Vp-FTBVM~WxU+j1sfa3ib6bJ|m@RoKs7{-TYrkbX5*VGP1> z9aTTwtUGLddVc8Z=)w4=mj{<({OwCKzXQDZdPxxSuJlJvl)*nyFq`R`R)8w^R=>Xc zx|_Zn%B^MSsd)Ic9|dBqD$}jc8tzEOZ9@)(rn%Cid9L1&#{|M_P7y=x$`xVfje~&~ z#lQ>Y)AWJ;L#PUftV}fsT#$_!NyJT%h=?>dp+9m^Zk)AYiv4;ZvxQ{p8IAb10aHnm zH%psl?P15HDUS%AT>w1{C6bQ=V2m!kmN<- zu3B6@n&&xFWi6Onc}Qqz{sGCOacRVC>(aG?XBE&%SznR&-VYA3UsCsKd-mj+v()w& z>I5%iFgvDILw@eUT*pYHV!owZ{5Y?LJoD2R7?F6CWFi}aCN!yj^G6<%_a~ zv%9XZA_{K$4A;GbMdvX~{CltLf7fPO*P#k`WEg@Pbk!(H#P1> zeJg<7Q;5S>QX{YgC&tM>N%$DxGR(=px!HdB=U8<*4N@f_uk{*aWXLk;Olcy0!hMa_ zGH@y*)y+s!IOHaS%70qAP4H1ns{6!^2cw&}fA?(&Su_>x?ik4cmVD2X(%a)|_l2AK z62h?lz(aZzB<;H}C+iJE)qvQ-L#xk#qX-0#D5IXf3*#zqmV?;j@}LpUC#$iq8LvN1 zyH-WBVkheipSp<_vM4Xg#`XyeghNAGCH-6Vhtb{pDDY3C9$G5lxSQpGvsr4Rf9AJJ zX~6f}yAnTZ@3d&O`$9%cFYiIl#;lt%2PdW8{JkpJ(R7jga3?2ZJw)cqQv3>elTpF3 zq8AQ4KUGy_vCZ}qT9+E9A8w_>eyZxtgq28I{lyHTKDFVPdNhW@+vNkD>MNZ#?kK8A zGn9Jo+AV%}-g9eKf~e3JPp)A@)jo!Z2-q*r+zHRG$u5g;Ak&|QOs=+-2I9J zG2y;ssyPP4^Ku?zJh#*M>C4b0oHU@`NA2F|ChlJFwC#Fb%E0Tnz91GdZH1gHFM1}o za_H+~xFxHw7XK$md->%Dwxu|_ef}zJ zJ0U`7tsGb@0t-dcZWrb6rK0>)cg{4qdTLPqEqD!37_Li_F!Nn$cJ`|$gtdI)nedDA z4XA0T;%J5{<)TtUBm@!1$-gf)|ja$A){83nW)LyU(aTZD%J zN9*#T{QY|_M_9f`;qIU~VfKMUY3S4ge&$xrA2}whn|s8-j6TL{`)V%W?=!Thrr#aQfm-L54-}H$c`!;#Fva z2(UUMU?^+%j(-DN8-_VT$Sq2?sdxMlfeRo6C0{uHvfnuy_PlMKDwV;^kYK9?hP(BN zyIMX=#Mq_Xp@O#E3vvBkC{AF&?W>{!c0lHby&BDOrph<1jjcao50G3 z>s4}p#yzCj2WRZ()YBy1k%u05=lKSVJ86EmBh`ELO-Il$ZrZ22|73Ha_h)U+MG7Iv zTuLLPX~gWeGMOKg*x^R#&{3?obknaz;9rR3^| z@f%xETGia-iWmiqsSvfO&LQsd72)Im6!Yg*`8v4IHk>b=4nVW)+Dmi-wZsrAfxrk^ zj4FVp=A^0qRNPAl#zJ>3GYKfc;YAa&?^I~R66z@AeL-?4hH7*~VRHQ@%Keq#NfBWJ z?>SoZg<#JCS>**zNA@sJTSl4?MI+B6)pDGCNir7ag_BEwzr8g}U<01OehPAs_fH3! z_n!$Jnk5;~DFb)uuoX0c_XJfV03DhZgCz~j87@aHhX>2uQ=tWkq|fpDe#>wo;}%10 zyXfSLb4bO$A&*?V>H1CUX+$T*YqM+o=VhxHPEOrhVN$Pn^2!mgtNndmn$YqkO{3Ql zsfZIeXr~CB0#l5au;5AzyG~W_91N`193r5{t!E)2aa4wUB2i( zx%Jl*X~rKL=$&h}1@>>%$VbLjJMRfTeD;uwolAYX4Ppcb&G;l8OmoLI(Od9lFP zU$7l(85@2k>|L$Vdn7~Ha zuM8p<7~oShlWY!7dpm+R`?wf6)?M6(dgVn4fYVVTVQy3=L_ZnHQd!lM$FJ%b!^3br zQEJnU4->O%fH=Pk05AOGB?G|UGLBu-A#8W-E->&=Z!#xt%&vKfjj$r~XM^3tvHl;i zK7wRAdudRtNpMfpG-p+00`Cq|9d@}EIMk2TzM6lCL;=i}PaS>LB|B1#dd&Ij^QjDs zcjwC^M6Px|ZeBji_BPsi=-dEr)vbaBHXB;=R5n+eC1FlWM$4v6jEpwcx2{x4o@sw< z6&6-j^zQxHQ=+z#>BvF$r}6RE%w0v3QTfz&e(k$f6d?;htIfzClG{%@+HS~4c_-ZS zt$*_eTk5G-nukvqQg}=_){u zFG3EGwJ{wJLPy!Pa8{ejTgGk_bJE2#$y>%a@49Aj&-Zi1wB&uxWC5R?ZRS|gJvYxi z>!y3pulXgKG(6~BMI912q9VZ$$#cmc(KqJ6Wulv$I{cMx4!nGvcnB(-kAJ{hi@WqM zt=fUj=#LW>Y^v;t`h6jgPB^N(-3JMFV0#4W{yRbM4aEnibZCq(g3kC~!|78G-wzH&@m0z+&u#ImlV$p|0W}}Cd-z_U)U>CD^1s*ujMjn zel{>8mrAx?(jkuBO58vN^e_`vgv?C(m-CILK1E;V$?DIh^xwDmyNt3Ix&2edI2OAZ zo{cRQX*bsT8?v+x^{|2lZtSKKt+U_hgeJ^x#t5qCLI{;-8W)YyPUC1~G@Hzt2<}7V zcxiY0Fi8D5CFcmm(R5<|M>zfXtM|xa-Th!r?g&A>QOj!$k31L5iyg9KiGDQ7Cm-Z6_w8z1Z7ibFE=~P0=1@=B9yri*LrNr)G&hRHwiPVLS#6 z*SXJhEfF4!*z z?BJvMJKF}+!OyGk7lSlhx53j=GFC&xa~1HfRdyka7Q3~z2}8}e*zK>2*xSr>8?`Pb zY^pD{I;^mG{O2)EZkmM3xz8_0T(=QTRdU-G5c_&)(dWC}LXO8se@5OAPb)!j$mIG0 zI-kxgM&8nKa#dEN{c_@n4$jEI{O*~dY*L^>EDBYNHba-Vx6SNj&E?ICr|w9-?R&xr z+Oq?k^cydi6ArC|Ex~%B*=}FtAfL+1SnKW-Khl_a#Trg=a{UCk*&;lPm7=J(GgRK_ z>G*C%ZsEVAOAvh%4ax_F`|Dxhu?!o?J49$%2{BJdgvl!3S7c9K9gLERT;@CVWzcRJ zxZp`2W6*7JCFZBVJ}JJVyPILtwj4uzJxRuu~^HG*MJ2%8huy+i8F z)pA@&PXX^nV#HHezDtOhlodjT38$+Q<-ebNd3Cl#Z|&rq3}N9l>7h$&GG;f@of^CZ zKFE)q8sb^GTboe5CNinw-}u=>M-F7MS}OgaFK|~7{j_Y<8j*MS=kBtm5J|2W_#F{# z7Nq^47&-&t9yop=8^w49rGe%+w`rT-s+XT%o;%%Awv592Nfu~Lne$rbnwt|NH}aZ3 z70VC-XD?RvcFtCPM%+5R@NsJAf^Uj01`^714)T8db9a84Z<`GLHOU#cVv))bObuGc z0D%nEF~}xAbSo{W7K3?Y!>b$(W@^k_*5cP`XEaEWVo!{Or6g3MAUlRXG9-r$8t);wvAa~R*S-P2>)=5iS*xs}Y?AmLyE zylfT*iz~F6`BnA_tzxb8zTuk}Qma=Pd3oWQ{oF^wPdd^R1y1Xg@KN16ns&mvS!2!) z)3c-LN)6WJkz9$p>I(%=-OgBt&YV4w^x@l`!<*;Q=7~J~=o&x)wGe!Y!${28eC@3* zw0tYCTDLi;RA@A1qR;E$IHkNb$)tOlCbPE+zOQGCf#%;8`nJH>hLwcx zaGlRHU7G&+2b>h~oOqVYos>ERObDjjhyLJ|Q?5$IT4)KAl7RkkQni6u}zXOYb{nbM$UEOrg^=`3Ch;XtsT`>3u%~pwz2KC=q z@ejwdrtB2w41Ns`4yl*fSX~89UWkX4-qS&b4!ux)b&s5i(GdSZ?SIYgssWa>f6+P> z4f6P8rZDWr(F+^bNP4vX2-#3MMyfrL!eS3+7XVI@$Mam9wlh-KQiRy$$Qd9;Bb)UjzgKdIl>QOq|#~qh81sgm)|H?klUJUNF#E$bdSAj9h*vY zKidKbmOg8it9}OfcDAZ>c0cRMtNTBA0qZrxS@+Uu?e~dv#Iz06*$VwN&zns zuWBoLy&O>c_&_v;{rqh2==)uF-A<2tyrDF6lwx4$!KF#dimMp=QElZ_!i98f{6yB@ ze4^Cq^xXI%EERI9cIc+FzrRD(WNYoo8wqpUysR4YOFg~lV6<~^wKk#j;fX9!rz%Yt zDvNwgd%U?JCn8tlg-2i8%GJ0DeyD;Pb@9(Kp=*~rKa5?M;Z}*jemdAIsKo!|6i=ga zm5{Nv88y^B`tjST85IymB!rVW45#vcOHxD|h{G)dS3IP+>n!fQlC<4%GON=6Pf^#g zf52olcEitTBm?>sA6Hwpk#5jbUE(y0giPds=3%^3qTr0$*yt!~!2ndznsbK8Dn@t~ zPrDv-zQ_R7|)YDl!qjihPY^R2?`mge3=wN;ei=y+ET|%fkjA!_7>pS?>R=9Qe4ohL3Uf=1 zO%x;GqU<~f!>h+B$IPDf1|eC%R^UjTls|o3$Ww)1Mn{E=AN0leO_hQ(Rh!~ME=$tt zlCe~`A`lTbc${LRn<&iU3|p+9}gNDWsi&&Bf!by~XP6*dpWCw?A8*ZS?q z1{S9K=OXmG8v(>S4q!3%#3 zdSBFvOpc>QipHF*Zw|Lpt0U@`N8a_;&ZIh}KFa#n_e~WY&q5-cJ(g-*8qa?0_~%OJ zyL_9Wg{C8hOQpE+i2IRy-gtFr^@mwY)bOc4RK83yN&RN8i@-1RmA+9e14=-k$osH7wD^XYc6SXgGGA4_cbbY89 z-T=~SwfS1W{5VF>Ii(RB8V*m(!Y3)UgB#Nn4YdyHe1_;1~N zYmjmg&O2NF&;g7BtY#L%ath(`C^opoLt$NOZ)g8YiJti{&179+=+NifSA|LQt45kN zh$C78EehdHW8x5oILdh{Y;}x4Dx)xnUw>sBTC(x{8cE=Ok@81v+dMj*{h$w=5qlHo z#g^xqZTCXj{gDf9n5Ps3hTf!M^>yk-worwk8SQP-CP|nJe%&rBOiZF|38_QFTc#@K zerC%=Uz2?qZ(1xF+3}{$$flB zDd2>TH6)^jiezj~HVbt!e-mMpgO4jL-0vd}Pf!NXaL1aSg zmx6{SPUqiNeo}vvS2jHrc5yX+@%%uxPxx4kI3zAY_eM`ZC>~(H-enQ;GW8ATB$c?Y zJ#%OxZNE?U@ee*T3sn^HA-9L><1EYgd*r3Ve}3I57q?pqFVsN-U$r%mY^1|$_s)!Nd#=5=xQZtH zRV9wL*AIC~j-YVMQxl=Qs_>Ew1-T*isc~SC+h6Z7_q%`d1I+1O{WRmlGw)l3HfVM- z?s<|#*Lik+umn*@VElcGU^IkBC&@Vsl^$V*c zMd-u#g|9z4Ca%c7x9pub)WKbR=OL+zE4;URMCy*{Fs1(e-sm~a>cp;?UOj$Jfp8!z zg$#YR?b-fhIOc-yehnxPsIPX}rZA=YC?di4G7$F3F4EI;zVB@Ip;P^Ou&g+JWPa&{ z#R$g|&3{pYYw%P9BJYDW!Ut3YVYWnJa96#>$-xWngM_$$KU(2LK<%~z!yWI}QsMdr zgU})xlztPAeHnng@m&LfYgcv&Vc>o>SCZ<9{A&qV_R2;eehhakUV;&~-kk&yD1QCU zW+`vJkdaK@1H|zFkY_9o>!7F9Q1+{@gZ?0-NRz-d=4d)pJk{?u)X~?P(o`VCOru;7G1=ZiAWR z*E$j7-+y9CPH5h!>@6B6_h}M0OYiXZn@4==w8Gia?cwFeg6_Fl`WLD{Dc&cpI#hRk zYVmcLKJi1Md(ER2XH}MNs1{im+u*=}TBBn1g5Mz`+ehAKTiGYVwAARf@3KSAjwkeh zm+3jP_h&m!X-Yp4(=u`J_{#*x_8INyB0p8K;;;154+YPq2Y`yT`^o%(!k zzqE7Z`hyvJpKsOxODgj^A_{|cdg@N%tJ~a;1*$o7|voF9vN z$vQ};T$37YkjD5{y~aIWj_+l_{c_Y5`~(6)!*6NgNroKrBQ%Nfa$AqcFefxePBe-l z1G&F6KjiSah>0`adUw{ry~?E`alpHHGaRwb(-r(|~w|PC1POJAyrQ z;WzQ-^l$2qz|`9)rEp3g(T%&mj)rDvk&gQ)$#~vLVT>)@Eeb|rP7n^BhoE%J9dXaM zmybykOGLqsV@vpsTsVIZF>%eF(86Z&n8bm}SF3TUE&DMa@A1(y%R|*6&+*NYk{Sws zTX1?&_|>tIg=Zw4?U}_>8|-J>Ke2w1GqsnRQRIQVw~QDJ9=YW4@|5Z9Zd+D*`17sf zihq#pbKGkQUx_dl|AtU}s?0S+);jq0gU&=<;=ZRQC6-1ueJbr#+EUzf(c~s&=)N$D zLk2?OIq)mXobGtHb;|!`Sg-08JUcdR<%(3h_R!5sT~nOfyYxJ>zc^n0qpTstrzU{Y zg|u^aTjymwtmK4g6Zh`zlPJ2%y6QM8r3kmRVgK5-Ywg4;!$5Ad(?SD`j4i(==6pe| zE?f~>#!?joV5r&1+BGXF4MQ(dt+S=c`1|RPu1O?0;OP6a?PmA&3WFOf{Fvn!_68O{ z24^&FX2z~X&m@YJa*Ea`@wUmm!24|!GD2lWt#-8#D4X z!Z8OKg7PXA9n3E`l3;=es+xYN4^17;M{TH}ynY8bNTBP$@`>N9pcVH5G(racrew6A zh^02KyQkGxTPGMx5r);EVw(j^M47635u6*U&>&HvqyZT?3CLW{JOJ+mRqx!+SQtYo(r`_r+_iADpl54L^B8qZp zbDLIa$oVC2>TkIofF8L$60i_^EXhT!6Pt;F-^nbqr$;DY3ynBo_)OqJXO~muO?c_W z)O(PeA83cX7^`RLZ*ZQ~uh=utls_D)N8>ljzSusau0C%KIUm@6)pz}F(?BDAZm=2h zeN|2D4vnBd%a_CRn6~h;^g<+J=P^kU3klqHp?q4&@9&D6R%NxMTCZ~R9e*0Y- zdjD@^(Vc8@P`(i(^mUvtD;JD)rga)lBOPuT)M}%q6fWwV4VEkig?5&qOK?`1qc{YH z8DK+-r#dgZB-a_Rjae=UpqIqbvB92%bkg8uzSuzQl2@b zWeq}l+oV>&A&h9-aynas^)k6zS?vS=w0=r)S5`rbk@__{Tq55twlQS-xM>!kd{^qA zcIsaYq{jT!s%B6)e?nY*Vru5Ig|Gap>8Sym?ZUkCK*%8IrP#?E_VZT)-NP;-;1bNr z|CesGq7pM?5?McY8T4|1Z;FEu2z8R`XgD?AwN`S<4~zV4UD`BFr1m~4B)7gkj(eKt zj_IC?g$mL=^&gf0E3Hcf&Z+PMl5jqTwo?UkYWgpdimD)tlql#C$ffunLHt*HAxs2| z8Fs>vxzh;e{sx}MGUa#viPDpmvV2iZ^3%myIPJpuh|m#=qj>%y0?i+P(xHWw+SIbu zmd<;QEr2zmQJOQ1|3)9x7{mEd3+tVkOo%rVicrBx)%}}# z$sbFY$Xut&eL!YbG))=P>7wJgiM?m~sUWDf)26}SSsQ6!4wAaLu2cQFD&X|5zto$J z2-R$rZpyjuMc&bN7)FN=j1ookmOc-ZFvY2;;Pkl&VPy%?ZYnTc={wgx5?C>U8>_Kx zjTm=$dnM*rlguvR&55g`Csw*L7YIY~NMjk~w1LOuoB37&!c6M8;{<1Oby}`^;WF5c zBc&OQzH+HFAJ; zAsnGU4$o2>J1R%2xaCKm{FdH76&cix@X>DwiZ z9L4;rl(WAbDeS4?3ewucr0dnKV3GIzTRY#cNfx zSIF3}`gEJdm-1jlP$4h)%!)OB9?cRJ*zir z$k!x(&2Dhor*R$Ln^0c*bB}=XVk$R`LxX4(X=G4|xmU8_LE-8^C#ePrkG-^*K)9mN z_={k_!63?sfP{+$bC*sDOpKkTVsFQ$9r&=vcyld<5T_-apZeH|Q)23%COnlXtGBPUjbF;L=l!6R zTKSI_3~n^$_Fnw-Qi!KQoRfxqaFskV)7rhqXHdLVBP{jq%0&3uP;@6WCiJC}Fn{fz zY1&z6q5*fW4aYw{{BJ#(h2F9ZqFtoI>}cuG@2$XpJcnplrJc-cFwRQf@sfcaKjaHD z`-BFAc>^k+u>KfGDjAbn3&t&7Q(x_g2$;_()YinbAFo~_&MVJj3yXh{?<%^C%41l) zrn0Bap0&1)OzMQsmD=~E=LIeNCf?mu8#^nC?rk~ltY?~doEJNIcih?LnJx2#ermzQDH?(NfeF=bOC5Db4!Im@ zm%XjN-BE~rZQXOX{jZwqnkqzk`V$QjCQ$`VYgstPUJ2|_JnDyiSD_$Q*L^bgY5Y~0 z@LfNE?XTH-G!~pipj)$gf63a5udO}5KUexG>8IxRsPvpYE_q_ksLv{RLk}xnS?zw* zj0m)kQGpw~Z|?BTI=h2c983;R2`CEEadrnIM*UY^&OP_+;K`j{^egRB9Rcq@ifd`h zkN$ah4hr)KU|ZFvgOQ;mP;#CaU@%Tg`MQnR`c2flMS^Z8uqr+Bm?gFH7CAX_;&=E| znz;vR!HR*}qTS-4!~kMy`NKVs=jr}+wS6D*wh-rqi6f_k_{nUDlgGTJnQ8i)l=~3^SJ@}W{zW1x3n4!sG!q~UTCjUIy=%D;VIx|pAqIyp zVIX6L26N=eo>F2bWY0YdW{<;uO*ZW#cx(UYsE7;S)~_f;t@qO4;=D&{@m6~!c>Ae* z-&u`IGeLdlr}}~@#95QbIM#h>(1A1>Z~m!tC-#gBv*fPo+lW9an*xEhiiFodV2>zq zbk}(7hHaKQD_|o2t>7|fc6B8rN6lGel8zhQOM5XiX0jXp!tp7*JdLJK{T#(1Yh?c5 zACY6e%*OhgjRQ>e-Hqc{Wi<%7%&CXBkF2h*l&qUrpp>@;XTF6R%pq2gzQN#v3$w2I zBF$d4@aW85KMX*biLK@tQjqgV_|BZfMZx9~$C1Wb)?YGhDBL|nFlF)M8r=2b1&hLL zhjLo!jL5O^g13g4i=+C2F@1G!Ii_!YPwixZ^)s6M?~VExp&Xp+x74cixPjn8$>#lY z92)_Xh48*B{_1m~c9%GFJzsd54pG<|X`%)tD-RF|80&7~TlTKLJ=0&Xzq_uUuX@58 zTxt^N&@EN%I(7DCt`u2TMoL}TzMvcJ-485}6(uiOI?4L#NR7)V6-N>f|Na`}mQ#@e zzn2N?wHB!lOdt6!DAR~n+wb`^dXdvuj?IOYz0Q)J9C z9~L%n@3ApyRsORJRoZ@PT;y%-lwn*Kaa+PDWpTnfQ(4Z;S-A_ODF@^OpaUSORO*e_c9e4aL zbxIm;iQE^|jM_2?XA@-4VXdeCIjfE{(A?M?X2@jneT2Rg7&;Wy=oF(y)%`Dg^V{2e{PXQ1^yhbaf^&EmMp_{jG@DC zXNoR#fnT|n0XC@#OYl+f+)4bSL&tw)B*{uNC((1pf9o3$#ippmo+}A5A2(mUm%q^y zgS+c!J6|ZinA`XKatFn0(Uy>p*$~f9sIODy{yMk80!N*iorE&P?-+AN#b>w^m1j48 z{kgn!-5%cE)x`=*+A{o4o~R8?#6SvJet9C6wU3jjy!C|V+{=?&s76@@^T)!|Bout9 zdO5^?aia&F>bVr;#VHp_L1Z3>-r2#zc@6T|MgU{n=wQQ~0nY8+NJ{w_R90buQCp*H zqh09m5wn=QF=_t_+Z>#=lX#U-ee6u?Cya^l*RA8F8TvfAV-M5b7sQ7ybzP0{m1Rf? z&#qE$Y9AXTN5^v8Y0Sb7D;Z2@A*EW8zLaRk^Fg0EX6eo%dg-7F^q_l-)MZ?dKv@ zde&_5zk;(+__DC%q1(BASyL>tQJJrUpCgQ*>8Z$KVg5WfJn;4bVoT7}&i7d1O=|6W zy!gaS-H|TCUx6S8g6&323TDZU8_ zJR}-+#ysTCU><6P6e9kGOfHL&*#c~ZGGJcN=H145nTz=M4BpRPUskI=MLgKTdE#cF zBZl<|&QWFPQ2ur{FdDS~d6*fyEi&`lto1XtrSwcbMPaqbkYYCGDFR!mhYu857_5^( z?^^i52a#hw;*qAdcQF3VEhj&$7s@IsX$$)H`DRxFO64$|d~3cc`Psq}-RU_C4Q!HNBL0Tg3fDqt_JXiSTqbE1EHO_pFkb+?*1xY8&qoDPX{-B7x9s`iv2_?un1Adg zPOu}^o0^+$!A#I&!TbbY0*4|_JWAi5(rM1#mPB78M9iN1?MJq*kW6A>+hCsFa9dWg zyAYMh6v#*BN`1B!79#|zdCAcy zy5dB(fZ`FgKzFQl9y)FtY6;2d18jbNJTHM-UEv+1HbBn*kErF_t?|s z>tC4ctG-}#j}GskMoXT1BYbxR#u*Ib^^^?xeWwII8jVgbeWZ19=lJ3Y}V=BHWLvoF{&Kl~VAms|Y=8YH%&EbS?O^!JzZd)Jr4rq|dRJ zirVLYcWL$B?xelSrY))N93}d^>Dlgiw}rm$!UK&iLY@@wz#b9)H~j+N($k(=^1th+ z{?${7_lKN&O!iEPLNttSQ_@|4fN%>RQdKJMaVmgm2(@P4JP)q=Dwz=2S2KSL3Wvfm z91&YiDD4vpp|Z1}GsPSAI-2X8v;SI!JwtY*B-CggyVgUf4p!q@Gb z*H7Av&0kcvU#>tkq&&jatl7v{&=W`{d={m<$#8{`XPHPeJAp`{GK7R-_v7(Q?B%^c zqX|o#AlIqE*QaOh=+pR19QCN(cv(ZOXm`PmyH!_1dpcbi38bH>rV~|L@N|ObD z*;*QvxSX=3Ccvy#6b{MSig?WbEU$C?js+6xzGu{+TMQkZFo|DoW#T`EJIlR z9}KCr-CsO0EfQE>W~;INxxw!XDPhkN zb##XlPaGoSah?V0$P{9EVt$@~lkVm_C7}~)vbq)Bp39kElNgw0vF(>W|V%JgR z@mf*B{XI4Bn?Thx_c)?qOgx$3_)J=yq7Zie|H;=Y(Wu(_gh>I7-m7kWQUR$SAd4qWEz5U0gPt4y=O zkNdUaEF^Ig*1SUp(^+{LJDyq1!Ao;{lJ{iR?k_mep(n9t!O+;u-9Iin^Hh_LAf&f3 z89NQrhd@^qGWzp^GFfK3A5eLhFRUQa{D5h(D#6h2+uvajs--yXh}Q%c21dvs%-{p! zOTd#*UN;~Yb4my-oR4z@qh#}xPC}umw8}CEbYPhL_SM9)wfR%?bIZo(c-(MX*iBcM zTm(M@OqC=>h-fiy*?U2v=oHkrrtn^`lw@yQ*wh<2haAEALzBJ4(wLE20)0k3!t^g6kQz3sINb_vrblqQ%K>6>- zahUOtJOcKVU!;ErnPURGsk{l7=}c4bl;ieM_b()mk~Zhfrj$7!_`C|UJw+%57RwC% zNvhgT2=4U9p5X)v4R&3cAX!uj$|*M@v)^5m6Am3ez6rm7Xy!j=U-rEC*^(A{pnhE2 z(`v1QeZqL9i@VPI5I=-HU(isHmecs%&g%D>8>#2^-(Xfz*v>RUXP!Fd1d|px@9y89 ziTxHKXJt%4*HP*m@Vxirv+*IM_oPu#a0~-m;AvOPoWR)+&Yrk-n1E@&nO2V9{hc?q z^V}4pHPMdx-1zc~>hR*scOn(v%~G=`=wSS`ZZIG&g|c)He4_mEmtgL>BvGVPM#&5V z;*OcSx>EI~CmWnX^-GLgmF*5g1)b+VEuM(p+w^CCz~YpinvJ)4z8@Nd8Ujr=cZ>ZM zpV<&{G{}kP#=TRW88>k7|Dihw)okCjzbf>r2x0h_*1ro-a(#*)Pl14z-M_qMe+~6c zA^T;U^z^G!)N@DOoGgX%96JG9{D<>ol!G!-NRqb(!^`L+&oHKODR5uf=)P*$m`XAn zd+DiOcwrckShaxb1u)pr{0i&2V;9!c_~|RTLuxO0dK^0(3u{VWIASr9XX>`;nBz&! zk`S02*l`V%M>+Gc4CLaAf^6})Yi+?x5CigJiTI~y6-5!w#fnS>EZ7fxX|`ibj2frU z3{C2e3zqqe@0mMr6JJcjmT4fLi)qGwvG*!A)R4nyO(LFC-qql+Q4zfL*>ZZs;3+4p z;xt=B+Q~+7`d}OX6b92Q5pIIV>H1YSD=z-g6PBgAc&&!_m^cs;0osH&vK}_xw`+^R zi9SlLm6-jD;G6lTyq~3!5_AZ9=RFvX68sFg=qZ-RqAM<~6XedIfAwXZpUUo_QVv$z z)&w~Hml)u5cmeMt4#9>RgnIoHXGx9ytQEFoyPL(w!#{#Vz%9l1RZZveN7G%KtnL>~ zwFz1;_*PFJ^Ht!cP)FrlRclxMshLbzvqCrLVirqaAMg{6y}SHYZ$%^2|#b?k)y{xtS-t&AuKVW?MfG z?@{j?E>%&cRSjELVV=64hbUYs|2k4kl@~aA%KBa0H05ynu(Rkr&BYgjAnsdn{ey^* z+SR~D=d;YiKn&+k9kRM!!3jOzO{VL;=)Zb~c)PF@*oCd>XPfSFwsc}C3az{~B}z*F z#M@>PFWNrrih#fXM`@_j!P)XUvrei`VM=WD`y9buXY;2WhhiF^MU?wWN|oNMcHHs# zcBbR~(Fm zzL#9Y0Y3iNi+t4?VI@p#L1TqVfL+9c%Tqr} zqyJMy#y6d#i90?nr!#E{bm-pR{veY0Qp;lDo{F*P(jmb`r0?9>`oJO80wuaj1{$8e zIGhyxS-b1K)yJB*Kj+>`!sojm(bY?pwMj~^#_&lssz5oruXJCWuSiDQ!z68d$bkyQ zQ;nP1RDw?imXV~4E#xb69r0QAr764a8*4$>b!7*}JP{bW+22_62wk@1vWJkuYDG4R zUi+vB@v2J~4~|JYY6*mc>4zZRaMD3FF9(~#U=cl6H# z;ARFrmNTkp;xm2Z`CE$HCuEk+NHq?NxlI!|79cpPAZUMw+dm-Oc!al@ z*(1TD@E%EwZIykDU6`FD}G@wS!%WgGY;J3zd8?T?$x32xO{0|eAXcw8=4@${lrx^9sCM&l zmySf{vTgg0g=OoG-e0zOsdHPGq+GpjhpBqF??TKUhs&)U&j4B42*de|B#oBVC!V!S zY4#^z{$VQd%}}}ZY!ihD*56&Ezyu@r>R ze^A%VRbv`s+;KnGk6}bq_D*I9`5i|>hu>_IuMO2xG)(X$UKV%Qra;Sxd7vZ3y&Hmk zXfm01R5IS8T8Fs8fb;l1o!{jJp)+d9XEyHBGx|37&v>UK{9zDO-e=Z!8S`_#73C47 zS9Q<>NFA_!(fmvi@|3+wccLVa3>;HeU@sNooqtSm5$E2T=u-?;LhizL|KiT%(%nJ-VtfAn z1>X5-R)Hu4TIUw~krZj@N1anNCt>^Y$_4T`H}rMrr)4Y3R0bOlmBd)QWEH^Lg3RuR--wLs!_c;->0YASMJpfkYWqwq#y8 zeD2-d#agvt?2&PsM$6|0>!O?6FS@}5jShQ=Z8gRqX}Pqy9}n#3J&}wwvwAJNNe!(`E|y*2V{7C zlTU*apw|922C_<*JFx1x%A;*{F3)e5rCnXjH2==HsIk}ipR_+{;-g)MbuBPzCCIxAr?oWY&CP z=|LY90iM2sg%j=sL#=D4kXk`SK_?pabrwx~$;9$J;4NV53Jb;kJ-$+bHPOb9h9lSX zm7Di=$zVl21~V?F1$&!^nyU{{ch{__ETC+ylp!4OcV8C!oarAS<>+Ymv4;KX+pSV^ z?^=|#OrS)kpuQVW07Q|E(!|yP6FF#%-5xImGhs&Tb`hfK^_e9r*rmy?$LPj)Bf_Ut zkE>wBtk;eHr2R7}QvP(`)*C9Pm(5EWe40(Y{hM}ECVhMj1C?@xp@*R~DEA_1(7I2N z=UPW0zU2yhpMj<*6GL`^&8vB}Z3Pc?t&!qin)=Cgp8gJl^YzPx5C|d~T_*1Cf<~!Y zLkN5eY!SZP5gL0ZmA8?lviVmK&X-qbz3%&b?6L4w!EE=z=Axhj$M82E%ey)x<~QAK zwVglr*Y=3I26$_FW{WX$JmhX*{cH5u8#RN`xj=+Ka_)1^C4>?<>iP*S0=)hs2+S!X z9*;p`35Vp%&o)H$yu5-{43EXBmrQE1?gm;J?2GUVsqQ#do{}jy6tIHRv}QFNB$H(k z6m+0G;Mc!qLkxac!!UAGElI<`P4D65(}HEa9y+#j3>oTT+%s+6p^^hVZOeQNJ5KMZ zLMxxkV$?8L-8*N__L7Sl32ww8vD&ptb~?Eg`8-SJTWfBg0N+~Mp!BAii1gHV)lS3(m} z(ZCfI%1DJW?xPe<`Zg#TrIIL$l8n2C2!*DGoRX1s_PV>z@BRC)f8ycud4E2i*Xud6 zt@CPJ=P9DhKn4kvIN@eLy_+AAjD<&Qemi{Wv7<7!dKiO`7BaMPVuOUn;+vV~uAj^c zqt^VB9lf+ms$*)t+|0n++^AiF%IEffTNh~2LUy?yyuajP(_D?Y1z$|-hSh=llRSMm z=ov>JQWvf|Ida$sBR&!rqv>%8IZ9IUj(2qjeCL`JVms+T4?>hp@`RWPLQ%Nm(E0v$ z*iz)yel}FFdziic->W|HF--6pf%nEbA8X>|i1>ss32J2LeNS7sw_Oj`BBirAH5pji zzEn_PHU(Qt&{q+~Q$^eJG2+M}*Bc`5p#5N{9`SMGK2Is0+1U96fk~9j34KJd{k2@t z7EDEcm+xWkLeP~zEjPekBMq^(NCZemL$fncyJeFRJyfKGabwV1M%T+oz9Zr;#-bpP z#2+-m6!~?&p1i(RVKI)o+ZciXDeB)ee=e94OhV7!CAT4BzCxJLvUSfl>Gb{7lU+TV zx_Vt?aweLP71CE%bP~*erGG#v%$)i~jC+Ra?$y_(tM$P3e6`DDc4uE_=kvcAUR0!M zNVI}8`=R1dFCCuj+JU(b^ypy8+p*)=PEBG3BU?A>pXyf$Uaxjk=pn|$N!y{-1v_eVDiZ9bq5N7{Qs8Id^5gWa-ER(a7@Om#&%Lf z@*T&f?*Af`hzc8irLRs0#~0cIg}(J?H`?@=QPG$lI_FAt_b@$7^Aw*V9!=&AA@5xxbFirYM8| z$T6EJ2h<)TxoowPMsX365v&2GhvR!sB<{Eg+>Php;eK@*tOY}&fd64BLT}cb5e5{L zi9&$xPwYhzkXrbx9aFtyXy?tLEPh^AQO2P1iE-WmAbvYkJ~_&qP~MoeT|ukpEK@n8VP#LB9c3r~|F)QiS{_nBTBz`kA3L^I?xmc>H_r9&%Q70qsXJ=Rpnol-JHjo%ahI#!YapKf)GcX()3g zX4vu@4eO7C^+*W|MoU563+?y zShXWNpVei`31%LRX7{zydM*=NO9sB5ezs$xnbQq&iJTFuoGsh1a3T>mzr-|zwc?}Kk8+5s6%qP-Tm<& zFF9$_mu@aJ7iaV)n$GHn7F@*BJ2&jQ=#1hTT|a%)up)%fdufxT#3_r9b6pG@WaD1- z2vf4pTM+M@@~8XE?)K&Buf3SCSKqM3Fp##Ec(!btY3K4b&S6&I{Zm`H-YKusJAPiH zybY!tI{x^4>1r@Mk#qS4B<37*$X<8nQE~C|w1s;||KN~(LmAS$+icnNL}-=M&=td* z7o!Y|9DfaFYIS$QWNew5!lk&qz*-TNfN^CPIr-tbDHsH-hmv^|o^lA}Fs1|Ss0u;K zf3OZ)wiFa6Qn>(V^P#fNOfy2gA3Dkt4}Tvc#OrHjY=M|bj{xg`WwyZooC)t&{S*Au z#QC3FB#2PAu#_cCEf`xh06BjB!uGfSpGy)qF)Lpn*Fy-Q(QX8+-B}upc?)xn5=c23 zBo+FA%5=&dD-YVzB1uix=qgJjdTzg=O+`z~zftp+xCibJt{&R;TleV(VH1ddP@NB( z-xN38QV%~>@o4^_rE|{@WU#@DBZ(vohV*gsM*}*HkzlT;qsb2w8^W^NRRA zVMfNzMh9I=j)`F`tv#oS1$^%d6>MjCehPL<@#Lyk7(nZODj`3^P(-c_QOm9kqI1sR z%k5k-Ru$o12`YQ|4nxV>uP%mN;%J}e?1)rM9LJoMXiu{-JlZcd{e#GPTn zaxxp3RCmZ}`(Z(tK#l!^UUCT~<=uKxw4s<&@u@S!4_%1c`W5dnYyy4_T z%X6yHWSMQe!!$9yU@?Gp1FcT%-o72P*ss#wC^Z}5&OCu zMmS%@dQxuP7P4aGm^)N?`*h_LiS=rWe9y4^y1h}$>Y~poP`4qw^T*rOA1K^_)?+X7 zJq_W0;s&$G4xQFV0A>s~B0pzq62HcK=uYERxeb2m|j}fcq zoH930)^&PpocKg?aq=~z$3cdI`F!Eb-EXZ$QlI~23`gF-*fhS>Xyo+jTQbGF>NuRs z>zBSJhi~)6PzyP|pId!olm;_RHo`1lX*}JnSCc4XYe{@E8IP-$p>EcZ`1HE!lW0qS zvn5*^c!EP!T5T6VHtx^6GR!f1JztY&ZE&1GT{kC9@Ob>~&Ft#T2;r z>%x(<#yI^EjQFQLkoc_kxoU^sQ7}p8Wby{Po}@=dE2SH_b17F{{&WF-!9=}vzT0DS1xYQL)e)Z-eOt7EPI2Ajx%3L<%aOLP z!ZG2$gDy7Pu5I_4tmrLk4_#~dVsfawOgZnStU$MO>4r%oe6!Osl zDnXzWxnI0^LT?`aJ6{DpVPk`~rKtWX>I~LDEx$-~2yecU=hb9}bGJxB&O9&nxCCSB z1!vRI$G%Hc+n0toIruylbqM6yoQXj??Kn^8Oi>tB_-btS!Lg*6s=JffGk=?WV>@i8 zgcQh%o&!vE$dUw65{2j&sp-&*o}KW}qQ`taUoLZW1LY}_@Xl_=RFN~0zoCOYc+g~{ zXgmimGZub5QZ_BxUgV9w(cw=h#0)H31;_*+s>L~S9Ng`ruE&9C+fY@~icHHd=6N6X zWsO{1K^b~X+PKHxHaAq5xc1Lx`Kn9OTTCufng#MtqOL0LPZQRzsyJR2zP`$JGA`uV zK8>TXIN|Sj=~AZSD}O3{nuvOI$1O&FRupOerdYdg9yWVlH38G0@@Ul%3pE`=9HIdGGm&ziMGG^=UJ(+2wMZCrF!O&z1gt6 zgbBODb7;`*a%#zR(SgO}(+_p#a=F(fcP>8vyZPM+8Y3ny>BbU%LuH&Y{c2Q^Oq7xQ z7q#65=4~dD1XW=dp>bftHa`AxvS&SOa*y!f%$pd_$HE&WXvaS-Z$#_{2ess`?E2?m zwTOcF&#U1O&_?WSUTi;V!R<~N8|<@ZIUZY!H?O?bwGSwKS-MKG;CbfyP-2K|P*UV# zOdphjDPeUI&sp|dhbG$TpSiUYbouZG(n$czPj z5YUz3{CtjBqB1dI-^gKK$e=oKwPRHn3u@Fe;^b>~R8Q0@`z4$WCtpeM8?rfv$LgX) zn-&vmaDF7$L54TX5$aCHuiff!wes8etMe&7&ZSc=@~Svmes8zXS`j7xd3K1Mx`inCQhZL7y8>8q zClFhu?i=-aE<9O#s$OD#!5=E5ofFM5?8{zDZGN6u!FrtrYBZ=8!K|Jr`zK;q_FUMVEzDBdH zydp?riPI_B{n@F1qEI(gaeVmHnqI+(`gCI^U2QOvpm6(hu1KA=7u8I+yBM17bso|e4)O5 z6|;px_7YKZ><<9w%{6*tIb?R7LA^{-vnfyD_W0*%?33vFp%wzWo_zfW|&as%qzd@JR6mA41 z6UV`KwulkSm&91-KtVa-=4Qzrm7GSgzlKxl!~1tP7GvDi_tSr%N;@UEM<-;EVrO)m z9WBuFDL!jw2z7;wC`*iaK(AEBA#o)3t3$r}OYG3VRlUXBaPIqgbfV8|mGw$-%xeW$ z-6z*z$AZ()Zdj*QQm+41}mtxNU}n*42gEA`HI2vme{2 z_HiZ0Ts+;kG;L=1>y^#UPrA*J&I=sVLniqJ8=E&= zNICpLG`Xc!#eG|p|M>MMEhcH$%$?xe4Bsf-uRVu9%9k3w5O`94G#n`-|6Ffj8%2We0Fxm9bX$&(z=|_nRDmgeZ z!>-B(_(L>`DJalo+}GyD?+_?;=Fo{3&NjRF<57~Jj1%V{P>IiSaMGOEB0jU3_fvEh zEJlaar%OM!DdORZ;Lt9~bx|66^NjoJPRc^*MY0|3^MlJ3xvqvlV1V)Kuc^aY!o^>X z{{FE!Q-N!Rh|2_^&yaKBc{go^`9hM2hu#489hgagXJ(rga; z=$#+1(0o(hzr6A{l|IXct`XV~w%^^UB{)`iXDI7_N?ssa>%$oRn4tV1dG|LN_xFpW zn-24W-V~F@y?{?eu@0w)yj-wP6T*ML++pO>x9^QnU@Zoj22^4q;o;V^ zlB;JYuZz6l2F-fr+{}iw1HYagbumFElwcfWXPer#ZGjuFw(==A8t&q&o#{u`0=?yK zlb?*T9Ppm|dIZ0$l!4F;72FxzMiXKVc{H1Dw=Ne{HD~^hpe^@U^!?;FjxN*r( zPNN<1LFJOr<$an_0_9FUtpU4hI!`B6JGq+s3Za^(jAYlLmvhXlC(g8&Ad1O;v2%V) zFgWtTLbd(rDHt*2^|ea3&i-A}9r$be-R7db-xvofZBfg5@mf$2LjxGm7^~OE*e^$0 zx`cc;7h-lxi`V@JQ3F2J$LBkAeq$@e!IZ()LJK_E0{sO_koa!WhB=5$$$uw(lCBQg z1A=qW_yqh)P0UvYDkpU1i}Er}fV)nSJAN25mn&AboaqhPYawj68mBUAp2t0y&ENbd zEradAzx~sZu9`I4`l7IU9hF|?`0ZvO`BwA2EQcV;?xO1GFN;n5tHQx{YnExJiJtXBR80GR2^i)cp7yvQMVXD>N zf;)rCb-3~8KIOcowx=O&-?x0dX`rDlN@C5*>%8 zhjK3(@g-|51b)|(=T@Mi4b?U3=zB7_Nt4qwK559c-Y`w`kszGaSW{q}^}3byumZ`W zFy?sF)W&Juaq}e1l9D4`{Zx`^EOl{=cz+%s)?IC+{mI6v$zPiH#lAVe29-O7b zdq|1et%G)cC)^ykB_>$xP~U<)j9Xt!77Gm_u>13ZhrU?SXlCi{PiE|C>0^|Uo6K!N ze(9oUFIADspyiM3_LZt?LXX^5zn4c33f*#w$Jo`QoUB;YW5c``xe_sRDCy$B$dk`; zmoSE$CszUvdu4!6-sP6Yqi9Ox96(nESM`UGhG7B7?>eK#q4=i?O$gqq29X6 zduf8ZB1BhExa37UkV7W~^^bZ#KJ@wfp|Y$W9Mwhf=7op;ox9RqZjkfSKlk7|<$d{& zBC^+YFN~7YTHSZy&U0IA#d)}A)7ula|25eca_)IW$DkF`G9B7weva>0bqSgoKdq;} z@iK-sxSB|URrB(7&ja_5-*~m%dIfc<)f)AcYb_~J#V6ZSJDe(zIbFzL=v%)~G0yqG z7EHN&iOCXWA>I|i(-!WecF&^(a^RIfH&zm$YBe>wgZo&kD;n69u<0*~;tWdbu1)Rs_-n}L<< zrHST8-ZtPvp$hOGFNaWlDBSN;_Ar$~t6|cku-hu!A6biT!*8q0&Ry#ky;B0RP^o&V zxzX$8VE1QIulk)fD%_%bW+^f!z6DNJ+&P-c)zVe(XUoB}j-r2qn8wLiefmn)Yhe0_ zq~ahPadV50)&aL~JXbX}1y6quMVsDMdS-clO)U&rC&?|lv*h)c#2!ZqVH#iSQFBAc zSNX8s>y0_@=`w+JvbsTt=iktsjuAY=2Hb@PuHZUvdo^b`Mg_|`C7}a2(-7lMtkW|*0oZ*r+b&Xj$KZUhr)(f+ktl>X;d0Yp(pVh+ zFC`xDoRt&PrY|U$y|0lC<}z75(SdrrwDelEnf~@88OT|d_MD%ka5=4P6o!J zZcZ*LW0GYJ+DMv!t>a7bhpg5Y2OjA%(>b9#$VTII_FfU6GE?Yy_ zaCCk#?5~|^Z}9nDF>IKgIC_Eim;%gF@hobx2KQK?)(KL}PK;PgyfLJk(ufcFZ=msHOPCJs9#EqUdlU_l z7;`7tr>5RA+|F7$ts%~Fg{kiDDC{S z&E`6qKfFlm#EKOv#_~@~CIpLhnvT6Ysd<{vYt!5b-%3HKp~wujGk3zdMQiu5%RP3> z6Z!cO>Onal-n`m;=ll`4qU3ke2C`=e2V&CoW?IpQ8D&h+^@l7x4*!+{*Gio!4m18^ zURM9G>3N*H&9t6ZK%CFmawFnAM(mxb|LGXX{iy07QlJPEu#fE#IPFn6W10QO_hntQ zoVm=D=9nyzTj3G&?@|hq#m*8+-g9`5KO4ed%vjzW={rwHUK>agrb+Xr^DwvvEHkDO zQ7>1$f4*)-qsSAntS2$pfdYoYKXYFGRHab})F|i2bv@+!b2`KwHkj(s3zSr(I!7E< z)-*FO+5WVo*D`d1I?R$#m}$3g)jCm$JWsBW+$5arbSs}=)DIX{T$qUexEqYAf(!Go z9PQ#WU@{*I*C~z}+H>f^*X;8XFSO38H{>Y8J?A+L@*7i{`SY~BoQi|ON2rwIMdFUY zeAJTNBx;#F_Nx7s;CN`Z9FPI$iAIDP{o7#(5=7>Lt!?H*TVIzlj#s(F{LHf0KCr!5 zcTwdW=rQ>mKrV<2C5IEkyPl9fp5x+J>5-PwsF0!1+`#trg=Fp<(@T_J%IO1%J8r(q z*x%gx?Yr?{!K;y6S+pa+(=;%^}D9a*Iy@>F7A+o`Q!7F4T+y3&&tw^t7tHh9f69T zbq#?h+%;8pt#cJOLU$XHdWZC{ol9)}g56bs(fd+c8Lqw1DnLqQ|Hbt4j7Emsu6aU* zS;m%kjNNx*Pp#rsQkXVlk9zsjoqQ*O?zP(2;_tqL%3Xv~V0DWU<#hX(RMyzTmcM|0 z9!A#^%b8&4o<$yYJ17-W!Qnjm5{D&PP}cz0KJ4?A-6ITJ%w#&X`V>Gp@PEj<;ZQGw z{_gZH+ohksoOIlCU$%%V9$WL9Sq|y6=#e9rXuJ|X&cuXnqnLYCnFV zMvnceN$J1q@-;{{o|$KGMK11jtUp4Xad$sP+5w29px%kH| z!hMCRC3ub$l@eAXD*b_!x3+u87G;IENB@+)4ET7@pp83U#sw%DGulC-nqjpx}NtAI&M`?EXJPYzCbW8iU6 zGyJ<#GW{gBTfWyo9G=KP4;Cmxxv-0PwmR1h=Nm%x)Oi#Di-ph6S=1-p)m~^Mw-PLb z(a&RD%{%+ZPxHLx;O<-{aK>PZAR@$gYQYtkR7)$1`erhG&M+~!HgP7rXVA6i)Hg}4 zBswm6irgJx)k2YxMzk5!Jq9NDUP+~Ji{8SZOR5Afb8-v5Mo*%+aUpX(9$hci&A{j< z;qC)b2?qKw_}_1*08AWHNh3XOym`%y4gt8N`zG6BRCj`OKu&HL#JwA=m`+%z3b?mO zo3H-ZB$4F~$n>TR##bp0!h*W#vk7QbWo>M5g5s^~<8GVS-O_YgLkC6iR7HMsggZAX zD`xQEYD%hBx+S+}Q`~dWqgV9~$`5(kre|pU&c)khY;fL-ybShHvQ1<#soO=)`yT%z zK0@XD?7O6ND&Tam!(dGtfjm#q8x~A%L(t(ONZ0w8;e)-Duoy3-gC!VB9SqysiHzYQ;20#88eiK_x0WuxIgqeu{-x#V1~^Ht!3> zUJqv4H;$ipZYl+z*2k4T8<1%m>gny!WLNA(f=NwoDxvFWg^uR1AWmld-dS3D>54JpvP1Zj@f7jnqu7OClA`UiX1b;EsMk0`}S3oL;Zy1 zj%%mtzVbjuvheGAWAVd2J@>f}TG$;nt}*NOZ$(QO>O`$Z0Tw-Y^qwIh5NhApM&O-4 z7l9e5*nw7eoxCwxf{_05zt5B5!x2tQ2SVsBOW5eT9e7s)RLn#gv0qL&p(c%atMMvP zHxmAO-yA#~U*iMe4eM^hYE{-{FdcXMPw1sg++9vAp`=QDf3@MPXty-E*Oe%43;n$h z{rum%Eg}3zO5Ueu2TyT~#b`)IZe*S-E(ez>+|8)&EiP9$`HL~Md%o_N!^6>~7+scf zd$_yJW>SNh&erCm_%0P?JmUzZGipSusuQhEoZmz7UfND6@`jU#UkzHyH?Je>+iX}C z^tcm$*X^(#(pagP6X(8|NYt|G`Z8x~oIyY;dhQh-pi{VuJWFL#*W^=A+%t|AwpqT# z!e^c?Ezo;{TX>Q(|F4y@iM972BkM%nONgD~l=$BmQK*=zb2&RceivQFK}R9ddq%gd z=G*ZI@|EDD$dbx};@#bv&(X>KSsL(dG0x0YW-eYtezc+kS4RTD)R2@iR~1$>ctMU> zwi2vahwt1+W%-=(F^PMGVUz7_@^hoKKwJPU!iXnHqtWDvH{$6Y|NQ1xH*7Rrrfhsn z@Nq3dZ#&-SbOLvtLqN$L+iHWR3Q`M8?mFYXDw+3+L-G@hSWl9c^ z>l?8R4l`;tIDsvWC(fVvycONK*j_Vbc~uM^tFPeo`40~PxHy__2#}*&)a(^{p9kGa zGS~?{k(jj?y_|bL7nQz@Vw}>%p8x3( z>*>k3by_Z?-R4Qvok6#WDEE6^A2*X=6HOUK+5K7iYc_9E zGH><&gXIU8^^>f9+fKlOI}z$dG83O`^9SE!Zk}_EA5H0+A3QenF6Neq<+sg&XJL zQa9Q3dC;m4tv%PjNYbB69GwM}eal*AJbd;(PW`0-uw)QV6{;c?^ z#B$*GC=+d>Kkwf4;5LjW*y7_LBrzDnI{lB_Dqt`6on0Svus`>Y-^!W{V;u|Ny~lEp zp-CauBiiUF=+7~iAhu(0*Ekw?__UC&#Jn%4{XoV^3r@(WP?%G5t#~EGuUsl*iE9Yi zKAYs2K{h#)@^Ygo>-)uHP0OJZ+43E9gq?z+f1fSXr$3KGs!VS-_5SI; zBEzO-fds+cYsA8deoh2}kwXoED;F-ez;4*yv?*^qPkhGc3WQ&n(B19KxHDhSbH|!F z+OXH&;K{H!9*)3!@k}RkHutf_ikasHm8;~r)DNM+NRvb21CD72az{&G1(4dRd@j(UX1> zAPEH8<|MesD^dNZ?hpMF%{c5lHlMvyXlYe4%1|k@TA;k}I{R)Q6|ACy0|Ly?gQg^L zO#(rP1BuR;3S!>jIStw6hliejW?NsuZkuvTcb5etqF@blP@8qmT!s7>aykoj45bxt z*Y7ioRQ;vew;aT=Vnz5ZcvVPcPO$H+PGjeLtlG}2Q=x#*p6VJEu7#4=uP5c(ZP9WqwnH(-_9p%afonY{sTEV#Mn&)B(A`J*S8QajCcnPEe( zZb%(?cy6f-es3=S?iD#`p+5VjL1>7l1NixAtO$>`MuXf+(8K&3o~--gyqu5HtqE91 z{V917GYs2RnzmcQV4BL4;4Yf{i7rTPio=Wrop;)3vo`aOUtz!X{-QOU8+de3?SY3y zoB7y=Ftd9)l>GgWC;IW56w`>`9B)bL8uh^FKSe>Wi?97*`TD;@yJXP)F=QS^@UfZQ z^oVl1s6I_TYKyuj!dmQ8_J8`pjGbf+&e>1Dsc^RQR>GliuKC15q3l5K$ zIoiJ(KNQ+J&jwv!@ly*#;v1_S@$8??k!d9pL1cr2GQYq4`{pD4rC(0&TQCoplL`fJ zcfM_WTyUxDY|7(=n>Uq(e=Wt~&*!Yj*^lfg2$VzFIU!I{V0}m6)|C&Y<(_g?mV!2{(Jon^8z1erh{dg`)ybg zp4(*Bg?Stu%sviB>D-O>S7OKI;AW7cSU0-`V>xWBqQDLn&utQVx;m?Sx1vyec=~&? z+mFU@eg=(#0ty;P(`GHmRDA?T)rnADv`o03e6t0FomJs7(Ju~>11o`@%6Rv}33bxM zx+^<9UxKxH%KEdq&$4|9uFNJp=Q;(7T$H#@LITaHF=*jzjXNIl8sn+xxZ|L)xk;E7 zB=io&ukD`({{1Bi#>>g!PtFZ%|71r9ttbiw@lIIlw7kWv+l0Fk0W7KxyhfP{bq<*! zoAVpv%B_xDaGxr@#41lk>PMeD=ju8!##a|#9^2DK)am@{Y?qzt%Z`uD0z#+ON`Ry$ z)ErSl{f_4L4k~Mo>XjqxhJtGbZktPzUa>S1=HH?+8?0&PL=?|3e z-b1$Ebmmuo`+IjHJE_;XJ>~3l_CW{TT(ghP-$v$pMU_1B%?Hmcj(em1OOaB!ODOQ2Rbi)m#=?cV zD1d@1;W3_FvY~D#Y_7n#E}x!mZDl7H)-Qzbhb2Jg6@^tX9|@L+6XhVt?OxD8d)6FH zeAEPN>TcQn<5tH7BcE9Lfp#5dv8i{4pwGQ4j)o-!UJar;S{A9L12r0Rkq1$6R2}%M zEWtZ0mxkyHN!-u_?a<;_D!J&gPmCNboX1^I)U3>G(c(9dV%K)b_Z3k&8bcWYX>(Or zgVQo+v*)mL#0t?6^JVPIw8ULqH)|2AkkWHHme2c;BpNRGKP07-C(V_{{$f*dcQGd= z;`(S^$NSIZZp$8r@3oCbE=#$qO+^7W^dJr&5(@|vtTOh@|+dPqyDP)a_w_!yT%@|!x-YD1=(&vx9gW9 zRz~}AgZ+6AV#V!)gny2h1Sm0Mc06cN4i6Y|EOxAdaO7Z(PuMD!S958=_1rJtFtGvFJcow!GcV?ONJEY5PZM+{84Rxxegg@snj? zzv?p^yeO-#pe-u=QzK){OdJ}_%Ge3zo%`-o9mA-InnlwG`?>^OAbk8|?b{{p2e8CN zDqjcO1vh|afpNb8pvf|J{{}HRNLPmDm(e8@q8zQb?N=#Cd=k#Ip!YLo(FDz$9il48 zp)$nBn$Sv~%!2f-!k-Z>BmR@^_wGXTLTMsmHXCDh3Q$zku)k#h_GSYQEw2V*bO|uS z!~f4Po|`r~ir(jT+bPWEl_S7Yy87;IFczY88 zMMCkg3~BCo&<7JGVw*5|PctQz26;5BQU{86Eka}qfV&>i4K(U4p>E2j3x!6^b7H?e zrKojhU?hRCd@s@EiX=D7g?d}MH&w;xZi`GrP{kS;+u<$k|9At+`ir*)W*cE40lME; z;@~Vy8CrU*(cAIJ;L4 z%&Z;*22IN$T&)<0TSDtYSr{xrL2H3C>Z*YB;41+v(ScR*%T0f&D*+T~Yhm?18n5;M zHP8h8&mhfkG}$i1Y$VjL(ZB#R&ndSNN# ze6*7dmroZKc|D)Gf1`u(=&0@6gnT?zfw+J8MVI`<6&o7uAsHV)K1snh)Gcia-N~7F zJ|DrRbr`EU2Gl&%F{UrB5C=Cfl=o1y?+~Ov6+|_-b*vwMe#ZptGJcR$DD#-vEkQV0 zZ9IFI!i`3sXW6~_qeZps z61Akac`v^p)k=FeDBLBbTLaKOx0i-7&$l3phO{Q6hDL$$81^56|LXZ)U;aW9*OLe` zU7WjuISIG_a-s&3`rxT0jrn_IM_TMmiv2krrTPPBJF3TvpG{w zl2@#W4r?N6OmKT}#*m4_0B07>#!>BPFw}!PKOrN;uwlrR2=k}R;VJ`-==*aeO;IiS zzlT7itH> z$pHJqA73PLu+_gj9ka{)7|ZRp%70)y;MG?y~T37rvXHi%{l*38rZG_OmpkiG1aAWXZC?jl*gqdO##f{eD_#zTxO zv4$ZRM$;(}MD1o~p+jIf9b)&qhu5Sg`bp0U*aO*Kv}d0$fttGxw#M2>o>?z^_3P=T zHxT$^Pcka3>Ij-x3p=k$!>VLO=2oW0p2@87p&}0hSoA6ZFBP^x-6+ZT>DWZykMetf zWzDtt^d^6oNmu(ayooVk;2E;jpw5b0ed$x!(zUHLUYWqeC}cZUvk*3lPf^}r_e2Ps zGoHlEFDq^&k};d`qFClr96?UxzwLXAe4HSM&v37SPMj+lH93$o&|R|4lxNv{(=naA zhlGSb{0@kCt$aYzdEqV zcg?Wk{`Y&Lu1E2fxAG_{6E6)fiRr|tDDYoja?=!hHkXpFWvpr|VSSE~DQ-T!&al(* z3n^(MlGjO`PU1~5R<{UZtZq#z+*n+SC#Crcx5!dos+?FT39OMRuduInej;J%%VI(7 z;_GN#s^3&oln7BGOMw~Np2aPI-tw>Y*|Tr*dL)}4b~vYYSd&D2^3aL5W17flm;guu z8UyHGn*2621I_N({{F%iQ-9M&MyB+sYZDxH^oBn2L+9JCKm6F;Rq}sFl7s_VH^jkb zK)YyHIjL!N`u55K-1vzRlw%_q(q7a`msBw_ijP@9NiNF~-ou7N!!n5XMIq&&__bH$58ZGWHe;^P4 zmu_0``^CNx{)#a;_upJf!!^a8IapP(P#m{OLcFKsnqAmUuGzh_ zNqGM8;(LC4y+2J64sV3z6G;~WtB;@JWMut_B37zu^gdGB zXy)=SdC&lm84nt4T0?4u-IVTldvS%mh(DxD0j|ih)yB?lyBLhoU7DAFyC`pfRB5Ke5u7+CRymsy^{6Gl z7IktkBzm7srv+GjW=OXa^3kV|`Gl&oeI+4F=^Q>2W-Fy!*x+D3j z6K+$ACHOu306%u{GX4)w&Qa3w5LTHN>=@?Br82~@U$Fz8oeCR`vU`U}zip9S;KV$vl#V7yCu)PzG?9m2}@P|=xG8_BixBCI* z9K-M{=d?5PV`{lve^qz}Lrk8Yi|gEU+%C@1l`a!B*T7742vJQVp139gfZjKZpxZig`x} zUtawv^CL>$K$(N87Yb3c1M7bjU3Wax{~v#S?v6YAtVqTwMG>N+jJqh62H#YoaH)(2 z5+UP08ni@P3oSH^jF5FLD{rk`3;qfp&_xZd(uh(-X6=%;~6&ZeY zQ!ptbBGe^gSHFF98&p}0o(GE&jvSI((uRWvW76+yp2bk;EEzHCl{b?eXqaT|)xCYn z{QaUdhOdk_Q67DUzMmytx@N?>l4(6xt)GfyY|93T-pa>$mS!VOmrU$pu5LgI2rM;d zqI7b7k5Uqi4u;J(J>E*Ql$fTL1=G_bX!^?CrIwgClDt%RubTq}S&YnUcd|0p!*L9% zWwF&FxWGI`0)(XyE(`*rhO&EOM{9X)=jOfRI{mQJ(wq;pvg8T>MNF|q( z_j*7aCLJV6bf`DvDo~PoF~1kmage#r9GYc8Tob+^XL6(%I!be9+eRK%SrJk|BM7(l znGW+mv4xpKoZVKGDvT}K>UI^yd!I7l-dd_WnRvO70*$u8pc8~ukhxS0KY|a3s4&ng z1-*M*v!i_RakbPo*LyuOw7Iju6C|Gs%kp<#Z4vsal6H9>tejQ7Jye7UY0dU zkEZhOSCd)jhAf&z;}r?2rIlC!w}G*Zgcy9|rdg*&tX?}Zex7dFIi{pP*_Z;{I}^JD zG$koC^sIBk(Ehs)R=a~Sa6NQI7>iN64h<=w2oX5el(w0aM8@|EO}o``(@x9WsvaR> z2K&BCLJpr8!x+Sa0Bcd8S&G2-4`hfr8Z9-eY(2i+uxcCt7zvdk+$!_<@Xvh*pA`tB zj~_RDIbFmb#|!=H>BN6(Mtp)6kE-ANkeZ3WBOKi>bM zPFjRb|8udk2&?cQn?lf%Z99z zs+m#PCK~Sy3B}*Stp$Wg$Z|$P^7G(K8AxxC@%t!s4f7+jWM16lxi(myflPbOH5&Kq zhM{{aFRI;{&{01hw`yAaI@mdfO%IIpZEX&Bn|jr(VO8IusS za7FK6>20ce z@GJtY7-dHA;}m72C0i7NZB-=W@9DKm}sAG;X_K-d#{bm7g>5J=G2y+ONja5XTZhAwNMyTDy&Bh-KbGB#P*?*3=XefDT;>89^ zr1u1=R?`GdYZSV^Bm1pZOLBcr+~ze!pNKAw4!cK?hz)rGOjYp&PWF7sXlX+=$_O|& z*YS{`ck8SED=w{*YCb??29l=N(Ri&vf-U`1-ZMdK+wu&5I=+e+@cyCXe@T7Gt=mQw zm64;spmM8oEjN+;M0L7lqY@KG3yA-&Z54y*hDWx5W)6ftZvj6la??;?5_=a~S+nQZ zk0m5~l}9R@$h?})>;bBM2EXHOWrDvz@5okM-~tdZzNg!MZV?}fA{ne0$SnSdv8+Q| zMHMjakUOvwSc)U1d5bjhqiI+31r=LNAj$H-4UUPEkv9c{*4ts=b^Ubgo@1L(AMojL zo3U8!Q8?50M-<3QC^&K-ieaoC-kWRR-khlvCCQxCvUMrHHf8sCDfg1R#oq#xl};y+ zwE_&t(^JIEa6FZduKhokQ*jsr;tjyQu`NP9?=q-JgU`>uz*B(FfAt*Qke^j>C4wXd zZ;gmHVEh$*wvIUyTeAzM$?;@B`7^uZ7;$A7`+dYxbi{6-RlwMffSr~FnL=&I6sH@R zutY%;UKdFf+|+_Q?CV$;jTiYG|4)Q9qp9^^+B1H7;U|M?ADPzL7+cSR-~Ko2i0#Yq zE5=ZlAZ~I_o@@1^$ph>oXB-vr)#93>Njt*{Mc^;T5E+vslZ=5|a4q9>`!-;0OK(uH z{n6La{--aIiDf;K60Jj7-gFKfSUH5N7?ipexZf#lwINM4KTe4b>zFvBVut(jN=1hE ztHI;0F0*eB8217ebBBpIQPSh?kzdTZ#K+&F_{eh38x*0S?y>RijE>;ppcLlOd%0d; z=5u>VTS(1Ambi@yqZ;{3)@s9w8h=uJ6s+!R>zD1e@RfQfkEns6t(|@z$r_*LHp^)I zb9r}o26_@`g!&#g68bk}+jW zf>i_dV;|dhw7`Y0cmP_Rokfc+iM|1~zuSJy5PXnaQ->c(Sb&_9>r;MMQ$(`RbInpq% zT8?@^G~4|r1Tx4L{{O=6#S>g$G-4(5ZH^H%2Rn+N?y)%?^0Rd*!-*f%hd*~&s`5W= zUgBMcDwzfO4&He1h4AJxDs%MhMTh0_kPQlpJ6%eWsJvrt?$QhkSS4W?NcyCObMixb zUhe5ncMeGZkmJ4+dfg>?2MS(YDYmNXAoLzg{wSn@MSN+GnsmWcK={CS8%E!Kzyv!3#m&}x9&xI7fzT+gqLe0~~o%%SpLaQbz{j|c| zn-g^+&4lc$zKp=z<(*;d+|nborf-6&>{|2)W8;m}v(0aWMvzp`491k~o&>UT$3DHe z_Tr6rH})UdVWNKWQ2DAQscY8+JkAaso2Z~QnJ2Y>7pI>UII8ha|IB&`MO5}PE z38Ov~wH7y64f)$`66&(iza%>2OnwoHK(u( za{1*A=n`$YMofJrv&6v9;PO!0Rfpx*)Fn<0SHJqlX-i zoLtPhG?y;>31egm4{HyaePy~tZa+NFyJ=S=5B4lcWA#G))2Y*gs8l`VVgU)uXw06WXbm5yT*r8$Vgq*zQft7gRO?AJ{W!%G80L| zXqb@(zRhzw%R1CsgpBHbJ7jD4|CeghVBf!{D4TBoV~{Bg3>o}0>>auEv|Q*d@E+1s zZN#`I-q_J-oAGTEl(lAChHx`ARetC5w$S_d7Fd6N&%;mGtf-l0T>^pEbS`hIW5Xp{ z(3!qOf8w|t&nMxdw5pR3(w@J=kZ*{NQi;?{r&hggNBBu)j13oq)qih9gV(U&G!=L6 zVIfPk)Ny7^Cd>uI=*y3DfTj8mmmw~609@&Vq zo|6E-P0*n3^vmJmso9;60zkPn0eAdl^gJo! zk_UGyTY#@LE_?K^CW*TcxL_I9xv{5r9|`yG5oy?ebHaA&!XLG#xhf^89RIPOfe3yw z8DSdz-!<4QUeS$ptmGSkVT1k;f~1-p4GE2N_mVO0xV-8!OshEZZ(0WTVKd-!!D+&wCMs$>{=T~M1XxtNw2 zxbvCS0xaoi6+*Ej%G6L+*2gJ2fKwh4b2cHh@=| z2wdJ;_beL)XK{GDS#sRMu%m(ux2g+vHbUkPVg=3oANU>VL**w!on&6+M^)_jUdsvW znm%L^VO>=V@h^nCJfw||ttlDc$gf5Uio(0gLiE@s;t;BF@T4HCM+Aw1I`V?7!s|!AV3yPvB{rxtId4hz4hZ)(G%}G}4p$)8X`@_`LZP@WeNhi!Ih;Mthp>5NbjPDx` zlJnxptab27DO+O0k_GQ?GVqloT;r!s5_J*qgG6KiV>j0H_vD7HcD?Y927#+7<|g$a zFEcWRpJCkW6uXazDJ+Xu-Y0^d=k~DT6sx(~WdaiZABuz5h!%S^aQ+=id`J@owIzpy z@AeKorn2*mPD^)m7_ZxP|GsLPEFAr%hQ51l@PuNKddA&%qS0sykD|dZ3jW5QNLmN& z1D*y+&aDh*;VqQY7m0)w4uD6HaXHksw_#MnR?_C>non|~@0?fB4KZ#cAHlZGrrcta zni_O<0rw(zt#B4rOZPD1+$44w6ZZ13&kHh}F zmVvd)kI3Ao;@xiRphb(}j5vVHin!y~#2v~1f49*fjMZ#RVYO-iPPMbTO9R4p7in}M zv#nNZu3~8h@l-PI{+;>qFFQ(pVeDTQk8hq$>2Wc=P$Ir*L5$tl|hi9jm-Xv-xgtj@?i4kM3u4ws}zVOl64JV zdlwsDIy7M?LmFWIpI*V^Eh84K)A&x0`$jshEOD3ut0-|~C|Sj@spE^T8SidQREBCN zj!PENDi6oele-%!2}m_JQaf8oA5;$9Vr|AQ+9kz}9bq3&aEe!wK(a@pJ|4KJ!xQkMkOF4^5^AW)^e9kdNncG1^TKDM} zo|t6>G1XGzc>0H4p;`uQm6Tm&=-cRf!hWY4DMTLc(s_YR3)ektp^{J~D znmLjxvA_~h5hVJp18e&?lMtm;vhFLH-zW;N+nPxvY0zT8vU?yxf;A^%v{(*rXASgtBea$fP1!gz zwLj@POEY~h-QzY@$Yg18KfLB{qd?n78`l3Z;$}M$@Ds#p2Wf!^orJ{3Rg@$m5t8Vz z^#2a!PRRfFd|!S! zfh$v+NYsuc`mKjZUY<~zSUnK0!0i~w8(2X3ae>aF;3bhGtuKPFk6z}QM6rqJ_8I=T z)wTbee)s`nGTI!WPHGsK4K*xK2gP}lT%s`d!(5WQa%o@=_5?EDx#jmPp+@a_7-bs9QwGP5#w* z1&A%C)Xf(L+5H^l#L=dba{vlMBafC(x2*KlKBOS&=JCAw;q_WVP z)$X6es5t+y2cp`mI5ZP;5!fGb@jo1p25f~`ofv|*9Z}(JbAkKU*_r(<3X^T;G43!8 zo}wK5y4s*;Rg3Y4KPNCymNaZ@VDf)H7_?a8t-^Yqa)^G^pnsy^&HWeB-`X7HD{8X6 zSuTphQo(O6>(_`Wk)!EBQ&-v5tb*c{ukN7S{Kfl|vc=(3;Zfh}^A@cG2W#zHl#9nw zr~32xEuI;Hd#0cK3_lBomQhEo+in7nge9%5KN)${V9Cl5{`7^;v4?VP?T#*|1o!*X z#UOZ16y~K;SMsP6OY#m>0?FjTr4!hbZY6mbr~Rq@s+i*Qb1dq;kMO3p=FeF%6y4|L zz;-i~VAzTWzl!+c{fIpM;-5M$Xcyl{_F~T~jb`8|mq9nFE{%jv>O-&_-KP{vd^hY1 zX}q0h@F^_vQb7*|F{_m3K45KH#ab&8=lS^F=nQj8-(>77@3G&*mT3o$GlGI68WsZM z2<9Uua}lNOOYeCl4ddyK$t!xo8PGF}X3yD)@YR`QNWpYRI5&_jjJSyLpKcl({x76* zGbyEw<>a^mxg!PIAgPV4HysLdMyIYYD8d$z%mGk*+-DB> z6m1aB*{#A?i|MSv%4`((3(GEZe%@Qeu{^L^*ydmPyH*dl3D$MtXS@^)Pj9>H5;_)LfV};8**8IHI;+=skL< z{KStnr=DWJ243X|-S$5udcGVl=v&$nqM9oUH~f5tWiiIElAbu;B|=k88hWQ&!R=_2 zXi}&jYUumo#?oiguqPu^pEwUfwrg&y3nkS{{hlOrvY>$NA&IBqu5XoDhZgg#gI4_> zzCCrrV5qY?#p~(U>oUfAy1(eJEr&m!lHIu#`p9u*)R08ZUvhUk7>{O?==H%2+e@6V zf4`!tbx*d$qL77E5ZwFN576xgemRE)XE$|UuxO20fhVje!yc|&C6Yt~Rgv#bOMx}< zV(6xCQPZB6p?^wkYq@Aayx2|n|8dM655SKX~)no$BvpJ7GblN`xX%w=9NiB%bK`*Ff$GE3wL zZgB^>XyEVTKjq7GC!95A7v!ZEMpTNAlO_?xz#1ntnQ|4~R*)d=bvfkUT`k72!)SEB z2MJ1)quS4Z==(0yn^}|h#}-2tmy4=kdmGo;Qw>S+BJ{1es;Cw;A3Z4f4nt<%1~@ES zqe$P6Vxo!W!$Jv2YAJmoiDz$ZN-O<4xlUqwP7D+%cxL(a8;wZ2J4)!>CRCTE6zkT^ z`$q)5Z%GWrE_d9HnXbKNjEcVCU4_$b%P_-RH%SXGs^fQ%=iz8K=J$UFgN7qc?U=`K z>hLzdefG_@7qR%yGAB%J-^>%C=37BOX#UvU z!g&J`VB;gFj<2Y7h`vNRkl?Pu>pSx5j^1-Y$JqCeu{ycejv&*E9*F_w{@hmRTqTcf z;V&Bq?YdrU7!f`4=k##P-$&8chGvF1`GO!3@_gUFV?JA>qO$SysR?F;luBFwhaQ7M znM>?5xd$_T?7mJmSHpL)xErPU`S_K$2~ILwSI-^S4K^5zpkFMKS>Jf3&IyLb{OvnepwsqTD)By_w&+( z>D9dH^=nA{+ni^zUePyl#vKGNIR!3{5@<=8pJLTRt6#yw?|cPl!sI}`XsUf~l^E}f zL}S3;fc&&_4#f+Lg9lPV|-PfNu znRXPzy?vqbE@xjHodTbKFRzZ}yrPz#*`M2qv9@UjC~ze;=XIU?Py!(J5caMvFaNCK z;Lb8o-x-J-sKwB6DFlU9zp;VrMM!yy)T33H+VoFtixinOQTt@rfZ4@09Th_$HeFA0>{) zh#~)$MAEgEY?I&GbF8gF7;m9EZXb;7m@rcmu(ITP-p39NM-Nq!j>`(@LTV0$(&z`e zS+J1sR7#3lkNLcET&^5JVr`Q74XC0KFP>(vy95|GByyJ{L?jGug+j9!qp>#BR$cK} z#DUnB*eM(KnMdEm>^ zQSj#dGh0VQ!j{`C4oAxZQ}R8Dh`I7K#)1s)+U$Nxjv`^?dSo5`W0?#$_rcq2@d|f@ zq<{LByJUcA@?)r(|6MkAnL6G!Pl%~zqI1AM%qBT8#3rVnZJ^=$)_tPpQK&Z&JFtJU zV%L1(1xwZ!Q^|b|I2p7SBc1%Fx!Q)FpcBr*id}h^{4rJqdO9dr-FQC*wT`AqzJec@ z;0~9naf(Q#eZ4|CJXL8#&z>w^lE`H&?GG(T%9XisPUD6(v=%?XMxZw2_Fm>Pnc%$l z-vciCt3FP_n0&*PrGnt*h($ZAOB3X;Bj(b8yCmRViYx1z1V7~=ZT=Gqf}McFp8$O6x6mkZy!?^D3 zw?iF0T5yb9r$zBI@Wfnm{bX||mSAuLYWIeov8UAiu$BR9(sN8)5O^?m1BC&iQ_Gbn z)3Fw!WC%?FgA?@^md*hUeDH{BI@kn1J-Amb=h`Xv10nPnPO~IC?88P#z3WA+`bf3W z@D?cHpytxkxrp7zoK=XEJ^HJN3M|*uy({<{yN@De`}?{r;aAgegPfqo%*!ND?Fr^} zUYo3`y1&Lm@1SN<%DF6s-IO}OTMr5}@1WDIh|W-jx$K?z!N~`^$x*rGOI)LVFOrj} zUU^wPY`zvNT6=84>+%JE5oN+7-}P-%7M%ax&|m?p%@KaXIZYZ>W}(y_N49=Jl9tK z)!rv=i3aaf;OFP9gdb`3f2a3n5wbKfCk=d6KJX}hGHBXrv-_66LX`gk<7TcPRKe!p zX7An+za6s+&^tipMURH-g1dr-+5Rh}8)WVuLKtce&4v zSwMNd{hl>`zu!o-kz&LlvwY>%72i+Fa9NjdRLo1*jdrXzhjYHg8=(2DD!0*tu%NPH zCE@hOh3H8!U)mCSh7{nVAL&Kjy&Woa1s-o_3*C_(+k+E80gU}(h*hs4G}}MIAA5~r z^tTQaYXKEsDgqU!AUEjV-&iAV%3T%6jFPtWlUB7KJ4j+3#uN!G?}ewhatie?&b zB63B2$AvM{_>ctNb-qU<>YOrHmhoIf4l`dvw_8f}d$8=y1{PJJMf9b`_hppMSoRN% zcV^P8?h9P?+jkT&mit03*-g+V^I9nm7@yItHPvR(b1WMbs-VvkJj~sRcekHRB#MOV zgMC}H5?({Jpk%L8>p{;SSYFt$2+Y$b30=VF{txp6Z>QoDb9v%Wg@KDjMbick*BDJ8 zqY%r;n$Et3djA;PDd{m^Fnfcb`qwhjQUPZ2`GZrB)OV+y*j$LQLOXOE$X<(3reu-; z4L+;7hN+NAwhyABmYiFDu7B3ilQ_33vEYm}ch|GF+E3=ocP4on?#a+4*od}vm-FP$ z%S_4`U;Vi@U_Q7aSkxLQ{leg(J<6Q<6R?2jID=xC~O zP~-(rxkt^vVYnDRW|BqJnZDYxM3n1N-?YqDNO+MdPTV(oFk~=h$W6rHyIV8H_$mn> z&PS2)SoDu-BiUT7qX>8iCd8u_sQY&}$U=K!*S=zz!&jJhB)D1K%LMCwk=aWkZ%#zF zcYn!DG>sDUGz@b3(3X|7mRy%f=B5I7;~}Q_ZFI?6@Fl-QMZ&1}pGn}`LZ{VgzmF(w z$bDyDE;OzDpw6aPkuq6L8s2!dJAd_sEu?X`1MA=%O0T`HWQ zK)a-AA|<{@*y5m^^h2o!C3(hX4+QEwpiux{7-igUJ9-gQuAACDTykXE?nKD&nBDNY zB0KNnB%qr-92SGcVwtIJWQHVHIP>evUcISQQxYag;y>y+iDa>DEk7b0!SG7i@yWls zQqW9Ow)shCbYlf~PAMryT82}T6DJd|Un9#&WgVV~w3RykiIV#0@%K}v=EC|cZz*bV zH*1hIO_ui$7JpJljRA8F!$!(bIRE{t(phpDlNb?B&ZWbNd;6c z3SSB!Er8=C69Y{PNURqr*%_Wla-ni_y0t2El!V(7(AW|qS(5F~j}1jOab~0R+!cv; zDxr_8ntgQxBOzYA*<@2hk~}1LuAZe1rJP`|Al^vaT(fAzF6MnhT|}f+w#Kr#VZa`; z=ZM4(&34^pZa9M*|D=5y0n?&IpYL=%beN$%JsoCHyDL(U=&emh(z z^GF*M07rg7VH!Hn#Nz0X9eb*U^BJ0~UXnjuGw12!Pi9gCo+Pf-PfplAg1HP#NeTnZ zgdG@!=FP3|8oh9)xj&$|^3j_wYUJy-^o$)GBwG{Y9pQd1z(*8?r`1t!hV}u*H`&gN zrkp0zrRUrg@Ewy~828oXBcz?q#-LS$I3fndEjeZsyYktI&sT%A?h{+(P>92-j>IP9 z*?Ye3U6|EpWjuL`wf60g`spqbO$O*_U!v1j*i2Uf!8_FP0yz z&zikHyRnsF)TEHOP+rphwbJ@yu4iS6A4aC(il4SP;oj15>I$;FG?R8JI!rD6;oxkV zB>ItBxOW;`KF=8o9Zwa^|P>Zx=-vL&SecAsSOLN zz3zG@YuL(Q1xL3OODd9D}QlSp8_2eff5_9yTXn+0ZGS*^|n0IyTr49q0 zUkzQ6zk*DPyGt3kE@1wg@BZvRiy3Hh3uZIYDH^DoxX zwzP8D%&zPD6)qBgV92QM?o6-7(YIG5|Ko!nu|`|Ocg^;SEyge*A#0+uVA=5*O*Pn# z*)L%|M{Ef2Gy&w6txF8q@!Uu#3+!XhU)5slCnRZ&kE2q*O}XnwM_&ljuOHnw{rKqq zW=_$;y&7*F1Gh;%I!ROZ9eit!OP`mp`4*CT`S$v``9=U8QJpt4!z02Ki--qhMOSKh zEU_UtkT%fE>wg@1-53e0TSZxF9|Pcc!y2;}gUXBTwjZ3?eN^`wRu`>+UL-1CBphAx zPNx+j2&``_x|jwXA?q;ql})hgrkXf~q3@-I*(>djP|J$r7}M>);awR|Eg36+kBE2A zO}0pwQ<7A1FAcBmjs`d~H!*GnRaPLeNF7hR^Ql+$Bhy{oMdUh(@dxRfdMQaGDdtpG z0Y|f$c;%C5!D&Bmb|b>Jy4{pBZ`U&WFvGjI9&I!ASYUp1Dx_YLWc13l*%RWXC>3jd z#c(dE_0{vQej_p(d?$eBFrb^Q}02-L3OPJ>w!Z=281QMOV^%G2CZ>?lSw{#k>n<$GvE# z7t8l27EivvC$it8Bde^MSkszuor58RV%3sZQKh|<=2o_q_V$#?DC}3 zmB#jRJ1(%`R`n_gVmSYFW8fE)!Is=P`dBkV?~uvL{a^K1-?2;uKNaW-1k?Do@j^0h zW^S*Z)5yi{&Y^7-JP47T0VKak}x7-h3@~+ZbuN=OMx$__!j$mes!Ed zQ%?=7%Gun4#p!VOoClvF_luN`KZCEVJKWLlin*@&n4t=%4{To_#&iK&5*1Fce94oy(>f(EJ=q>uUJt zM#Ss)9Jpat_6B!~3j6y$=2~3!`K-)-W4xx!D#({HnEZdn^H73V(e9( zf6@SK&l@(>Yy1|vQ!XyIoLoEu!H{a4hP?pY0^`Rzt#;^6Ht``i)W|xu0{>9+-S*%-h`s z`{#zLc<2m7y@~gfgGaab-Rs0;Sz%u7bG7Jib-W@4M`s0K*tMTOk z_}>6{eQ5=5-En0veqE$jfliAXpIB-#bU>ff>=_d+Q$nxCo1aMd{EhNoSt~&-PlU&W3F44liJ2u-=)VUd>`ccO ztqiYsImI4&x-d=-yYh*hS9OwijzSZW7HxAd zC-HNKTJq`Le^aWsQYRjrR@@^ptmkV@9cSmd+{e(cfcx;@62KN5<7WQ%l#LZY>f>^p0%Rk6SIfK_A41eSgVB zbP;)PofCji7i#t$SEVqbG)Z-WTB)}kz?+D*2e!tVvde@-+S|XE8dnf zl~mlJT-K`aD?*W$FE3N-NL>|`Zr^@{;S{WsE!ZF$=D3X`HpvX&Kc)&hHCBo;WVjM2 z<~wv`Q$9opryK8*!90(Np};8B*%2h|Fi=dCK`CM~!25a&<*5^+JMk+WW?Fzx7U!^Y*o_k zLo^)x2G_j0Mae`Cwd)ilEjup#%m|nY7q!_}6SOxgNr!N*a z<`^}yPi{Q^JCvtD2Uo;Gbs}ITik!55jksm`$Ekq%ySfv$3l;3sjQ95rWE%?iy-F?3 z%Gy;uoo&5_$a{YvPLD$ZRLw<|aYJE@ z9zM8*TvUeP;rMQdpL9}Vw{uP;CdBCgO4=Olvv+MhiQ2BvEh=CN^v=S{rE?b%>B7|$5Vk4`7niF z9Br~1cvTZQ#0%NF%g6r>4+Wdd>pPDf=3QAbd*eut_n)$VR|w_54Z+wt+h!Nbql^{O z5{F>qVi@Zk63V5i@qMnKU>y`Cc8AHAkvVVz_$GjBTTuAFw=w5hN=x{?)`%)PeCbH& zp&X6DOwXPdQMI32&8h5F-8WDWrkEk{PDj9;7bpxyD%#ML@N}P(opU$(OBaIqZb=MT z8R7w-iBPR1=Y?%0_Fch}vem`7(+TMj7bT{Ilkepp5)$8PWC9*r`kg%+K6I?-ugR}j z2UF?oclsF+Bcd0y0FqDwmGYnCX#~Xz9Db2~AHI(Nq9GE-I9uNwtg9=m7Rf9K?LDu_ zO*(9_{>;n1g>?;UD)m3@JF;7r?6t{RlgB=M`RTRfS$zP}!WFse#n|(0KX?3a%{yJ` zuR!tuz5yU{M8cf#crFssu^KS;+SqiD7o3Ap0>&%#NFt}SO_uFy3>Tk8RQS_d4D|ue zGEpSqaT4_2&JJE25B!`^!Vcy|jYHY>WbT;&_#IhGL3>*+YBKRd2SXHW*#brX7MQ+S z+io)_lM(prx{j1Rnwzy8eN#miMZ8&H`C{1>j*l^h|4PbU263LSe#dGuZjdY`F3FP| z-bTg8jr3G)xEuJs_2{UnqHtPgAW z&ob63R9YNPThbt-u8Ix z@YZljb!Oq?o(rj?=W>5|ll88u4t$Y!<5%`?-56UT__KG5u;WlSv8On{Co&^R$^I~w zCCUGMR}vy-M=d&jh_|nNv)yME$?$<3RD>rcPk4o=A3QrN=^{E!Yj^fq+m3PlK*`Bo z=MFxuxbj#oMXD~K*77n75$*UlTwk4`E?wq^yt|Tare=uw2^dI8+OvP zPy>k=HxqrT;K9Pwn6ZkNA#l1ODf!pz) zbdtFfot-jW_ zEUJ?z{;st3f(=>SnO0W!>7cEKpQ$OMmN{sdU!_9S4e2W4aQRz{-o$$(K3sw15Ezn0e!cFO1&eF}KYBvhBkS1V4{ES)HuguI zLyEaGv*#Z4y!;g|&esNep+-IFruVRhQJ{SS#Zc>Mn1BAz%CpK9DO;mP@^a6-sJ8`W zBoPq@Q4u&K3gL~$f6~aW1rEzu$9j^sGu6LekngpBHbIDm?s&w~*L+rG^#68YJoLma7!C8RhKvsRs?v)ouTjzu?7IK)ZyvwD$$HTgGhY$(4B-xTrEd9ye>kNK&5MsCy&l}XBA1*oh zdLe5CNyikM-!{D8>NyjOSgoM$}f9(40M)}SgFz&bKjzj~~JV^_Jup+h-u15~; zY&AL4^-%s-d`wy5)FM&=Hh- z#`0ERlqeyEEWQUj>j7W|w^8O}G5QE@AoDBn!)&Jq$Mxo<)bJ2=_#U{y3)7Oys8N_I%AceAXZgE3No_$8)gM z;%)Ua7HK1HVxWpx;WCz*?)bZ@e9M{Oc>tN0moLq{|GCtqjQjA(ZPg@YqSSW-B7e8 z-*OOMw8e_WS(1h;Y5eamDd6}-Dvr)hSpiRI>;m0^wL#vta6CA51GeJp&8wvRkY!2x z$Na>S{PBn|^i0N}Bp_VWjC{y`bqtHppT+dBp z22I3zR*JAHA4)(8i^@_Nv@2-r4tLT(eLK={YQQ*W=8~G%EOGx;#MZ|1>!+>~Hpy&Y zttLGo<1v7c=!_4-j1*XT&4sCWnUJUTz}9hh&^Sl`g8Y>(I(A$O&gr>X?_@ad#ywmvrWi z3qInYT~^yD27^yUpm#MWYxoXEmp|rw*QTJp6WI;abDcIV;w0U0HF4TSOkZ+)<8@K{ zvd@_W`S1Egq@c4h>rdyj<0tP=mWKO^POqRrQ->+WH4g-9NL%)8@ zV`CJSbEhQS55jDN3I}VSy)LdR+D!>I+mA^=_n3aw&`SHy^Li47C1NJZaKHoDr9vw` z!JEnGk(3j@F0VW|{T51f7;i5bE}9LK_vw(6*u;<8N6ZIm_;EpL6-q z?C6NhS3{94h5QLmy|}dTD|<_V?-|U~?~1Qb@g6!0!d<}4Kxjw7WxyHS*)N{YHGCsa zS*MEBT81{Q4|rqcD2uK6E-~Uxrq)|8R@Is#R;h1U*md>2!(NPiE~=nArQojKgp3;e zMdhg^?pwP0=X`ayRQ$v4q*#;q>o~ zNn;Nb)SV~Q(Z9(3yA5jjcF@b_6fU(nE64-dZyW&3>0C0EnFZ@f3N%EG2Efd<3MCbL zW&wzDqaCb{ZV^R}$K+rGI;vSOf4Y-T6So~m`P(#20 zPYq+YTU|nca)Rg=d}kx;*4)IT!*>s=hxpO8r8&dBSZP)=DY7*<%6@8ecjjt>+WXs> zK#;i{f#S*qd}vun^FG4n*VPGS9^bHj`ZZ7_KUZcuwNeIb8}ag-JIjW*nM5YcwI+ zvV~bUkK=@AFSi=_jU?B4mI1~^m<$6Jy`_UVKyd2IjnUih$)PnpE3HY0Jpm;i0G6vk zX{|mmNaJm~(W+RrS13S7rQM@Pj{Wz=t}{xg#iRTpE202rE`tL4bUj4nJ;&3pBE@)y z8wbQnl)ii1od)O@;euc*At@IGrL}Kn`d0=X=*+~U>K)itb__skm{bm6>AdVQm>tSU4_G)CJ;Lms^k8EVZ*a^WefBi&#FxOV=eeETWvJm6sV#PaId#V3N>*YL zE)Ri-76Uta(%4%ROoFD#04%p>DR~Q$0we(Xq_K`UCfjEuM-yUL+v2pl$)S%PfVWvZ z3{xD`VcgqGebvJ&&w~$_Li0&M4>{0hoPx@Xf;31SW?a$4AC~Yu05MFDUKSc&V#tjR#H`DU*)u11tTRA3u3uIWL= z=aVgv10)83*=X?-VFye=;}*N6VvZQ=1J^qq$;wHIJdROA8N8mYh1l#7#&>U?jqOY? zpjtdz@Z}b+qNllpZjo|>zIr7k0GW=E0nq>yO3)w5LoFBp*hZ(t+`2;kPK36b6HdOq zzC87kyt<1Eh<#?8nVQUVCkk92SiMBRu=xk>;18p(An=Sw2u;pJCgl8 zj>3X~0ZF=@5^~9@hcB->Qxb?DHu(zjl-^Rn_|S1U@Kv0yuLNJ&MljTIXSM?`LV#FiJ&*Eay1QhA?!JT_%V2MGe>$|kxjvtqADZ=S zh>7JvH|KQ{WBaToKazixM7y%M3ls{^A}B+{xJgb)_~_NYkoAO zC3f>|Q_I@vI6~t%b^HMWW1*;Zsa4pbJ{o)wz&?H6uM3MOTyBDi*B1}0zc@enAJP8R zL`smNMA+e=t~VLzQ~o4^sd)f+Q?5baOvY)XmqiySpw)jY4aDm7Pp zRyF;tY7@WB{YUPIeBq2!aJZ9DCU=wT+ldO_h5bB8+r%hAQ05^oFx_hqL#6|I^l@d~ zB%7przHjcl^P;%1iWLOSz=^Sf1L9z7R2;iJR~fZA2m~5>$va;Nd}do1$$I|m zH!|&nD1$hcvLQ)%JN%`YTU(-t2&H$MBw~D{i>;jvPMs~-btFtKda^BQlR;Pg2-wLa zdRgRlExBnz_`uV8s*WqNYuKFPV);=vnZH#T^$-mKMF$M%Cf$bMYu!YIE4H7L4tLkU z?zzytrOe?c-5U;W1L8X?#CcTrC7E6AY8l$t_(&R1Yf}}XyW7M?F$Kuh-mRtukKV8+ zOn#5CEZSy%*CEvjeeHws?Db4pW;0b8291L;qy~_{E5H`*1hOIbqF>=^6oug0{kF7! z`s;P|tK>Hrr2cmEZ7@BdSlom>6PK~62>ch4$mQmeA$i9gQ-wVNJ+OY-FGSW`mqd<-S2N~} zkDPh1xjJaUq0Px*BeWMBZCHD7C`0DWl>SUlky(QW9|sszL~gRMkP)bcd4<|MZ#dB?Xk@{K70p1C1*GX4qCV> z5eBDz|FpgQ%<9oEHfCTir+h)AeBtPpRX2U(aPg6u176Y!juJS=NmnE?zMaZyCa|zb z0ZJ3r>h;yT`Dxdq&2QKD6V11*9M}<}BymHa@N-HQqA&TA7rDJ%zg*(i(}3P_OQ3yo zMOkw01QJHpTpv)jFx+hXw-|VmSmz(vb)9&>l%LFR#NbaHsjIb#v$E1EW9X z(J}{m)3tvK*Sg~*@SaEUU&+&C1n6;LFB8$4bM#4qry1>@7LV^vm@^NGHbm~}@pu~e zvuE${$j@2I|4M)M0|$oSJqpP)R-uHi7m)Ztp%#HYOFd`}`fP&@`Rn3mCN*85zY+u$ z!`Gm@u%{el)$0O)Vf0|)bo(O_g*(^IQV7#Jw5;|+-IcT6T;zFsVW;>4?C%Q6(N6&jV)(Wvk zv<*0`0XSUiQ8Z>!2*+V!qdRu|IXv!M=3^`jk!DTGG zdlwq)@nx3$Jed!dckYuLr|h087lfuV=o(*vor*kgLERWMoa@srMlEm0`vM*$kCjZsvbP=iIGLpa?+I zbj&SvYhnr8j;zuz5mKshM!z2Sxy9fGN|o&sCPrN$)|pQ68E`g@3sxJAgj)ZokyQlNhC6urz{taHHn}ga`fRk@ zfMoT2aHuONXIA}sc{i(W7x=6Dqi$W`I0d0>0mljU#~f+i7JB@G)-2KTyxqhci(hB& zDRFf8*Vr_>dlX~~DS!LxW%-pmXAB$ z^kb8>uAKPz)2P~~E|iUNBw`>#S#o^g_~j88}NqAG@ss4Rl)}ivXT-Ft{Ptf}TZ!VOE9&%bYT|GdA@m zmyRJ3gF4u4U??yp(88;Rmp-e+7<*z-kt7UGKpAkSCjma@36_qF*Xl%_AEes}z!puJ0C-`}p+&S~!~ z__XJbhX4-2(}vi!G01T876zR3JA|{Gj0?8-o|?}mF?9r*M$>n9r!nf$oZs6{vq-iS~=Kd?JYe&HcBJejhtMlwaOM{ zaC$oUY|>}v4=U~QE})_+T(wb~z9IBT&U^yu-%HMM(gH(y4haZV&Q*@)*Dstob;zR6 zh2MVYK!V*i=MTiTUmYQDp89YS4^9j^COC4G<=2D_ynJ(_d^S0N!$D7x-yE7xJYyg< z3&ndz{>Su*x%=qmI!s28Q2;%`;4MGB72(Y89!_blw8p}fzg<<6t%!^1$>J?6xn9W> z9ezD+6bTqDk(&i_%~Mn&dJ#s%G)v%%w(zL0?rSw({MuW(IM&*1_w}VsEM%qW;JIQi zbq-dd%gBx@@DVTn1~o6ihHqOx{mhB}D*mB{+M;_MKAgm=1L)^jm5B$7FG+>EEOFW&MlbD@WL_9s8Q@tykY) z{#^dcvNH3;_}HPi5CPopR>8e9cP%s&q?VIWUT=~`vb$=1Le%8Ene*UC+4~0~%C~># zo_Wo%anXc9&K{5%$;8;t%bYHP&vJ(jOQTZ(3h1Vj z$sMX#CkT8?;CzV-xx9|qofo16vF6Sq!HwJhy++IyOeT$b0w53fcm^P#acT~!T%fT1 zETs?u8z2&wY%ubuceRa6-oS1W=W>G_rHhGYD+c7|h}wUe>tbG&rU-#h@hDLcf9gsN=~$ehT*AaSFzyHBui&fqXAyz8>P{CBJ(z`fTfhRqqXsit*~Dmv#Iz&i`wD<%xHKwhMwE^>A;G3V@wN$A*`pEjzrJS*2RoRCmML z9IF4VuOxaldm?1MxY}QuQ=SCcR4cRJ6B7>gAU9VspJLqLnwb}%EMga7IKmz-RUZOb z_e^Bo&+p{_4v87{JdM}n&DM8xk^?3Et3MwPNc9+C@7Bh*go7U#IZX&{JkW&z!ap+k z^mbO9Ta8X!;O=W{A8%=@=$)qICf>%rEoB(A9?=(P>q+~#yD1;b5il{Fdba6QTQ;M0 zn9riO_8^o*y7=!nAx}gX&Ts(hcYxN9M{oaAx>nnrN3G*0fp}cQYU_ACbeo7FdvT15 z>%*0w_!vMcgi$`OxN$c0k3fE@=iVK1!245*~ZarVHTg#^6HplVYmEgd= zh_4nZLb16)K^zc#_1f>0$$g)G^0&Qei66h@h2zj*uI3+am|}N5G5WEgG~W6O)sY7- z?Ba?HGL`)pTj*OIQUb;*K>j!^2%jLaAo{a5YSuJix&u&5;e^;H6@gR=cw?UL0IEb_ zji6!qqo?n0SM28nn+VvBqd>b9p0Zfq!t4J`=W4q%2T(k#Yh* z6fpj=GjJ=RJ@rrY8|R3KtDx<63iHq6+@Y}2pWW2?U-QfEeaf`gw!IwcU@6B?`%Z|> z)%d#SoZ!|9RL8nslXW42y>VBz%LJb48`|j6^V>LPSR-~Ok5>Di(=_#gM3U?0{bF%zJfh$w571?FQyzkw2n>zZ2llB%@Cb*#1gg;PXvR)|gl3LVJ{q^*daQ-{DbS7IGDm#Q>@ZeJ z``MaV9pHpS=Z)hFAn#kl@G#{d*Gh{o;eF!S0;~P^3La| zh`h0SXdA5mMMD1>1NrY_!u0eU9-aiftE!pefArTmm{($wFFQ8fxD}q`)YW+2(}c>i z+JPSDQ3`ypD$xAB=c;U)Sqs6~!FcrE&k*Z@nSw02T&+Gyonr1#nZT}k&t#KxnI==v4>gLk?Z$@MV7!1lhX)gWIs6c z@^D?y{jRB>cr@Mo|9HKxJzmdLxjZ`_>E!=|F-#PL{sD9ODFn?rvn01d&4r8Tv;&OE zGXdLC*R6ThD|}X6YWY8zUTk@lk+I zwmYGs5OY=C9w^h!VF4WID3@&KlUOP9iutkCnUSYAUuTwYc@=W;H}*xnCz@wUfD2gi zLMI1&CK4b}Ku`4;Z4rn_0MA1nGx%&y+BePl&D_y}ZTLUSJG8F_4~j!EboJaHY&O>8 z1^3xEKgDkigvo+P#RTwLU=|OP$>(S+_=oA)y3N`D9E9=}z*pDsNAQyL&YrEc+LY!y zSx|MHqB?JPlZSTZddgQ5LHdG z;$_t;-4wL!PC8vcMBQ(FFMlZwl0TC#FHGgL8gxBK@OHI#F@EyZSWkVg?k=j`^Q&MH zeRx?J4S-S7AKe42YzbBS?2qsEGt~$+usI50lyqSr$;if0ipoBB+EPTm)oKGV(eI~E z4CH4~_GqkJt0AAf)=wS0))ccXXJoBh1Sf8v^^qdNT+5# zekOO}=`Ep`4u1#ihV6*ts|XN{Tv? zeK2ME(2W43E88CD7Jqi^u;<=lE8pki(SQBU zy;ILMu9-BI$Wc3F=^{N}`96N2;i6^capFJ}jU?g=%Fe$Nw^*ey09*!s%^{w;G_|WV2ODWC?k$ zyU{8&(vO|`#M(pozF|a#_&&EnS3t*{`_#rj&-z9~VX#W*2X^0YiZbdTpbq6+r{&Q& zQ1RcgKm@{}ff{gvm!&8Uos>aP^5ph}EdV{2A=;%mH&l;xIcHLr)sn4!r+#>f6*kQl z9X-FH2LlZBw%LU1`U`x%d)2a&S)&iGBT2AV)Js^neIOPeox5*Y#$M|1(-*aCxHK_K zp$Jv!583sxEz!_g&#JG7u(Vb8i1iU?k7dAUbcPBIOCZ4+xv>z{^{D5<)}R7z!Gn@N ze>MFprIMYdkLi`6PXWb=I0lKZMWb{bPBgd&fpmc7&>`y2+fOw)-U(~rI>BC zC-(lxL)!5W#o|q^sO9k7YK2TYqc=b7ys3-YWJ-5#8%BnB4 z0<@{r;5C)%f=J%3ZYr}~+;`hf>o4Qp>o8-3;ZCW`h@+}JDv@O`{j);W$pQW9sjHoZ8Y`BLDmJv+l}py4Rfa?y1Mv|J$d}E zplwZf|HUKkGajZ%Ih)j+w!+WU_gLo_vK$v1f&l&ez$(4su-B`d(2xGq>FIfQ9Y9N(cIEovJ7&D&RY+iCj!||aM z`Isv|vfu19Pu@|4TjK~C5NOeq3-}$|1q#=3h|16n#(aDH`s2>371AT=~GkZdRvWK3X!z+s~zJ1Vo2|s%GXZ=^^*$AL@(1&}zoa@i?xsm5Y zYSX8X=HfL8O(8TP^E_R^86+vv|8w}Jil$AIbu7+WDE?OvzTQ~hoMW+}sEWJ8@1C>I z_9aJR>(E!^!J>WD^01wTS>gPf|NK}NV}>?4N!Skoj~DCBuM6f4j+6c>cxi+e)&fYJWZ@0{pJ02jnj0B=Hyu&LzF0 z`Vv@xeBX`oU93*%;qP-V^Q|u8&o79|Gz4+yyBK@VMw%D={7ym+pD3@&T1eMNKI|8# z|LRO!%plQMaHcz`yZ?J2h^*c531yl2#aFJ0(7ze&yHXoP5O)?`}aw#8`eMlMDE&D0890k3Mn$2|t9s!+Z1OGI`EvUtX{1%v6@q z@Y}VK?|M&hPpNBrqmwXs7{*m`^sVr`6C$6v5SDZ0;Kfg*SLdOJnO_jXA#FIoKdQ`I zHFG&e( zcg)B_bETdxL*ixhocqJMf-9^fei-k-QM5wA;VVK!!_aVPmyv>(Sa#*o*f#9*Vw-wB zYga$3o<*$t!*>7nd$ z5!(9t-WTyH&S$v!&Tf^@eCm9AX6$?|TZ7-zjq9SV%YGixk3;COkF{k8Gy45U{HDK@ zyc`H3Y}P+cL~nuOcB`?QC7x;qiKQQp!U0XPie7(It+O9SdXdjNtqIp8rN2`u?M&NYmX`E*0&f_alj;1BYN3!KaTSK8bO!Ht7~O_&M?$HWf< zD>OWsHep9S-(0YI20I{N6$f;dd`?ucty>nr<^=+=quY^mZ%KwuW6~UG^P?UoB7gbSz-eb} z1X3bK}Hb__-;2gj_tA?ZTWcltf0X1(mdkmG9GV!jfBh+w&2`f83M}Dseh%Fx$+zC1Chr?-{8KqHNl=BHAQPC0 zMaF?GM0s%Ym8j|^n0?^VE2r!I+u8G)*hRvnTb^c@xtjKQYLp1M(Cfl?8wMh!oMgU| zKf_J!^N04SA&jiJrfrD@o&Op}hYt#B!I!A7`{ki1fF9q@y**)H=fb7KXSQd&TNT@O z_s7;vjNyFkWoFjIxjWx)5K!vo&?nf@4vK=I8X3x5^PR2E5wf6mQar8xHe{*n1g%^Q z103fokiruGh+Q!-XcsFcR-za6OR#@GYd}yeDE#|FtOzsyT?vb&?+6f}6N%^$=?~Y? zh66x3evoef`kV@AV@{pQkwuS6#$8S7#=>sl8QUbNJ1c@iHn^6z2lnSjH%T=fTf+O3 z!zsYIknq{+Suy^7xd8zKPOJsh{ z+E~*_ZDw7h)-W#o4k%n*`WzBiyZC)>o;qyQw^cS@WXp4)=!BOsgL|0VSJS zSw@P%)1-)K)FnVG^?2@gnvzlRSps2f4XNsYW7(5UU#UbejChL5BdAG?=>}ssf~gUT z0?N=W5d|-`G-MC3)Gx|ZHG?O;Jh;O(ThqREpO{>W!0#p%T=pNCo%4Z2U`_ykVD+^0 z*=pz)&}!@alKj5;WH%qU)WijX3%T8dPU7uL78|~ci5SwJN3`cxPVE9;(@fXbjC@*I z4b;uRz|8Dr@+!1ccny6#wPuhoqeVM&WB!RN(6R-!n-@U%jEo5WRn265+xVujeB99a zwke!{GXB@mX%5GxD|E@0xq~<_op%^_fbqA*ju}GDXobbDCvoYTYunJOh^yg;l634 z2L3wu8ZN8OFOLzy$=DPuBHga?)ztErt<`}5{7wsDS6|!)f`VU_0eJ=VSBRJuz5N$f z1MKf-5bO_%auRlStNr|d)HUCV@3+46Lw&2cng5UG#3#|y1hy=0+s=>~gL!2JEE zV0E| zRd_pO;p|j_loh3`;wgpp28qG#m{Ig3v5QOQ{t_cL?QVbnSCE>_ULCyl3v1LI#6-7^ z%5@w|2Xpn)v=>S`Z{N^yAUZRbF2AoQ@)B6P4yK2`!;^+-CX>q-k1&49|+FIpZ(@ZLLcmK0^d^(Y-$2eS45GE@yX^h_I?^`pRP|0 zAJZ3jJI#_n?(H9ee$fE9+;E?A14O|;>|uJpAVXRf&Vm7b=D}|sR=h_BRKwh=|LTaR zBtXgKiDA-H#ER`l}0^IxQA`Q{eh7s5LCpCP++#2r}c1I z0u1RR07IqZ%is@4{;o|S0=;>*i2Tjh7w~tkLb}VF!@x5FnPa+>z@sT7TOGbd{fK}8 z(C~pdH}J~9V}nZ`Jn^^#=lpZj#nHg%#l;~BR>rJ({|%e~;FZ5elof5)qo@h#YR99W zS!D`I`pbK+jOI^17JnB0hs%3SZE>B7tx};Itsvi*RrJLj01Y68r#s8`UHv^D%4@|O zj+bLEG#3o%@LXvPHLl-x(HfzbVb|72&FqLwV!;tEoq3a*FT#M;v)j0Zao^^g0gx@}ZHnFQE0OHw6m>Ac`?*X3`)|KwO-^rSIJL_8|;Oyso^{Q}Y zgH`6Zz9~9b0qF2xicn@M@By`G9O#Mg{)&uST5`(Aih*U?LWCA>8hb38A`UA|o$$x^ z-kuD6pG(bxS+ELSuH8>8`RPJ!N8-QN?h4ikly~ih?KlB`^GS%gNDFw(fhmAX-JQ$^ zqM#Yeg9p%Bpy6y6C=mpT#jnqP%fQI z%5vOEKe_86ClJ(GdGrstdTU!NR&257-+XL9eT*1s89VL;E|2*&!NaD6I|Xzl6W~B1 z^*!TS_>(zpXv@6yA*Ye(%?pg{AFp6NJVAjojTaC9aciqqv3mgY?cUThJjPnXIbF59 z_A!toAv8xAc;Xl=F%X0*qdDqvcSo(6;>Q6U#-ji(={LQ6c z^#z#Jla?U!-13-$`CsBx#AEb~MbFLb)x9L7kWULRGVKvM>}7M9Z^~T0Xy8_ceggZ{H++^CTj0rPjjC2^>X1krB_oo0Jqg zB47f@zir;KirD@A(Pp?cqn%WXhPkP3D(2VYJzYqNlnrZ({nRMnMtDEjp2^a>MrwO; zcJ(?ZDUyRtSk#XcS-%#>a*uq&E$wMVCm@5&iI_>Vn~1NGCjq&um+6%_ItN)Nd3m7vh_4Zhy{`G=Z;pED7P1uhuPu<&Ua#+a;Tk=pPRFcCQ>uIX6iJc{8^B zAI@!d*}vm?QI@4yoy1X6B&E*^ScfqKBIKCMQ-)_?FbbrPn0dqMvI7 z56HlQiI05NhFM{>33!|71R}uI#Z2TJ%$|F5O>hkWcya`q3R~UgKsRk@I{ZNsYe0Io&V4xmKmu#AhpWt+i;o}%g#*GKKH&vLe^8?>yhlo zi<92~8rkuxvV;0sed|>Abm(%hFqxmA@ z6_`}ZZ#=_XX&ARw`~wsU%;$c`(-Kj*b|1*1DZZqy(vbUT3An-cZ43o)#)&GcRnnz9=dq!LKIkHU#oWgeVddm7B`F<6? zX3SHYc-&e>|0N|b-LC`bT(aOSZ~>m8s4enW1C|aQ4v9Rcd*S6?5V?-riDo~{e4P&| zCX_dYmFpYJ1qiqclN4S(JzX5p85=|W+d`0A@}Maa!)p|Cv0!7?jX(U$6-1* zP{Smp2*Eo#`>3nF;|r%=)CccF`WNoa1KKF9hib&*asr$Xp#OYhH*{=IJhi@AH1TOl z#@X$5)G8@JFPx#Ab^){r>qEvjWa&|*TuUSo0lFRns-VChTHZGP$T%jPV-G#OQ}!dx zqp7TiQxbu@jA9Z60GnIoZHX3+u1(P=YzOqX;$wChfa2pbwQRbh_TB8!DPRm_l2YZT*E)UoqDAO1`U3 z-lsYSKUcrBJ@D`EMrl~j&cj6TaK)!!?SjJN{O^N(T^qlPTod`S^)p}Z9<#l63R753 z(PH=$^586SWH0LG8{_x5e~luKLi9%yp#MztW5BwLoUoY?gik+Mu70~~x5Sm*Vf;B} zKp~dCU-sJ(;7MW#C&#^Ne2Gum3)U=d@iZfMjJW0K;Zhr`53&4<2AlPj^x22$x zx28YWGo9HXFCf-&(83SDB)7>r;B_^YCLw5WAp86 zp}P#OyM);FcvfJ4)R0IYCxn24w(uiS%xFRMp9V|eGE!4?VJl#K&=&xzD@dC%4|Rf4Nt|BM6da9pHc)C|;0|AT-m@+)=iL{F7?fyx9*dLoJ2nBP2h@k3Q!GIv(9^v$#wLR`KoUd-qVD|4IPE-UxngHJJ(^O)maV< zu@|fII32o@;Z-M3b(w4<@u5|;-n<|E?xFDH<+eTM@V@VPR zi`d>3;my`F<+{_&>IbDyx{G<1@*z8SoVJT{gub#hi|qu|zD(SH&o@XpNM~uhl_@~*Cka!dUHQzQs#YOKU|IEjh;+0)*DG|~7R2Spg;IIb2IuhEHnGk~>TNMUR z#O_{WXwwqoZ(A2bIu6j{_v6Aw+c!2rkohFS2l7Z11noFNe^qdt3tAAhrx9SF4=(0_ zL&h-lS3aFnIif=Z`I~fMM#}e4MfVFqkWTVU5CFNMbLT3OtW@ZSZ}1d^Z1pVW#h=2V z0LsPfNFXmt1@~7G9hyjt@a|g@1m@h(-!seMbp*JCj<>zXmtc?FH^ooHRc@0 zi9s5uhhe+Wyk90VzkA4)EI_$#a6gsWicsX>_RVgu-PpmsHTdevZXA8;qYjK^^xRyr zP*iUcJJblT^?G99w&Qkw+TE+SE%a)-T_AWmENv`TL+eU@fZ^tDYp@2VdAHZ{IPF}( zS{*OWZ347jRZ+AMCW7oGp7?z=;FU8!$mo{(hg|(HFSs4UTV(qZv|uf+jCBzHUWkohEzFp zWq{`{%)O|TUE!5sN#2*$<-zLuc&k%N>Ph;QjLT@mLaWgo%&*_R(lmq%cpg+ZPxAUZ zl28=<0kII8{}TU{eX$^4n$*!KXW+A0$>!u0q z?ADSqpae_$#=53fsteXN&_b!g1Yqw)Kna2opn^yA*(Kn05b=pz2%r2&gfHs=ysm_N zPiPDPoAuU+r%V<2t}TmBd^^DjlBxi1vjD;Dn^ALQoBDo9T=+60 zD|Kr&Vj3?-3POy_TuGeiRY413_1MDiUF5e3nkOAyc6DQAJYW+XO|h)IkE6u+V3pcw zH-&+{E4udjzgd0%pR-1QX7~OJ34FLo1n2O)n*tz62-TA$!B0(x*M+~AcB6|vO(+*S zz7RFCwq-zk=5}se8zE2S*%~t>6?@rQ-EqwqNZcw_hKrxUiyH1S{Lc!##sPY(NF2u` zIP6#V`Go~GvCD&`A>5A@dR_kdN$l7US$-67I5&BHyXt-U&8?40mkH?JmGy=Tp}PF) za=F2QiToXENdf=8e)wv?q{t%#IB`=lKOT%oQSo&}P5|FU;8_@YCUX4!rjN$23ke6? zlqNqc3^&Vq)JA;!`&r7#E=518`DC^Jx3tYR^KVtzTPRRtzj&f0GZS1oHgXtT5(2Z+ zTwh*p>DXww?*yS@E~ejqT}=?|$*(EMFM-D&dg&JBrmq8l?Og;cRSCnPp7)e2L>0-# zLfZ41nI#0u1KIPX*p5CPa1!@KW2+D1Sy^EG3p@YD%v){)_YRL#8CE_W*?ms6XoSBpHrVFvp zJI8!?{@!j&VH{He3|-%c+oH2T&Bl%Q%U!vi2()YfgSQXl;n6*4Pte1JpT_`7Z1LSx z=pH6GJ%h-jhx=c>dLTh-Ee>iVp-Sl_!+-Vc5ol2J$17`qhlHDgs1jNb?0{QCFQYmN zeiL4s183mDbXRQy#F|rVaEt+AO4Ib_zn2>$aGk55rx11&yx-NQU!WQpo`LK$-!9U22~>f z_@Gqp083nCry&Tx<~gJ%JeS@5*NuQ%Q#=aD@4swvhqY*mUuF0#Oig#Uu{Rq5bfR7d z^mBX1FPP(cDz?UX3Cv2X&xbdh4#zuvcQy1*SzE*dd8LNb*XwWf6%qTbsXBojz9(a9 zzmL7X5uZ>rDdA~tf>?7!qFvUMYq`AMpCkZ3jsW?_NjM4vskl0|@rP@EX7IS&nWdMyz~^5TtkClD*5k(P25_H=_%nB3h|* zVQoIh|I9`D2q@fd_%o*bq}9uXC;EWmxB-0K>6ZcJ75k{q7T|eKd#~YY-L}MUdqp1{ zC=_qUji*yUI_P{EQ04dKht=Xw=b!WS_xA%V;OP0D3~`ia6(Jc`x`TadnXeE1DK_$V zTf4i1d(`9MTFa~T@;(HO_8g7+A`;Vz5NJ@S0^3|eI%%O7JcD^uPWn}Top6TElv~Jj z2K4=&wLeU70ee7ljBc``6WEzVp!hKLaI`C^cQXQ-((3BB_B&b8`*!$`1zxDWs@i&^ zB&ntK88m3^84LI{hY5TmFY_UcvwiozeG;<$WMcaZe)al+8Yc}k&*&^0xi7nhZ=Y_7 z-RcrGhGSeif4^v?P5W^Rp)D@whxYFJ4TFPR!2OCd-=|vXlr3Ul1dh`<1}fIW4x`doj}JkR6wnRZI;RlnN%+%w89Xd?@guARRjChM#Sl z!EwsbHQjrukO83d4SjZMyFA}mYV*CU{nPQ|FBX^Hettchq382crt$pOQa)5t(D&VH ze}#KJ4&9$~FAm5<7hLl${xs$N>jWNfkYfvujLzQ4Er`66froM%JQ%};i@iY+&=qEU z)318R8f)`+(Y=*yA)GuU_O;#zT0?&j-wDY_q4fK|pO{~eyPGs@@oRx0QjL|XA-o}! zBn4E2h5uo{H(;82(jnXV8~HC_B>a}Gkj!59D0!%akvey~w{)u<+;{}yrao2=iR|{c z=l@=p2oJ(GvEL<`ryZITHv*oG=+ahXBf$BoagA|b>oaiV$z3cyXt#L}cNBuq%o0vSF}&5LfG_Q zJEX8Ss!3B*T?}|$`*D#ffnpjng|D8o#?C$fuXDHyBZhjfzsvEBzni*zNaU%{p?z|~x+wbr@{Zt>X7C^Nph)3hDRF6n7Qb=mC?7Fpo~fh?3&?I`#*f6-V+m=W0<`k7W_Sl8&ja+MW>)-tK#ksaO?kEV{U*T z722qJk*fln<(@Y%7(?1D_HC!VCOEFkqLg?uf_M!$50;)*}6~71aMlR z1J3}ID)1E!W zdbiv~PFoCJVcn}f09;4f#yh7&e#@jK5Ze5-s^%4I7l(^twBC`~&N0cG7Aeb+GROQW zeM*e}dI|I=o(1>ngI1=k`rX4LhdWyX2XsOP(n+&BkAkF8`Ep4IjnO{kQNOxp4+)?! z9H2ViYs|Xz6DTS4lVg33NM&z9S?e!rV14|$H(+iB=WvA_U|!-Y)^w79$}GNa{&#P! zr*Xnj`1V1ELM)%{H({IQ)8hF`Oat^#b?_39U=Gar0Pic7!C+MJ($BJ=TfpS;6$9Uo z;LWPpR{;CSsgS!6%thl39-VB4iyoAb$WfG5a`S8%X*p>ky8< zRc$rXFCFlLH8tQ1wBF{WilUt0CM&+HTo2ukgH~$iJ4XMGsf|>#|1++{MCAT{&3yVe zjk@(jz@CS5GGpI}OB(%p%zKSj*vlVP)xe%ZqW^vEu8Kd)RV2RzLh&LPc=eBs%mEBW)6BFSS2XobJO#1PY+v z`K&R37jj9qypR?TSaLzoG>7P|J&Ja{)htdT2+$``Kt)gw0{j3pOkR?OzuGl0wVJK~ zWqEnZY&lz;y#Qsgq{(3tR8(}{06RhW8NfDV$f<$6{DoC-U`v+!A4g{%4(0o{@#~ox zX6$R(!jMX`C2Pb;i%N(>DzpnlA-j3BP{~sAjfiQnMV3O!HZ7u3WG~9TZzKCQ^WMMr zzy5F>nZ^BF_j#S?=d9vl&1*M2nKp^d7Hl%7IjuTgnrpnU(!5kEB&b^1(eZIUfFJx9 zh3{_W9}ay7Xekl~3(J(pA>9#vCiK?A9oq(Lom?=yGUm-z0##(2FVp=s}Q+dIAZrqrMP47Y;rthG?8)EzA<-#e)L@RvC#yXTjz{fn7+VP z$@=GWshh)+rRX7<0J{fXeg@HId8dcE)b+oFS$iABl+!ZEZncxUcN z6(YFCMtiUGO1ew5XwltWHS*>u-FnqrW7nrJ8(w%gvWEiR=d`lS#!WIH#ecb{%I|OJ zpyvkR`h54%mL10itwe!Ep&91HcfZ?xjL>dG+a^Ob0qaGi+)b_BtPhTTexaa!ejzkZ}9y`GHAP+arg^-6t)?lK7E7_|bizkA70CmbHP+~oA=x@rt9G(MvG+33|-V1*ul*wLj_ zch~;e0(nVFq5>bd+#gnK&9eu|G$EXwpta2*I9lZ(fgz67eu$W>L-k1ie#cxs?_@EW zr{aUUgMia|2ADTnT~`Cd>P$Qaq$YlG!@2CKilF~iTd(!6oEd1Ao|1o`mu85!a@;tJ z6pd@8Od_g|MeO#Pe{kj$q*^OLaFghumC^}_{SH0`px@uhMLX&XB?kRph(5*ar$uZd zruw9BWzcpaY>%lUFnJ2Gwrv42PWPsOiNOcAOS^cPDHnzaG!*ZHM^~_c&d;DtVGN`m zh(&r-TVoA{xtkZ6FMt;&*1JSA+mkKIgw1)t{q6a z+zG!$%o*>=a24yAdcLZY&;M>KwcP8^W$saLsiBPDMCzGq^2TP3X-E zTZj^>q#{^^#!=3=y^Y0^l~2BAzU*$U7S{CV-HN228wEL@!%vE=TJ95VrmpS+$IC<7 zw4%QY`Oo+`e0D}SpcCgD?DV`2>Ze2q4%>XIn+E4!rt10a40GVxuTfs|^wS-I1K#G( zu=nPnlRJ0htoEwKNH85jR8_d}r;1Z(!$Mu3s!G^I>n}-yuDRQFwVf{vpoMKVh_0JJ zt0i<8*`ELx9Oc9>@m&i8SMy^X->d=a#zbzL~E^S zW~cE<`OZ6gf{IEfgfN;fA9QI_Q=dF6ADm!iV_INs?IZxo+c+uheM#s(%1eZj#Cpai z89mjfBxw4u1-g>@)j}QayML~$GYrNomNag#+Q$6P^}PQQRf;11W3whV!c6s6{M5b=rmJ>Ia~VvPFV4=FNllHfh5QjR`4t5}O6$px0RNG!!IYb; zdcaiQJZL3f8pJu#C_Uk<85YNJ^6zz2PH2NtT*Fe8Ss(OyZq|%=wb_R@L>O z?eXMaYt{N4{X5cL0rl~R>}vf5VbKNda{RSLLHV-jeZ;QpYB{nec5R2mZBZN zrXA1{^NTqqEW}(pPGp7O8$hQlerL`ZKm;~J$+rOT{}xX~Vx)%|?eCEmwzv1az<6nQ zxrGYcI$EB(j$6z8q)B4T>ipE!v)SnPMgAc&z73NP5=TAg_tz2}R-4!d8~-zMIO+jF zmoF5EP4F1~rkDO(qW8Gs_+VNTp0oN!>245O4i+{3x>mR#_rvT}FPR8}a{ixd(P#JO zAg-JH(-=P|S-%v*)tp%*m2|f{ytimQI;CArMhbJ&dtV+bxaaO{%39ug9~J%$y}Y?9 zZ#m_auThddFL4gSIPL- zgzF?+M!tKwssbUEUYC=NZ=8`Gqmzx_JBA+hZ`CRK$ITx~&Svkrx7H|E-ZJoWrQb~@ z{yky5vR|H5q-~QyaueFF@NxXQI1%z)q%qFh*VVeY&L;HL=e|N{_`Pl~F{1OwPJm** z@%3n~<=HaMyNrJsQ1bYE)uNMC*?kSux%XPfqdrCLBpF;KC0s zDbtWohV9r#BKl-dL7D!J3lpmRQaYe%Mub=;XkfdOQGMNBn7Czs>=ssgir-~rp`Sg& z`IpT5y07UBw-a`VRlG9yCvA;?%pQenh}3nVNdewJ9K3bt#y*Y$*MiwK9uSqxYoY(V zXn@h=rrzf8hF{r8a0s$ojNctfq21h;D@aq-)SZ_;Kk|0Vqs-hNcfHaVJOxi}cPFY= z>{~Uw9<|+v&KDcmgF=%jPWW{(gPFkA;X zGH21k-c$;Ye?WN3&(Imba8W#o=WZeRDY`4;ua{PwpPxT2j?2tH&?T_=*d0%dd(^#1 z3m?&m9ic|Ztmf=Jkgk(rodILoeoS~aBNHt*`;A+R-KEQOtc`duE5*wwWyV7^>-3E_T$R3Z(v9FfA?PZ#)gdj z__v{B@s&pJ2iblr0%J9T+|^7hN!asdy^kSHg!$U!*(&|eo#*UBxlwZyf$T-u3^_*S zUp`Dz%ek*=Wb=4io$OqLo`Vsn+sl_whMS|0S31knF1fDa?Mq4ANZFI_2S?TW@ z`|g(?t?fr1JyZ$MuYw;o>U+Bhq_OzB`k;O&~T4e?`_6uS^2-W z-e2(I^zA_+s-gElG9b6>6ERQILCcAd;8vwVUL-?3bu_CyUO;Q8xo7xdoifeSJ&f?n z|GU!_ac1dUpSMk1>ao*2kjVY<=Bp2hF|ONX5YqAiS3qdwtl8#VN1*N?eZr8-=WxkY zw$V6|IZFRQ@bBSzfTft^se>R%-%ucTHyMzEe#ej(7QBz@Tz&r`EeG=LQZIu%D2o$R z)u&!Se!n6NQs#{YPWk|O@&4Gq(iJJs#%G5%h}NEjwU)dgB`AF54Pz!h-=t(ZbdDo4Ld?Oix;HI}F+ zEdoR9^WP~S!Q(P?oM*7EYcp7rFw-ZAWDc%IrtL9F?;vv>f>z)H;B`)hkC9lM-$;O} z0zXqhoQSt>`d+6(V3dR#K@;dd- zV`;iQF9q;-z!V;#BOs zYC5(z?t;@Uq0rsv6++=Bkwrggi>huIN+&Y(e%Z8gw~uG*goe<*t={8RUJN}opJmy> zh%Qba!qfTql_J`etn0%y_IG_XxxMH5Foi8eA@hGSF8g`=*W**oJb*Ht!{#AD$CBA} zl|FYGowru}_W!_%-CSbJxYaPi*XoAZc}dIDdi z@AbJSf{T&x#%j9*kx_R|BaVC&_!1P=68YcWV82y*h2C?E*E#-b3%^LR&$h=aZrpFUHhqEQNdn_ z`Ky@(6vN{)?Mk%Yoc+bw=eW8WehKN5;pUELf?tUf0{c<7DW}mUn4cMLVrCVc)Or**2WD*%= zpUGg7#S>|Mwc`3~+7a97@{p*Kria!hwqw7}%B0i(bdcrWc@y?y4=r`us4~Jrf0eA28pEspf}ZyM>riz|8vCu0zPTH3RAvE=b8ySB)R9FTOdS|6QP=Dvo=8JSt}AA0Ku5BRGNi{`?$zLJ}x|^79+hUYqZS zu9bolR-TV^vtAY6<^Ds!*)0hQA!U)`P$IDiF4>@U0*`$A>R&V9dwTlB9$){#r-u9o z@+~YP-yNY>LadFg7|hAfN4c>>AoI9>(A9T-l$$#CF;p&>MSHWNmpueY$-|>D-AS7- z!>+(7>d|AZmzqrrNQ7o)s@Ny(Fbu4~^QAUodLtpII^__UjaV_j3ESdw_M2 zB0t<2x;lCy>c_mOV2uO4<9Kt0H}sJpdFN-j4ZRUFu^IY2Oacvw*h~A~m59J^OAyC| za4!6yt>4Q4Z9cg5Hlxm)8mkX1+X_Lt{h5(TRexjyan>%*r_5D;ErPY&UZ|dMUWE%b z;2mq=g_m2(I3wr)_l^h49X~&E-YvI4tPs|8HEJS)!b8It8*lA&jqM!kNV}1joSGGp z^2(N!sO#{=Ua3~+(4y&H<7aXQJ!qA=#XpB8r`;q1?@ov4#V?9sU>(`NPE&sD2vDY62d{^sim_l2SgGXVzH1@8+#DBTY1r`dP~p@BOH zYc{@pEzJC1%7*WSoF*(*_uUTH(y4G0ho8DYrOOKUEnPT!b z2gVIJYoLi$8mB$CcmLsYyqBNkG?<*g7&lTSilx5xi7pi3N6-p1zlOlvHm!HD2$)Av zX%?EJh+ly@JWPN%i%t_mK9<5=_&lhZE&Yb_KQL_9Qw3lL^sA$Wv`%sGkzZKdA>3u0 zFg|?()d){kvvy^!w9pSj&16{DBUF|Z@$5sW;pBtk`e0Ge;&5Tmc^6w}p>D6ypJ&mhv|C>>LT| zT$VFVX;mp{d}DQ*9!CZ_mE^;lG6l$98+3l6LiA-%`F#;1$ zgR6-P1z7LTUv5uZauR;A9=6T~F3S7E@r{h%ba@zaph-}y<5K)6)W^#McPAbYYG+M~ zg%N$04D zbLrRd55)k7HUSqFU2N=%)qdWg08I7(^XkUsdYo_7zx`Ltrqi6Lk@otsh?^iBJ_ia$ zKbQ89Jzg@$9Fn?BPl!F@d@6N&cF+99!&R{M5zdyCM9?+X`_w{esPmSWbQ{3?zMe_V zGM2oheRj-5lykW{E%XtRtDi{WDIca~i;zx4d!sGih zyc3T8PrPT~wp2PVtSGs29`oVzWBX~Qu{(#U&msTnYIK&nofujz;PTYg+1(_J`L^VJ zoo^@+!+UmtEY~fR6rt;8oaduH#%gxwE(L4?nto3&8KsLvyRO6&;jh{9q`W=|_uqLI zLx8!}_uu|V6PQCw>^DhVMuFi^4g1dk{wL|;r2Kyh9k~FB@xood+3{29)y+p$TH^Uy zt+gjq)i-}s;N0N)vB$XY@dD%gVWayd7v6L)5hFTF$BQ}D^Xvn@vz;pk-_x^x-rxBj zkLs33`XcF%RSsVss?!hJAIZ5*(OzK^avYT%zGjW=IlJ1*%>&3Hi1KfJ;4uy%E3YvfLf| zXY07Ot*-|r7vO=wimYA-fG2VX-+2bf$whTPDZ-igX$6bdxIn!J!}aHMy}LbyJSa$1 zi+F|~k{_JMt~7|02fTt1Uh7{05GKZ~Nu;|TK2TTcIlEdK)RIl$r@jA9P*FDa8ImG` zMxrqKZxTrOC7MQsmq+jK+r|InR$>&PsK+hFx4LxV`Fg*wirqbacm8c(jam41gbynk z>HLme^S?{%4w+x`o2Tt=fayq2#i}a-=Z87YQ8iKUUkg-0u)`?1hacJ+!*SVLpT!Cs z6kD4A=vXv%HhmZ!bk&H%o*ne4*%V$`k*DeVvc^= zLo27x#RkG}$21;)_@IzIG!&g3aFM60VKtaiKSR%BIiclWJK6GtCBHR3X z#Yglna05pJP$t1aqY+mHkH2M$c<8`5t3D=G^&Tr{we#M~}*f zlWzz(V-2n5#xtU+C1h%cU$yv;k7mSPbKEuPq;%1j64mCjKiCmh1irpq`Vi;yy33G|#W0=>+gK4Iqs?H~TMVNMd zB4BCrME=x|-MU}B|2J8Clu4c%+kH+Ftt$e}mI#PoPs(qfh9OPnwsv~*H#Wy<(sUyO z&Cp*kYiNremnA~Q@cexk#`MjFXl>*gDf*?9MInJockW#U*JCCLHD@MHANrO$|G~K0 z!2Qdr8Rw`OaiSouVAW_ZxKPKK?7?{xPN6?IxrpK`XM?}3T-^0%rgts)uWH!;RI{NH#|4JWcKPc4>F?qX*Iz!nt6Pis~w9g4$QAU#}&0P^km(w@RAE1t;Mp;ZvaA z3;0Q9?0FG6D-?y$K05Sa*I-GVU>=81r&`2M&X5!_7ktxllH@4{3dN#Fps1*5YV84# ztVM;ywvWlb%9pq`3I1(h7D6z_WGVPV=Xeb#$(t`@PW>lj1P{f&{0-B`7zee)m!B^S z2k~lc6?Ukyf(zpCXz2+iu$6SiDl6(?m8S|69{!I**P)1F^BqUQ8oiZ+5cSgB_@MO(Xa z47R+Wz^UZ|Wu^W%oHbX!Ac&gTmY|`V0)+TMy=BYO;#e?bQuY9var+h~4vkkf9t7*J zind(%A?FOltZZLZzFUtGVX z5vx54o9f%8!(PYA2zQlzh* z#4m7;a(CT?CXCfpxXp9LUt9v;L|{(wHE;`ee&Pz;OJM@;&Rv5j$i)~q31q|SKHB?c zlS`gG=kk^d{9o+|@@~bVuiUFEo#@cIvmp4lVEfvdXl$kD`zqO;S5Sf5>tP^DQs2}z z<^8s3?-V@M_S>wOF{zsFN-h?J4l8Iw++B`yQTPC-KmcjK4Ltb+m7<{XY0WY2xbuSOY{kc{9iXgWQ3`KqNIb(f5Da!Vo zv^9sus}8PJ4aQ~9;}r0iscV13)E(x3==LgUZUgsYRct?o5>@);%~{^a#E60IifqK|xqr163?5 zuOln*zJhC)393}3edho0FPriP3Ts}EU9L1IBL759nB3`pea16M?yk3-s<}Zj{5ke9cQ4!e4|12BkG>**_gpYh z0#EK@m)^l1EJr+3Rwb(bZ+)maJgB>>cZ@CxK(Q9_v8@ zs&z<5u`of#F8FZ?AhzpxaumOaUC1N{1+L8nE$TB$ z-OPm#dIR2RXY1w`$=L&p&ntVh&Lc#w^?I;2QUT>^G`x)wRncfHhXYXC=zPG{Gn}m) zJDg*mIR4ObelCt=9p8EuV|*zb+t=Wb(F^eDXJc7z^~Q(&!@tu5#hR^r(mXOuD3Nh< zoKd&?OZZZYxrG?7 zD9HBsob5coNju;A*?woir}bOb2d}%>9rxJRdPmbfY38Pkr!Oy(;2oSC%Wvzlz~$>g7XMU1H#gRLEr)lt4jgA5`lw|xD8 zRw2C2VW+n|K%Hii%ZHvSF$CNeyeWz)zs!C6n8&@jj$wUf^s|8GLcLhVycY5QKXiL> zu$*{o{Dq9)EMec4nRq81TdE7K=}7EZz-SlKvD^)R2&1% z>)z!%;X6S)Ep!b_?MPz*C4PCXvR3Zsh5k_GR=Hb32`Aik+M)W&X7`YZOaGx-xiS6sxI;RvF;zi6##1T|=u&<;ap4z&Z-xBm#N>Go}{w zogXD(2V@6NPrgNWG8gZLV&-<~g?)o)>x_AH52(^q`;d%nTy|+r73|^wRme5C$UR&Etd8u6lgNPKr>K zD-cTn-8y3a0YJgoLpjC;?{a3$E5!$&t+6gNG@ydljT88>M@Cm{jgiaM)wkjGPU78ZHuavg98Z#3IER=sT2?^%9i|rGn zjUqfzJ=?p@Z_R;KG*SxS_yk1Zlb z&h0aO?kJ22xGIeR-k?>4uZ4}@GY@ARd^?HN+t4$$>-|S45&;Q@y?>IMTN|@I+gG=n znDpDvC!JXHr2CdXSn#74cD%@0^WrU%ONtm78hNLTZ4?jZd#X7e9shkx679V7CU5e& zOh2pJ@m-S1N8vG-qXuD?Nu=-B&PWSWyQ04;_JRYeejRdGk`Ryb*4}71BUvvJVfHKo zg0I(tCy8-v&zqS=tH`P!zVA8XfEzuL{xj|QWupn0D_GyOAlN|H4Y&O}WBLcI?mlOi z2EwL`Sl=Ps=}%DnstQlv>7fm2Q=gOi_L6qJ%UCC(Ik7ovbyhU>?MnOxx5g>Tm0|op z*)iKkn;1P?k3CB`Y_>W7?RE+*NC*Qjb_+gZv022Lcp@!C?oD*oW^Ilsg=vQ4@Crq3 zyfFvFp)i%Dj<0+V=bSqVnnk3-eZ1ugQG78%L{LX#eRXiJ%$0Tm)Q^UqD6mEKEtaPQ8Sz&M150t5lrBY#t?%OL zmS-__h&!JmoZx0$yZ(aw*jlULJ9>Ar)#r{Z;ixJTSbRX!@fl)%BRdt#A^7iALhOZM z4n>GL+!&O){f4ul6Q}cY=SM9^x1!b-Eg1@nF14x%+nhcVaMJ8PF#V`zJ6cydCw2Jx zX$;@c2sa>IU;!t2Eo8PZBZDvN~(1+d)xKQ!*>6 zV6UbJUFAWE_L#!FmB1G1k^>8 z6!yiylDM!*4Yj60%@5@BS@21Fa=4WOS_+Uu#p5xEg-35qj~)fY&jlN9$`$0;yzx8b zAPJ?=p{qRlD2IeUmd3iWGx=1BhyOn*PD~E|pvMXQ%$Y2YKYuo$_bCAnl`n;!iLVgQ z_}CzQl?*x47&9IMqu_18K;*MWT9vCU*&aUuTh=^Mq2<^fer_5=5~DAHT9ie90Bq;Jjit_K@hebzjJX+<7w9Gtb&t7 zJ;AmB7&`aykHCeE3syYNpXFS?F#pv-`L9cjJlH(jc4G8wiC-{dM5 z9RYn=?H#kIJUv6JZq#3K{}nL(i95h~Qy{BctNvk2MVh@g#1(yJ`^~n@h5!^;2cGF{iu0+laLBfk&Zr?us!u_4PpWZrh$f8Z!`RsLg#3LC9 zeaTr^z8s7oe&kDBnApbO9>e7DC8dV2htJa&l&jImN+UB%&(B-b`GXSXwJvwug|lT- zJ-aTDIS=&{?lMrsDKpVLU)A$0%>!VxX)BY89S0JhnucbYP;2D*8TQk<)oo5E9{d-+ z=KDmwmEz0^&?Xn=b)fbQA=<~?1c)T`yIXpkmSTR)_K*S|{3UGEIez1;P#(LP$gq*Xb3Dg9jLe`u z4|UA%TThh^jdv$yqNHp;m4~$<$BjLnuIqfY?90{0!|+v}$Gm^rit<{`=}@}&=#tLl zmFXP13wv_{-2-s5=Vv8tEr@{=zp4@CWW@CgFzZX`;^5yu6K%%0bZlL?o@8D56jA)_ zIT)IJGTRvcD<9K6#x(?we*QVt&RhTG^{kdx4fksKt`xV+Ada$P>tK}NAO=jWvVdPt zDO$r%zqls1$nQLs@|T@`U$o|AxgCCueb`Uc?%UPirlKZRd|iYAi6%^y4S1gN;duxV zLbBvul$K@$-Dq9@L9}jt+>ioU-5QlEPY0#>7h{#M=&GasFj8+9JF#k>69=&+dz^{J zAB-k)tm+xP>(~bR*A#uVXD)7b8p`&M^%yTF`6WfAA5 z(`%|^uo{2ObMoQ%R}XO%oNQ8;$#_eARq_NEV;LKDi&FRmph;5W>ibV2?ya8XLA{UU zJwmS?#WS2&-h1a6zd>dp60=xhu&yHL%B;4&WD&260xwucf8TmPax$3G$`L*RilYnF zmIwpB58H)cx!BX33*Y29eqT=rcFn!IF`#3lCoOd*cy4jL^4DevZk5A3z&hOqGJoc^ z+M!(y%QJWDe@^}lQbAK11;$m$aVHLP?Y(E_pLS5RDW$jKxC0G?$h;(s#09ak5@a6GLX@Vt-4AZh=ehYKG#@`EdX0^5#l)RBg+9ZGO% zKT=ImU!nIc*bUapb+Y!JYnhWmWS|XJ>Io<-lRh1^yOi=Fnt2Bds#g|;UHBLE9#s6E zFdEi-d&tbuPWdKYxxfQ>rA{p|c>j8|mMh?JgJlXCJT|~kfACH8wr^ip^eqW&&cK~c z*Pk#0$NIe4S6T~JQjR8f{|y9uZSA_(&1*uYA`3Gm)(mgWBvM)6;b<4G;V7a5^;PLc zMGo)W*AuVjf8N`~>J9%!-vjqg6zDHa?=v-)9y^}3JhuOhFibBu79r-czoK-nK2ziJ zr1TeVT#iUm9zGDv?w9!E@iWE~_b=8s+WOzfGn=Uv8H=t+c-BsFcajT5=>$@P3PyM8%*YiAiK&NeU&RG!VH{oFhqCwbC{q_4J z@dO&et6Nl-vNa5@CAHBHw%L+2KYcbSd!o9i*7(T8{_CJ0S$xzIgr^3dw+YisFWf#O z{K9o=hY&7+vErr>IKu4?57^%O-&N-WntOfcPov080)n96aVW)&i_p#-lK~v{ttDKD z$T{@CTLSY#RWGtFFiMX<)!|1%eqapun6$a`_ICvWVsK@N(|mAn4K^Upog*y^dm`>r zNmM#n1?4EBcrOSXoVe$`Wizzd(Vjy{_{84nk2z_?vT1|Pc#UnVAL>K1HVXaIS7yH% z4tp|W&fufHTT~`_`6|Ha&hh?AqweLEw~c$_OW1>3c)%v|n-*Y*+_@l!3uPL~p{uL$ zrMFhB2a#%oS|v;x%{(r+%w8^CK4M7<^X*vWMH0iNcS4H(cONV{2r17(nI&jy{LIiH zyCBq|v)`dct}|5D$F(q~&)64rEIDL8Z$XyaRnRE2sh&~~V9V*uzb}j@tTI>Jw=h07 z{tJhurQTc{?izW>HvqQ>M|2<86_fsrnb>uHB1gP)EcKk&4;?#4C%+RuMDd~TIxmU! z&nh+EnD&SrVNCOk18c?EufMVY+U3Hpc5L`6eLZKZ-penC00p$at;iygfXx!1zG3rD zg>gaa^j^W)-oAR{h`Jf*+KfRBfE^cJ$_2%|a9C}(j;tAoQh@B^yW!M5akGEBz+>!Z zMEkwGSP4lpkG~Ik(*kpw{DN2B5B?!u74B--h~aV=f;UNB+Ey9sD_`h?>L!rkT2ge` ztmg4+QqesBJ9;^R-Gvh)->8SDBl||pJ zOLxanMNab2P%361b6&vI{rSWFpTnPZWVlZ~@hu8jjSK-7DJD+=$MZU{*DgnH=Xd#Y z<0(oXsY4x6v!cdnS^oX0(+hj{%3|VSm@wu19~Up3-Teie$eByu{r7E-szh|!Z8zzB z6sD(2jx4t7XIH>S(}fNv+vAJ1fxB+Yp_J?^!N28FQ-tbAFR0fxetR$Bej(`MDW|_=|v^s z78JaD$t_QUTDAB0jl(06hn)`4FJm|2VS8lGHP4p3S9R~?_joJ~l6xFqRN*R|h8th) zMQ_283%5TnUlyARGoMeHPu=A2dL%7}M#jsm*`J^A-&e<KRa>vY&Ez)<`MVLT7$Ac4 zZH*opjeuJaOPmj2n_jvjw1TKV%y6HrKGfwxCbj<(H7ZB+ z2wJa#bU0U~@$w7X;L?xfJku2yMHhV$W%?dm>?4tFRXiUUV^S zrLp>%$~PA{=si;0;3eVI4-7|)DU&T*++%|zFXei)=rly_C?BTNewGhd{pmCN8u}{b zxrG3&hzuw`P`D;P9K1fDUWo^yps#p-*y8~_wbGz4vUGmN>jEo&0jNd`Zkk%_WQH5B zlno8aJ5SL3#<%=wjfW)*en$1-m3g60>aETd9bw0oXk@M>Z0qCIDYhNhs)h)2t~ zGfb?1VB%3MSTFaAAlyK~k@MR64h1X_!6RR`tDrh1P*4QxBTe-OEUA&RZRN(vi$F$(t+og!Duj{Q+G9Haveg<9tznunko-p zD+AWLB!0sfBI?$N%;{+eEt<=1qs^%bVBE5P)4Y~>vf7;Ue_w=VRxrnoj8}4DD5{B* zwXQziino8e^Qq;uH>oS9tSz+SuS8u|5Wb~z@GK?@m#R5CPzwhMH=&;lM2vbEFrlx( z(b*gIXHeUKh2TzkZb}3P3AAYSmmqnu>8QoU^RGDrU68m_w>-Byafm8`jVXcuBokFM zn*j>Qp_(Mfel8qKVrm0{dG)s+=TWDz^=Rriw1qywe%6U`1LE`ULt#G^u*#KS&282o z?}lF|@V;|7m6NDaCV?kMDo8QunR;Mvfm*4i8v?pd>IZQZbkCp8b z!V6l+l9-Em6S7*FpbH!RT1IH=j%2!mPkO52>()2teV|L? z6x#Ri7r3-T&jR%;g4fVSQK&`NZ4DI|!Z%%yygn<*I^@5U7_Rpq+DGT)9%mmGB@!Fc zr$zG-;L~Z38X?>?h^1$-@ri^~h%J-$d%BUZ8*5!czv zb}gHM|I=^d<(aP;qSEF*P9wNpm{VA;P({UM17q55Lmse~=-Bo;%=>^$ED`^bri6>F zRSqmj9V=svb$?b> zPk{~DU-~6<5%mK+c*iOM&b^grSnVUg54P>b!5G6%Of#rTzm;S@&KU~9S40#j zx#aTT=k{(2t|}(;XsF!`D4UrgOis)<__T070{nHpUo$bUHE}{wv0OPwy6{{UroUMY zXfRm2e-|>hzq#@$UCU-;edy|wU)2X+RyvOLylVdzxlIoDfUalM<KL{MvWHb?vf3eyfXTA^Wg61ga!kxoF<1I8LnyMoz{^F>6rLR4}AxCD{$K?@n2 zo9dTaoYN}Mzr5_BYr2ICkOBDa`T*JLxt&V*Hc=ufA1M4^z>cK3DsG4!yDo2TCE4g% z*nbywTVu?zQSa>nnz4$2x$vO!dLpceKE8&QKydLih=Ua;S~SWy^S)ru?pAT{D-y#i zcFters}k}#ef_PMXnrcunpnQF4mC}R=D%Iacz*EfFC8&=UX^;%kZyau^Zw@rlHM1y zXOC0y)FGfrWBI{Qm#9w5UzusV(!KtGC|eceT>amF`(CAz#pU6|c#R+(F4xU>Kr)dU zg`@J1BLt);LW3E9{Zphvt_~{$X z>{+Y4!^>5{z#zlY^WL~`vZ;c-7chM9NEep52~{Y55IPVg%ybSs!(!D#<;FuvW&cI@ zh{~;5$>$8UyB}BrC{jx&#d6Zm^!#hptKcToG%+hmxNslaP0~Dc+0!y%doLY-5wkTk zcH%<+0fQ585g*lPt|rH*JLrj}qku!-=KtiH))?*{?TdT;^sul2ey^zw>3=R6^riEbo`k05Niopo^Wu1$EdLT4 zK`UI2=aV;U;DNjk9gcB@kO1)htySEA+}JtP_%g4Scr zi(5RWZ>Oa0BQtjq@DfP>TmI79)LZ#c+&XeO4HPM|a%%a}0*$P*;OyuvBGuK8N*AVB3BG zhlI>*2}Eq05n8FiXdD+6g8i=NI&yFSvt-PB#T{Nzz&-zA>qUZhUKH~NE_hlX)hFZ_l=}%0+R5SE;Zp z)GGW0bN>8fC-YX%SY=bKwu@$%qKd08W^Vda@bj*w{7YleJWBY7qNH@KAq_LU&UmR~ znj3UaD{6YGl9V7{1aG5XusiBt(DIvJ(-xA`VTe}D%d7MC7>*DtMJqS(pE*lISDpPh zWQ6;=6uR3f+tasQ?FKx6ii@s0$14%n)numK0hpD4SJ%9M(b6F_&xy)bP49a$sMd7) zkd*G~VsSSXA4zeIcM)F0LNWcXI;_0#?DQJcHDXX*pi;w**w0dMnAz1uP(~Lb3J`fg znusPD0t>}<)@|cvT|U5X*SQ_DkfuJ5!bz}`jsP}9bg_V%egc&3##GDK* zG-)T|rQ0~BYhdP_C9jJxH3v!Nv?q&x7s2fGk8OJU>ZZON>UY}pO~bDQb2=r6uI1yn z^KKG=3oj5+jatk(iMM`ly63Ggnn>j1H!o%o4lN!8M%J~B1Kg7)vL8?^B-h{}0XLWl z{j(Zl56qR9W@H~}VGK{CI}%ZJ`~J^gX5V;V^}5*^e0|84V;KC*zKikiIkZl4Sy8uR z90OJD6;A4{AkOK86(QsCk!K;!7oba;!0j_tt#LqIP?DjRj_NcpxLcoegO3I-&n4;@ zB8U96MK7X=$CVbBO;P1@>qcHiRYf54ooVmsO)t)V2boE599_h(__wfj;dvjucY0hCYi{AcmkI@4p%Ha{E7Uvi>G-4|! z0Dy<_ddQbjr(3*R>b70xf#6^S2Jzs998GShp)f|C-v3%4W&unxY+X?RbKb6}D)?9B z@AREVO0KV%UOR;0-}KgepM4`wOx{Aq=YJkyM}f=FrRZQl`}B4@u&&Kjon5o0S$h$UoBl%>*w+m5ma|%kxhvaa z{}-Gr0GABxT>z7i;`{`H8g3h8$a*(*QG2i4Jis+r52=@0L?mre(%zrl@n!N!#yr* zP_dflK@dcwK#R zCe&dpbNSS{Eng4>&409adzw zycGk#ugLs|#k7Fbw>3d_Eh!PjnSb041fCu-QJnc_MHgQ@TDr0yW)t2%#%7AqDu;&=?fIV@1NW_$jC zBGz927r#-;4QRcmTws@A^E=%8WP;EdX+q~ATGMS>rUrX3PD|z78IU;liY&rjhDjZxeFb*~(EqIvgxJGd%i{ z+a#1$R$CQKVbqGvJGJ6%X`uI12ep=flrF&^cp79CW3K6={2=gVztit#iyeG8^s=|p z@qjN)a*Riz4MSYOmCpy)oK2^yD!qK z7y&&Aqlh+WpA#a&`}@X9Hn!;>Zd4G^$?ACQQL&Ps0O)`KQI8)}S*v)k1^Y(iD`80H z{B`d+eJ6rj#Y%Z@$v?RWtY%@bOp3up;6dV#M%HUaE%A-7tnL}-4>Of?^_YEa+!~(D0}f=-`8Z$Sj<pA0_I+TEO@8`W@uNQKee_rZPhA=JHv%``_6DXj)>#pHPYDEM0d*KnqlvU2@Tw?mV0|KlbUVzSp zO`sZ3loYw%>-9M4VbPeD3XzG;)jRMnF<@W_eTxEG^SXFLxFF0+gOtL^&_H!>r^GJY z`-}s@YR3V7*gehLly-m*i;uLw@jJK?Tt@3LGeab5MfN=+$;iC-Sn4Rbfe60oTZ?{) zV5#EJ4fEOk8NH|Lo)u5B4*yB>D^Y` z6q1{&wkJ|Py&U8LRykt1F7|pSt4%lJ-O?nGmgYc78{A-65R!Ws3TJ)UC5iZD7N^0y zWTs?&uw)nKqs$q@w-1!s8*9e~{tTlf>p5W#hHlrjiQtRYA=cpU7Cps8peODILub|S;0RRLTCvQ+6r#b z$9!*W@ik7)JFEN3L16fq(Zv7(e8@k%lE<(AEOh7RpZs4NfsW5uTBpU%{S zRYCY%Ab4f<#xNpvGs3Vl8#4u7&x1qmsIHr3NOimRwifw=J1|VXdHByO#l;;KuLP!i z|ND=nXi=-5@;wv%>2~Hm0*yqg_BL6ZS4~4Jp7ETvshn%{&q?_%wtJkdbE7a~JZiJ) z|G-GAvmOX#4XiSXPtLxs(9?^Um7AdYZ6pMo^LaG5|81;(+NJT$jB6@XZI1po&s_ht zvgxM@5J0>o_NP&NvG;e-fhMUPZrd-eZ~0|RRzOM}(U-Tba)ao*dt@QPmq%{^ZP*sc zhroUaSaDx&S~1VmSASA~vAua|6kyY}eOq#+$3aybwSXOq9Hcvsl^_PKq6~wertx@p z%i8T%PpxdJg`DQqwPgPlK2BExQpx%Lx9YpU*7$f-J^sF8{tJCnUFvl2v z(hy=BFFCFRdS8CtGFE%3us3>)p~*mg3 z4vpS`#mtt?=-N3U7{^2{9ZrYylAzIFE2-RRMf)QtG+G{LiGOE01GeY^Dkt!rUz!y0(`Kgeum%o1&R`OkI}3QDEE! zMVM15(xw-#_bW$3WewP`k-DV4Y~8p2eQ{A(%Bvt_v~RF z8bkDs=a`4vB%ge<0dwe}swQU)*Vi@1PW;=^``laBOx;eB5hnne+kp~=>b-mjh4}tQ zbtk6|{lkHq1Z5B0KO|xCP!c-avBJKb$Fnxh94u?NiyMPZp|bM$VVvV({Z%r<`71Y+ zMlAtzo*ppKw3Y+RTh!}6?h_eAD9p*?1K{ zxqs!f!ROq<&%f!`xY7#Eh5@ZtqOMW^A;$@cPPgyMobLFD<#$D}BIdwgJo}pveo*k^ zNAWi#N3LcG(O3TRFpEM!<^s6Y)$ktFTQP?72t^oua~+~csN!t<{tp?NigDP9o~Q!B zIPZ*)a+v2k05g+`4R*f7yB+={QNflZFp~KF4Tn5o`pMP|y`PDP)z?4#7QFKUy_LU> zbcgRPc57(v&t9tf?>-(Jco-^O0v6&P7<^&}=CTs# zUxy?BCAbGcKjWu6!v2NY1Z~II3wMcj*Qcw9a1Boe3Ze&C8c+y9O^Lq-((G@)<)ZWm zasv-DT=6jH@%fH32zuHInEb|8=I+*sCD>h+`B6@qRX-(LY3z0xp&Xt9babo;w+)k> zitmLntW!_y)E`;?oFmkif%pB{oT(`mnm+Q!9B+6KZ9|r?#7n@-)K8Bw>NZpnkV10vBJR2I>iEyLw&G-CzlxUDwl@1E z6WPwB;y+AxGu55k=)GL5)IAcT^!{~OuBui8;|c5qQi4={Y!A3=_QFaTMxz{A0$TB> z@-PTE#EVWPWV6i`pyLYT9fyh)d!EF)Ogl<@PO!%w>#BW+!MaoRw1FL=pzSnFSmk@5 zv*-SRB8%q}>7a|A02i4D`%v?NG&X$JV{wVKD`-9$rO*cGN5o;WZ0ll=w635dsWjcQ zd$fx4ywqgb(TFhR9$R?opfHvMXd$3yTIL~#A8jGSsi#g$QB}1-i)m=A^ZvW@A4YE5 zEDKg*t`W#+&=zCtJNDaoMVY_$dx-}yQ4HdX@B!`5dP0C|6v_*8Y7%x1TZ}#mpzPC2 z+Vfg2J)7nSueR1+F2IA^e1a3!I-uMZ|8r#0QA5y}7Y-yJLQZWT*x9BM2cRR1mjQq4t^nik)>Qb?SIxMd&V!12&$v1JIS>V4+^!m zg%tZ_(_1$f{i0=F>MM6e99VI|4qZiRVB|vU z3t1XOEGcAT4Hs}WAYy5{Zuv~oIAheRHP+fTBq+@ZdSkE!6KUc@%W z7yxer6ln2pS#6bT{dA*ub0!7eP9DBg&GVJO-^ZtBjJl&f!p-vy;3W(L;#0fbDG;I@}jq#;IFZ5}caTT_@;=C+JSMCZjh%x%z#uM?oKRRRwB)cH-FX zxNH_1>OIUOBaDD?u5KA!Y?fnSU~mQ?Qb42Y+r`MGomlH5(lzQ$6s^Yv%eZa(ShjDI z0>XFvL;ix$bRbP=;nUg5UCLlv#J~aenl@s>ZJ__%7YzT01Z3Q(BK*?G?SDl`t1;}= zTzi{7vyH8If2#=Hp??^=@oE`zR`auA1lV&H2h!1!oGhm*PhW zwm9{jDk?;S^w;_rx9ltZ%K3_bB_*rM(**3DAxwY#_dWTbtL-t(`~(p@tV0-!>+D9i zVF*=5MeczXG4z;5tul^AVw5D}?7HU}CHHPg9#wR?L)rdy?q#70V|aiwI9auUaK-77 zs9!Wz$m=$Ov9DNt+}KnvHOK##zoX&QU+D-#rc3&n((^}Gw0`WABM#sCrHZ~<9UsA| zU-%Mb*!=5m#BEFA`3R!j-KZevrOd-rMF7D3aH&fIal(F-%mWG z+T=#E>gdbU$$76P*U0Y=Em<6i>QYG!+LjS&HeO|o%Tnc{7}U2B9dWkD2-Bj-r(lLR zJFMyJVAG>5iyp7m{!fa3C|ivoPv-zgPq~;o&x02idJUgZGPx{!4~FwOo2q!p8#bV7 zTOWAe*_J1r6nE6J`ORDgH#6knmIL2yo~5zpAmVK=HSoe*{8c9!QY@Us4feYbMkejN zi^T!4Nt@>@7@j@oqSU(smrzrN?QZC*lIg0r$( z1#{3mb;g8tLYaGKetW`fe59rkW|WmPEKEBJ+N-K?7NOM1*5KWctgL`VzV+9;Z%j`9 zMjEyzC?+-k_U(#iHOEe$uU@s={~h z-Zk#T);EX9Ny@&u+CrsUHylCpxNb~L^S%3{dh48Tf#p+yBhJcj%j(X~hdLU;nz<33^3~#@gm%?^bK*26GPuTnDt%D zA(Lg+?;pUL;t6c*<>@}m;mG|7MWX-ck`CNDq6C_ndDGal6L`+x${UlXg1Eut_E+rZ zIm1**mYQczkBR!ywG9GOPmO~XUB&gViO2oFB2U}UUj=n5|NqSP@52-ZCWrkO&{V$} zSeJHC@9}ax?$pq5b=CZo{GHP!QNL6YIMa0`PV>9_5b%PP+LOSsO-DazUnuz2e8hTJ z$a6%5P&iau^IuwK%TN%F@#*_0ep-sgi_RKBv=A!ZG&l$KkCbC@j2B-p(84me4TGJz zdoMRbgbRxfGY(+^*PI21GC3L%^(|1$EcZN)ofw;zsOYxLcz((J!sDd@BQ18L`a2^Q z@k@OXeJ{65URPt_7!nwk-4I5J(|@}-y4xqfN(SwWrfhd9-4ExpBHxkA^6pOR#y zp(A7(a|5Li^nN);<$*2ccyN1#qaD4lX=^+gc%h*1A)1u}iUnaQ~FZ z7K@O9b4O;qzjTz{AS7a=N1$YqZ=}qAu)y!w4IIi=G;kh~yYEW)zYaF>@gm972<_Z)q#-w>j6a@3fc0yc zeII6+4F~UI|A|QD^k>n77(K?Ly=^6a{el3=jF>eAp{R!|0wGR>9R4+UE6Dub&grxD zCM_VkVOVUZGVDIfi3kU-Va7}JKIh`!mHnTyl}KQJ>qT{)%ikqLy?Nz{?FpD>E!f<3 z4^e2lPr9zulxH|pL*t&fboRBz%U|6?Us-{bbmO+218l{F3aVaWM$-iZJ^W4Rrtx3; z$mB?VUXAKp=WPuKKmV!q8I@%1n5eav?IoQ4A|nu;cFg! zRbPQ|S|99GA-}T7p=|qPcZ*S@NL@ydF2p)i!)gWD!=9;z>uc*yjp0#F9P4IMtB9nzN60aXeQ5c?{_j9 z*wHImp;hesO*bj}a%`sbmyA^;zx(wJ553;)^Ik1>TEkT><7!#mW&QIHLso0vmNKY; z`!;@jpcgW^XTTH(!?=2C!VP>VW*MGhXmL`3*@;Z`1oB99pP29Bt=!RCQ_fr};J9$n z;)}2%iD(TsxlM3uGf2JF67PMAA2?QM--pM};qgEyJgc!8uK)I&ROAJ4xHr1*TLN`` zK(V+gx^J?N#a@WGNkDtr@Bvd|?Ibb;6l^41CNLY~u_t;D&XzFkgsd)7ui*ygVOsh& zj&TLB_P0=0>x%(CIET+wK>4fYw!=KbXdYlEYJog3j%s?EuyOp=`dBQd-Q)-2*X_{z z+DnOtU#5)R#9428acrrtJ+fc^h-_k0=bMWhHmm8CBzF4A`rA~WX6U{iv918;9|Amt z>5ch)^w@^bbIlR&7M!E2Sz5hEDw^VT!m}mmKG$}~C2sh>d$A+ur}K%(Q*)vb!i`TC zCu@G3-KxD(cb;KhcXIJywSY4!fXRO{8N#vQ%(FLzYsfIc*$)gSA?V;A9v_V@WS;u8 zliGm5!H7JtQekEZGo_+Rgz)yz+^0PBd;1Ie-e`AF2>7q$C>Lae)#4aOoDR)$WBl1V zgqP+6Cppgq$YA?l)h_cRJ=jBswq)+X|3VCVp02A7$xIAM5n&f;v_kC+y>{}fCu)z*;AF*WB z7VSGHHf_i0cfBuII)3sc84nX%4)0=~bvt9w7!q_h?9y42%cp(iPso^lH0h7UA~7!7 zn4<>@m&P}d8BVIG0OV?^!Yyt+E&f9LO|FHt?^pf00BV2u-N?%;pteYEehr$sMW zbS$E>@vIQ#G-m9k07Lzr!s+Ub_%-_I$@OzkpHeS2G} zX^?={;9ym22H;Db05VOwjL~qE5ru(C1kQw%4{c+=|MzaSp<8+hWS?oA5t_!R6cN5t zB$01E>>|Fx!=8i|L1q))L!7aM0Kcai^60_g1;)3#+dX=!*1mjNGX8S)r?RvX| zFIGF#KmF})*H%{O+Ray!J**E~NKNIQ{Vfq5lWk&*O)_}w_`X0!cP}?dP0s$JsEX7RV(&}Uy#C+RD$7-Np3sLg2kz0@7@-~`|pix+(|tN6n+ zH0~v=&u3HrvNrf>87;L~hl`eEGIWwZOum`VIQHh@!e-Ag*GCWO#8X{w9Na2?QP(U^YC5N!;!yV_u2g}y~auX;;h;e^(87}DXM9#Ao8nD#-MA4{*Xc6 z?u#$~OL?3z6w&@iDEemy@A6R@l9cNAH(n0fIRHC^nO|#GkB(wBL=*ML3idhu_1ryt z_g$Lqh~JBHF^D{W3nvxVGI;X1JC5>pleW1egel?-o84Dc z^&0=8N1fPRlR4aVWhQzjFeWqa49iMo-rI$sm1q`Spd>TmY^xY!Sw6)e*mmt<+04o2 z-RSN2%~U6r&P~PFQAsgZ3{r7-es^{m@x2pxvQGNQpX~xckK6;M>W9-^8yolYV#cl% zqeLeHq=fGmhp(jUmKQrpW|YojNt(EM4lW^Y*6OFTw{cFPzm&t}a5evsyl!U#f@%qz zV`n;d2YPGCY*gYS-$m>3&3jPI1o~?}`G6W?*0;YnitC3}a;hL|YRg6W0Ewqj(&CN~ zhMLgp-hvk~u?d7nIEwwn`X{WSQAJCB;VjO>#}IsK^M>cYh%^Qf_2*mLOW}d1BxHKj zz%#iT7a%1B_c*S#tDMj5;<>QdiEl1dCk=>@&Yr{th+;2V+)-4)R06xj*0_V5!bGK< z=C8>iZcF}{XGO8vAq);D2r2w_>+?8{DSZWbN4+wKxf8C5!M>iAUUnTm?x=v74CPfi zbuDaN^Z4(zVKuJIwVjvEOrSKm&yt{Lf7uu^cfVX|J^&lxsnYb)oNK6`09mw{IQ<-rkpvzUa6xEzw|W@@MayJ03fsij=~DfEX+p2+ z7@ZGokili`MacvUWcvR#+b!oqWhjSvnTYz7&dy^Ud}LdI-6Rv@zbkN z@&(30VMhOhG?kyX_4SKjTO{t@#wHEln?t*AR3Z_4+Zl<9x=bnbsg^l<3N0vZ--Bpx zI^|we3Z0f_@ZhHACUi4x4YAmm6^A%)5$A?oqVRhaMlD+Z!z|~tj!fy_cCZ!Ru?sYY z3(2-g{HUDG_4yuxTUxv!);i~b=*yk1R9YW>37-K(H#OvV) zDY4U3l@afFPAa|r;D+GZa+qCR+lyoJjksohqDd;N5oXc^7y9$)^Lrv*CXWuQEwbYoy!h@ zpFrF3%)++xJVP8+7Qpj}!P)K&sPP*EoHJJP!Z6^Xul72=CeK_V$QA{%oeV_xI z0rxo$v=6}Em_{+<8{4o0nZ0hee|FsQBLL;FIEQz>T>$&ELTpd z2RfgmCUcz18oyq(GX7)pUiSfZt?#o-9ys$F-s2As-m15#FD1E|-TU`^g~7Qhg_?G3 zJ#o%=uc1W1mFCz(?+cB~dOd2VRnI%$Zs-UjSgDe~&WBf3-K<1TgncJK-=787sKj>P z+<%f2AAj834DSRWZB6Qs#)&qL9as^|i-#_~!E#4|HL0aB*Kj>)M9f`E&_D+MOZo81 zYdlz=L+ZT1=)p0+yI4bFF^?w55IUT{a^AlAH^h;-_I;hszr+65_LP8yK%?!hGfQFL z?Jk@;CBi?GFKtJhyl>sTFEV2rbplGVb!?~)vjib#<-q8c%ZCh)a|ypF_`%uKx^`$* zalljrL0ZBht7x%_dTuUH}Ghwc+!5XZz+u*HSt(dBRf<2xe|5HrP`RV z``t@-o0dZ2z=&q(f1mw%l(}>q$qX6o zOXT|Fr3wOm+|xl-!`C&*v=OR!!CI1I}XdyuI`5Z$Y8LqqBXii)9ieG2+!XB2edT>hZBU5f6VQwKgy>}5>qn#Bi z)lPJ_E`6!QzkF%jhsy5K4K|u@cA}hBeP6M>>Xf`ED?Cfl9n5ekonbSn=BA>kO=$MV z9%8tq8@{lSadNAhhX5!X;5-dBB8bO)yh9ZSs!(S79+;~5wfce|i}pnx)P%gI1LBa3 zsIO@c($k>>CyJ^e3RD-nV^y5Q8^OHi|5N|_r$@gwW@D#*o8)-u_L-`Wd_dG*394rQ zAyJp_Hz^1&_Sya7Ip?G9Z!0E#8#5x^NlQ;pPdi0%du&pQ5NIpBHdiXL4`$ZpcT}8T znmlDp$YazDfcHB+W99rW-x`CI3R-9*53dy*W(1*ScxRj&e%bJM-w8C(Y9Tmy-;Fms z$^UNT_(dRATrAFjN z5gzi4QDDe2*U6JMNd(pS%kUDGk+&EJCadxO=zA4AAylr ziKwyce+l0%#BAdi{&GcTCOk;)*nzuG25R`QgQqH*EC^K?vnM?!u6?WF0}=p zrpm?NeHAk;Pm+z+KS?Tq0;}IA*-a=Z1Su5eqgDIN;j*O0o1O$x3mj`HCr%%H&r8vU zQX*D(&fEwaqR$=Mg1xz?N@|F33U+caoRF8Gmxp8ArRs%Cx!uA~ze?`itkGFD!c&&1 zcO}6+lS$aX*r<*@L0)(icc+|Mk~iOy;9ov-?lgGip3B{V*mgDxjB0sr^|nVSrgt%1 zgj}NNnQU>{8Q}PLJ33zz9CVFL#GyNnHzh&mEp3w{ z2gek2knWU4^OQUs+mAl`{jbU|i#Y#E+anustsgmz)5=l$gA_hs><4hb)t&z2FT}TEj_WB`Nz{p{?5>X9w%>}U#0Tw4N z1RsZ0LKgd8$4c^W9i|W07Q49Ff5aXl*pt1xFkJ{WoH&1*{|I)Dos+>WmwIyIag03> z_JauhIJXI19+W#>0`yl7ssie-1n3!lFjoird{&HyQm*#ukWF?<9BXh;y663fYgTvx zSJ$6SXh)Usq73zN;_o&2GCwxf{${g&>_m3^&SuvlhPO2_Zp}3rWn;CjS$n$<1&C=n zVBdLrikG;}z$flt{NEbIM~-Z#rphHQzBa}rCzl5_Y@d~}QEnVA9P3AIp}!ttf0=7D zmRiia&c38Aq}?m(WwP5XJ1CPo2IO+bN$y}wnOEq&v(s5@_GnLvS$L>3=fr;Id% zB<&n)iZmv4S_jp{I|?1vi|OoJTRh(vLgub9mLa-ET_hFUl8aT#S{)gr?!m2Vahz61 zJYO1o?I(u%tOfUT_zX8=j&`ygc8vnazY@z5tVyz;rDjQh1MG^~tQWW< zP|$V61Gk(=Nw|OARj77+QdOJzO#Kn#iZ?gEB3TmGp(q2se;WArf}{QX?$f+CIQ0FA zINKa3egBM z#m9#NsNRbQ5B}sMZ3`y4wKftM?6_wukB-A~rUO#E;G-NGQ^u)yk+X}2JAdgz@WR3F z^4&?Tv9h!04O&WWvXtQ;1xuhtQI;fl&=(mdIowCULf=b=h(0XsvP<8{Q9DNN&~A&m zd7fU;bKz1sv+C~p=uICBs4)QV|Vun_2;rN zGZO61car1}NT*VSR@V4FPIg>&)XQlxWJ+rIC~_7GGqybzeMU%e_w44U@lrDI{G3-F zx+gcogmkV6I;JnP^ohGU^eG|DuCzzU6v`w28>2_|V4giZ7@iC|DDHiFaaGWZC?HIe zrXg8dVO#;55Mg>Vfzc+}n+=Yy1`C)YozFz!V^0LEJ@Ze#c=bdwRdhF!HVlPvxPXzv zvTFk7suA9SZ6do3TWK)(iw&(*Ezk^hj0G1M{He3IQSCvg&fl~l$FH0zo)5&|QkAE4 zlu3yva)~=%c^h$2O1FIWra$Z}(!WonxjZV$aj5xA)f;6fiBLm?h8p`LB14yYZ?uSJ zUu|&X3B^C0KM`RU&f2z**iovJI7PxCN5SyiNsyD1QOPPXzII)NL1bK=2}e)v#H>h- zYi#XM9SnV8|Dtb7Sdmc<%VOB2ks=23i26iEw2>bYuu5_Ps=GY%ROrOP2YUNA>=g`X zo*6Y+|E{bv%s{-**tG-AyZ%+J_`4C7t2phP3F z?DJu1?6QdjOG<7ZOQK2T##xU=Wg}&AI~65i4`7SvS(*XuM3s=M({b8 z-sNpjj3ubDv@e)mhEQ3JJx=K?g8Liy6#R%iTG0-(nE7rS zgYP;b_EY8rN*7QNWIl^={d+ZCx#&mNA%;q7rl=rKZ|aJd>S}^2z~i`^TxAsUmtyv zI^XT&Y7s9kgZ-6`yv+ofWb);FTY&R7tAq^oIdclf`Ez~UByvy4{!PuRkyLJrZccpx zsuI&t6+(l2dlR8q%k`xAV|u4-GG%c_d7YA3ektxa0d8=Vpf~z2qw=4%eEjV9&E33W zk9EZ>UK3wpcu*OISV{C;vI^Ipbj}0jjNTahm0h7P+}6NU^1?KyM1hS0QkerHI?!06 zxAp$2sgTf2tR5%9QJJW%zy+F(oEcSA<~VpWIZGt|mIUl!Zr225cx-iYv$40a(bB2t zB~6%>_zDH$ViQ~ycZjQvZBatT!msB7feqO4}rgC#Xo8^8UTj8XZUn zl4u&?IGX!e0t$usOfDq4?g`c#rD4cP#z*PdPEc862#H0vLzqSRhzAEe_ z{w}0PA~I?ZcdQDh92_?&YpTy=xaQh5?WUE72lQ3`d*aLa_4CUNXGQVmk)^(>%J*4s zmVa*+25kr>)3Cu>VEPP|ONmXxt1l!paKbX`@-NWpRy@rh;IjfB{XJR z)a$Cuo8_l)XsF8#o+SS-uLOxO1~IFtk)abZ;$VO)R46n<*l&uCV9nmYD@mqexBVZj zCS^&|vf%0MLN4U^u&ZFLa}&?4_Z*H$yM#qdA(z{hC)lwOSta2Do$AoJD`tKZ)UV#( zRn5iNM1(lT^CuHSKBbM0b7D7UV(u0|_{z;FQ~cY37XInrm;U4|+?@&YN(FI99i@+K zczMbAMuZFIhJSwTSGGv3iwfOCG*p#mh-7X zTbw!ZJ|d$7Ckd6ZJgc0+PU*ZG@612`rvrzLXDnDY#{%PU=&d^iXHoPF5v>UWA{yy3_^Rabb3v~1 zMQigyHfQ)#6`L8WQMLX><6I=N>Us3KX@o73bL4?T7#ZT@4{h>(@I#`o3@3vr?|XnC z@CIjwPU&_T$%rsmEjj{l;EbxUVQ%S+ZZ)(~m=q{yvmp3kHgKV`eWj$PU` z@ZmKY`?xb-LZT)9s3U!l5O!c4V-tZmihW7RB%ZE|n{ITwC8qfWj0^eJ?bV2d!P4UFxO>Frza z^N*e*;TUQO^NlKctGJz0;7A&pVZ9a1nQd{0RzGr7%Q8P~Wfuh~B$1JM;se9ORctnA zn#2hhiqGcf)P~F9HWXzrmI8J#}7`HND7D1rm)zAY&ocNWvh-(M~`l=!KVu_{UU^f z3*v>-VTD@P;Ot=MrWS*z-UaC^qHONVqax);+-fc*v}(9LLJ3y|Y&IT+pc%Y1bj!<@ z2U?CVwNLEJl-+k~LOMCO?x*gr2W0|hC&KZm{dph15a?16t-9a-Rfv?OKob6Q?UP~*`BuMeV zIm8(v-N&nLQd1A{>pl3uO)EW}#|J-U%<|WedChiH1aW{kJMPntQk&m?kt`^FlIMNo zsKI7RQS`k2y=c}#QvnSESR@8w+tRUdJu`dVb=W1ZFiNXHyF^BrdF4PN%D^_WSvVkx zLssms1xH54R*#|=dXE}1d!O7R77N+x9_`X(=VTB3K>k!w=f`H3fT*I`2I>#95 z{$L~}+tC@iomS{|e`;}4vZtrd)=#oe3poSZ%o!PGUL$QlxeICyA$}I$@w)1?R@i?V zG|n!mDT|`pBsAM2ER%{deP4Cj7tf@YcmZX>zt!;Q27fRYocM%VieZu7CV?O#L$pDf zS=-aAf?eAr)zNc@(68&!^9xmeF+@f`g7ZHN0ShGdl0J;$I=qg--i;tOLjhw$lI`O05}^a#$_!W{C-_6*l8vNd@yg(BUzL)=70!$?~xH8e{~_@r=xSlzlMm3#Y(UKdSC9)YEWr{$K6pm4uM(j3kW z`>eWq?Y{FAU*(r50g|BdMoe%nws%LxEEnEKn)fF{MS?$1=hNxf4n zw10Hs*YB89C&VB@D{2oi?LdZWA!P^H)WRvAZSY8QFNon*AKEiF=UZ4YL=PQuYv6tN z9Nh}D@tnN0&oU)&+5sA8`mZFtBt|YL|96MvhDj)ibUT{71EW17Z;?s7-3Ya9R6JIbjM`8Dd$q!S;^sfhC*g)bx819ba zYEup40`D@Zo0v9Y;kafa?@J$AUwQd>+u}mR9p0D87KJZYpft5-i%2s8GKl~A&f#d` zTWIIiVTTY+98JeB9!KMx7F=-4O6okz+k2O#Jx|~)O!yi1nRLcm=o7qz$r$GX5wZu& znlOhq0uP9Nh((x`LNyV<4RK14o4_q(i^#n=&gnL5YWse_#6Lf$qdZ0j#6`GlkM5qr zdDTwhD70g8`#4h0NGX;Iv5c;cT+g)nm)WwZApS)38Tu=kth+dG{=#xv{AI*j09}Ty zCSW1J*l1>9`8G%gGp{-C-SW}L4$I=hNz~z`{XJkPUD8^+nD`PxWwQ98Hh4ft5U=VD z8vN&6N**kn@hB`=(rsIJyoi|LvZPV0>CBQ{B89pi#)yTzKAU9P{#7O4xK|;1v10gD z^;i9(`p7wcUHJP6Qf@|zbQ?_w}uVA`T;yU@V-8mq_oANEJ!Hay;Ca(0K%4cVXL z2vEpwX};(!PWDe-jyeui)MI^Yoye&Cu*EbM6Jah7y@h)e$bya2m96q};`Retzf^8> z%*URJHMgZZVhcIzM>h_TJ+wRSUAi#rBO@!{{U3$#reYp(c5kmTQY&QlVVN+>WuCK} zBkrea{8o>j-hWgFp%FphUoAJcxfMY4M^8Qd2Q2xyGiX2C`L4U_JE7;?;;`=KI%iN9 zu?ro-ACQAWQPL^wEaSF@2L%Ovt&LkP(wp(pe9W&6%CJ1eW@NNj|B4^2J-!J?8_ec& zy!H;q5D0M1Kh14#OY}OP^$XdBOwX_R0VpHPGcdUqh9&mlG(A_UB0n1nw9!Le?_(@6 zIC@*Ju4DB+r;&W7XI=oC+b~T%0MTo8@N)2`vBOq0#R$aG3%di}Rx2wjk>UL4QZViC z3-yM_u3RAk9d<-Ul)Xp?5}V`I{IS?$SHY!+t^!ya?hn$st!w8kNwN(dI_3h=#7`}X1-)(Y`GsZ zK`bllLYk>Wa0kutOdcXQa1;=xIwz!DA`W+fuoh@b00#+56*txvOa=n~n?fpi{4O{9TeZ%#{(*pSNjP>)Xorx-1Wfm-AVA{7-y#90|BD#W+q zNRhp_dw$RFzx(UC^%?K?>-`$Y-Px(C*iq`9o^_6V(tr02yWD?a_u#0ZhUVF$L~APh zJ!Aa?mco4NTT#Ci_AqVVLSk1;IhTxI-{L}s=*k(fxBEr}^rs_C6)?l8$_ae25#L5@OjAcbv^nVNT1#dM!A3XU4HXEl95D01Snuj?h##zJ#=N2e$0zo3H10z zx6y#(q?7o=0+{sXJ`tnp7U4HEOa@kEjpqUR`ggD;8+`%Yar)44e5NVLB6Bg{5Sj^) z1`kx8o4c-@6348b4pobG#y(x$n*9$G1K4M^JD`_mIPaHfo4tmkOz43FGG#9u)m%FdNw^J5f{))FD)P5>6*hU4Y=zUQM(=- zzZYa->)-dTl1YzLP(>*8aZSenxc~_W}5bK1OE{Q?RMMm<+Q;S2mwR(F+1sq()2# zG<}LK4go8x|F*1fE*4$VB{X{l-bU>}m(rC@G}7QC2tD3qu5Mv|$-M%z7g>c$3GrNe zzQjngXxOhles%n~BKYt0Q5PVLL;iYAW*@jxw9&4I+CB_ryUU9QbMx!MH!YU8{99vCJa18NOQY+x#&YgeYDPFHvHGm~f#-6uZ_oYO zie``iP(@m!?~F(OE1O~5gTY?TuZyni{OC>zIs*xt(zMPENWZ~)pW#f9(8bMsb?O0I z%m~+NzEtgKNb2skILOkzBzcxGV(Awil4L7-`%NnwjSK?*hVPF2IoKNK!VR%MAwHO4 zj?Xr_|L4}Nw}F@2<{g^EUUD^&3(OseJ_^FtoZ=Wc>nmsfc66JtnDS|k#OnIEgE*G< z(0%KRHMlyt#}Qky^>I5FsB6QwGfHZeNV%#Oh+hKFLrc` z(L~v^Kmi|G+ZmM!zg{(^T@UAMb{QemRkuGJWoW?fHchR*%AWveV`^1INRSsUv-lP* z2DnWb&ottb>oB{KtG#J^xuiGYSTOWMaUKbCiV2J6RzhzRQ9J zZ$39*z22L)<|dg16L-<>*wTzH&y6Us^$D!hhog11e+$l|C9+hG+<^K+#>7d;QUKvW z0*qQZ7>0P($#UQds#p7Gzdgws@4zEr7~zR6YG)VcWEYgae9+<9z}cZ!X;`2WszRg< z=Aaaa#zot5&|xb%9um{m;7=p!uEq(~xWB#Mg{Sj|l>?s&YKPWu!q4Flwh}!sq3$(| zIdnA|+bg^57+BaD16~f-t_cq*q5H@RDQ$=kuNg#10^;K@kG!hZ{Zuh~Li#Tk5f4J0 z{Y<YxoM9Z0L^}hw%5i(~d5%xW`k{f}QAuHg>2VQ~mc+5gWRC+RP zt!e4vj|1I?P^ab(V?&youVihvjj$Osdc1wqVmakG8K~Dca9Qj?zM?99ZV*$EqOMWQ zgGsK=Elt<13{5vro87Yv)z5$^7)`B|+m7oDs^J4OuVc=hx*yr~tqMeP3OCm@^K#%c znZWv0kaH~RofEi)9&iPtQ&%sW)JLV|+=M}cx=a=v)P$K98c+w__OEL5D&3bdS*#Lh zAO@vhLadVK7To!P)-TtR+b^CT&JvU)0g9|Tsb??FZMuq=6}{hMdi@KzjQ5pXC!b0F z!Fx{4f3&DpUrryUsX+Exv;tMAT8YVtf=@nv$aC$AHE&U(2J*g2?G^OZ0~M&%TK*QB z%+cNOJ?5p0-(D-X;T%Dvcn;Xs|JSaMUHZA=U&SoxGSI(oOEFmehR0F|RR02EXy@l4 zNAdg-`i+F>3_Bh8cpqNcifc&74rF3=!vjNz{s$~3v%k#YGDiuGa?LTo&3}f*87WD; z1K;35)IGDjhogFtoI3HL*7Y!P^8UGIVcbU1sN2h?Ij}G)gBTHLOCzn5%d>2q61J79 zR{I^xM33S3Lz~_mz6b2`aT9ibl=)rq!HQ!2e`jH>0SM}x8TI1lp8+~YAr_q`3PM>p zBw>cCc8@@d+05^y@k$U6Aoa!2(epsIQkYW6J<*Mv92S^4%!Rdg!)sm*2=^`46NMkV z5UZ(nmZ~XV9kCyS$Ej@^fIVmhbVB*S8t;^Lg6#89|QhS%c;+S5Yw*?P+Rh5Z? zK&lMW)5GyFyW;`JkcY0oJzJ&8@`K=ZpdPmxm8nx|q4+Zc{G1W+F{M~&W&T*OzrhKo zT5k*b3)2Qu;v{g6cU+W5b;7Ud1IIb9K7s0#5^>IrpzVv;8TS8UynM$tanjXthkKK` ze!EpWVvn-4x=3Z=3HZflWXzCsUY+VkD*F#zExOlS7#npYjSE|gV);bmKi)lfFs_P6 z?x5P?W~;eZ5eXi|F!ISp_4lWBi>uw*;o~3H(>t4QvAP2Gg7#N;J=B!ohJ&f`G@Hcf zSkWjQbBxp;WgWyFao7;>{XAk$SJ|qezOdRdt%u$u07z@|?a~*x^J}&UlqNZPzamM= zFzJ{890w|XPe&@ zq~$@#<*R$`w>;qZnqT_;=I_@FD;$B`$^w|(DW`z!%R)n@ CIemm+!s5}r1Nt~_3 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 Lz}~9T!Yko_3jQsn literal 0 HcmV?d00001 diff --git a/static/assets/index.4338282b.js b/static/assets/index.4338282b.js new file mode 100644 index 00000000..ac02491a --- /dev/null +++ b/static/assets/index.4338282b.js @@ -0,0 +1,362 @@ +// modules are defined as an array +// [ module function, map of requires ] +// +// map of requires is short require name -> numeric require +// +// anything defined in a previous bundle is accessed via the +// orig method which is the require for previous bundles + +// eslint-disable-next-line no-global-assign +parcelRequire = (function (modules, cache, entry, globalName) { + // Save the require from previous bundle to this closure if any + var previousRequire = typeof parcelRequire === 'function' && parcelRequire; + var nodeRequire = typeof require === 'function' && require; + + function newRequire(name, jumped) { + if (!cache[name]) { + if (!modules[name]) { + // if we cannot find the module within our internal map or + // cache jump to the current global require ie. the last bundle + // that was added to the page. + var currentRequire = typeof parcelRequire === 'function' && parcelRequire; + if (!jumped && currentRequire) { + return currentRequire(name, true); + } + + // If there are other bundles on this page the require from the + // previous one is saved to 'previousRequire'. Repeat this as + // many times as there are bundles until the module is found or + // we exhaust the require chain. + if (previousRequire) { + return previousRequire(name, true); + } + + // Try the node require function if it exists. + if (nodeRequire && typeof name === 'string') { + return nodeRequire(name); + } + + var err = new Error('Cannot find module \'' + name + '\''); + err.code = 'MODULE_NOT_FOUND'; + throw err; + } + + localRequire.resolve = resolve; + + var module = cache[name] = new newRequire.Module(name); + + modules[name][0].call(module.exports, localRequire, module, module.exports, this); + } + + return cache[name].exports; + + function localRequire(x){ + return newRequire(localRequire.resolve(x)); + } + + function resolve(x){ + return modules[name][1][x] || x; + } + } + + function Module(moduleName) { + this.id = moduleName; + this.bundle = newRequire; + this.exports = {}; + } + + newRequire.isParcelRequire = true; + newRequire.Module = Module; + newRequire.modules = modules; + newRequire.cache = cache; + newRequire.parent = previousRequire; + newRequire.register = function (id, exports) { + modules[id] = [function (require, module) { + module.exports = exports; + }, {}]; + }; + + for (var i = 0; i < entry.length; i++) { + newRequire(entry[i]); + } + + if (entry.length) { + // Expose entry point to Node, AMD or browser globals + // Based on https://github.com/ForbesLindesay/umd/blob/master/template.js + var mainExports = newRequire(entry[entry.length - 1]); + + // CommonJS + if (typeof exports === "object" && typeof module !== "undefined") { + module.exports = mainExports; + + // RequireJS + } else if (typeof define === "function" && define.amd) { + define(function () { + return mainExports; + }); + + // + {% endassets %} + + diff --git a/templates/unauthorized.html b/templates/unauthorized.html index 56b3a57b..efaa3b95 100644 --- a/templates/unauthorized.html +++ b/templates/unauthorized.html @@ -1,4 +1,4 @@ -{% extends "base.html" %} +{% extends "error_base.html" %} {% block content %} From fef66f335e66ca30935b7fe33d00cc171698e53e Mon Sep 17 00:00:00 2001 From: richard-dds Date: Mon, 6 Aug 2018 14:27:35 -0400 Subject: [PATCH 157/332] requests fixture no longer needed --- tests/domain/test_requests.py | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/tests/domain/test_requests.py b/tests/domain/test_requests.py index 6553cfe6..901caf73 100644 --- a/tests/domain/test_requests.py +++ b/tests/domain/test_requests.py @@ -7,10 +7,6 @@ from atst.domain.requests import Requests from tests.factories import RequestFactory -@pytest.fixture() -def requests(session): - return Requests() - @pytest.fixture(scope="function") def new_request(session): created_request = RequestFactory.create() @@ -20,33 +16,33 @@ def new_request(session): return created_request -def test_can_get_request(requests, new_request): - request = requests.get(new_request.id) +def test_can_get_request(new_request): + request = Requests.get(new_request.id) assert request.id == new_request.id -def test_nonexistent_request_raises(requests): +def test_nonexistent_request_raises(): with pytest.raises(NotFoundError): - requests.get(uuid4()) + Requests.get(uuid4()) -def test_auto_approve_less_than_1m(requests, new_request): +def test_auto_approve_less_than_1m(new_request): new_request.body = {"details_of_use": {"dollar_value": 999999}} - request = requests.submit(new_request) + request = Requests.submit(new_request) assert request.status == 'approved' -def test_dont_auto_approve_if_dollar_value_is_1m_or_above(requests, new_request): +def test_dont_auto_approve_if_dollar_value_is_1m_or_above(new_request): new_request.body = {"details_of_use": {"dollar_value": 1000000}} - request = requests.submit(new_request) + request = Requests.submit(new_request) assert request.status == 'submitted' -def test_dont_auto_approve_if_no_dollar_value_specified(requests, new_request): +def test_dont_auto_approve_if_no_dollar_value_specified(new_request): new_request.body = {"details_of_use": {}} - request = requests.submit(new_request) + request = Requests.submit(new_request) assert request.status == 'submitted' From 6be3ce89bf70ea3c45a0b8ad9d426e8a54bd9cec Mon Sep 17 00:00:00 2001 From: richard-dds Date: Mon, 6 Aug 2018 15:02:16 -0400 Subject: [PATCH 158/332] Remove unused import --- atst/routes/dev.py | 1 - 1 file changed, 1 deletion(-) diff --git a/atst/routes/dev.py b/atst/routes/dev.py index 7faa18c9..cbd02cea 100644 --- a/atst/routes/dev.py +++ b/atst/routes/dev.py @@ -1,5 +1,4 @@ from flask import Blueprint, request, session, redirect, url_for -from flask import current_app as app from atst.domain.users import Users From 6c4e27655d61c7be3998ab88fd62d8f457f72603 Mon Sep 17 00:00:00 2001 From: dandds Date: Mon, 6 Aug 2018 14:27:42 -0400 Subject: [PATCH 159/332] do not apply auth to static endpoints --- atst/domain/auth.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atst/domain/auth.py b/atst/domain/auth.py index 4dcb7e22..ee3ff973 100644 --- a/atst/domain/auth.py +++ b/atst/domain/auth.py @@ -3,7 +3,7 @@ from flask import g, redirect, url_for, session, request from atst.domain.users import Users -UNPROTECTED_ROUTES = ["atst.root", "atst.login_dev", "atst.login_redirect", "atst.unauthorized"] +UNPROTECTED_ROUTES = ["atst.root", "atst.login_dev", "atst.login_redirect", "atst.unauthorized", "static"] def apply_authentication(app): @app.before_request From 2fd34194b30c1ebe08085b8777bf242c057aead0 Mon Sep 17 00:00:00 2001 From: dandds Date: Mon, 6 Aug 2018 14:39:10 -0400 Subject: [PATCH 160/332] fix some additional login handling bugs --- atst/domain/auth.py | 2 +- atst/routes/requests/index.py | 4 ++-- templates/navigation/global_navigation.html | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/atst/domain/auth.py b/atst/domain/auth.py index ee3ff973..c1a25c95 100644 --- a/atst/domain/auth.py +++ b/atst/domain/auth.py @@ -3,7 +3,7 @@ from flask import g, redirect, url_for, session, request from atst.domain.users import Users -UNPROTECTED_ROUTES = ["atst.root", "atst.login_dev", "atst.login_redirect", "atst.unauthorized", "static"] +UNPROTECTED_ROUTES = ["atst.root", "dev.login_dev", "atst.login_redirect", "atst.unauthorized", "static"] def apply_authentication(app): @app.before_request diff --git a/atst/routes/requests/index.py b/atst/routes/requests/index.py index 0de74bd2..79090d67 100644 --- a/atst/routes/requests/index.py +++ b/atst/routes/requests/index.py @@ -24,11 +24,11 @@ def requests_index(): requests = [] if ( "review_and_approve_jedi_workspace_request" - in g.current_user["atat_permissions"] + in g.current_user.atat_permissions ): requests = Requests.get_many() else: - requests = Requests.get_many(creator_id=g.current_user["id"]) + requests = Requests.get_many(creator_id=g.current_user.id) mapped_requests = [map_request(g.current_user, r) for r in requests] diff --git a/templates/navigation/global_navigation.html b/templates/navigation/global_navigation.html index 79728185..6255e604 100644 --- a/templates/navigation/global_navigation.html +++ b/templates/navigation/global_navigation.html @@ -18,7 +18,7 @@ icon="document", active=g.matchesPath('/requests'), subnav=[ - {"label":"New Request", "href":"/requests/new", "icon": "plus", "active": g.matchesPath('/requests/new')}, + {"label":"New Request", "href":"/requests/new/1", "icon": "plus", "active": g.matchesPath('/requests/new')}, ] ) }} {{ SidenavItem("Workspaces", href="/workspaces", icon="cloud", active=g.matchesPath('/workspaces')) }} From 61270fbb4024d3f59248fdda97a26cd7b4661ef5 Mon Sep 17 00:00:00 2001 From: dandds Date: Mon, 6 Aug 2018 14:52:23 -0400 Subject: [PATCH 161/332] use user factory for testing --- atst/routes/requests/jedi_request_flow.py | 2 +- tests/factories.py | 19 +++++++++++++++++++ tests/mocks.py | 12 +++--------- tests/routes/test_request_new.py | 12 ++---------- 4 files changed, 25 insertions(+), 20 deletions(-) diff --git a/atst/routes/requests/jedi_request_flow.py b/atst/routes/requests/jedi_request_flow.py index e1c646e6..e750a9e0 100644 --- a/atst/routes/requests/jedi_request_flow.py +++ b/atst/routes/requests/jedi_request_flow.py @@ -124,5 +124,5 @@ class JEDIRequestFlow(object): if self.request_id: Requests.update(self.request_id, request_data) else: - request = Requests.create(self.current_user["id"], request_data) + request = Requests.create(self.current_user.id, request_data) self.request_id = request.id diff --git a/tests/factories.py b/tests/factories.py index d1a129e5..11b11a1b 100644 --- a/tests/factories.py +++ b/tests/factories.py @@ -4,6 +4,8 @@ from uuid import uuid4 from atst.models import Request from atst.models.pe_number import PENumber from atst.models.task_order import TaskOrder +from atst.models.user import User +from atst.models.role import Role class RequestFactory(factory.Factory): @@ -19,3 +21,20 @@ class PENumberFactory(factory.Factory): class TaskOrderFactory(factory.Factory): class Meta: model = TaskOrder + +class RoleFactory(factory.Factory): + class Meta: + model = Role + + permissions = [] + +class UserFactory(factory.Factory): + class Meta: + model = User + + id = factory.Sequence(lambda x: uuid4()) + email = "fake.user@mail.com" + first_name = "Fake" + last_name = "User" + atat_role = factory.SubFactory(RoleFactory) + diff --git a/tests/mocks.py b/tests/mocks.py index aa6a9ab1..a43ac930 100644 --- a/tests/mocks.py +++ b/tests/mocks.py @@ -2,18 +2,12 @@ import tornado.gen from tornado.httpclient import HTTPRequest, HTTPResponse from atst.api_client import ApiClient -from tests.factories import RequestFactory +from tests.factories import RequestFactory, UserFactory -MOCK_USER = { - "id": "9cb348f0-8102-4962-88c4-dac8180c904c", - "email": "fake.user@mail.com", - "first_name": "Fake", - "last_name": "User", - "atat_permissions": [] -} +MOCK_USER = UserFactory.create() MOCK_REQUEST = RequestFactory.create( - creator=MOCK_USER["id"], + creator=MOCK_USER.id, body={ "financial_verification": { "pe_id": "0203752A", diff --git a/tests/routes/test_request_new.py b/tests/routes/test_request_new.py index 320802b9..0927f1be 100644 --- a/tests/routes/test_request_new.py +++ b/tests/routes/test_request_new.py @@ -1,19 +1,11 @@ import re import pytest import urllib -from tests.mocks import MOCK_USER +from tests.mocks import MOCK_USER, MOCK_REQUEST from tests.factories import RequestFactory -ERROR_CLASS = "alert--error" -MOCK_REQUEST = RequestFactory.create( - creator=MOCK_USER["id"], - body={ - "financial_verification": { - "pe_id": "0203752A", - }, - } -) +ERROR_CLASS = "alert--error" def test_submit_invalid_request_form(monkeypatch, client, user_session): user_session() From 94223e1869c73651b95c87b409f40741c5f7245a Mon Sep 17 00:00:00 2001 From: dandds Date: Mon, 6 Aug 2018 15:02:09 -0400 Subject: [PATCH 162/332] add session expiration config --- atst/app.py | 1 + config/base.ini | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/atst/app.py b/atst/app.py index 305d3b6d..e1af87c8 100644 --- a/atst/app.py +++ b/atst/app.py @@ -86,6 +86,7 @@ def map_config(config): "SQLALCHEMY_DATABASE_URI": config["default"]["DATABASE_URI"], "SQLALCHEMY_TRACK_MODIFICATIONS": False, **config["default"], + "PERMANENT_SESSION_LIFETIME": int(config["default"]["PERMANENT_SESSION_LIFETIME"]), } diff --git a/config/base.ini b/config/base.ini index ad7afb41..2ca8f9f3 100644 --- a/config/base.ini +++ b/config/base.ini @@ -9,7 +9,6 @@ SECRET_KEY = change_me_into_something_secret CAC_URL = http://localhost:8000/login-redirect PE_NUMBER_CSV_URL = http://c95e1ebb198426ee57b8-174bb05a294821bedbf46b6384fe9b1f.r31.cf5.rackcdn.com/penumbers.csv REDIS_URI = redis://localhost:6379 -SESSION_TTL_SECONDS = 600 PGAPPNAME = atst PGHOST = localhost PGPORT = 5432 @@ -19,5 +18,6 @@ PGDATABASE = atat SESSION_TYPE = redis SESSION_COOKIE_NAME=atat SESSION_USE_SIGNER = True +PERMANENT_SESSION_LIFETIME = 600 CRL_DIRECTORY = crl CA_CHAIN = ssl/server-certs/ca-chain.pem From 2234812019f3f8797d102a6141c38d6973dc3cbb Mon Sep 17 00:00:00 2001 From: dandds Date: Mon, 6 Aug 2018 13:16:08 -0400 Subject: [PATCH 163/332] remove tornado handlers --- atst/handler.py | 42 ---- atst/handlers/__init__.py | 0 atst/handlers/dev.py | 62 ----- atst/handlers/login_redirect.py | 38 --- atst/handlers/main.py | 11 - atst/handlers/request.py | 44 ---- .../request_financial_verification.py | 64 ----- atst/handlers/request_new.py | 228 ------------------ atst/handlers/request_submit.py | 20 -- atst/handlers/root.py | 9 - atst/handlers/workspace.py | 17 -- atst/handlers/workspace_members.py | 17 -- atst/handlers/workspaces.py | 22 -- 13 files changed, 574 deletions(-) delete mode 100644 atst/handler.py delete mode 100644 atst/handlers/__init__.py delete mode 100644 atst/handlers/dev.py delete mode 100644 atst/handlers/login_redirect.py delete mode 100644 atst/handlers/main.py delete mode 100644 atst/handlers/request.py delete mode 100644 atst/handlers/request_financial_verification.py delete mode 100644 atst/handlers/request_new.py delete mode 100644 atst/handlers/request_submit.py delete mode 100644 atst/handlers/root.py delete mode 100644 atst/handlers/workspace.py delete mode 100644 atst/handlers/workspace_members.py delete mode 100644 atst/handlers/workspaces.py diff --git a/atst/handler.py b/atst/handler.py deleted file mode 100644 index 2e9d9462..00000000 --- a/atst/handler.py +++ /dev/null @@ -1,42 +0,0 @@ -import tornado.web -from atst.sessions import SessionNotFoundError -from atst.domain.users import Users - -helpers = {"assets": None} - - -class BaseHandler(tornado.web.RequestHandler): - def get_template_namespace(self): - ns = super(BaseHandler, self).get_template_namespace() - helpers["config"] = self.application.config - ns.update(helpers) - return ns - - @tornado.gen.coroutine - def login(self, user): - db_user = yield self._get_user_permissions(user["id"]) - user["atat_permissions"] = db_user.atat_permissions - user["atat_role"] = db_user.atat_role.name - session_id = self.sessions.start_session(user) - self.set_secure_cookie("atat", session_id) - return self.redirect("/home") - - @tornado.gen.coroutine - def _get_user_permissions(self, user_id): - user_repo = Users(self.db_session) - user = user_repo.get_or_create(user_id, atat_role_name="developer") - return user - - def get_current_user(self): - cookie = self.get_secure_cookie("atat") - if cookie: - try: - session = self.application.sessions.get_session(cookie) - except SessionNotFoundError: - self.clear_cookie("atat") - return None - - else: - return None - - return session["user"] diff --git a/atst/handlers/__init__.py b/atst/handlers/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/atst/handlers/dev.py b/atst/handlers/dev.py deleted file mode 100644 index 8beeb983..00000000 --- a/atst/handlers/dev.py +++ /dev/null @@ -1,62 +0,0 @@ -import tornado.gen - -from atst.handler import BaseHandler -from atst.domain.users import Users - -_DEV_USERS = { - "sam": { - "id": "164497f6-c1ea-4f42-a5ef-101da278c012", - "first_name": "Sam", - "last_name": "Seeceepio", - "atat_role": "ccpo", - }, - "amanda": { - "id": "cce17030-4109-4719-b958-ed109dbb87c8", - "first_name": "Amanda", - "last_name": "Adamson", - "atat_role": "default", - }, - "brandon": { - "id": "66ebf7b8-cbf0-4ed8-a102-5f105330df75", - "first_name": "Brandon", - "last_name": "Buchannan", - "atat_role": "default", - }, - "christina": { - "id": "7707b9f2-5945-49ae-967a-be65baa88baf", - "first_name": "Christina", - "last_name": "Collins", - "atat_role": "default", - }, - "dominick": { - "id": "6978ac0c-442a-46aa-a0c3-ff17b5ec2a8c", - "first_name": "Dominick", - "last_name": "Domingo", - "atat_role": "default", - }, - "erica": { - "id": "596fd001-bb1d-4adf-87d8-fa2312e882de", - "first_name": "Erica", - "last_name": "Eichner", - "atat_role": "default", - }, -} - - -class Dev(BaseHandler): - def initialize(self, action, sessions, db_session): - self.db_session = db_session - self.action = action - self.sessions = sessions - self.users_repo = Users(db_session) - - @tornado.gen.coroutine - def get(self): - role = self.get_argument("username", "amanda") - user = _DEV_USERS[role] - yield self._set_user_permissions(user["id"], user["atat_role"]) - yield self.login(user) - - @tornado.gen.coroutine - def _set_user_permissions(self, user_id, role): - return self.users_repo.get_or_create(user_id, atat_role_name=role) diff --git a/atst/handlers/login_redirect.py b/atst/handlers/login_redirect.py deleted file mode 100644 index 7746e934..00000000 --- a/atst/handlers/login_redirect.py +++ /dev/null @@ -1,38 +0,0 @@ -import tornado -from atst.handler import BaseHandler - - -class LoginRedirect(BaseHandler): - def initialize(self, authnid_client, sessions, db_session): - self.db_session = db_session - self.authnid_client = authnid_client - self.sessions = sessions - - @tornado.gen.coroutine - def get(self): - token = self.get_query_argument("bearer-token") - if token: - user = yield self._fetch_user_info(token) - if user: - yield self.login(user) - else: - self.write_error(401) - - url = self.get_login_url() - self.redirect(url) - - @tornado.gen.coroutine - def _fetch_user_info(self, token): - try: - response = yield self.authnid_client.post( - "/validate", json={"token": token} - ) - if response.code == 200: - return response.json["user"] - - except tornado.httpclient.HTTPError as error: - if error.response.code == 401: - return None - - else: - raise error diff --git a/atst/handlers/main.py b/atst/handlers/main.py deleted file mode 100644 index 737d3bd7..00000000 --- a/atst/handlers/main.py +++ /dev/null @@ -1,11 +0,0 @@ -import tornado -from atst.handler import BaseHandler - - -class Main(BaseHandler): - def initialize(self, page): - self.page = page - - @tornado.web.authenticated - def get(self): - self.render("%s.html.to" % self.page, page=self.page) diff --git a/atst/handlers/request.py b/atst/handlers/request.py deleted file mode 100644 index 6918526e..00000000 --- a/atst/handlers/request.py +++ /dev/null @@ -1,44 +0,0 @@ -import tornado -import pendulum - -from atst.handler import BaseHandler -from atst.domain.requests import Requests - - -def map_request(user, request): - time_created = pendulum.instance(request.time_created) - is_new = time_created.add(days=1) > pendulum.now() - - return { - "order_id": request.id, - "is_new": is_new, - "status": request.status, - "app_count": 1, - "date": time_created.format("M/DD/YYYY"), - "full_name": "{} {}".format(user["first_name"], user["last_name"]), - } - - -class Request(BaseHandler): - def initialize(self, page, db_session): - self.page = page - self.db_session = db_session - self.requests = Requests(db_session) - - @tornado.web.authenticated - @tornado.gen.coroutine - def get(self): - user = self.get_current_user() - requests = yield self.fetch_requests(user) - mapped_requests = [map_request(user, request) for request in requests] - self.render("requests.html.to", page=self.page, requests=mapped_requests) - - @tornado.gen.coroutine - def fetch_requests(self, user): - requests = [] - if "review_and_approve_jedi_workspace_request" in user["atat_permissions"]: - requests = self.requests.get_many() - else: - requests = self.requests.get_many(creator_id=user["id"]) - - return requests diff --git a/atst/handlers/request_financial_verification.py b/atst/handlers/request_financial_verification.py deleted file mode 100644 index e6061c39..00000000 --- a/atst/handlers/request_financial_verification.py +++ /dev/null @@ -1,64 +0,0 @@ -import tornado - -from atst.handler import BaseHandler -from atst.forms.financial import FinancialForm -from atst.domain.requests import Requests -from atst.domain.pe_numbers import PENumbers - - -class RequestFinancialVerification(BaseHandler): - def initialize(self, page, db_session): - self.page = page - self.requests_repo = Requests(db_session) - self.pe_numbers_repo = PENumbers(db_session) - - def get_existing_request(self, request_id): - return self.requests_repo.get(request_id) - - @tornado.web.authenticated - @tornado.gen.coroutine - def get(self, request_id=None): - existing_request = self.get_existing_request(request_id) - form = FinancialForm(data=existing_request.body.get("financial_verification")) - self.render( - "requests/financial_verification.html.to", - page=self.page, - f=form, - request_id=request_id, - ) - - @tornado.gen.coroutine - def update_request(self, request_id, form_data): - request_data = { - "creator_id": self.current_user["id"], - "request": {"financial_verification": form_data}, - } - return self.requests_repo.update(request_id, request_data) - - @tornado.web.authenticated - @tornado.gen.coroutine - def post(self, request_id=None): - self.check_xsrf_cookie() - post_data = self.request.arguments - existing_request = self.get_existing_request(request_id) - form = FinancialForm(post_data) - - rerender_args = dict(request_id=request_id, f=form) - - if form.validate(): - yield self.update_request(request_id, form.data) - # pylint: disable=E1121 - valid = yield form.perform_extra_validation( - existing_request.body.get("financial_verification"), - self.pe_numbers_repo, - ) - if valid: - self.redirect( - self.application.default_router.reverse_url( - "financial_verification_submitted" - ) - ) - else: - self.render("requests/financial_verification.html.to", **rerender_args) - else: - self.render("requests/financial_verification.html.to", **rerender_args) diff --git a/atst/handlers/request_new.py b/atst/handlers/request_new.py deleted file mode 100644 index f9f204f0..00000000 --- a/atst/handlers/request_new.py +++ /dev/null @@ -1,228 +0,0 @@ -import tornado -from collections import defaultdict - -from atst.handler import BaseHandler -from atst.forms.request import RequestForm -from atst.forms.org import OrgForm -from atst.forms.poc import POCForm -from atst.forms.review import ReviewForm -from atst.domain.requests import Requests -from atst.domain.pe_numbers import PENumbers - - -class RequestNew(BaseHandler): - def initialize(self, page, db_session): - self.page = page - self.requests_repo = Requests(db_session) - self.pe_numbers_repo = PENumbers(db_session) - - def get_existing_request(self, request_id): - if request_id is None: - return None - request = self.requests_repo.get(request_id) - return request - - @tornado.web.authenticated - @tornado.gen.coroutine - def post(self, screen=1, request_id=None): - self.check_xsrf_cookie() - screen = int(screen) - post_data = self.request.arguments - current_user = self.get_current_user() - existing_request = self.get_existing_request(request_id) - jedi_flow = JEDIRequestFlow( - self.requests_repo, - self.pe_numbers_repo, - screen, - post_data=post_data, - request_id=request_id, - current_user=current_user, - existing_request=existing_request, - ) - - rerender_args = dict( - f=jedi_flow.form, - data=post_data, - page=self.page, - screens=jedi_flow.screens, - current=screen, - next_screen=jedi_flow.next_screen, - request_id=jedi_flow.request_id, - ) - - if jedi_flow.validate(): - jedi_flow.create_or_update_request() - valid = yield jedi_flow.validate_warnings() - if valid: - if jedi_flow.next_screen > len(jedi_flow.screens): - where = "/requests" - else: - where = self.application.default_router.reverse_url( - "request_form_update", - jedi_flow.next_screen, - jedi_flow.request_id, - ) - self.redirect(where) - else: - self.render("requests/screen-%d.html.to" % int(screen), **rerender_args) - else: - self.render("requests/screen-%d.html.to" % int(screen), **rerender_args) - - @tornado.web.authenticated - @tornado.gen.coroutine - def get(self, screen=1, request_id=None): - screen = int(screen) - request = None - - if request_id: - request = self.requests_repo.get(request_id) - - jedi_flow = JEDIRequestFlow( - self.requests_repo, - self.pe_numbers_repo, - screen, - request, - request_id=request_id, - ) - - self.render( - "requests/screen-%d.html.to" % int(screen), - f=jedi_flow.form, - data=jedi_flow.current_step_data, - page=self.page, - screens=jedi_flow.screens, - current=screen, - next_screen=screen + 1, - request_id=request_id, - can_submit=jedi_flow.can_submit, - ) - - -class JEDIRequestFlow(object): - def __init__( - self, - pe_numbers_repo, - current_step, - request=None, - post_data=None, - request_id=None, - current_user=None, - existing_request=None, - ): - self.pe_numbers_repo = pe_numbers_repo - - self.requests_repo = requests_repo - self.pe_numbers_repo = pe_numbers_repo - - self.current_step = current_step - self.request = request - - self.post_data = post_data - self.is_post = self.post_data is not None - - self.request_id = request_id - self.form = self._form() - - self.current_user = current_user - self.existing_request = existing_request - - def _form(self): - if self.is_post: - return self.form_class()(self.post_data) - elif self.request: - return self.form_class()(data=self.current_step_data) - else: - return self.form_class()() - - def validate(self): - return self.form.validate() - - @tornado.gen.coroutine - def validate_warnings(self): - existing_request_data = ( - self.existing_request and self.existing_request.body.get(self.form_section) - ) or None - - valid = yield self.form.perform_extra_validation( - existing_request_data, self.pe_numbers_repo - ) - return valid - - @property - def current_screen(self): - return self.screens[self.current_step - 1] - - @property - def form_section(self): - return self.current_screen["section"] - - def form_class(self): - return self.current_screen["form"] - - @property - def current_step_data(self): - data = {} - - if self.is_post: - data = self.post_data - - if self.request: - if self.form_section == "review_submit": - data = self.request.body - else: - data = self.request.body.get(self.form_section, {}) - - return defaultdict(lambda: defaultdict(lambda: "Input required"), data) - - @property - def can_submit(self): - return self.request and self.request.status != "incomplete" - - @property - def next_screen(self): - return self.current_step + 1 - - @property - def screens(self): - return [ - { - "title": "Details of Use", - "section": "details_of_use", - "form": RequestForm, - "subitems": [ - { - "title": "Overall request details", - "id": "overall-request-details", - }, - {"title": "Cloud Resources", "id": "cloud-resources"}, - {"title": "Support Staff", "id": "support-staff"}, - ], - "show": True, - }, - { - "title": "Information About You", - "section": "information_about_you", - "form": OrgForm, - "show": True, - }, - { - "title": "Primary Point of Contact", - "section": "primary_poc", - "form": POCForm, - "show": True, - }, - { - "title": "Review & Submit", - "section": "review_submit", - "form": ReviewForm, - "show": True, - }, - ] - - def create_or_update_request(self): - request_data = {self.form_section: self.form.data} - if self.request_id: - self.requests_repo.update(self.request_id, request_data) - else: - request = self.requests_repo.create(self.current_user["id"], request_data) - self.request_id = request.id diff --git a/atst/handlers/request_submit.py b/atst/handlers/request_submit.py deleted file mode 100644 index 116e996a..00000000 --- a/atst/handlers/request_submit.py +++ /dev/null @@ -1,20 +0,0 @@ -import tornado - -from atst.handler import BaseHandler -from atst.domain.requests import Requests - - -class RequestsSubmit(BaseHandler): - def initialize(self, db_session): - self.db_session = db_session - self.requests_repo = Requests(db_session) - - @tornado.web.authenticated - @tornado.gen.coroutine - def post(self, request_id): - request = self.requests_repo.get(request_id) - request = yield self.requests_repo.submit(request) - if request.status == "approved": - self.redirect("/requests?modal=True") - else: - self.redirect("/requests") diff --git a/atst/handlers/root.py b/atst/handlers/root.py deleted file mode 100644 index ec68bfcc..00000000 --- a/atst/handlers/root.py +++ /dev/null @@ -1,9 +0,0 @@ -from atst.handler import BaseHandler - - -class Root(BaseHandler): - def initialize(self, page): - self.page = page - - def get(self): - self.render("%s.html.to" % self.page, page=self.page) diff --git a/atst/handlers/workspace.py b/atst/handlers/workspace.py deleted file mode 100644 index 2f1b5dd6..00000000 --- a/atst/handlers/workspace.py +++ /dev/null @@ -1,17 +0,0 @@ -import tornado - -from atst.handler import BaseHandler -from atst.domain.workspaces import Projects - - -class Workspace(BaseHandler): - def initialize(self): - self.projects_repo = Projects() - - @tornado.web.authenticated - @tornado.gen.coroutine - def get(self, workspace_id): - projects = self.projects_repo.get_many(workspace_id) - self.render( - "workspace_projects.html.to", workspace_id=workspace_id, projects=projects - ) diff --git a/atst/handlers/workspace_members.py b/atst/handlers/workspace_members.py deleted file mode 100644 index fcf8110c..00000000 --- a/atst/handlers/workspace_members.py +++ /dev/null @@ -1,17 +0,0 @@ -import tornado - -from atst.handler import BaseHandler -from atst.domain.workspaces import Members - - -class WorkspaceMembers(BaseHandler): - def initialize(self): - self.members_repo = Members() - - @tornado.web.authenticated - @tornado.gen.coroutine - def get(self, workspace_id): - members = self.members_repo.get_many(workspace_id) - self.render( - "workspace_members.html.to", workspace_id=workspace_id, members=members - ) diff --git a/atst/handlers/workspaces.py b/atst/handlers/workspaces.py deleted file mode 100644 index b6fa1dbe..00000000 --- a/atst/handlers/workspaces.py +++ /dev/null @@ -1,22 +0,0 @@ -from atst.handler import BaseHandler -import tornado - -mock_workspaces = [ - { - "name": "Unclassified IaaS and PaaS for Defense Digital Service (DDS)", - "id": "5966187a-eff9-44c3-aa15-4de7a65ac7ff", - "task_order": {"number": 123456}, - "user_count": 23, - } -] - - -class Workspaces(BaseHandler): - def initialize(self, page, db_session): - self.page = page - self.db_session = db_session - - @tornado.gen.coroutine - @tornado.web.authenticated - def get(self): - self.render("workspaces.html.to", page=self.page, workspaces=mock_workspaces) From b9f4a4be715000830beb18f587e6f712986cb53d Mon Sep 17 00:00:00 2001 From: dandds Date: Mon, 6 Aug 2018 13:25:36 -0400 Subject: [PATCH 164/332] remove all references to tornado --- Pipfile | 2 - Pipfile.lock | 38 ++++--------- README.md | 2 +- atst/api_client.py | 60 --------------------- atst/app.py | 2 +- atst/forms/forms.py | 2 - atst/ui_modules.py | 3 -- deploy/docker/tester/Dockerfile | 1 - tests/mocks.py | 44 --------------- tests/routes/test_financial_verification.py | 1 - 10 files changed, 11 insertions(+), 144 deletions(-) delete mode 100644 atst/api_client.py diff --git a/Pipfile b/Pipfile index d7cef862..1312960b 100644 --- a/Pipfile +++ b/Pipfile @@ -4,10 +4,8 @@ verify_ssl = true name = "pypi" [packages] -tornado = "*" webassets = "*" Unipath = "*" -wtforms-tornado = "*" pendulum = "*" redis = "*" sqlalchemy = "*" diff --git a/Pipfile.lock b/Pipfile.lock index 1ade9ff2..b9b8cab6 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "647d98b5384d1942bbe6bfe7930b1cd249886da2f47645802cd6f93369f44538" + "sha256": "2b149e0d8c23814a2c701b53f5c75b36714a2ccd4e2a2769924ef6e2a3f09e97" }, "pipfile-spec": 6, "requires": { @@ -271,7 +271,6 @@ "sha256:1d936da41ee06216d89fdc7ead1ee9a5da2811a8787515a976b646e110c3f622", "sha256:e4ef42e82b0b493c5849eed98b5ab49d6767caf982127e9a33167f1153b36cc5" ], - "markers": "python_version != '3.0.*' and python_version != '3.1.*' and python_version != '3.2.*' and python_version >= '2.7' and python_version != '3.3.*'", "version": "==2018.5" }, "redis": { @@ -304,19 +303,6 @@ "index": "pypi", "version": "==1.2.10" }, - "tornado": { - "hashes": [ - "sha256:1c0816fc32b7d31b98781bd8ebc7a9726d7dce67407dc353a2e66e697e138448", - "sha256:4f66a2172cb947387193ca4c2c3e19131f1c70fa8be470ddbbd9317fd0801582", - "sha256:5327ba1a6c694e0149e7d9126426b3704b1d9d520852a3e4aa9fc8fe989e4046", - "sha256:6a7e8657618268bb007646b9eae7661d0b57f13efc94faa33cd2588eae5912c9", - "sha256:a9b14804783a1d77c0bd6c66f7a9b1196cbddfbdf8bceb64683c5ae60bd1ec6f", - "sha256:c58757e37c4a3172949c99099d4d5106e4d7b63aa0617f9bb24bfbff712c7866", - "sha256:d8984742ce86c0855cccecd5c6f54a9f7532c983947cff06f3a0e2115b47f85c" - ], - "index": "pypi", - "version": "==5.1" - }, "unipath": { "hashes": [ "sha256:09839adcc72e8a24d4f76d63656f30b5a1f721fc40c9bcd79d8c67bdd8b47dae", @@ -353,13 +339,6 @@ "sha256:e3ee092c827582c50877cdbd49e9ce6d2c5c1f6561f849b3b068c1b8029626f1" ], "version": "==2.2.1" - }, - "wtforms-tornado": { - "hashes": [ - "sha256:dadb5e504d01f14bf75900f592888bb402ada6b8f8235fe583359f562d351a3a" - ], - "index": "pypi", - "version": "==0.0.2" } }, "develop": { @@ -522,7 +501,6 @@ "sha256:b9c40e9750f3d77e6e4d441d8b0266cf555e7cdabdcff33c4fd06366ca761ef8", "sha256:ec9ef8f4a9bc6f71eec99e1806bfa2de401650d996c59330782b89a5555c1497" ], - "markers": "python_version != '3.3.*' and python_version >= '2.7' and python_version != '3.1.*' and python_version != '3.0.*' and python_version != '3.2.*'", "version": "==4.3.4" }, "itsdangerous": { @@ -640,7 +618,6 @@ "sha256:6e3836e39f4d36ae72840833db137f7b7d35105079aee6ec4a62d9f80d594dd1", "sha256:95eb8364a4708392bae89035f45341871286a333f749c3141c20573d2b3876e1" ], - "markers": "python_version != '3.3.*' and python_version >= '2.7' and python_version != '3.1.*' and python_version != '3.0.*' and python_version != '3.2.*'", "version": "==0.7.1" }, "prompt-toolkit": { @@ -663,7 +640,6 @@ "sha256:3fd59af7435864e1a243790d322d763925431213b6b8529c6ca71081ace3bbf7", "sha256:e31fb2767eb657cbde86c454f02e99cb846d3cd9d61b318525140214fdc0e98e" ], - "markers": "python_version != '3.3.*' and python_version >= '2.7' and python_version != '3.1.*' and python_version != '3.0.*' and python_version != '3.2.*'", "version": "==1.5.4" }, "pygments": { @@ -675,11 +651,11 @@ }, "pylint": { "hashes": [ - "sha256:0edfec21270725c5aa8e8d8d06ef5666f766e0e748ed2f1ab23624727303b935", - "sha256:4cadcaa4f1fb19123d4baa758d9fbe6286c5b3aa513af6ea42a2d51d405db205" + "sha256:1d6d3622c94b4887115fe5204982eee66fdd8a951cf98635ee5caee6ec98c3ec", + "sha256:31142f764d2a7cd41df5196f9933b12b7ee55e73ef12204b648ad7e556c119fb" ], "index": "pypi", - "version": "==2.1.0" + "version": "==2.1.1" }, "pytest": { "hashes": [ @@ -713,11 +689,15 @@ }, "pyyaml": { "hashes": [ + "sha256:1cbc199009e78f92d9edf554be4fe40fb7b0bef71ba688602a00e97a51909110", "sha256:254bf6fda2b7c651837acb2c718e213df29d531eebf00edb54743d10bcb694eb", "sha256:3108529b78577327d15eec243f0ff348a0640b0c3478d67ad7f5648f93bac3e2", "sha256:3c17fb92c8ba2f525e4b5f7941d850e7a48c3a59b32d331e2502a3cdc6648e76", + "sha256:6f89b5c95e93945b597776163403d47af72d243f366bf4622ff08bdfd1c950b7", "sha256:8d6d96001aa7f0a6a4a95e8143225b5d06e41b1131044913fecb8f85a125714b", - "sha256:c8a88edd93ee29ede719080b2be6cb2333dfee1dccba213b422a9c8e97f2967b" + "sha256:be622cc81696e24d0836ba71f6272a2b5767669b0d79fdcf0295d51ac2e156c8", + "sha256:c8a88edd93ee29ede719080b2be6cb2333dfee1dccba213b422a9c8e97f2967b", + "sha256:f39411e380e2182ad33be039e8ee5770a5d9efe01a2bfb7ae58d9ba31c4a2a9d" ], "version": "==4.2b4" }, diff --git a/README.md b/README.md index ccb33c69..daac877e 100644 --- a/README.md +++ b/README.md @@ -96,7 +96,7 @@ To re-run tests each time a file is changed: ## Notes -tornado templates are like mustache templates -- add the +Jinja templates are like mustache templates -- add the following to `~/.vim/filetype.vim` for syntax highlighting: :au BufRead *.html.to set filetype=mustache diff --git a/atst/api_client.py b/atst/api_client.py deleted file mode 100644 index c41e0682..00000000 --- a/atst/api_client.py +++ /dev/null @@ -1,60 +0,0 @@ -import tornado.gen -from tornado.httpclient import AsyncHTTPClient -from json import dumps, loads, decoder - - -class ApiClient(object): - def __init__(self, base_url, api_version=None, validate_cert=True): - self.base_url = base_url - if api_version: - self.base_url = f"{base_url}/api/{api_version}" - self.client = AsyncHTTPClient() - self.validate_cert = validate_cert - - @tornado.gen.coroutine - def get(self, path, **kwargs): - return (yield self.make_request("GET", self.base_url + path, **kwargs)) - - @tornado.gen.coroutine - def put(self, path, **kwargs): - return (yield self.make_request("PUT", self.base_url + path, **kwargs)) - - @tornado.gen.coroutine - def post(self, path, **kwargs): - return (yield self.make_request("POST", self.base_url + path, **kwargs)) - - @tornado.gen.coroutine - def patch(self, path, **kwargs): - return (yield self.make_request("PATCH", self.base_url + path, **kwargs)) - - @tornado.gen.coroutine - def delete(self, path, **kwargs): - return (yield self.make_request("DELETE", self.base_url + path, **kwargs)) - - @tornado.gen.coroutine - def make_request(self, method, url, **kwargs): - # If 'json' kwarg is specified, serialize it to 'body' and update - # the Content-Type. - if "json" in kwargs: - kwargs["body"] = dumps(kwargs["json"]) - del kwargs["json"] - headers = kwargs.get("headers", {}) - headers["Content-Type"] = "application/json" - kwargs["headers"] = headers - if not "validate_cert" in kwargs: - kwargs["validate_cert"] = self.validate_cert - - response = yield self.client.fetch(url, method=method, **kwargs) - return self.adapt_response(response) - - def adapt_response(self, response): - if "application/json" in response.headers["Content-Type"]: - try: - json = loads(response.body) - setattr(response, "json", json) - except decoder.JSONDecodeError: - setattr(response, "json", {}) - else: - setattr(response, "json", {}) - setattr(response, "ok", 200 <= response.code < 300) - return response diff --git a/atst/app.py b/atst/app.py index e1af87c8..7e5ef2ae 100644 --- a/atst/app.py +++ b/atst/app.py @@ -61,7 +61,7 @@ def make_flask_callbacks(app): if re.match("\/workspaces\/[A-Za-z0-9]*", request.url) else "global" ) - g.dev = os.getenv("TORNADO_ENV", "dev") == "dev" + g.dev = os.getenv("FLASK_ENV", "dev") == "dev" g.matchesPath = lambda href: re.match("^" + href, request.path) g.modalOpen = request.args.get("modal", False) g.current_user = { diff --git a/atst/forms/forms.py b/atst/forms/forms.py index a930fd92..2aaa4973 100644 --- a/atst/forms/forms.py +++ b/atst/forms/forms.py @@ -1,5 +1,3 @@ -import tornado -from tornado.gen import Return from flask_wtf import FlaskForm diff --git a/atst/ui_modules.py b/atst/ui_modules.py index 68b40bdd..9dbeec8e 100644 --- a/atst/ui_modules.py +++ b/atst/ui_modules.py @@ -1,6 +1,3 @@ -from tornado.web import UIModule - -# from tornado.template import raw import re diff --git a/deploy/docker/tester/Dockerfile b/deploy/docker/tester/Dockerfile index bfec5729..5486ffa1 100644 --- a/deploy/docker/tester/Dockerfile +++ b/deploy/docker/tester/Dockerfile @@ -10,7 +10,6 @@ ARG CIBUILD=true ENV APP_DIR "${APP_DIR}" ENV FLASK_ENV ci ENV SKIP_PIPENV true -ENV TORNADO_ENV ci # Use dumb-init for proper signal handling ENTRYPOINT ["/usr/bin/dumb-init", "--"] diff --git a/tests/mocks.py b/tests/mocks.py index a43ac930..1e44f96e 100644 --- a/tests/mocks.py +++ b/tests/mocks.py @@ -1,7 +1,3 @@ -import tornado.gen -from tornado.httpclient import HTTPRequest, HTTPResponse - -from atst.api_client import ApiClient from tests.factories import RequestFactory, UserFactory @@ -21,44 +17,4 @@ DOD_SDN_INFO = { } DOD_SDN = f"CN={DOD_SDN_INFO['last_name']}.{DOD_SDN_INFO['first_name']}.G.{DOD_SDN_INFO['dod_id']},OU=OTHER,OU=PKI,OU=DoD,O=U.S. Government,C=US" - -class MockApiClient(ApiClient): - - def __init__(self, service): - self.service = service - - @tornado.gen.coroutine - def get(self, path, **kwargs): - return self._get_response("GET", path) - - @tornado.gen.coroutine - def put(self, path, **kwargs): - return self._get_response("PUT", path) - - @tornado.gen.coroutine - def patch(self, path, **kwargs): - return self._get_response("PATCH", path) - - @tornado.gen.coroutine - def post(self, path, **kwargs): - return self._get_response("POST", path) - - @tornado.gen.coroutine - def delete(self, path, **kwargs): - return self._get_response("DELETE", path) - - def _get_response(self, verb, path, code=200, json=None): - response = HTTPResponse( - request=HTTPRequest(path, verb), - code=code, - headers={"Content-Type": "application/json"}, - ) - - setattr(response, "ok", 200 <= code < 300) - if json: - setattr(response, "json", json) - - return response - - MOCK_VALID_PE_ID = "8675309U" diff --git a/tests/routes/test_financial_verification.py b/tests/routes/test_financial_verification.py index d7c29e18..60f0f9b0 100644 --- a/tests/routes/test_financial_verification.py +++ b/tests/routes/test_financial_verification.py @@ -1,6 +1,5 @@ import re import pytest -import tornado import urllib from tests.mocks import MOCK_REQUEST, MOCK_USER from tests.factories import PENumberFactory From d5ced0964668f010b7ce1c677451ad5630022456 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Mon, 6 Aug 2018 15:41:05 -0400 Subject: [PATCH 165/332] Remove ui_methods and ui_modules --- atst/ui_methods.py | 27 ------------------- atst/ui_modules.py | 67 ---------------------------------------------- 2 files changed, 94 deletions(-) delete mode 100644 atst/ui_methods.py delete mode 100644 atst/ui_modules.py diff --git a/atst/ui_methods.py b/atst/ui_methods.py deleted file mode 100644 index a3ccbbba..00000000 --- a/atst/ui_methods.py +++ /dev/null @@ -1,27 +0,0 @@ -import os -import re - - -def navigationContext(self): - return ( - "workspace" - if re.match("\/workspaces\/[A-Za-z0-9]*", self.request.uri) - else "global" - ) - - -def dev(self): - return os.getenv("FLASK_ENV", "dev") == "dev" - - -def matchesPath(self, href): - return re.match("^" + href, self.request.uri) - - -def modal(self, body): - return self.render_string("components/modal.html.to", body=body) - - -def modalOpen(self): - # For now, just check a dummy URL param - return self.get_argument("modal", False) diff --git a/atst/ui_modules.py b/atst/ui_modules.py deleted file mode 100644 index 9dbeec8e..00000000 --- a/atst/ui_modules.py +++ /dev/null @@ -1,67 +0,0 @@ -import re - - -class Alert(UIModule): - def render(self, title, message=None, actions=None, level="info"): - return self.render_string( - "components/alert.html.to", - title=title, - message=message, - actions=actions, - level=level, - ) - - -class TextInput(UIModule): - def render(self, field, placeholder=""): - return self.render_string( - "components/text_input.html.to", - field=field, - label=re.sub("<[^<]+?>", "", str(field.label)), - errors=field.errors, - placeholder=placeholder, - description=field.description, - ) - - -class OptionsInput(UIModule): - def render(self, field, inline=False): - return self.render_string( - "components/options_input.html.to", - field=field, - label=re.sub("<[^<]+?>", "", str(field.label)), - errors=field.errors, - description=field.description, - inline=inline, - ) - - -class Icon(UIModule): - def render(self, name, classes=""): - with open("static/icons/%s.svg" % name) as svg: - return self.render_string( - "components/icon.html.to", svg=svg.read(), name=name, classes=classes - ) - - -class SidenavItem(UIModule): - def render(self, label, href, active=False, icon=None, subnav=None): - return self.render_string( - "navigation/_sidenav_item.html.to", - label=label, - href=href, - active=active, - icon=icon, - subnav=subnav, - ) - - -class EmptyState(UIModule): - def render(self, message, actionLabel, actionHref, icon=None): - return self.render_string( - "components/empty_state.html.to", - message=message, - actionLabel=actionLabel, - actionHref=actionHref, - icon=icon, - ) From 488419f38948f5ed8db7ca9c64f88c6c2b85d7f4 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Mon, 6 Aug 2018 15:41:39 -0400 Subject: [PATCH 166/332] Remove old session manager --- atst/sessions.py | 71 ------------------------------------------------ 1 file changed, 71 deletions(-) delete mode 100644 atst/sessions.py diff --git a/atst/sessions.py b/atst/sessions.py deleted file mode 100644 index f7f4dfd8..00000000 --- a/atst/sessions.py +++ /dev/null @@ -1,71 +0,0 @@ -from uuid import uuid4 -import json -from redis import exceptions - - -class SessionStorageError(Exception): - pass - - -class SessionNotFoundError(Exception): - pass - - -class Sessions(object): - def start_session(self, user): - raise NotImplementedError() - - def get_session(self, session_id): - raise NotImplementedError() - - def generate_session_id(self): - return str(uuid4()) - - def build_session_dict(self, user=None): - return {"user": user or {}} - - -class DictSessions(Sessions): - def __init__(self): - self.sessions = {} - - def start_session(self, user): - session_id = self.generate_session_id() - self.sessions[session_id] = self.build_session_dict(user=user) - return session_id - - def get_session(self, session_id): - try: - session = self.sessions[session_id] - except KeyError: - raise SessionNotFoundError - - return session - - -class RedisSessions(Sessions): - def __init__(self, redis, ttl_seconds): - self.redis = redis - self.ttl_seconds = ttl_seconds - - def start_session(self, user): - session_id = self.generate_session_id() - session_dict = self.build_session_dict(user=user) - session_serialized = json.dumps(session_dict) - try: - self.redis.setex(session_id, self.ttl_seconds, session_serialized) - except exceptions.ConnectionError: - raise SessionStorageError - return session_id - - def get_session(self, session_id): - try: - session_serialized = self.redis.get(session_id) - except exceptions.ConnectionError: - raise - - if session_serialized: - self.redis.expire(session_id, self.ttl_seconds) - return json.loads(session_serialized) - else: - raise SessionNotFoundError From 0260feadad62f069202274df34ec88e9a2ab610a Mon Sep 17 00:00:00 2001 From: richard-dds Date: Mon, 6 Aug 2018 15:42:23 -0400 Subject: [PATCH 167/332] Remove atst.home --- atst/home.py | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 atst/home.py diff --git a/atst/home.py b/atst/home.py deleted file mode 100644 index 883ec8dd..00000000 --- a/atst/home.py +++ /dev/null @@ -1,3 +0,0 @@ -from unipath import Path - -home = Path(__file__).parent.parent From b6f14a6c73d05cd8fd6857118f90d8a057b6e408 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Mon, 6 Aug 2018 16:14:20 -0400 Subject: [PATCH 168/332] Add console script with ipython setup --- ipython_setup.py | 9 +++++++++ script/console | 9 +++++++++ 2 files changed, 18 insertions(+) create mode 100644 ipython_setup.py create mode 100755 script/console diff --git a/ipython_setup.py b/ipython_setup.py new file mode 100644 index 00000000..125a3d2b --- /dev/null +++ b/ipython_setup.py @@ -0,0 +1,9 @@ +from atst.app import make_config, make_app +from atst.database import db +from atst.models import * + +app = make_app(make_config()) +ctx = app.app_context() +ctx.push() + +print("\nWelcome to atst. This shell has all models in scope, and a SQLAlchemy session called db.") diff --git a/script/console b/script/console new file mode 100755 index 00000000..0561ac99 --- /dev/null +++ b/script/console @@ -0,0 +1,9 @@ +#!/bin/bash + +# If a command fails, exit the script +set -e + +# Ensure we are in the app root directory (not the /script directory) +cd "$(dirname "${0}")/.." + +pipenv run ipython -i ./ipython_setup.py From 19a072d67e8e57e4361151cbdfc6d270173e926a Mon Sep 17 00:00:00 2001 From: richard-dds Date: Mon, 6 Aug 2018 16:21:43 -0400 Subject: [PATCH 169/332] Initialize CSRF protection --- atst/app.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/atst/app.py b/atst/app.py index 7e5ef2ae..84e7d7be 100644 --- a/atst/app.py +++ b/atst/app.py @@ -6,6 +6,7 @@ from flask import Flask, request, g from flask_session import Session import redis from unipath import Path +from flask_wtf.csrf import CSRFProtect from atst.database import db from atst.assets import environment as assets_environment @@ -31,6 +32,7 @@ def make_app(config): static_folder=parent_dir.child("static").absolute(), ) redis = make_redis(config) + csrf = CSRFProtect() app.config.update(config) app.config.update({"SESSION_REDIS": redis}) @@ -39,6 +41,7 @@ def make_app(config): make_crl_validator(app) db.init_app(app) + csrf.init_app(app) Session(app) assets_environment.init_app(app) From 83c1cc858431dfb3693564af048466e4c6e00df0 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Mon, 6 Aug 2018 16:21:55 -0400 Subject: [PATCH 170/332] Use url_for for requests form links --- templates/navigation/global_navigation.html | 2 +- templates/requests.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/navigation/global_navigation.html b/templates/navigation/global_navigation.html index 6255e604..b2311665 100644 --- a/templates/navigation/global_navigation.html +++ b/templates/navigation/global_navigation.html @@ -18,7 +18,7 @@ icon="document", active=g.matchesPath('/requests'), subnav=[ - {"label":"New Request", "href":"/requests/new/1", "icon": "plus", "active": g.matchesPath('/requests/new')}, + {"label":"New Request", "href":url_for("requests.requests_form_new", screen=1), "icon": "plus", "active": g.matchesPath('/requests/new')}, ] ) }} {{ SidenavItem("Workspaces", href="/workspaces", icon="cloud", active=g.matchesPath('/workspaces')) }} diff --git a/templates/requests.html b/templates/requests.html index 288520ff..17993dfa 100644 --- a/templates/requests.html +++ b/templates/requests.html @@ -40,7 +40,7 @@ {{ EmptyState( 'There are currently no active requests for you to see.', actionLabel='Create a new JEDI Cloud Request', - actionHref='/requests/new', + actionHref=url_for('requests.requests_form_new', screen=1), icon='document' ) }} From e9cf73279848f47a94018eecc99963edf272935f Mon Sep 17 00:00:00 2001 From: richard-dds Date: Mon, 6 Aug 2018 16:26:47 -0400 Subject: [PATCH 171/332] Use full_name property of User --- atst/models/user.py | 4 ++++ atst/routes/requests/index.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/atst/models/user.py b/atst/models/user.py index 6a1b530d..643fd3f5 100644 --- a/atst/models/user.py +++ b/atst/models/user.py @@ -24,3 +24,7 @@ class User(Base): @property def atat_permissions(self): return self.atat_role.permissions + + @property + def full_name(self): + return "{} {}".format(self.first_name, self.last_name) diff --git a/atst/routes/requests/index.py b/atst/routes/requests/index.py index 79090d67..7e098b47 100644 --- a/atst/routes/requests/index.py +++ b/atst/routes/requests/index.py @@ -15,7 +15,7 @@ def map_request(user, request): "status": request.status, "app_count": 1, "date": time_created.format("M/DD/YYYY"), - "full_name": "{} {}".format(user["first_name"], user["last_name"]), + "full_name": user.full_name } From 84947448018bc5c430e798e49367bd639a941e09 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Mon, 6 Aug 2018 16:35:59 -0400 Subject: [PATCH 172/332] Disable CSRF checking in test and CI --- atst/app.py | 5 +++-- config/ci.ini | 1 + config/test.ini | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/atst/app.py b/atst/app.py index 84e7d7be..4b7a0806 100644 --- a/atst/app.py +++ b/atst/app.py @@ -83,13 +83,14 @@ def make_flask_callbacks(app): def map_config(config): return { + **config["default"], "ENV": config["default"]["ENVIRONMENT"], "DEBUG": config["default"]["DEBUG"], "PORT": int(config["default"]["PORT"]), "SQLALCHEMY_DATABASE_URI": config["default"]["DATABASE_URI"], "SQLALCHEMY_TRACK_MODIFICATIONS": False, - **config["default"], - "PERMANENT_SESSION_LIFETIME": int(config["default"]["PERMANENT_SESSION_LIFETIME"]), + "WTF_CSRF_ENABLED": config.getboolean("default", "WTF_CSRF_ENABLED"), + "PERMANENT_SESSION_LIFETIME": config.getint("default", "PERMANENT_SESSION_LIFETIME"), } diff --git a/config/ci.ini b/config/ci.ini index e7e5be1a..3ee7f480 100644 --- a/config/ci.ini +++ b/config/ci.ini @@ -3,3 +3,4 @@ PGHOST = postgreshost PGDATABASE = atat_test REDIS_URI = redis://redishost:6379 CRL_DIRECTORY = tests/fixtures/crl +WTF_CSRF_ENABLED = false diff --git a/config/test.ini b/config/test.ini index fe38c777..614cdb7b 100644 --- a/config/test.ini +++ b/config/test.ini @@ -1,3 +1,4 @@ [default] PGDATABASE = atat_test CRL_DIRECTORY = tests/fixtures/crl +WTF_CSRF_ENABLED = false From 7b83804281d030ca196db5abd795fa737051a0a2 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Mon, 6 Aug 2018 16:47:52 -0400 Subject: [PATCH 173/332] Fix some old tornado templates --- templates/base_workspace.html | 2 +- ...workspace_navigation.html.to => workspace_navigation.html} | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) rename templates/navigation/{workspace_navigation.html.to => workspace_navigation.html} (87%) diff --git a/templates/base_workspace.html b/templates/base_workspace.html index 0ccad5ba..fedc3278 100644 --- a/templates/base_workspace.html +++ b/templates/base_workspace.html @@ -4,7 +4,7 @@

    - {% include 'navigation/workspace_navigation.html.to' %} + {% include 'navigation/workspace_navigation.html' %}
    diff --git a/templates/navigation/workspace_navigation.html.to b/templates/navigation/workspace_navigation.html similarity index 87% rename from templates/navigation/workspace_navigation.html.to rename to templates/navigation/workspace_navigation.html index 6b1c0317..e39ee185 100644 --- a/templates/navigation/workspace_navigation.html.to +++ b/templates/navigation/workspace_navigation.html @@ -4,7 +4,7 @@
      {{ SidenavItem( "Projects", - href='/workspace_projects/123456', + href=url_for("workspaces.workspace_projects", workspace_id=123456), active=g.matchesPath('\/workspaces\/[A-Za-z0-9]*\/projects'), subnav=[ { @@ -18,7 +18,7 @@ {{ SidenavItem( "Members", - href='/workspace_members/123456', + href=url_for("workspaces.workspace_members", workspace_id=123456), active=g.matchesPath('\/workspaces\/[A-Za-z0-9]*\/members'), subnav=[ { From e40dd7ec018b1cf26337d873efcb4efee727592b Mon Sep 17 00:00:00 2001 From: richard-dds Date: Mon, 6 Aug 2018 17:03:09 -0400 Subject: [PATCH 174/332] Update README to reflect current state of the app --- README.md | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index daac877e..32eca8ab 100644 --- a/README.md +++ b/README.md @@ -4,18 +4,19 @@ ## Description -This is the main user-facing web application for the ATAT stack. All end-user -requests are handled by ATST, with it making backend calls to various -microservices when appropriate. +This is the user-facing web application for ATAT. ## Installation ### Requirements See the [scriptz](https://github.com/dod-ccpo/scriptz) repository for the shared requirements and guidelines for all ATAT applications. -Additionally, ATST requires a redis instance for session management. Have redis -installed and running. By default, ATST will try to connect to a redis instance -running on localhost on its default port, 6379. + +ATST requires a postgres instance (>= 9.6) for persistence. Have postgres installed +and running on the default port of 5432. + +ATST also requires a redis instance for session management. Have redis installed and +running on the default port of 6379. ### Cloning This project contains git submodules. Here is an example clone command that will @@ -103,7 +104,14 @@ following to `~/.vim/filetype.vim` for syntax highlighting: ## Icons -To render an icon use `{% module Icon('name') %}` in a template, where `name` is the filename of an svg file in `static/icons`. +To render an icon, use + +```jinja +{% import "components/icon.html" %} +{{ Icon("icon-name", classes="css-classes") }} +``` + +where `name` is the filename of an svg in `static/icons`. All icons used should be from the Noun Project, specifically [this collection](https://thenounproject.com/monstercritic/collection/tinicons-a-set-of-tiny-icons-perfect-for-ui-elemen/) if possible. @@ -113,7 +121,7 @@ SVG markup should be cleaned an minified, [Svgsus](http://www.svgs.us/) works we The `/login-dev` endpoint is protected by HTTP basic auth when deployed. This can be configured for NGINX following the instructions [here](https://docs.nginx.com/nginx/admin-guide/security-controls/configuring-http-basic-authentication/). The following config should added within the main server block for the site: -``` +```nginx location /login-dev { auth_basic "Developer Access"; auth_basic_user_file /etc/apache2/.htpasswd; From c06f0d03c1c5b60a168295b6e0da8525f792a238 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Mon, 6 Aug 2018 17:10:46 -0400 Subject: [PATCH 175/332] Fix typo in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 32eca8ab..e07d91ea 100644 --- a/README.md +++ b/README.md @@ -111,7 +111,7 @@ To render an icon, use {{ Icon("icon-name", classes="css-classes") }} ``` -where `name` is the filename of an svg in `static/icons`. +where `icon-name` is the filename of an svg in `static/icons`. All icons used should be from the Noun Project, specifically [this collection](https://thenounproject.com/monstercritic/collection/tinicons-a-set-of-tiny-icons-perfect-for-ui-elemen/) if possible. From 69fb8217eb402b7c9876c0786aeeb4ad5941591b Mon Sep 17 00:00:00 2001 From: dandds Date: Tue, 7 Aug 2018 09:33:46 -0400 Subject: [PATCH 176/332] add default value for WTF_CSRF_ENABLED --- config/base.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/config/base.ini b/config/base.ini index 2ca8f9f3..1554b261 100644 --- a/config/base.ini +++ b/config/base.ini @@ -21,3 +21,4 @@ SESSION_USE_SIGNER = True PERMANENT_SESSION_LIFETIME = 600 CRL_DIRECTORY = crl CA_CHAIN = ssl/server-certs/ca-chain.pem +WTF_CSRF_ENABLED = true From 3b36066315d54d6477a4cccc364458969ad9e45d Mon Sep 17 00:00:00 2001 From: dandds Date: Tue, 7 Aug 2018 09:44:10 -0400 Subject: [PATCH 177/332] remove authnid base URL from config --- config/base.ini | 1 - 1 file changed, 1 deletion(-) diff --git a/config/base.ini b/config/base.ini index 1554b261..f256fa3a 100644 --- a/config/base.ini +++ b/config/base.ini @@ -2,7 +2,6 @@ PORT=8000 ENVIRONMENT = dev DEBUG = true -AUTHNID_BASE_URL= https://localhost:8001 COOKIE_SECRET = some-secret-please-replace SECRET = change_me_into_something_secret SECRET_KEY = change_me_into_something_secret From 10cdfcbbaba4e9390acbf861658c83fa32502b11 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Mon, 23 Jul 2018 14:44:59 -0400 Subject: [PATCH 178/332] Add models dir --- atst/models/__init__.py | 0 atst/models/request.py | 32 ++++++++++++++++++++++++++++++++ atst/models/status_event.py | 17 +++++++++++++++++ atst/models/types.py | 10 ++++++++++ 4 files changed, 59 insertions(+) create mode 100644 atst/models/__init__.py create mode 100644 atst/models/request.py create mode 100644 atst/models/status_event.py create mode 100644 atst/models/types.py diff --git a/atst/models/__init__.py b/atst/models/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/atst/models/request.py b/atst/models/request.py new file mode 100644 index 00000000..5762e857 --- /dev/null +++ b/atst/models/request.py @@ -0,0 +1,32 @@ +from sqlalchemy import Column, func +from sqlalchemy.types import DateTime +from sqlalchemy.dialects.postgresql import JSONB, UUID +from sqlalchemy.orm import relationship + +from requests_queue.models import Base +from requests_queue.models.types import Id + + +class Request(Base): + __tablename__ = 'requests' + + id = Id() + creator = Column(UUID(as_uuid=True)) + time_created = Column(DateTime(timezone=True), server_default=func.now()) + body = Column(JSONB) + status_events = relationship('StatusEvent', + backref='request', + order_by='StatusEvent.sequence') + + @property + def status(self): + return self.status_events[-1].new_status + + @property + def action_required_by(self): + return { + "incomplete": "mission_owner", + "pending_submission": "mission_owner", + "submitted": "ccpo", + "approved": "mission_owner", + }.get(self.status) diff --git a/atst/models/status_event.py b/atst/models/status_event.py new file mode 100644 index 00000000..c5c5c715 --- /dev/null +++ b/atst/models/status_event.py @@ -0,0 +1,17 @@ +from sqlalchemy import Column, func, ForeignKey +from sqlalchemy.types import DateTime, String, BigInteger +from sqlalchemy.schema import Sequence +from sqlalchemy.dialects.postgresql import UUID + +from requests_queue.models import Base +from requests_queue.models.types import Id + + +class StatusEvent(Base): + __tablename__ = 'status_events' + + id = Id() + new_status = Column(String()) + time_created = Column(DateTime(timezone=True), server_default=func.now()) + request_id = Column(UUID(as_uuid=True), ForeignKey('requests.id', ondelete='CASCADE')) + sequence = Column(BigInteger, Sequence('status_events_sequence_seq'), nullable=False) diff --git a/atst/models/types.py b/atst/models/types.py new file mode 100644 index 00000000..b2e1c6d7 --- /dev/null +++ b/atst/models/types.py @@ -0,0 +1,10 @@ +import sqlalchemy +from sqlalchemy import Column +from sqlalchemy.dialects.postgresql import UUID + + +def Id(): + return Column( + UUID(as_uuid=True), + primary_key=True, + server_default=sqlalchemy.text("uuid_generate_v4()")) From 8a80ba426f2eee47c3b884abb27bbf7a3d325a5c Mon Sep 17 00:00:00 2001 From: richard-dds Date: Mon, 23 Jul 2018 14:45:08 -0400 Subject: [PATCH 179/332] Merge pipfiles --- Pipfile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Pipfile b/Pipfile index eb946fb9..81cadd0d 100644 --- a/Pipfile +++ b/Pipfile @@ -10,6 +10,9 @@ Unipath = "==1.1" wtforms-tornado = "*" pendulum = "*" redis = "*" +sqlalchemy = "*" +alembic = "*" +"psycopg2-binary" = "*" [dev-packages] bandit = "*" @@ -20,6 +23,7 @@ ipdb = "*" pylint = "*" black = "*" pytest-watch = "*" +factory-boy = "*" [requires] python_version = "3.6" From c6636bec780ef5028f33f73920f334eedc18b34e Mon Sep 17 00:00:00 2001 From: richard-dds Date: Mon, 23 Jul 2018 14:58:26 -0400 Subject: [PATCH 180/332] Models and migrations for requests --- Pipfile.lock | 180 ++++++++++++------ alembic.ini | 74 +++++++ alembic/README | 1 + alembic/env.py | 85 +++++++++ alembic/script.py.mako | 24 +++ alembic/versions/b5b17d465166_requests.py | 44 +++++ .../ff1c9c02fa61_enable_uuid_extension.py | 26 +++ atst/database.py | 8 + atst/models/__init__.py | 6 + atst/models/request.py | 4 +- ...tatus_event.py => request_status_event.py} | 10 +- config/base.ini | 1 + 12 files changed, 401 insertions(+), 62 deletions(-) create mode 100644 alembic.ini create mode 100644 alembic/README create mode 100644 alembic/env.py create mode 100644 alembic/script.py.mako create mode 100644 alembic/versions/b5b17d465166_requests.py create mode 100644 alembic/versions/ff1c9c02fa61_enable_uuid_extension.py create mode 100644 atst/database.py rename atst/models/{status_event.py => request_status_event.py} (63%) diff --git a/Pipfile.lock b/Pipfile.lock index 2fadae1e..d87dfa97 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "3bea02ccdb0e3877f2595d7fb405408114ec8947e0484d5b4aaf14a4c8ff78b2" + "sha256": "7cd87f2c2c42bc776a6aa6f72fcbb8b30d4e703e50b6480ce1c8ace6ae6dd0a4" }, "pipfile-spec": 6, "requires": { @@ -16,6 +16,26 @@ ] }, "default": { + "alembic": { + "hashes": [ + "sha256:52d73b1d750f1414fa90c25a08da47b87de1e4ad883935718a8f36396e19e78e", + "sha256:eb7db9b4510562ec37c91d00b00d95fde076c1030d3f661aea882eec532b3565" + ], + "index": "pypi", + "version": "==1.0.0" + }, + "mako": { + "hashes": [ + "sha256:4e02fde57bd4abb5ec400181e4c314f56ac3e49ba4fb8b0d50bba18cb27d25ae" + ], + "version": "==1.0.7" + }, + "markupsafe": { + "hashes": [ + "sha256:a6be69091dac236ea9c6bc7d012beab42010fa914c459791d627dad4910eb665" + ], + "version": "==1.0" + }, "pendulum": { "hashes": [ "sha256:0643d45824e6789b88187728337dfa6075a0233f6976c2abefba00d064156309", @@ -32,6 +52,42 @@ "index": "pypi", "version": "==2.0.2" }, + "psycopg2-binary": { + "hashes": [ + "sha256:04afb59bbbd2eab3148e6816beddc74348078b8c02a1113ea7f7822f5be4afe3", + "sha256:098b18f4d8857a8f9b206d1dc54db56c2255d5d26458917e7bcad61ebfe4338f", + "sha256:0bf855d4a7083e20ead961fda4923887094eaeace0ab2d76eb4aa300f4bbf5bd", + "sha256:197dda3ffd02057820be83fe4d84529ea70bf39a9a4daee1d20ffc74eb3d042e", + "sha256:278ef63afb4b3d842b4609f2c05ffbfb76795cf6a184deeb8707cd5ed3c981a5", + "sha256:3cbf8c4fc8f22f0817220891cf405831559f4d4c12c4f73913730a2ea6c47a47", + "sha256:4305aed922c4d9d6163ab3a41d80b5a1cfab54917467da8168552c42cad84d32", + "sha256:47ee296f704fb8b2a616dec691cdcfd5fa0f11943955e88faa98cbd1dc3b3e3d", + "sha256:4a0e38cb30457e70580903367161173d4a7d1381eb2f2cfe4e69b7806623f484", + "sha256:4d6c294c6638a71cafb82a37f182f24321f1163b08b5d5ca076e11fe838a3086", + "sha256:4f3233c366500730f839f92833194fd8f9a5c4529c8cd8040aa162c3740de8e5", + "sha256:5221f5a3f4ca2ddf0d58e8b8a32ca50948be9a43351fda797eb4e72d7a7aa34d", + "sha256:5c6ca0b507540a11eaf9e77dee4f07c131c2ec80ca0cffa146671bf690bc1c02", + "sha256:789bd89d71d704db2b3d5e67d6d518b158985d791d3b2dec5ab85457cfc9677b", + "sha256:7b94d29239efeaa6a967f3b5971bd0518d2a24edd1511edbf4a2c8b815220d07", + "sha256:89bc65ef3301c74cf32db25334421ea6adbe8f65601ea45dcaaf095abed910bb", + "sha256:89d6d3a549f405c20c9ae4dc94d7ed2de2fa77427a470674490a622070732e62", + "sha256:97521704ac7127d7d8ba22877da3c7bf4a40366587d238ec679ff38e33177498", + "sha256:a395b62d5f44ff6f633231abe568e2203b8fabf9797cd6386aa92497df912d9a", + "sha256:a6d32c37f714c3f34158f3fa659f3a8f2658d5f53c4297d45579b9677cc4d852", + "sha256:a89ee5c26f72f2d0d74b991ce49e42ddeb4ac0dc2d8c06a0f2770a1ab48f4fe0", + "sha256:b4c8b0ef3608e59317bfc501df84a61e48b5445d45f24d0391a24802de5f2d84", + "sha256:b5fcf07140219a1f71e18486b8dc28e2e1b76a441c19374805c617aa6d9a9d55", + "sha256:b86f527f00956ecebad6ab3bb30e3a75fedf1160a8716978dd8ce7adddedd86f", + "sha256:be4c4aa22ba22f70de36c98b06480e2f1697972d49eb20d525f400d204a6d272", + "sha256:c2ac7aa1a144d4e0e613ac7286dae85671e99fe7a1353954d4905629c36b811c", + "sha256:de26ef4787b5e778e8223913a3e50368b44e7480f83c76df1f51d23bd21cea16", + "sha256:e70ebcfc5372dc7b699c0110454fc4263967f30c55454397e5769eb72c0eb0ce", + "sha256:eadbd32b6bc48b67b0457fccc94c86f7ccc8178ab839f684eb285bb592dc143e", + "sha256:ecbc6dfff6db06b8b72ae8a2f25ff20fbdcb83cb543811a08f7cb555042aa729" + ], + "index": "pypi", + "version": "==2.7.5" + }, "python-dateutil": { "hashes": [ "sha256:1adb80e7a782c12e52ef9a8182bebeb73f1d7e24e374397af06fb4956c8dc5c0", @@ -39,12 +95,18 @@ ], "version": "==2.7.3" }, + "python-editor": { + "hashes": [ + "sha256:a3c066acee22a1c94f63938341d4fb374e3fdd69366ed6603d7b24bed1efc565" + ], + "version": "==1.0.3" + }, "pytzdata": { "hashes": [ "sha256:1d936da41ee06216d89fdc7ead1ee9a5da2811a8787515a976b646e110c3f622", "sha256:e4ef42e82b0b493c5849eed98b5ab49d6767caf982127e9a33167f1153b36cc5" ], - "markers": "python_version != '3.3.*' and python_version >= '2.7' and python_version != '3.2.*' and python_version != '3.1.*' and python_version != '3.0.*'", + "markers": "python_version != '3.1.*' and python_version != '3.2.*' and python_version != '3.0.*' and python_version != '3.3.*' and python_version >= '2.7'", "version": "==2018.5" }, "redis": { @@ -62,6 +124,13 @@ ], "version": "==1.11.0" }, + "sqlalchemy": { + "hashes": [ + "sha256:72325e67fb85f6e9ad304c603d83626d1df684fdf0c7ab1f0352e71feeab69d8" + ], + "index": "pypi", + "version": "==1.2.10" + }, "tornado": { "hashes": [ "sha256:1b83d5c10550f2653380b4c77331d6f8850f287c4f67d7ce1e1c639d9222fbc7", @@ -128,10 +197,10 @@ }, "astroid": { "hashes": [ - "sha256:a8d8c7fe34e34e868426b9bafce852c355a3951eef60bc831b2ed541558f8d37", - "sha256:e722228b5259ce8c7cbf75f3b0ee8b483cfbd4df01167474a84087d1aeade22c" + "sha256:0a0c484279a5f08c9bcedd6fa9b42e378866a7dcc695206b92d59dc9f2d9760d", + "sha256:218e36cf8d98a42f16214e8670819ce307fa707d1dcf7f9af84c7aede1febc7f" ], - "version": "==2.0.0.dev4" + "version": "==2.0.1" }, "atomicwrites": { "hashes": [ @@ -197,19 +266,35 @@ ], "version": "==0.6.2" }, + "factory-boy": { + "hashes": [ + "sha256:6f25cc4761ac109efd503f096e2ad99421b1159f01a29dbb917359dcd68e08ca", + "sha256:d552cb872b310ae78bd7429bf318e42e1e903b1a109e899a523293dfa762ea4f" + ], + "index": "pypi", + "version": "==2.11.1" + }, + "faker": { + "hashes": [ + "sha256:0e9a1227a3a0f3297a485715e72ee6eb77081b17b629367042b586e38c03c867", + "sha256:b4840807a94a3bad0217d6ed3f9b65a1cc6e1db1c99e1184673056ae2c0a4c4d" + ], + "markers": "python_version != '3.2.*' and python_version != '3.0.*' and python_version >= '2.7' and python_version != '3.1.*'", + "version": "==0.8.17" + }, "gitdb2": { "hashes": [ - "sha256:b60e29d4533e5e25bb50b7678bbc187c8f6bcff1344b4f293b2ba55c85795f09", - "sha256:cf9a4b68e8c4da8d42e48728c944ff7af2d8c9db303ac1ab32eac37aa4194b0e" + "sha256:87783b7f4a8f6b71c7fe81d32179b3c8781c1a7d6fa0c69bff2f315b00aff4f8", + "sha256:bb4c85b8a58531c51373c89f92163b92f30f81369605a67cd52d1fc21246c044" ], - "version": "==2.0.3" + "version": "==2.0.4" }, "gitpython": { "hashes": [ - "sha256:1ec4c44846cf76a1e55769560673a97731849c9d05401e035e607495f10db959", - "sha256:b60b045cf64a321e5b620debb49890099fa6c7be6dfb7fb249027e5d34227301" + "sha256:563221e5a44369c6b79172f455584c9ebbb122a13368cc82cb4b5addff788f82", + "sha256:8237dc5bfd6f1366abeee5624111b9d6879393d84745a507de0fda86043b65a8" ], - "version": "==2.1.10" + "version": "==2.1.11" }, "ipdb": { "hashes": [ @@ -239,7 +324,7 @@ "sha256:b9c40e9750f3d77e6e4d441d8b0266cf555e7cdabdcff33c4fd06366ca761ef8", "sha256:ec9ef8f4a9bc6f71eec99e1806bfa2de401650d996c59330782b89a5555c1497" ], - "markers": "python_version != '3.3.*' and python_version >= '2.7' and python_version != '3.2.*' and python_version != '3.1.*' and python_version != '3.0.*'", + "markers": "python_version >= '2.7' and python_version != '3.1.*' and python_version != '3.3.*' and python_version != '3.0.*' and python_version != '3.2.*'", "version": "==4.3.4" }, "jedi": { @@ -313,10 +398,10 @@ }, "pbr": { "hashes": [ - "sha256:4f2b11d95917af76e936811be8361b2b19616e5ef3b55956a429ec7864378e0c", - "sha256:e0f23b61ec42473723b2fec2f33fb12558ff221ee551962f01dd4de9053c2055" + "sha256:754e766b4f4bad3aa68cfd532456298da1aa39375da8748392dbae90860d5f18", + "sha256:c6bddbad814f23c7faaf88d8a186e9965243cc6206a23361b73023648e645794" ], - "version": "==4.1.0" + "version": "==4.1.1" }, "pexpect": { "hashes": [ @@ -339,7 +424,7 @@ "sha256:d345c8fe681115900d6da8d048ba67c25df42973bda370783cd58826442dcd7c", "sha256:e160a7fcf25762bb60efc7e171d4497ff1d8d2d75a3d0df7a21b76821ecbf5c5" ], - "markers": "python_version != '3.3.*' and python_version >= '2.7' and python_version != '3.2.*' and python_version != '3.1.*' and python_version != '3.0.*'", + "markers": "python_version >= '2.7' and python_version != '3.1.*' and python_version != '3.3.*' and python_version != '3.0.*' and python_version != '3.2.*'", "version": "==0.6.0" }, "prompt-toolkit": { @@ -362,7 +447,7 @@ "sha256:3fd59af7435864e1a243790d322d763925431213b6b8529c6ca71081ace3bbf7", "sha256:e31fb2767eb657cbde86c454f02e99cb846d3cd9d61b318525140214fdc0e98e" ], - "markers": "python_version != '3.3.*' and python_version >= '2.7' and python_version != '3.2.*' and python_version != '3.1.*' and python_version != '3.0.*'", + "markers": "python_version >= '2.7' and python_version != '3.1.*' and python_version != '3.3.*' and python_version != '3.0.*' and python_version != '3.2.*'", "version": "==1.5.4" }, "pygments": { @@ -374,11 +459,11 @@ }, "pylint": { "hashes": [ - "sha256:285c9ae7255acb584057fe31051a37498985e632b99fc0ec93b7eb38a1b137f9", - "sha256:dd5c0fc4e6a4cb9483a4367699099a7dfc8a13de9ecac4cb16855ffac68d49de" + "sha256:2c90a24bee8fae22ac98061c896e61f45c5b73c2e0511a4bf53f99ba56e90434", + "sha256:454532779425098969b8f54ab0f056000b883909f69d05905ea114df886e3251" ], "index": "pypi", - "version": "==2.0.0.dev2" + "version": "==2.0.1" }, "pytest": { "hashes": [ @@ -403,6 +488,13 @@ "index": "pypi", "version": "==4.2.0" }, + "python-dateutil": { + "hashes": [ + "sha256:1adb80e7a782c12e52ef9a8182bebeb73f1d7e24e374397af06fb4956c8dc5c0", + "sha256:e27001de32f627c22380a688bcc43ce83504a7bc5da472209b4c70f02829f0b8" + ], + "version": "==2.7.3" + }, "pyyaml": { "hashes": [ "sha256:254bf6fda2b7c651837acb2c718e213df29d531eebf00edb54743d10bcb694eb", @@ -428,17 +520,24 @@ }, "smmap2": { "hashes": [ - "sha256:b78ee0f1f5772d69ff50b1cbdb01b8c6647a8354f02f23b488cf4b2cfc923956", - "sha256:c7530db63f15f09f8251094b22091298e82bf6c699a6b8344aaaef3f2e1276c3" + "sha256:0dd53d991af487f9b22774fa89451358da3607c02b9b886a54736c6a313ece0b", + "sha256:dc216005e529d57007ace27048eb336dcecb7fc413cfb3b2f402bb25972b69c6" ], - "version": "==2.0.3" + "version": "==2.0.4" }, "stevedore": { "hashes": [ - "sha256:e3d96b2c4e882ec0c1ff95eaebf7b575a779fd0ccb4c741b9832bed410d58b3d", - "sha256:f1c7518e7b160336040fee272174f1f7b29a46febb3632502a8f2055f973d60b" + "sha256:1e153545aca7a6a49d8337acca4f41c212fbfa60bf864ecd056df0cafb9627e8", + "sha256:c7eac1c0d95824c88b655273da5c17cdde6482b2739f47c30bf851dcc9d3c2c0" ], - "version": "==1.28.0" + "version": "==1.29.0" + }, + "text-unidecode": { + "hashes": [ + "sha256:5a1375bb2ba7968740508ae38d92e1f889a0832913cb1c447d5e2046061a396d", + "sha256:801e38bd550b943563660a91de8d4b6fa5df60a542be9093f7abf819f86050cc" + ], + "version": "==1.2" }, "toml": { "hashes": [ @@ -464,35 +563,6 @@ ], "version": "==4.3.2" }, - "typed-ast": { - "hashes": [ - "sha256:0948004fa228ae071054f5208840a1e88747a357ec1101c17217bfe99b299d58", - "sha256:10703d3cec8dcd9eef5a630a04056bbc898abc19bac5691612acba7d1325b66d", - "sha256:1f6c4bd0bdc0f14246fd41262df7dfc018d65bb05f6e16390b7ea26ca454a291", - "sha256:25d8feefe27eb0303b73545416b13d108c6067b846b543738a25ff304824ed9a", - "sha256:29464a177d56e4e055b5f7b629935af7f49c196be47528cc94e0a7bf83fbc2b9", - "sha256:2e214b72168ea0275efd6c884b114ab42e316de3ffa125b267e732ed2abda892", - "sha256:3e0d5e48e3a23e9a4d1a9f698e32a542a4a288c871d33ed8df1b092a40f3a0f9", - "sha256:519425deca5c2b2bdac49f77b2c5625781abbaf9a809d727d3a5596b30bb4ded", - "sha256:57fe287f0cdd9ceaf69e7b71a2e94a24b5d268b35df251a88fef5cc241bf73aa", - "sha256:668d0cec391d9aed1c6a388b0d5b97cd22e6073eaa5fbaa6d2946603b4871efe", - "sha256:68ba70684990f59497680ff90d18e756a47bf4863c604098f10de9716b2c0bdd", - "sha256:6de012d2b166fe7a4cdf505eee3aaa12192f7ba365beeefaca4ec10e31241a85", - "sha256:79b91ebe5a28d349b6d0d323023350133e927b4de5b651a8aa2db69c761420c6", - "sha256:8550177fa5d4c1f09b5e5f524411c44633c80ec69b24e0e98906dd761941ca46", - "sha256:898f818399cafcdb93cbbe15fc83a33d05f18e29fb498ddc09b0214cdfc7cd51", - "sha256:94b091dc0f19291adcb279a108f5d38de2430411068b219f41b343c03b28fb1f", - "sha256:a26863198902cda15ab4503991e8cf1ca874219e0118cbf07c126bce7c4db129", - "sha256:a8034021801bc0440f2e027c354b4eafd95891b573e12ff0418dec385c76785c", - "sha256:bc978ac17468fe868ee589c795d06777f75496b1ed576d308002c8a5756fb9ea", - "sha256:c05b41bc1deade9f90ddc5d988fe506208019ebba9f2578c622516fd201f5863", - "sha256:c9b060bd1e5a26ab6e8267fd46fc9e02b54eb15fffb16d112d4c7b1c12987559", - "sha256:edb04bdd45bfd76c8292c4d9654568efaedf76fe78eb246dde69bdb13b2dad87", - "sha256:f19f2a4f547505fe9072e15f6f4ae714af51b5a681a97f187971f50c283193b6" - ], - "markers": "python_version < '3.7' and implementation_name == 'cpython'", - "version": "==1.1.0" - }, "watchdog": { "hashes": [ "sha256:7e65882adb7746039b6f3876ee174952f8eaaa34491ba34333ddf1fe35de4162" diff --git a/alembic.ini b/alembic.ini new file mode 100644 index 00000000..08ce3124 --- /dev/null +++ b/alembic.ini @@ -0,0 +1,74 @@ +# A generic, single database configuration. + +[alembic] +# path to migration scripts +script_location = alembic + +# template used to generate migration files +# file_template = %%(rev)s_%%(slug)s + +# timezone to use when rendering the date +# within the migration file as well as the filename. +# string value is passed to dateutil.tz.gettz() +# leave blank for localtime +# timezone = + +# max length of characters to apply to the +# "slug" field +#truncate_slug_length = 40 + +# set to 'true' to run the environment during +# the 'revision' command, regardless of autogenerate +# revision_environment = false + +# set to 'true' to allow .pyc and .pyo files without +# a source .py file to be detected as revisions in the +# versions/ directory +# sourceless = false + +# version location specification; this defaults +# to alembic/versions. When using multiple version +# directories, initial revisions must be specified with --version-path +# version_locations = %(here)s/bar %(here)s/bat alembic/versions + +# the output encoding used when revision files +# are written from script.py.mako +# output_encoding = utf-8 + +sqlalchemy.url = driver://user:pass@localhost/dbname + + +# Logging configuration +[loggers] +keys = root,sqlalchemy,alembic + +[handlers] +keys = console + +[formatters] +keys = generic + +[logger_root] +level = WARN +handlers = console +qualname = + +[logger_sqlalchemy] +level = WARN +handlers = +qualname = sqlalchemy.engine + +[logger_alembic] +level = INFO +handlers = +qualname = alembic + +[handler_console] +class = StreamHandler +args = (sys.stderr,) +level = NOTSET +formatter = generic + +[formatter_generic] +format = %(levelname)-5.5s [%(name)s] %(message)s +datefmt = %H:%M:%S diff --git a/alembic/README b/alembic/README new file mode 100644 index 00000000..98e4f9c4 --- /dev/null +++ b/alembic/README @@ -0,0 +1 @@ +Generic single-database configuration. \ No newline at end of file diff --git a/alembic/env.py b/alembic/env.py new file mode 100644 index 00000000..6a9d9749 --- /dev/null +++ b/alembic/env.py @@ -0,0 +1,85 @@ +from __future__ import with_statement +from alembic import context +from sqlalchemy import engine_from_config, pool +from logging.config import fileConfig + +# this is the Alembic Config object, which provides +# access to the values within the .ini file in use. +config = context.config + +# Interpret the config file for Python logging. +# This line sets up loggers basically. +fileConfig(config.config_file_name) + +# add your model's MetaData object here +# for 'autogenerate' support +# from myapp import mymodel +# target_metadata = mymodel.Base.metadata +target_metadata = None + +# other values from the config, defined by the needs of env.py, +# can be acquired: +# my_important_option = config.get_main_option("my_important_option") +# ... etc. + +import sys +from unipath import Path + +parent_dir = Path(__file__).parent.parent +sys.path.append(parent_dir) + +from atst.app import make_config +app_config = make_config() +config.set_main_option('sqlalchemy.url', app_config['default']['DATABASE_URI']) + +from atst.database import make_db +from atst.models import * +db = make_db(app_config) +target_metadata = Base.metadata + + +def run_migrations_offline(): + """Run migrations in 'offline' mode. + + This configures the context with just a URL + and not an Engine, though an Engine is acceptable + here as well. By skipping the Engine creation + we don't even need a DBAPI to be available. + + Calls to context.execute() here emit the given string to the + script output. + + """ + url = config.get_main_option("sqlalchemy.url") + context.configure( + url=url, target_metadata=target_metadata, literal_binds=True) + + with context.begin_transaction(): + context.run_migrations() + + +def run_migrations_online(): + """Run migrations in 'online' mode. + + In this scenario we need to create an Engine + and associate a connection with the context. + + """ + connectable = engine_from_config( + config.get_section(config.config_ini_section), + prefix='sqlalchemy.', + poolclass=pool.NullPool) + + with connectable.connect() as connection: + context.configure( + connection=connection, + target_metadata=target_metadata + ) + + with context.begin_transaction(): + context.run_migrations() + +if context.is_offline_mode(): + run_migrations_offline() +else: + run_migrations_online() diff --git a/alembic/script.py.mako b/alembic/script.py.mako new file mode 100644 index 00000000..2c015630 --- /dev/null +++ b/alembic/script.py.mako @@ -0,0 +1,24 @@ +"""${message} + +Revision ID: ${up_revision} +Revises: ${down_revision | comma,n} +Create Date: ${create_date} + +""" +from alembic import op +import sqlalchemy as sa +${imports if imports else ""} + +# revision identifiers, used by Alembic. +revision = ${repr(up_revision)} +down_revision = ${repr(down_revision)} +branch_labels = ${repr(branch_labels)} +depends_on = ${repr(depends_on)} + + +def upgrade(): + ${upgrades if upgrades else "pass"} + + +def downgrade(): + ${downgrades if downgrades else "pass"} diff --git a/alembic/versions/b5b17d465166_requests.py b/alembic/versions/b5b17d465166_requests.py new file mode 100644 index 00000000..dd701f9c --- /dev/null +++ b/alembic/versions/b5b17d465166_requests.py @@ -0,0 +1,44 @@ +"""requests + +Revision ID: b5b17d465166 +Revises: ff1c9c02fa61 +Create Date: 2018-07-23 14:58:05.044456 + +""" +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision = 'b5b17d465166' +down_revision = 'ff1c9c02fa61' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('requests', + sa.Column('id', postgresql.UUID(as_uuid=True), server_default=sa.text('uuid_generate_v4()'), nullable=False), + sa.Column('creator', postgresql.UUID(as_uuid=True), nullable=True), + sa.Column('time_created', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=True), + sa.Column('body', postgresql.JSONB(astext_type=sa.Text()), nullable=True), + sa.PrimaryKeyConstraint('id') + ) + op.create_table('request_status_events', + sa.Column('id', postgresql.UUID(as_uuid=True), server_default=sa.text('uuid_generate_v4()'), nullable=False), + sa.Column('new_status', sa.String(), nullable=True), + sa.Column('time_created', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=True), + sa.Column('request_id', postgresql.UUID(as_uuid=True), nullable=True), + sa.Column('sequence', sa.BigInteger(), nullable=False), + sa.ForeignKeyConstraint(['request_id'], ['requests.id'], ondelete='CASCADE'), + sa.PrimaryKeyConstraint('id') + ) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('request_status_events') + op.drop_table('requests') + # ### end Alembic commands ### diff --git a/alembic/versions/ff1c9c02fa61_enable_uuid_extension.py b/alembic/versions/ff1c9c02fa61_enable_uuid_extension.py new file mode 100644 index 00000000..a6f6206a --- /dev/null +++ b/alembic/versions/ff1c9c02fa61_enable_uuid_extension.py @@ -0,0 +1,26 @@ +"""enable uuid extension + +Revision ID: ff1c9c02fa61 +Revises: +Create Date: 2018-07-23 14:54:05.422286 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'ff1c9c02fa61' +down_revision = None +branch_labels = None +depends_on = None + + +def upgrade(): + connection = op.get_bind() + connection.execute('CREATE EXTENSION IF NOT EXISTS "uuid-ossp"') + + +def downgrade(): + connection = op.get_bind() + connection.execute('DROP EXTENSION IF EXISTS "uuid-ossp"') diff --git a/atst/database.py b/atst/database.py new file mode 100644 index 00000000..6191f62e --- /dev/null +++ b/atst/database.py @@ -0,0 +1,8 @@ +from sqlalchemy import create_engine +from sqlalchemy.orm import sessionmaker, scoped_session + + +def make_db(config): + engine = create_engine(config['default']['DATABASE_URI']) + session = scoped_session(sessionmaker(bind=engine)) + return session diff --git a/atst/models/__init__.py b/atst/models/__init__.py index e69de29b..ef5d9457 100644 --- a/atst/models/__init__.py +++ b/atst/models/__init__.py @@ -0,0 +1,6 @@ +from sqlalchemy.ext.declarative import declarative_base + +Base = declarative_base() + +from .request import Request +from .request_status_event import RequestStatusEvent diff --git a/atst/models/request.py b/atst/models/request.py index 5762e857..baaa92b3 100644 --- a/atst/models/request.py +++ b/atst/models/request.py @@ -3,8 +3,8 @@ from sqlalchemy.types import DateTime from sqlalchemy.dialects.postgresql import JSONB, UUID from sqlalchemy.orm import relationship -from requests_queue.models import Base -from requests_queue.models.types import Id +from atst.models import Base +from atst.models.types import Id class Request(Base): diff --git a/atst/models/status_event.py b/atst/models/request_status_event.py similarity index 63% rename from atst/models/status_event.py rename to atst/models/request_status_event.py index c5c5c715..d7c363cd 100644 --- a/atst/models/status_event.py +++ b/atst/models/request_status_event.py @@ -3,15 +3,15 @@ from sqlalchemy.types import DateTime, String, BigInteger from sqlalchemy.schema import Sequence from sqlalchemy.dialects.postgresql import UUID -from requests_queue.models import Base -from requests_queue.models.types import Id +from atst.models import Base +from atst.models.types import Id -class StatusEvent(Base): - __tablename__ = 'status_events' +class RequestStatusEvent(Base): + __tablename__ = 'request_status_events' id = Id() new_status = Column(String()) time_created = Column(DateTime(timezone=True), server_default=func.now()) request_id = Column(UUID(as_uuid=True), ForeignKey('requests.id', ondelete='CASCADE')) - sequence = Column(BigInteger, Sequence('status_events_sequence_seq'), nullable=False) + sequence = Column(BigInteger, Sequence('request_status_events_sequence_seq'), nullable=False) diff --git a/config/base.ini b/config/base.ini index 431eacf7..8b6e68a2 100644 --- a/config/base.ini +++ b/config/base.ini @@ -11,3 +11,4 @@ CAC_URL = https://localhost:8001 REQUESTS_QUEUE_BASE_URL = http://localhost:8003 REDIS_URI = redis://localhost:6379 SESSION_TTL_SECONDS = 600 +DATABASE_URI = postgres://postgres:postgres@localhost/atat From 5f7720deeede3a1213b69b98fc46a36d9a10de93 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Mon, 23 Jul 2018 15:23:09 -0400 Subject: [PATCH 181/332] Requests page working --- alembic/versions/b5b17d465166_requests.py | 3 + atst/app.py | 4 +- atst/domain/__init__.py | 0 atst/domain/exceptions.py | 16 +++ atst/domain/requests.py | 130 ++++++++++++++++++++++ atst/handlers/request.py | 20 ++-- atst/models/request.py | 4 +- 7 files changed, 164 insertions(+), 13 deletions(-) create mode 100644 atst/domain/__init__.py create mode 100644 atst/domain/exceptions.py create mode 100644 atst/domain/requests.py diff --git a/alembic/versions/b5b17d465166_requests.py b/alembic/versions/b5b17d465166_requests.py index dd701f9c..b8d47c06 100644 --- a/alembic/versions/b5b17d465166_requests.py +++ b/alembic/versions/b5b17d465166_requests.py @@ -36,6 +36,9 @@ def upgrade(): ) # ### end Alembic commands ### + db = op.get_bind() + db.execute("CREATE SEQUENCE request_status_events_sequence_seq OWNED BY request_status_events.sequence;") + def downgrade(): # ### commands auto generated by Alembic - please adjust! ### diff --git a/atst/app.py b/atst/app.py index aa101838..058a3046 100644 --- a/atst/app.py +++ b/atst/app.py @@ -20,6 +20,7 @@ from atst.api_client import ApiClient from atst.sessions import RedisSessions from atst import ui_modules from atst import ui_methods +from atst.database import make_db ENV = os.getenv("TORNADO_ENV", "dev") @@ -55,7 +56,7 @@ def make_app(config, deps, **kwargs): url( r"/requests", Request, - {"page": "requests", "requests_client": deps["requests_client"]}, + {"page": "requests", "db_session": deps["db_session"]}, name="requests", ), url( @@ -160,6 +161,7 @@ def make_deps(config): ) return { + "db_session": make_db(config), "authz_client": ApiClient( config["default"]["AUTHZ_BASE_URL"], api_version="v1", diff --git a/atst/domain/__init__.py b/atst/domain/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/atst/domain/exceptions.py b/atst/domain/exceptions.py new file mode 100644 index 00000000..802997d4 --- /dev/null +++ b/atst/domain/exceptions.py @@ -0,0 +1,16 @@ +class NotFoundError(Exception): + def __init__(self, resource_name): + self.resource_name = resource_name + + @property + def message(self): + return "No {} could be found.".format(self.resource_name) + + +class AlreadyExistsError(Exception): + def __init__(self, resource_name): + self.resource_name = resource_name + + @property + def message(self): + return "{} already exists".format(self.resource_name) diff --git a/atst/domain/requests.py b/atst/domain/requests.py new file mode 100644 index 00000000..09acb0af --- /dev/null +++ b/atst/domain/requests.py @@ -0,0 +1,130 @@ +import tornado.gen +from sqlalchemy import exists, and_ +from sqlalchemy.orm.exc import NoResultFound +from sqlalchemy.orm.attributes import flag_modified + +from atst.models import Request, RequestStatusEvent +from .exceptions import NotFoundError + + +def deep_merge(source, destination: dict): + """ + Merge source dict into destination dict recursively. + """ + + def _deep_merge(a, b): + for key, value in a.items(): + if isinstance(value, dict): + node = b.setdefault(key, {}) + _deep_merge(value, node) + else: + b[key] = value + + return b + + return _deep_merge(source, dict(destination)) + + +class Requests(object): + AUTO_APPROVE_THRESHOLD = 1000000 + + def __init__(self, db_session): + self.db_session = db_session + + def create(self, creator_id, body): + request = Request(creator=creator_id, body=body) + + status_event = RequestStatusEvent(new_status="incomplete") + request.status_events.append(status_event) + + self.db_session.add(request) + self.db_session.commit() + + return request + + def exists(self, request_id, creator_id): + return self.db_session.query( + exists().where( + and_(Request.id == request_id, Request.creator == creator_id) + ) + ).scalar() + + def get(self, request_id): + try: + request = self.db_session.query(Request).filter_by(id=request_id).one() + except NoResultFound: + raise NotFoundError("request") + + return request + + def get_many(self, creator_id=None): + filters = [] + if creator_id: + filters.append(Request.creator == creator_id) + + requests = ( + self.db_session.query(Request) + .filter(*filters) + .order_by(Request.time_created.desc()) + .all() + ) + return requests + + @tornado.gen.coroutine + def submit(self, request): + request.status_events.append(StatusEvent(new_status="submitted")) + + if Requests.should_auto_approve(request): + request.status_events.append(StatusEvent(new_status="approved")) + + self.db_session.add(request) + self.db_session.commit() + + return request + + @tornado.gen.coroutine + def update(self, request_id, request_delta): + try: + # Query for request matching id, acquiring a row-level write lock. + # https://www.postgresql.org/docs/10/static/sql-select.html#SQL-FOR-UPDATE-SHARE + request = ( + self.db_session.query(Request) + .filter_by(id=request_id) + .with_for_update(of=Request) + .one() + ) + except NoResultFound: + return + + request.body = deep_merge(request_delta, request.body) + + if Requests.should_allow_submission(request): + request.status_events.append(StatusEvent(new_status="pending_submission")) + + # Without this, sqlalchemy won't notice the change to request.body, + # since it doesn't track dictionary mutations by default. + flag_modified(request, "body") + + self.db_session.add(request) + self.db_session.commit() + + @classmethod + def should_auto_approve(cls, request): + try: + dollar_value = request.body["details_of_use"]["dollar_value"] + except KeyError: + return False + + return dollar_value < cls.AUTO_APPROVE_THRESHOLD + + @classmethod + def should_allow_submission(cls, request): + all_request_sections = [ + "details_of_use", + "information_about_you", + "primary_poc", + ] + existing_request_sections = request.body.keys() + return request.status == "incomplete" and all( + section in existing_request_sections for section in all_request_sections + ) diff --git a/atst/handlers/request.py b/atst/handlers/request.py index d9bec160..1373280a 100644 --- a/atst/handlers/request.py +++ b/atst/handlers/request.py @@ -2,16 +2,17 @@ import tornado import pendulum from atst.handler import BaseHandler +from atst.domain.requests import Requests def map_request(user, request): - time_created = pendulum.parse(request["time_created"]) + time_created = pendulum.instance(request.time_created) is_new = time_created.add(days=1) > pendulum.now() return { - "order_id": request["id"], + "order_id": request.id, "is_new": is_new, - "status": request["status"], + "status": request.status, "app_count": 1, "date": time_created.format("M/DD/YYYY"), "full_name": "{} {}".format(user["first_name"], user["last_name"]), @@ -19,9 +20,9 @@ def map_request(user, request): class Request(BaseHandler): - def initialize(self, page, requests_client): + def initialize(self, page, db_session): self.page = page - self.requests_client = requests_client + self.requests = Requests(db_session) @tornado.web.authenticated @tornado.gen.coroutine @@ -33,11 +34,10 @@ class Request(BaseHandler): @tornado.gen.coroutine def fetch_requests(self, user): + requests = [] if "review_and_approve_jedi_workspace_request" in user["atat_permissions"]: - response = yield self.requests_client.get("/requests") + requests = self.requests.get_many() else: - response = yield self.requests_client.get( - "/requests?creator_id={}".format(user["id"]) - ) + requests = self.requests.get_many(creator_id=user["id"]) - return response.json["requests"] + return requests diff --git a/atst/models/request.py b/atst/models/request.py index baaa92b3..42bec6ed 100644 --- a/atst/models/request.py +++ b/atst/models/request.py @@ -14,9 +14,9 @@ class Request(Base): creator = Column(UUID(as_uuid=True)) time_created = Column(DateTime(timezone=True), server_default=func.now()) body = Column(JSONB) - status_events = relationship('StatusEvent', + status_events = relationship('RequestStatusEvent', backref='request', - order_by='StatusEvent.sequence') + order_by='RequestStatusEvent.sequence') @property def status(self): From 6444453ca0e99058f89197c36dd00b6b1f7b7fdd Mon Sep 17 00:00:00 2001 From: richard-dds Date: Mon, 23 Jul 2018 15:58:57 -0400 Subject: [PATCH 182/332] Fix request_new --- atst/app.py | 6 +-- atst/domain/requests.py | 6 +-- atst/handlers/request_new.py | 83 ++++++++++++++++-------------------- 3 files changed, 42 insertions(+), 53 deletions(-) diff --git a/atst/app.py b/atst/app.py index 058a3046..64e87e56 100644 --- a/atst/app.py +++ b/atst/app.py @@ -64,7 +64,7 @@ def make_app(config, deps, **kwargs): RequestNew, { "page": "requests_new", - "requests_client": deps["requests_client"], + "db_session": deps["db_session"], "fundz_client": deps["fundz_client"], }, name="request_new", @@ -74,7 +74,7 @@ def make_app(config, deps, **kwargs): RequestNew, { "page": "requests_new", - "requests_client": deps["requests_client"], + "db_session": deps["db_session"], "fundz_client": deps["fundz_client"], }, name="request_form_new", @@ -84,7 +84,7 @@ def make_app(config, deps, **kwargs): RequestNew, { "page": "requests_new", - "requests_client": deps["requests_client"], + "db_session": deps["db_session"], "fundz_client": deps["fundz_client"], }, name="request_form_update", diff --git a/atst/domain/requests.py b/atst/domain/requests.py index 09acb0af..aa37b932 100644 --- a/atst/domain/requests.py +++ b/atst/domain/requests.py @@ -72,10 +72,10 @@ class Requests(object): @tornado.gen.coroutine def submit(self, request): - request.status_events.append(StatusEvent(new_status="submitted")) + request.status_events.append(RequestStatusEvent(new_status="submitted")) if Requests.should_auto_approve(request): - request.status_events.append(StatusEvent(new_status="approved")) + request.status_events.append(RequestStatusEvent(new_status="approved")) self.db_session.add(request) self.db_session.commit() @@ -99,7 +99,7 @@ class Requests(object): request.body = deep_merge(request_delta, request.body) if Requests.should_allow_submission(request): - request.status_events.append(StatusEvent(new_status="pending_submission")) + request.status_events.append(RequestStatusEvent(new_status="pending_submission")) # Without this, sqlalchemy won't notice the change to request.body, # since it doesn't track dictionary mutations by default. diff --git a/atst/handlers/request_new.py b/atst/handlers/request_new.py index d71c307e..49454874 100644 --- a/atst/handlers/request_new.py +++ b/atst/handlers/request_new.py @@ -9,17 +9,16 @@ from atst.forms.review import ReviewForm class RequestNew(BaseHandler): - def initialize(self, page, requests_client, fundz_client): + def initialize(self, page, db_session, fundz_client): self.page = page - self.requests_client = requests_client + self.requests_repo = Requests(db_session) self.fundz_client = fundz_client - @tornado.gen.coroutine def get_existing_request(self, request_id): if request_id is None: - return {} - request = yield self.requests_client.get("/requests/{}".format(request_id)) - return request.json + return None + request = self.requests_repo.get(request_id) + return request @tornado.web.authenticated @tornado.gen.coroutine @@ -28,9 +27,9 @@ class RequestNew(BaseHandler): screen = int(screen) post_data = self.request.arguments current_user = self.get_current_user() - existing_request = yield self.get_existing_request(request_id) + existing_request = self.get_existing_request(request_id) jedi_flow = JEDIRequestFlow( - self.requests_client, + self.requests_repo, self.fundz_client, screen, post_data=post_data, @@ -50,24 +49,21 @@ class RequestNew(BaseHandler): ) if jedi_flow.validate(): - response = yield jedi_flow.create_or_update_request() - if response.ok: - valid = yield jedi_flow.validate_warnings() - if valid: - if jedi_flow.next_screen > len(jedi_flow.screens): - where = "/requests" - else: - where = self.application.default_router.reverse_url( - "request_form_update", jedi_flow.next_screen, jedi_flow.request_id - ) - self.redirect(where) + request = jedi_flow.create_or_update_request() + valid = yield jedi_flow.validate_warnings() + if valid: + if jedi_flow.next_screen > len(jedi_flow.screens): + where = "/requests" else: - self.render( - "requests/screen-%d.html.to" % int(screen), - **rerender_args + where = self.application.default_router.reverse_url( + "request_form_update", jedi_flow.next_screen, jedi_flow.request_id ) + self.redirect(where) else: - self.set_status(response.code) + self.render( + "requests/screen-%d.html.to" % int(screen), + **rerender_args + ) else: self.render( "requests/screen-%d.html.to" % int(screen), @@ -81,15 +77,10 @@ class RequestNew(BaseHandler): request = None if request_id: - response = yield self.requests_client.get( - "/requests/{}".format(request_id), - raise_error=False, - ) - if response.ok: - request = response.json + request = self.requests_repo.get(request_id) jedi_flow = JEDIRequestFlow( - self.requests_client, self.fundz_client, screen, request, request_id=request_id + self.requests_repo, self.fundz_client, screen, request, request_id=request_id ) self.render( @@ -108,7 +99,7 @@ class RequestNew(BaseHandler): class JEDIRequestFlow(object): def __init__( self, - requests_client, + requests_repo, fundz_client, current_step, request=None, @@ -117,7 +108,7 @@ class JEDIRequestFlow(object): current_user=None, existing_request=None, ): - self.requests_client = requests_client + self.requests_repo = requests_repo self.fundz_client = fundz_client self.current_step = current_step @@ -145,8 +136,13 @@ class JEDIRequestFlow(object): @tornado.gen.coroutine def validate_warnings(self): + existing_request_data = ( + self.existing_request + and self.existing_request.body.get(self.form_section) + ) or None + valid = yield self.form.perform_extra_validation( - self.existing_request.get('body', {}).get(self.form_section), + existing_request_data, self.fundz_client, ) return valid @@ -171,15 +167,15 @@ class JEDIRequestFlow(object): if self.request: if self.form_section == "review_submit": - data = self.request["body"] + data = self.request.body else: - data = self.request["body"].get(self.form_section, {}) + data = self.request.body.get(self.form_section, {}) return defaultdict(lambda: defaultdict(lambda: 'Input required'), data) @property def can_submit(self): - return self.request and self.request["status"] != "incomplete" + return self.request and self.request.status != "incomplete" @property def next_screen(self): @@ -222,19 +218,12 @@ class JEDIRequestFlow(object): }, ] - @tornado.gen.coroutine def create_or_update_request(self): request_data = { - "creator_id": self.current_user["id"], - "request": {self.form_section: self.form.data}, + self.form_section: self.form.data } if self.request_id: - response = yield self.requests_client.patch( - "/requests/{}".format(self.request_id), json=request_data - ) + self.requests_repo.update(self.request_id, request_data) else: - response = yield self.requests_client.post("/requests", json=request_data) - self.request = response.json - self.request_id = self.request["id"] - - return response + request = self.requests_repo.create(self.current_user["id"], request_data) + self.request_id = request.id From 0400e2c864fafa9a9607524f0ac60c87354e762e Mon Sep 17 00:00:00 2001 From: richard-dds Date: Mon, 23 Jul 2018 16:04:06 -0400 Subject: [PATCH 183/332] Update requests_submit --- atst/app.py | 2 +- atst/handlers/request_submit.py | 22 ++++++---------------- 2 files changed, 7 insertions(+), 17 deletions(-) diff --git a/atst/app.py b/atst/app.py index 64e87e56..922b2ca7 100644 --- a/atst/app.py +++ b/atst/app.py @@ -92,7 +92,7 @@ def make_app(config, deps, **kwargs): url( r"/requests/submit/(\S+)", RequestsSubmit, - {"requests_client": deps["requests_client"]}, + {"db_session": deps["db_session"]}, name="requests_submit", ), # Dummy request/approval screen diff --git a/atst/handlers/request_submit.py b/atst/handlers/request_submit.py index f4d19b3d..ff27803b 100644 --- a/atst/handlers/request_submit.py +++ b/atst/handlers/request_submit.py @@ -1,29 +1,19 @@ import tornado from atst.handler import BaseHandler +from atst.domain.requests import Requests class RequestsSubmit(BaseHandler): - def initialize(self, requests_client): - self.requests_client = requests_client + def initialize(self, db_session): + self.requests_repo = Requests(db_session) @tornado.web.authenticated @tornado.gen.coroutine def post(self, request_id): - yield self.requests_client.post( - "/requests/{}/submit".format(request_id), - allow_nonstandard_methods=True - ) - approved = yield self._check_approved(request_id) - if approved: + request = self.requests_repo.get(request_id) + request = yield self.requests_repo.submit(request) + if request.status == "approved": self.redirect("/requests?modal=True") else: self.redirect("/requests") - - @tornado.gen.coroutine - def _check_approved(self, request_id): - response = yield self.requests_client.get( - "/requests/{}".format(request_id) - ) - status = response.json.get("status") - return status == "approved" From fadbf1cfb14fcab495ab625e6236ee50f55a36a2 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Mon, 23 Jul 2018 16:19:12 -0400 Subject: [PATCH 184/332] Add request domain tests and factories --- tests/conftest.py | 25 +++++++++++++++- tests/domain/__init__.py | 0 tests/domain/test_requests.py | 55 +++++++++++++++++++++++++++++++++++ tests/factories.py | 11 +++++++ 4 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 tests/domain/__init__.py create mode 100644 tests/domain/test_requests.py create mode 100644 tests/factories.py diff --git a/tests/conftest.py b/tests/conftest.py index c650b5f1..baafaeda 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,18 +1,21 @@ import pytest +from sqlalchemy.orm import sessionmaker, scoped_session from atst.app import make_app, make_deps, make_config +from atst.database import make_db from tests.mocks import MockApiClient, MockFundzClient, MockRequestsClient, MockAuthzClient from atst.sessions import DictSessions @pytest.fixture -def app(): +def app(db): TEST_DEPS = { "authz_client": MockAuthzClient("authz"), "requests_client": MockRequestsClient("requests"), "authnid_client": MockApiClient("authnid"), "fundz_client": MockFundzClient("fundz"), "sessions": DictSessions(), + "db_session": db } config = make_config() @@ -21,6 +24,26 @@ def app(): return make_app(config, deps) + +@pytest.fixture(scope='function') +def db(): + + # Override db with a new SQLAlchemy session so that we can rollback + # each test's transaction. + # Inspiration: https://docs.sqlalchemy.org/en/latest/orm/session_transaction.html#session-external-transaction + config = make_config() + database = make_db(config) + connection = database.get_bind().connect() + transaction = connection.begin() + db = scoped_session(sessionmaker(bind=connection)) + + yield db + + db.close() + transaction.rollback() + connection.close() + + class DummyForm(dict): pass diff --git a/tests/domain/__init__.py b/tests/domain/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/domain/test_requests.py b/tests/domain/test_requests.py new file mode 100644 index 00000000..f45d5be2 --- /dev/null +++ b/tests/domain/test_requests.py @@ -0,0 +1,55 @@ +import pytest +from uuid import uuid4 + +from atst.domain.exceptions import NotFoundError +from atst.domain.requests import Requests + +from tests.factories import RequestFactory + + +@pytest.fixture() +def requests(db): + return Requests(db) + +@pytest.fixture(scope="function") +def new_request(db): + created_request = RequestFactory.create() + db.add(created_request) + db.commit() + + return created_request + + +def test_can_get_request(requests, new_request): + request = requests.get(new_request.id) + + assert request.id == new_request.id + + +def test_nonexistent_request_raises(requests): + with pytest.raises(NotFoundError): + requests.get(uuid4()) + + +@pytest.mark.gen_test +def test_auto_approve_less_than_1m(requests, new_request): + new_request.body = {"details_of_use": {"dollar_value": 999999}} + request = yield requests.submit(new_request) + + assert request.status == 'approved' + + +@pytest.mark.gen_test +def test_dont_auto_approve_if_dollar_value_is_1m_or_above(requests, new_request): + new_request.body = {"details_of_use": {"dollar_value": 1000000}} + request = yield requests.submit(new_request) + + assert request.status == 'submitted' + + +@pytest.mark.gen_test +def test_dont_auto_approve_if_no_dollar_value_specified(requests, new_request): + new_request.body = {"details_of_use": {}} + request = yield requests.submit(new_request) + + assert request.status == 'submitted' diff --git a/tests/factories.py b/tests/factories.py new file mode 100644 index 00000000..b07b36fa --- /dev/null +++ b/tests/factories.py @@ -0,0 +1,11 @@ +import factory +from uuid import uuid4 + +from atst.models import Request, RequestStatusEvent + + +class RequestFactory(factory.Factory): + class Meta: + model = Request + + id = factory.Sequence(lambda x: uuid4()) From 373463bf37f6fc377b74f42f73a2a541ea6559c2 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Mon, 23 Jul 2018 16:44:39 -0400 Subject: [PATCH 185/332] update tests, remove MockRequestsClient --- tests/conftest.py | 3 +-- tests/handlers/test_request_new.py | 9 +++++++++ tests/mocks.py | 23 ----------------------- 3 files changed, 10 insertions(+), 25 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index baafaeda..a0ed8550 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -3,7 +3,7 @@ from sqlalchemy.orm import sessionmaker, scoped_session from atst.app import make_app, make_deps, make_config from atst.database import make_db -from tests.mocks import MockApiClient, MockFundzClient, MockRequestsClient, MockAuthzClient +from tests.mocks import MockApiClient, MockFundzClient, MockAuthzClient from atst.sessions import DictSessions @@ -11,7 +11,6 @@ from atst.sessions import DictSessions def app(db): TEST_DEPS = { "authz_client": MockAuthzClient("authz"), - "requests_client": MockRequestsClient("requests"), "authnid_client": MockApiClient("authnid"), "fundz_client": MockFundzClient("fundz"), "sessions": DictSessions(), diff --git a/tests/handlers/test_request_new.py b/tests/handlers/test_request_new.py index dfa57cab..8409fc13 100644 --- a/tests/handlers/test_request_new.py +++ b/tests/handlers/test_request_new.py @@ -3,8 +3,17 @@ import pytest import tornado import urllib from tests.mocks import MOCK_USER +from tests.factories import RequestFactory ERROR_CLASS = "alert--error" +MOCK_REQUEST = RequestFactory.create( + creator=MOCK_USER["id"], + body={ + "financial_verification": { + "pe_id": "0203752A", + }, + } +) @pytest.mark.gen_test def test_submit_invalid_request_form(monkeypatch, http_client, base_url): diff --git a/tests/mocks.py b/tests/mocks.py index a7290a03..105824f7 100644 --- a/tests/mocks.py +++ b/tests/mocks.py @@ -51,31 +51,8 @@ class MockApiClient(ApiClient): return response -MOCK_REQUEST = { - "id": "66b8ef71-86d3-48ef-abc2-51bfa1732b6b", - "creator": "49903ae7-da4a-49bf-a6dc-9dff5d004238", - "body": { - "financial_verification": { - "pe_id": "0203752A", - }, - }, - "status": "incomplete" -} - -class MockRequestsClient(MockApiClient): - - @tornado.gen.coroutine - def get(self, path, **kwargs): - return self._get_response("GET", path, 200, json=MOCK_REQUEST) - - @tornado.gen.coroutine - def post(self, path, **kwargs): - return self._get_response("POST", path, 202, json=MOCK_REQUEST) - - MOCK_VALID_PE_ID = "8675309U" - class MockFundzClient(MockApiClient): @tornado.gen.coroutine From 5f2ffe57b8da5d3611d7901751d61f79b724f34c Mon Sep 17 00:00:00 2001 From: dandds Date: Fri, 27 Jul 2018 14:57:59 -0400 Subject: [PATCH 186/332] update submodule --- script/include | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/include b/script/include index 7417942f..8597f54c 160000 --- a/script/include +++ b/script/include @@ -1 +1 @@ -Subproject commit 7417942f1614d6a7ad94e94d1621dca9b422dec2 +Subproject commit 8597f54c69dc1eb04c53a2fc487ebd7f8c8e648f From 0179a228271f1364a339bc234b5a8c3be3acb926 Mon Sep 17 00:00:00 2001 From: dandds Date: Fri, 27 Jul 2018 15:15:44 -0400 Subject: [PATCH 187/332] update and fix some tests from rebase --- atst/handlers/request_new.py | 1 + script/update | 7 +++-- tests/handlers/test_financial_verification.py | 2 +- tests/handlers/test_request_new.py | 1 - tests/handlers/test_request_submit.py | 30 ++++++++++++------- tests/mocks.py | 9 ++++++ 6 files changed, 35 insertions(+), 15 deletions(-) diff --git a/atst/handlers/request_new.py b/atst/handlers/request_new.py index 49454874..e43e6ab3 100644 --- a/atst/handlers/request_new.py +++ b/atst/handlers/request_new.py @@ -6,6 +6,7 @@ from atst.forms.request import RequestForm from atst.forms.org import OrgForm from atst.forms.poc import POCForm from atst.forms.review import ReviewForm +from atst.domain.requests import Requests class RequestNew(BaseHandler): diff --git a/script/update b/script/update index 8cb772c1..1baef9a8 100755 --- a/script/update +++ b/script/update @@ -4,5 +4,8 @@ source "$(dirname "${0}")"/../script/include/global_header.inc.sh -# Run the bootstrap script -source ./script/bootstrap +# Enable DB migration +MIGRATE_DB="true" + +# Run the shared update script +source ./script/include/run_update diff --git a/tests/handlers/test_financial_verification.py b/tests/handlers/test_financial_verification.py index 6e60bb4e..234c8d57 100644 --- a/tests/handlers/test_financial_verification.py +++ b/tests/handlers/test_financial_verification.py @@ -40,7 +40,7 @@ class TestPENumberInForm: @tornado.gen.coroutine def submit_data(self, http_client, base_url, data): response = yield http_client.fetch( - base_url + "/requests/verify/{}".format(MOCK_REQUEST["id"]), + base_url + "/requests/verify/{}".format(MOCK_REQUEST.id), method="POST", headers={"Content-Type": "application/x-www-form-urlencoded"}, body=urllib.parse.urlencode(data), diff --git a/tests/handlers/test_request_new.py b/tests/handlers/test_request_new.py index 8409fc13..3373c867 100644 --- a/tests/handlers/test_request_new.py +++ b/tests/handlers/test_request_new.py @@ -3,7 +3,6 @@ import pytest import tornado import urllib from tests.mocks import MOCK_USER -from tests.factories import RequestFactory ERROR_CLASS = "alert--error" MOCK_REQUEST = RequestFactory.create( diff --git a/tests/handlers/test_request_submit.py b/tests/handlers/test_request_submit.py index 0f60c1a1..635ff157 100644 --- a/tests/handlers/test_request_submit.py +++ b/tests/handlers/test_request_submit.py @@ -1,19 +1,26 @@ import pytest +import tornado from tests.mocks import MOCK_USER +from tests.factories import RequestFactory + + +@tornado.gen.coroutine +def _mock_func(*args, **kwargs): + return RequestFactory.create() -ERROR_CLASS = "usa-input-error-message" -APPROVED_MOCK_REQUEST = { - "status": "approved" -} @pytest.mark.gen_test def test_submit_reviewed_request(monkeypatch, http_client, base_url): monkeypatch.setattr( - "atst.handlers.request_submit.RequestsSubmit.get_current_user", lambda s: MOCK_USER + "atst.handlers.request_submit.RequestsSubmit.get_current_user", + lambda s: MOCK_USER, ) monkeypatch.setattr( "atst.handlers.request_submit.RequestsSubmit.check_xsrf_cookie", lambda s: True ) + monkeypatch.setattr("atst.domain.requests.Requests.get", _mock_func) + monkeypatch.setattr("atst.domain.requests.Requests.submit", _mock_func) + monkeypatch.setattr("atst.models.request.Request.status", "pending") # this just needs to send a known invalid form value response = yield http_client.fetch( base_url + "/requests/submit/1", @@ -21,7 +28,7 @@ def test_submit_reviewed_request(monkeypatch, http_client, base_url): headers={"Content-Type": "application/x-www-form-urlencoded"}, body="", raise_error=False, - follow_redirects=False + follow_redirects=False, ) assert response.headers["Location"] == "/requests" @@ -29,14 +36,15 @@ def test_submit_reviewed_request(monkeypatch, http_client, base_url): @pytest.mark.gen_test def test_submit_autoapproved_reviewed_request(monkeypatch, http_client, base_url): monkeypatch.setattr( - "atst.handlers.request_submit.RequestsSubmit.get_current_user", lambda s: MOCK_USER + "atst.handlers.request_submit.RequestsSubmit.get_current_user", + lambda s: MOCK_USER, ) monkeypatch.setattr( "atst.handlers.request_submit.RequestsSubmit.check_xsrf_cookie", lambda s: True ) - monkeypatch.setattr( - "tests.mocks.MOCK_REQUEST", APPROVED_MOCK_REQUEST - ) + monkeypatch.setattr("atst.domain.requests.Requests.get", _mock_func) + monkeypatch.setattr("atst.domain.requests.Requests.submit", _mock_func) + monkeypatch.setattr("atst.models.request.Request.status", "approved") # this just needs to send a known invalid form value response = yield http_client.fetch( base_url + "/requests/submit/1", @@ -44,6 +52,6 @@ def test_submit_autoapproved_reviewed_request(monkeypatch, http_client, base_url headers={"Content-Type": "application/x-www-form-urlencoded"}, body="", raise_error=False, - follow_redirects=False + follow_redirects=False, ) assert response.headers["Location"] == "/requests?modal=True" diff --git a/tests/mocks.py b/tests/mocks.py index 105824f7..96c22e4a 100644 --- a/tests/mocks.py +++ b/tests/mocks.py @@ -2,6 +2,7 @@ import tornado.gen from tornado.httpclient import HTTPRequest, HTTPResponse from atst.api_client import ApiClient +from tests.factories import RequestFactory MOCK_USER = { @@ -10,6 +11,14 @@ MOCK_USER = { "first_name": "Fake", "last_name": "User", } +MOCK_REQUEST = RequestFactory.create( + creator=MOCK_USER["id"], + body={ + "financial_verification": { + "pe_id": "0203752A", + }, + } +) class MockApiClient(ApiClient): From 54f2a0dce0b8406823930ab9ac56a12c166d2329 Mon Sep 17 00:00:00 2001 From: dandds Date: Fri, 27 Jul 2018 15:27:50 -0400 Subject: [PATCH 188/332] update financial verification to use requests repo --- atst/app.py | 2 +- .../request_financial_verification.py | 49 ++++++++----------- tests/handlers/test_financial_verification.py | 3 +- 3 files changed, 23 insertions(+), 31 deletions(-) diff --git a/atst/app.py b/atst/app.py index 922b2ca7..c56ea250 100644 --- a/atst/app.py +++ b/atst/app.py @@ -107,7 +107,7 @@ def make_app(config, deps, **kwargs): RequestFinancialVerification, { "page": "financial_verification", - "requests_client": deps["requests_client"], + "db_session": deps["db_session"], "fundz_client": deps["fundz_client"], }, name="financial_verification", diff --git a/atst/handlers/request_financial_verification.py b/atst/handlers/request_financial_verification.py index 4c81f9d7..a063692c 100644 --- a/atst/handlers/request_financial_verification.py +++ b/atst/handlers/request_financial_verification.py @@ -2,26 +2,23 @@ import tornado from atst.handler import BaseHandler from atst.forms.financial import FinancialForm +from atst.domain.requests import Requests class RequestFinancialVerification(BaseHandler): - def initialize(self, page, requests_client, fundz_client): + def initialize(self, page, db_session, fundz_client): self.page = page - self.requests_client = requests_client + self.requests_repo = Requests(db_session) self.fundz_client = fundz_client - @tornado.gen.coroutine def get_existing_request(self, request_id): - if request_id is None: - return {} - request = yield self.requests_client.get("/requests/{}".format(request_id)) - return request.json + return self.requests_repo.get(request_id) @tornado.web.authenticated @tornado.gen.coroutine def get(self, request_id=None): - existing_request = yield self.get_existing_request(request_id) - form = FinancialForm(data=existing_request['body'].get('financial_verification')) + existing_request = self.get_existing_request(request_id) + form = FinancialForm(data=existing_request.body.get('financial_verification')) self.render( "requests/financial_verification.html.to", page=self.page, @@ -35,39 +32,33 @@ class RequestFinancialVerification(BaseHandler): "creator_id": self.current_user["id"], "request": {"financial_verification": form_data}, } - response = yield self.requests_client.patch( - "/requests/{}".format(request_id), json=request_data - ) - return response + return self.requests_repo.update(request_id, request_data) @tornado.web.authenticated @tornado.gen.coroutine def post(self, request_id=None): self.check_xsrf_cookie() post_data = self.request.arguments - existing_request = yield self.get_existing_request(request_id) + existing_request = self.get_existing_request(request_id) form = FinancialForm(post_data) rerender_args = dict(request_id=request_id, f=form) if form.validate(): - response = yield self.update_request(request_id, form.data) - if response.ok: - valid = yield form.perform_extra_validation( - existing_request.get('body', {}).get('financial_verification'), - self.fundz_client + yield self.update_request(request_id, form.data) + valid = yield form.perform_extra_validation( + existing_request.body.get('financial_verification'), + self.fundz_client + ) + if valid: + self.redirect( + self.application.default_router.reverse_url("financial_verification_submitted") ) - if valid: - self.redirect( - self.application.default_router.reverse_url("financial_verification_submitted") - ) - else: - self.render( - "requests/financial_verification.html.to", - **rerender_args - ) else: - self.set_status(response.code) + self.render( + "requests/financial_verification.html.to", + **rerender_args + ) else: self.render( "requests/financial_verification.html.to", diff --git a/tests/handlers/test_financial_verification.py b/tests/handlers/test_financial_verification.py index 234c8d57..57b8851d 100644 --- a/tests/handlers/test_financial_verification.py +++ b/tests/handlers/test_financial_verification.py @@ -36,6 +36,7 @@ class TestPENumberInForm: "atst.handlers.request_financial_verification.RequestFinancialVerification.check_xsrf_cookie", lambda s: True ) monkeypatch.setattr("atst.forms.request.RequestForm.validate", lambda s: True) + monkeypatch.setattr("atst.domain.requests.Requests.get", lambda s, i: MOCK_REQUEST) @tornado.gen.coroutine def submit_data(self, http_client, base_url, data): @@ -64,7 +65,7 @@ class TestPENumberInForm: self._set_monkeypatches(monkeypatch) data = dict(self.required_data) - data['pe_id'] = MOCK_REQUEST['body']['financial_verification']['pe_id'] + data['pe_id'] = MOCK_REQUEST.body['financial_verification']['pe_id'] response = yield self.submit_data(http_client, base_url, data) From 3bd1efcd03d558e261899fdeb91482d9ee6d3f35 Mon Sep 17 00:00:00 2001 From: dandds Date: Mon, 30 Jul 2018 10:15:48 -0400 Subject: [PATCH 189/332] add new config pattern for database URI and overrides --- atst/app.py | 55 ++++++++++++++++++++++++++++++++++++------------- config/base.ini | 6 +++++- 2 files changed, 46 insertions(+), 15 deletions(-) diff --git a/atst/app.py b/atst/app.py index c56ea250..73e144fc 100644 --- a/atst/app.py +++ b/atst/app.py @@ -24,6 +24,7 @@ from atst.database import make_db ENV = os.getenv("TORNADO_ENV", "dev") + def make_app(config, deps, **kwargs): routes = [ @@ -31,16 +32,15 @@ def make_app(config, deps, **kwargs): url( r"/login-redirect", LoginRedirect, - {"sessions": deps["sessions"], "authnid_client": deps["authnid_client"], "authz_client": deps["authz_client"]}, + { + "sessions": deps["sessions"], + "authnid_client": deps["authnid_client"], + "authz_client": deps["authz_client"], + }, name="login_redirect", ), url(r"/home", Main, {"page": "home"}, name="home"), - url( - r"/styleguide", - Main, - {"page": "styleguide"}, - name="styleguide", - ), + url(r"/styleguide", Main, {"page": "styleguide"}, name="styleguide"), url( r"/workspaces/blank", Main, @@ -100,7 +100,7 @@ def make_app(config, deps, **kwargs): r"/request/approval", Main, {"page": "request_approval"}, - name="request_approval" + name="request_approval", ), url( r"/requests/verify/(\S+)", @@ -121,7 +121,9 @@ def make_app(config, deps, **kwargs): url(r"/users", Main, {"page": "users"}, name="users"), url(r"/reports", Main, {"page": "reports"}, name="reports"), url(r"/calculator", Main, {"page": "calculator"}, name="calculator"), - url(r"/workspaces/(\S+)/members", WorkspaceMembers, {}, name="workspace_members"), + url( + r"/workspaces/(\S+)/members", WorkspaceMembers, {}, name="workspace_members" + ), url(r"/workspaces/(\S+)/projects", Workspace, {}, name="workspace_projects"), url(r"/workspaces/123456/projects/789/edit", Main, {"page": "project_edit"}, name="project_edit"), url(r"/workspaces/123456/members/789/edit", Main, {"page": "member_edit"}, name="member_edit"), @@ -132,7 +134,11 @@ def make_app(config, deps, **kwargs): url( r"/login-dev", Dev, - {"action": "login", "sessions": deps["sessions"], "authz_client": deps["authz_client"]}, + { + "action": "login", + "sessions": deps["sessions"], + "authz_client": deps["authz_client"], + }, name="dev-login", ) ] @@ -146,7 +152,7 @@ def make_app(config, deps, **kwargs): debug=config["default"].getboolean("DEBUG"), ui_modules=ui_modules, ui_methods=ui_methods, - **kwargs, + **kwargs ) app.config = config app.sessions = deps["sessions"] @@ -173,8 +179,7 @@ def make_deps(config): validate_cert=validate_cert, ), "fundz_client": ApiClient( - config["default"]["FUNDZ_BASE_URL"], - validate_cert=validate_cert, + config["default"]["FUNDZ_BASE_URL"], validate_cert=validate_cert ), "requests_client": ApiClient( config["default"]["REQUESTS_QUEUE_BASE_URL"], @@ -192,8 +197,30 @@ def make_config(): ENV_CONFIG_FILENAME = os.path.join( os.path.dirname(__file__), "../config/", "{}.ini".format(ENV.lower()) ) + OVERRIDE_CONFIG_FILENAME = os.getenv("OVERRIDE_CONFIG_FULLPATH") + config = ConfigParser() + config_files = [BASE_CONFIG_FILENAME, ENV_CONFIG_FILENAME] + if OVERRIDE_CONFIG_FILENAME: + config_files.append(OVERRIDE_CONFIG_FILENAME) + # ENV_CONFIG will override values in BASE_CONFIG. - config.read([BASE_CONFIG_FILENAME, ENV_CONFIG_FILENAME]) + config.read(config_files) + + # Assemble DATABASE_URI value + database_uri = ( + "postgres://" + + config.get("default", "DATABASE_USERNAME") + + ":" + + config.get("default", "DATABASE_PASSWORD") + + "@" + + config.get("default", "DATABASE_HOST") + + ":" + + config.get("default", "DATABASE_PORT") + + "/" + + config.get("default", "DATABASE_NAME") + ) + config.set("default", "DATABASE_URI", database_uri) + return config diff --git a/config/base.ini b/config/base.ini index 8b6e68a2..92f40d5a 100644 --- a/config/base.ini +++ b/config/base.ini @@ -11,4 +11,8 @@ CAC_URL = https://localhost:8001 REQUESTS_QUEUE_BASE_URL = http://localhost:8003 REDIS_URI = redis://localhost:6379 SESSION_TTL_SECONDS = 600 -DATABASE_URI = postgres://postgres:postgres@localhost/atat +DATABASE_HOST = localhost +DATABASE_PORT = 5432 +DATABASE_USERNAME = postgres +DATABASE_PASSWORD = postgres +DATABASE_NAME = atat From b5055c8ce899c59a0179001b21661fc557b5c06c Mon Sep 17 00:00:00 2001 From: Devon Mackay Date: Mon, 30 Jul 2018 15:50:50 -0400 Subject: [PATCH 190/332] Change db vars to standard postgres equivalents --- atst/app.py | 10 +++++----- config/base.ini | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/atst/app.py b/atst/app.py index 73e144fc..efc649b3 100644 --- a/atst/app.py +++ b/atst/app.py @@ -211,15 +211,15 @@ def make_config(): # Assemble DATABASE_URI value database_uri = ( "postgres://" - + config.get("default", "DATABASE_USERNAME") + + config.get("default", "PGUSER") + ":" - + config.get("default", "DATABASE_PASSWORD") + + config.get("default", "PGPASSWORD") + "@" - + config.get("default", "DATABASE_HOST") + + config.get("default", "PGHOST") + ":" - + config.get("default", "DATABASE_PORT") + + config.get("default", "PGPORT") + "/" - + config.get("default", "DATABASE_NAME") + + config.get("default", "PGDATABASE") ) config.set("default", "DATABASE_URI", database_uri) diff --git a/config/base.ini b/config/base.ini index 92f40d5a..6e6af123 100644 --- a/config/base.ini +++ b/config/base.ini @@ -11,8 +11,8 @@ CAC_URL = https://localhost:8001 REQUESTS_QUEUE_BASE_URL = http://localhost:8003 REDIS_URI = redis://localhost:6379 SESSION_TTL_SECONDS = 600 -DATABASE_HOST = localhost -DATABASE_PORT = 5432 -DATABASE_USERNAME = postgres -DATABASE_PASSWORD = postgres -DATABASE_NAME = atat +PGHOST = localhost +PGPORT = 5432 +PGUSER = postgres +PGPASSWORD = postgres +PGDATABASE = atat From 6e9d8f92c4e392fcf5ac3de9a543b1c691693260 Mon Sep 17 00:00:00 2001 From: Devon Mackay Date: Mon, 30 Jul 2018 15:51:36 -0400 Subject: [PATCH 191/332] Add wrapper script for settign DB ENV vars --- script/get_db_settings.sh | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100755 script/get_db_settings.sh diff --git a/script/get_db_settings.sh b/script/get_db_settings.sh new file mode 100755 index 00000000..7b30fd7b --- /dev/null +++ b/script/get_db_settings.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +# script/get_db_settings: Fetch postgresql settings and set them as ENV vars + +source "$(dirname "${0}")"/../script/include/global_header.inc.sh + +# Run the shared get_db_settings script +source ./script/include/run_get_sb_settings.sh From 7f09be55912552cf054ea84f59f771e66bc8ff82 Mon Sep 17 00:00:00 2001 From: Devon Mackay Date: Mon, 30 Jul 2018 15:51:55 -0400 Subject: [PATCH 192/332] Switch to scriptz feature branch --- script/include | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/include b/script/include index 8597f54c..cb8cbe46 160000 --- a/script/include +++ b/script/include @@ -1 +1 @@ -Subproject commit 8597f54c69dc1eb04c53a2fc487ebd7f8c8e648f +Subproject commit cb8cbe46d0e8171fcd497e4d22ab719692347562 From d22f85508bdb16c083733080f4b6849587c16828 Mon Sep 17 00:00:00 2001 From: Devon Mackay Date: Mon, 30 Jul 2018 18:22:08 -0400 Subject: [PATCH 193/332] Add postgres hostname used during CI --- config/ci.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/config/ci.ini b/config/ci.ini index e69de29b..0469ae77 100644 --- a/config/ci.ini +++ b/config/ci.ini @@ -0,0 +1,2 @@ +[default] +PGHOST = travishost From 168bee20f8b7efb4050aa780ba9f515b87a39c60 Mon Sep 17 00:00:00 2001 From: Devon Mackay Date: Mon, 30 Jul 2018 18:22:42 -0400 Subject: [PATCH 194/332] Add postgres to ATST build - Add postgres 9.6 service - Add Travis host IP entry to docker container --- .travis.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 02dab0db..0b452ab2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,11 @@ sudo: required language: python python: "3.6" -services: docker +services: + - docker + - postgres +addons: + postgresql: "9.6" git: submodules: false env: @@ -16,8 +20,9 @@ before_install: - git submodule update --init --recursive before_script: + - travis_host_ip="$(/sbin/ip route|awk '/default/ { print $3 }')" - docker login -u $ATAT_DOCKER_REGISTRY_USERNAME -p $ATAT_DOCKER_REGISTRY_PASSWORD $ATAT_DOCKER_REGISTRY_URL - - docker build --tag "${TESTER_IMAGE_NAME}" . -f deploy/docker/tester/Dockerfile + - docker build --tag "${TESTER_IMAGE_NAME}" --add-host "travishost:${travis_host_ip}" . -f deploy/docker/tester/Dockerfile script: - docker run "${TESTER_IMAGE_NAME}" From abb16ec39798c47664c83e45d7f71e3b6712853e Mon Sep 17 00:00:00 2001 From: Devon Mackay Date: Mon, 30 Jul 2018 18:26:53 -0400 Subject: [PATCH 195/332] Add DB info and setup --- script/setup | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/script/setup b/script/setup index 925ced94..5cd11461 100755 --- a/script/setup +++ b/script/setup @@ -8,5 +8,11 @@ source "$(dirname "${0}")"/../script/include/global_header.inc.sh # Turn on sass compiler installation INSTALL_SASS="true" +# Set database name +DATABASE_NAME="atat" + +# Enable database resetting +RESET_DB="true" + # Run the shared setup script source ./script/include/run_setup From 1875dbc9fdfb1b53a096712e086a30ff612a05e9 Mon Sep 17 00:00:00 2001 From: Devon Mackay Date: Mon, 30 Jul 2018 18:31:18 -0400 Subject: [PATCH 196/332] Rename script --- script/{get_db_settings.sh => get_db_settings} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename script/{get_db_settings.sh => get_db_settings} (100%) diff --git a/script/get_db_settings.sh b/script/get_db_settings similarity index 100% rename from script/get_db_settings.sh rename to script/get_db_settings From 9cb5bee363a1e24f7bbbe082f981a1ab00d37deb Mon Sep 17 00:00:00 2001 From: Devon Mackay Date: Mon, 30 Jul 2018 18:41:01 -0400 Subject: [PATCH 197/332] Fix type --- script/get_db_settings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/get_db_settings b/script/get_db_settings index 7b30fd7b..c96970a8 100755 --- a/script/get_db_settings +++ b/script/get_db_settings @@ -5,4 +5,4 @@ source "$(dirname "${0}")"/../script/include/global_header.inc.sh # Run the shared get_db_settings script -source ./script/include/run_get_sb_settings.sh +source ./script/include/run_get_db_settings.sh From a2b893830f9d0b27566a0b58b90013f8d31f1b6c Mon Sep 17 00:00:00 2001 From: Devon Mackay Date: Mon, 30 Jul 2018 19:50:33 -0400 Subject: [PATCH 198/332] Remove blank line --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 6089986f..455d5baa 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,3 @@ - # ATST [![Build Status](https://travis-ci.org/dod-ccpo/atst.svg?branch=master)](https://travis-ci.org/dod-ccpo/atst) From 3dcdcdfb3b39cb976eaaf8ed38ec86d94394466a Mon Sep 17 00:00:00 2001 From: Devon Mackay Date: Mon, 30 Jul 2018 20:02:41 -0400 Subject: [PATCH 199/332] Debug travis ip and psql connect issues --- .travis.yml | 3 +++ script/get_db_settings | 3 +++ script/setup | 3 +++ 3 files changed, 9 insertions(+) diff --git a/.travis.yml b/.travis.yml index 0b452ab2..37b0fa76 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,6 +18,9 @@ before_install: - sed -i 's/git@github.com:/https:\/\/github.com\//' .gitmodules # Manually initialize submodules - git submodule update --init --recursive + - /sbin/ip route|awk '/default/ { print $3 }' + - /sbin/ip addr + - ./foo before_script: - travis_host_ip="$(/sbin/ip route|awk '/default/ { print $3 }')" diff --git a/script/get_db_settings b/script/get_db_settings index c96970a8..2c60ec3c 100755 --- a/script/get_db_settings +++ b/script/get_db_settings @@ -6,3 +6,6 @@ source "$(dirname "${0}")"/../script/include/global_header.inc.sh # Run the shared get_db_settings script source ./script/include/run_get_db_settings.sh + +echo "Postgres settings: " +echo $PGHOST diff --git a/script/setup b/script/setup index 5cd11461..c64ff07a 100755 --- a/script/setup +++ b/script/setup @@ -14,5 +14,8 @@ DATABASE_NAME="atat" # Enable database resetting RESET_DB="true" +echo "Hosts file:" +cat /etc/hosts + # Run the shared setup script source ./script/include/run_setup From 23fbc33f5d00b3dac30ab37616ea6df14c8540e3 Mon Sep 17 00:00:00 2001 From: Devon Mackay Date: Mon, 30 Jul 2018 20:05:50 -0400 Subject: [PATCH 200/332] Debug travis ip and psql connect issues --- .travis.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 37b0fa76..311e93ce 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,15 +14,15 @@ env: - PROD_IMAGE_NAME=atst-prod before_install: - # Use sed to replace the SSH URL with the public URL - - sed -i 's/git@github.com:/https:\/\/github.com\//' .gitmodules - # Manually initialize submodules - - git submodule update --init --recursive - - /sbin/ip route|awk '/default/ { print $3 }' - - /sbin/ip addr - - ./foo + # Use sed to replace the SSH URL with the public URL + - sed -i 's/git@github.com:/https:\/\/github.com\//' .gitmodules + # Manually initialize submodules + - git submodule update --init --recursive + - /sbin/ip route|awk '/default/ { print $3 }' + - /sbin/ip addr before_script: + - netstat -anlp | grep LISTEN | grep tcp - travis_host_ip="$(/sbin/ip route|awk '/default/ { print $3 }')" - docker login -u $ATAT_DOCKER_REGISTRY_USERNAME -p $ATAT_DOCKER_REGISTRY_PASSWORD $ATAT_DOCKER_REGISTRY_URL - docker build --tag "${TESTER_IMAGE_NAME}" --add-host "travishost:${travis_host_ip}" . -f deploy/docker/tester/Dockerfile From f7adeb5af327597dda62271720b03461c96534e8 Mon Sep 17 00:00:00 2001 From: Devon Mackay Date: Mon, 30 Jul 2018 20:19:36 -0400 Subject: [PATCH 201/332] Ensure get_db is sourced so the vars carry over --- script/get_db_settings | 5 ++++- script/include | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/script/get_db_settings b/script/get_db_settings index 2c60ec3c..701c2844 100755 --- a/script/get_db_settings +++ b/script/get_db_settings @@ -7,5 +7,8 @@ source "$(dirname "${0}")"/../script/include/global_header.inc.sh # Run the shared get_db_settings script source ./script/include/run_get_db_settings.sh +echo echo "Postgres settings: " -echo $PGHOST +echo "PGHOST: $PGHOST" +echo "PGDATABASE: $PGDATABASE" +echo diff --git a/script/include b/script/include index cb8cbe46..5c19aef7 160000 --- a/script/include +++ b/script/include @@ -1 +1 @@ -Subproject commit cb8cbe46d0e8171fcd497e4d22ab719692347562 +Subproject commit 5c19aef7482aa0035f2d85e4c30ee21dfd7969c9 From ab3ba06f18643163d3bda841ca60d3df268e1ce8 Mon Sep 17 00:00:00 2001 From: Devon Mackay Date: Mon, 30 Jul 2018 20:25:01 -0400 Subject: [PATCH 202/332] Ensure app env is ci when testing --- deploy/docker/tester/Dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/deploy/docker/tester/Dockerfile b/deploy/docker/tester/Dockerfile index c490c6ec..bfec5729 100644 --- a/deploy/docker/tester/Dockerfile +++ b/deploy/docker/tester/Dockerfile @@ -8,7 +8,9 @@ ARG APP_DIR=/opt/atat/atst ARG CIBUILD=true ENV APP_DIR "${APP_DIR}" +ENV FLASK_ENV ci ENV SKIP_PIPENV true +ENV TORNADO_ENV ci # Use dumb-init for proper signal handling ENTRYPOINT ["/usr/bin/dumb-init", "--"] From c551e02c2ee3db6318b58c6243608fdbdd0a3edb Mon Sep 17 00:00:00 2001 From: Devon Mackay Date: Mon, 30 Jul 2018 20:35:00 -0400 Subject: [PATCH 203/332] Add app name to PG settings --- config/base.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/config/base.ini b/config/base.ini index 6e6af123..6f63d78f 100644 --- a/config/base.ini +++ b/config/base.ini @@ -11,6 +11,7 @@ CAC_URL = https://localhost:8001 REQUESTS_QUEUE_BASE_URL = http://localhost:8003 REDIS_URI = redis://localhost:6379 SESSION_TTL_SECONDS = 600 +PGAPPNAME = atst PGHOST = localhost PGPORT = 5432 PGUSER = postgres From f6d6865bb3ac9727db2fd0be456dd62898cb43cf Mon Sep 17 00:00:00 2001 From: Devon Mackay Date: Tue, 31 Jul 2018 06:26:25 -0400 Subject: [PATCH 204/332] Switch to postgres in a container --- .travis.yml | 10 ++++------ config/ci.ini | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 311e93ce..3d76a657 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,9 +3,6 @@ language: python python: "3.6" services: - docker - - postgres -addons: - postgresql: "9.6" git: submodules: false env: @@ -22,10 +19,11 @@ before_install: - /sbin/ip addr before_script: - - netstat -anlp | grep LISTEN | grep tcp - - travis_host_ip="$(/sbin/ip route|awk '/default/ { print $3 }')" + - docker run -d --name postgres96 postgres:9.6-alpine + - docker run --link postgres96:postgres96 waisbrot/wait + - postgres_ip="$(docker inspect -f "{{ .NetworkSettings.IPAddress }}" postgres96)" - docker login -u $ATAT_DOCKER_REGISTRY_USERNAME -p $ATAT_DOCKER_REGISTRY_PASSWORD $ATAT_DOCKER_REGISTRY_URL - - docker build --tag "${TESTER_IMAGE_NAME}" --add-host "travishost:${travis_host_ip}" . -f deploy/docker/tester/Dockerfile + - docker build --tag "${TESTER_IMAGE_NAME}" --add-host "postgreshost:${postgres_ip}" . -f deploy/docker/tester/Dockerfile script: - docker run "${TESTER_IMAGE_NAME}" diff --git a/config/ci.ini b/config/ci.ini index 0469ae77..3796c0a7 100644 --- a/config/ci.ini +++ b/config/ci.ini @@ -1,2 +1,2 @@ [default] -PGHOST = travishost +PGHOST = postgreshost From baed8492291e53c408c26c64b2cd3256bb450b1e Mon Sep 17 00:00:00 2001 From: Devon Mackay Date: Tue, 31 Jul 2018 06:37:26 -0400 Subject: [PATCH 205/332] Add postgres host to running container --- .travis.yml | 4 ++-- script/cibuild | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3d76a657..479a8955 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,12 +21,12 @@ before_install: before_script: - docker run -d --name postgres96 postgres:9.6-alpine - docker run --link postgres96:postgres96 waisbrot/wait - - postgres_ip="$(docker inspect -f "{{ .NetworkSettings.IPAddress }}" postgres96)" + - export postgres_ip="$(docker inspect -f "{{ .NetworkSettings.IPAddress }}" postgres96)" - docker login -u $ATAT_DOCKER_REGISTRY_USERNAME -p $ATAT_DOCKER_REGISTRY_PASSWORD $ATAT_DOCKER_REGISTRY_URL - docker build --tag "${TESTER_IMAGE_NAME}" --add-host "postgreshost:${postgres_ip}" . -f deploy/docker/tester/Dockerfile script: - - docker run "${TESTER_IMAGE_NAME}" + - docker run --add-host "postgreshost:${postgres_ip}" "${TESTER_IMAGE_NAME}" before_deploy: - docker build --tag "${PROD_IMAGE_NAME}" . -f deploy/docker/prod/Dockerfile diff --git a/script/cibuild b/script/cibuild index e9d01564..387f61b8 100755 --- a/script/cibuild +++ b/script/cibuild @@ -4,5 +4,10 @@ source "$(dirname "${0}")"/../script/include/global_header.inc.sh +echo +echo "DEBUG: Hosts file:" +cat /etc/hosts +echo + # Run lint/style checks and unit tests source ./script/test From 07db14e9520ce83e61f7ae6d18cba7ccdd9e4444 Mon Sep 17 00:00:00 2001 From: Devon Mackay Date: Tue, 31 Jul 2018 07:03:49 -0400 Subject: [PATCH 206/332] Remove debugging related items --- .travis.yml | 2 -- script/cibuild | 5 ----- script/get_db_settings | 6 ------ script/setup | 3 --- 4 files changed, 16 deletions(-) diff --git a/.travis.yml b/.travis.yml index 479a8955..49883310 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,8 +15,6 @@ before_install: - sed -i 's/git@github.com:/https:\/\/github.com\//' .gitmodules # Manually initialize submodules - git submodule update --init --recursive - - /sbin/ip route|awk '/default/ { print $3 }' - - /sbin/ip addr before_script: - docker run -d --name postgres96 postgres:9.6-alpine diff --git a/script/cibuild b/script/cibuild index 387f61b8..e9d01564 100755 --- a/script/cibuild +++ b/script/cibuild @@ -4,10 +4,5 @@ source "$(dirname "${0}")"/../script/include/global_header.inc.sh -echo -echo "DEBUG: Hosts file:" -cat /etc/hosts -echo - # Run lint/style checks and unit tests source ./script/test diff --git a/script/get_db_settings b/script/get_db_settings index 701c2844..c96970a8 100755 --- a/script/get_db_settings +++ b/script/get_db_settings @@ -6,9 +6,3 @@ source "$(dirname "${0}")"/../script/include/global_header.inc.sh # Run the shared get_db_settings script source ./script/include/run_get_db_settings.sh - -echo -echo "Postgres settings: " -echo "PGHOST: $PGHOST" -echo "PGDATABASE: $PGDATABASE" -echo diff --git a/script/setup b/script/setup index c64ff07a..5cd11461 100755 --- a/script/setup +++ b/script/setup @@ -14,8 +14,5 @@ DATABASE_NAME="atat" # Enable database resetting RESET_DB="true" -echo "Hosts file:" -cat /etc/hosts - # Run the shared setup script source ./script/include/run_setup From 945eee9a6fa32b3ca3df5c5826111224cce93162 Mon Sep 17 00:00:00 2001 From: Devon Mackay Date: Tue, 31 Jul 2018 08:47:57 -0400 Subject: [PATCH 207/332] Update to most recent scriptz --- script/include | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/include b/script/include index 5c19aef7..90a453b2 160000 --- a/script/include +++ b/script/include @@ -1 +1 @@ -Subproject commit 5c19aef7482aa0035f2d85e4c30ee21dfd7969c9 +Subproject commit 90a453b2ac4272961b3ed5f7d77d60816a09e092 From 9c153e0772a0dea98b3002c921555d16c5e1d268 Mon Sep 17 00:00:00 2001 From: dandds Date: Tue, 31 Jul 2018 08:49:00 -0400 Subject: [PATCH 208/332] fix lint errors --- atst/domain/workspaces.py | 3 --- atst/handlers/request_new.py | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/atst/domain/workspaces.py b/atst/domain/workspaces.py index ca848425..b4cc85b8 100644 --- a/atst/domain/workspaces.py +++ b/atst/domain/workspaces.py @@ -1,6 +1,3 @@ -import tornado.gen - - class Projects(object): def __init__(self): diff --git a/atst/handlers/request_new.py b/atst/handlers/request_new.py index e43e6ab3..67c24585 100644 --- a/atst/handlers/request_new.py +++ b/atst/handlers/request_new.py @@ -50,7 +50,7 @@ class RequestNew(BaseHandler): ) if jedi_flow.validate(): - request = jedi_flow.create_or_update_request() + jedi_flow.create_or_update_request() valid = yield jedi_flow.validate_warnings() if valid: if jedi_flow.next_screen > len(jedi_flow.screens): From 432fb67506b973b89e6586aeb775c4a6792b07fc Mon Sep 17 00:00:00 2001 From: dandds Date: Tue, 31 Jul 2018 09:35:17 -0400 Subject: [PATCH 209/332] remove references to requests-queue url and client --- atst/app.py | 5 ----- config/base.ini | 1 - 2 files changed, 6 deletions(-) diff --git a/atst/app.py b/atst/app.py index efc649b3..a488b4bf 100644 --- a/atst/app.py +++ b/atst/app.py @@ -181,11 +181,6 @@ def make_deps(config): "fundz_client": ApiClient( config["default"]["FUNDZ_BASE_URL"], validate_cert=validate_cert ), - "requests_client": ApiClient( - config["default"]["REQUESTS_QUEUE_BASE_URL"], - api_version="v1", - validate_cert=validate_cert, - ), "sessions": RedisSessions( redis_client, config["default"]["SESSION_TTL_SECONDS"] ), diff --git a/config/base.ini b/config/base.ini index 6f63d78f..78d56c36 100644 --- a/config/base.ini +++ b/config/base.ini @@ -8,7 +8,6 @@ FUNDZ_BASE_URL= http://localhost:8004 COOKIE_SECRET = some-secret-please-replace SECRET = change_me_into_something_secret CAC_URL = https://localhost:8001 -REQUESTS_QUEUE_BASE_URL = http://localhost:8003 REDIS_URI = redis://localhost:6379 SESSION_TTL_SECONDS = 600 PGAPPNAME = atst From c1fdde4ab79030be6abb39b80a17bb2386214812 Mon Sep 17 00:00:00 2001 From: dandds Date: Mon, 30 Jul 2018 11:36:03 -0400 Subject: [PATCH 210/332] import authz models --- .../versions/4ede1e3e50d1_add_authz_models.py | 62 +++++++++++++++++++ atst/models/__init__.py | 4 ++ atst/models/permissions.py | 40 ++++++++++++ atst/models/role.py | 14 +++++ atst/models/user.py | 21 +++++++ atst/models/workspace_role.py | 24 +++++++ 6 files changed, 165 insertions(+) create mode 100644 alembic/versions/4ede1e3e50d1_add_authz_models.py create mode 100644 atst/models/permissions.py create mode 100644 atst/models/role.py create mode 100644 atst/models/user.py create mode 100644 atst/models/workspace_role.py diff --git a/alembic/versions/4ede1e3e50d1_add_authz_models.py b/alembic/versions/4ede1e3e50d1_add_authz_models.py new file mode 100644 index 00000000..d782b676 --- /dev/null +++ b/alembic/versions/4ede1e3e50d1_add_authz_models.py @@ -0,0 +1,62 @@ +"""add_authz_models + +Revision ID: 4ede1e3e50d1 +Revises: b5b17d465166 +Create Date: 2018-07-30 11:34:12.016857 + +""" +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision = '4ede1e3e50d1' +down_revision = 'b5b17d465166' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('roles', + sa.Column('id', postgresql.UUID(as_uuid=True), server_default=sa.text('uuid_generate_v4()'), nullable=False), + sa.Column('name', sa.String(), nullable=True), + sa.Column('description', sa.String(), nullable=True), + sa.Column('permissions', postgresql.ARRAY(sa.String()), server_default='{}', nullable=True), + sa.PrimaryKeyConstraint('id') + ) + op.create_index(op.f('ix_roles_name'), 'roles', ['name'], unique=True) + op.create_index(op.f('ix_roles_permissions'), 'roles', ['permissions'], unique=False) + op.create_table('users', + sa.Column('id', postgresql.UUID(as_uuid=True), server_default=sa.text('uuid_generate_v4()'), nullable=False), + sa.Column('username', sa.String(), nullable=True), + sa.Column('atat_role_id', postgresql.UUID(as_uuid=True), nullable=True), + sa.ForeignKeyConstraint(['atat_role_id'], ['roles.id'], ), + sa.PrimaryKeyConstraint('id') + ) + op.create_table('workspace_role', + sa.Column('id', postgresql.UUID(as_uuid=True), server_default=sa.text('uuid_generate_v4()'), nullable=False), + sa.Column('workspace_id', postgresql.UUID(as_uuid=True), nullable=True), + sa.Column('role_id', postgresql.UUID(as_uuid=True), nullable=True), + sa.Column('user_id', postgresql.UUID(as_uuid=True), nullable=True), + sa.ForeignKeyConstraint(['role_id'], ['roles.id'], ), + sa.ForeignKeyConstraint(['user_id'], ['users.id'], ), + sa.PrimaryKeyConstraint('id') + ) + op.create_index(op.f('ix_workspace_role_user_id'), 'workspace_role', ['user_id'], unique=False) + op.create_index(op.f('ix_workspace_role_workspace_id'), 'workspace_role', ['workspace_id'], unique=False) + op.create_index('workspace_role_user_workspace', 'workspace_role', ['user_id', 'workspace_id'], unique=True) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_index('workspace_role_user_workspace', table_name='workspace_role') + op.drop_index(op.f('ix_workspace_role_workspace_id'), table_name='workspace_role') + op.drop_index(op.f('ix_workspace_role_user_id'), table_name='workspace_role') + op.drop_table('workspace_role') + op.drop_table('users') + op.drop_index(op.f('ix_roles_permissions'), table_name='roles') + op.drop_index(op.f('ix_roles_name'), table_name='roles') + op.drop_table('roles') + # ### end Alembic commands ### diff --git a/atst/models/__init__.py b/atst/models/__init__.py index ef5d9457..fef82003 100644 --- a/atst/models/__init__.py +++ b/atst/models/__init__.py @@ -4,3 +4,7 @@ Base = declarative_base() from .request import Request from .request_status_event import RequestStatusEvent +from .permissions import Permissions +from .role import Role +from .user import User +from .workspace_role import WorkspaceRole diff --git a/atst/models/permissions.py b/atst/models/permissions.py new file mode 100644 index 00000000..9536348f --- /dev/null +++ b/atst/models/permissions.py @@ -0,0 +1,40 @@ +class Permissions(object): + REQUEST_JEDI_WORKSPACE = "request_jedi_workspace" + VIEW_ORIGINAL_JEDI_REQEUST = "view_original_jedi_request" + REVIEW_AND_APPROVE_JEDI_WORKSPACE_REQUEST = ( + "review_and_approve_jedi_workspace_request" + ) + MODIFY_ATAT_ROLE_PERMISSIONS = "modify_atat_role_permissions" + CREATE_CSP_ROLE = "create_csp_role" + DELETE_CSP_ROLE = "delete_csp_role" + DEACTIVE_CSP_ROLE = "deactivate_csp_role" + MODIFY_CSP_ROLE_PERMISSIONS = "modify_csp_role_permissions" + + VIEW_USAGE_REPORT = "view_usage_report" + VIEW_USAGE_DOLLARS = "view_usage_dollars" + ADD_AND_ASSIGN_CSP_ROLES = "add_and_assign_csp_roles" + REMOVE_CSP_ROLES = "remove_csp_roles" + REQUEST_NEW_CSP_ROLE = "request_new_csp_role" + ASSIGN_AND_UNASSIGN_ATAT_ROLE = "assign_and_unassign_atat_role" + + VIEW_ASSIGNED_ATAT_ROLE_CONFIGURATIONS = "view_assigned_atat_role_configurations" + VIEW_ASSIGNED_CSP_ROLE_CONFIGURATIONS = "view_assigned_csp_role_configurations" + + DEACTIVATE_WORKSPACE = "deactivate_workspace" + VIEW_ATAT_PERMISSIONS = "view_atat_permissions" + TRANSFER_OWNERSHIP_OF_WORKSPACE = "transfer_ownership_of_workspace" + + ADD_APPLICATION_IN_WORKSPACE = "add_application_in_workspace" + DELETE_APPLICATION_IN_WORKSPACE = "delete_application_in_workspace" + DEACTIVATE_APPLICATION_IN_WORKSPACE = "deactivate_application_in_workspace" + VIEW_APPLICATION_IN_WORKSPACE = "view_application_in_workspace" + RENAME_APPLICATION_IN_WORKSPACE = "rename_application_in_workspace" + + ADD_ENVIRONMENT_IN_APPLICATION = "add_environment_in_application" + DELETE_ENVIRONMENT_IN_APPLICATION = "delete_environment_in_application" + DEACTIVATE_ENVIRONMENT_IN_APPLICATION = "deactivate_environment_in_application" + VIEW_ENVIRONMENT_IN_APPLICATION = "view_environment_in_application" + RENAME_ENVIRONMENT_IN_APPLICATION = "rename_environment_in_application" + + ADD_TAG_TO_WORKSPACE = "add_tag_to_workspace" + REMOVE_TAG_FROM_WORKSPACE = "remove_tag_from_workspace" diff --git a/atst/models/role.py b/atst/models/role.py new file mode 100644 index 00000000..1205dedd --- /dev/null +++ b/atst/models/role.py @@ -0,0 +1,14 @@ +from sqlalchemy import String, Column +from sqlalchemy.dialects.postgresql import ARRAY + +from atst.models import Base +from .types import Id + + +class Role(Base): + __tablename__ = "roles" + + id = Id() + name = Column(String, index=True, unique=True) + description = Column(String) + permissions = Column(ARRAY(String), index=True, server_default="{}") diff --git a/atst/models/user.py b/atst/models/user.py new file mode 100644 index 00000000..f3954f26 --- /dev/null +++ b/atst/models/user.py @@ -0,0 +1,21 @@ +from sqlalchemy import String, ForeignKey, Column +from sqlalchemy.orm import relationship +from sqlalchemy.dialects.postgresql import UUID + +from atst.models import Base +from .types import Id + + +class User(Base): + __tablename__ = "users" + + id = Id() + username = Column(String) + atat_role_id = Column(UUID(as_uuid=True), ForeignKey("roles.id")) + + atat_role = relationship("Role") + workspace_roles = relationship("WorkspaceRole", backref="user") + + @property + def atat_permissions(self): + return self.atat_role.permissions diff --git a/atst/models/workspace_role.py b/atst/models/workspace_role.py new file mode 100644 index 00000000..86970e0b --- /dev/null +++ b/atst/models/workspace_role.py @@ -0,0 +1,24 @@ +from sqlalchemy import Index, ForeignKey, Column +from sqlalchemy.dialects.postgresql import UUID +from sqlalchemy.orm import relationship + +from atst.models import Base +from .types import Id + + +class WorkspaceRole(Base): + __tablename__ = "workspace_role" + + id = Id() + workspace_id = Column(UUID(as_uuid=True), index=True) + role_id = Column(UUID(as_uuid=True), ForeignKey("roles.id")) + user_id = Column(UUID(as_uuid=True), ForeignKey("users.id"), index=True) + role = relationship("Role") + + +Index( + "workspace_role_user_workspace", + WorkspaceRole.user_id, + WorkspaceRole.workspace_id, + unique=True, +) From b4050b306efa9823ab6e7d3760bc04833ad5b938 Mon Sep 17 00:00:00 2001 From: dandds Date: Mon, 30 Jul 2018 11:44:56 -0400 Subject: [PATCH 211/332] import authz domain module --- atst/domain/roles.py | 19 ++++++++++ atst/domain/users.py | 58 ++++++++++++++++++++++++++++++ atst/domain/workspace_users.py | 64 ++++++++++++++++++++++++++++++++++ atst/models/workspace_user.py | 14 ++++++++ 4 files changed, 155 insertions(+) create mode 100644 atst/domain/roles.py create mode 100644 atst/domain/users.py create mode 100644 atst/domain/workspace_users.py create mode 100644 atst/models/workspace_user.py diff --git a/atst/domain/roles.py b/atst/domain/roles.py new file mode 100644 index 00000000..1b5f66c0 --- /dev/null +++ b/atst/domain/roles.py @@ -0,0 +1,19 @@ +from sqlalchemy.orm.exc import NoResultFound + +from atst.models import Role +from .exceptions import NotFoundError + + +class Roles(object): + @classmethod + def get(cls, role_name): + try: + role = Role.query.filter_by(name=role_name).one() + except NoResultFound: + raise NotFoundError("role") + + return role + + @classmethod + def get_all(cls): + return Role.query.all() diff --git a/atst/domain/users.py b/atst/domain/users.py new file mode 100644 index 00000000..ace13eb5 --- /dev/null +++ b/atst/domain/users.py @@ -0,0 +1,58 @@ +from sqlalchemy.orm.exc import NoResultFound +from sqlalchemy.exc import IntegrityError + +from atst.models import User + +from .roles import Roles +from .exceptions import NotFoundError, AlreadyExistsError + + +class Users(object): + + def __init__(self, db_session): + self.db_session = db_session + + + def get(self, user_id): + try: + user = User.query.filter_by(id=user_id).one() + except NoResultFound: + raise NotFoundError("user") + + return user + + def create(self, user_id, atat_role_name): + atat_role = Roles.get(atat_role_name) + + try: + user = User(id=user_id, atat_role=atat_role) + self.db_session.add(user) + self.db_session.commit() + except IntegrityError: + raise AlreadyExistsError("user") + + return user + + def get_or_create(self, user_id, *args, **kwargs): + created = False + + try: + user = Users.get(user_id) + except NotFoundError: + user = Users.create(user_id, *args, **kwargs) + self.db_session.add(user) + self.db_session.commit() + created = True + + return user, created + + def update(self, user_id, atat_role_name): + + user = Users.get(user_id) + atat_role = Roles.get(atat_role_name) + user.atat_role = atat_role + + self.db_session.add(user) + self.db_session.commit() + + return user diff --git a/atst/domain/workspace_users.py b/atst/domain/workspace_users.py new file mode 100644 index 00000000..9ff139cd --- /dev/null +++ b/atst/domain/workspace_users.py @@ -0,0 +1,64 @@ +from sqlalchemy.orm.exc import NoResultFound +from sqlalchemy.dialects.postgresql import insert + +from atst.models import User, WorkspaceRole, Role +from .exceptions import NotFoundError + +class WorkspaceUsers(object): + + def __init__(self, db_session): + self.db_session = db_session + + def get(self, workspace_id, user_id): + try: + user = User.query.filter_by(id=user_id).one() + except NoResultFound: + raise NotFoundError("user") + + try: + workspace_role = ( + WorkspaceRole.query.join(User) + .filter(User.id == user_id, WorkspaceRole.workspace_id == workspace_id) + .one() + ) + except NoResultFound: + workspace_role = None + + return WorkspaceUser(user, workspace_role) + + def add_many(self, workspace_id, workspace_user_dicts): + workspace_users = [] + + for user_dict in workspace_user_dicts: + try: + user = User.query.filter_by(id=user_dict["id"]).one() + except NoResultFound: + default_role = Role.query.filter_by(name="developer").one_or_none() + user = User(id=user_dict["id"], atat_role=default_role) + + try: + role = Role.query.filter_by(name=user_dict["workspace_role"]).one() + except NoResultFound: + raise NotFoundError("role") + + try: + existing_workspace_role = WorkspaceRole.query.filter( + WorkspaceRole.user == user, + WorkspaceRole.workspace_id == workspace_id, + ).one() + new_workspace_role = existing_workspace_role + new_workspace_role.role = role + except NoResultFound: + new_workspace_role = WorkspaceRole( + user=user, role_id=role.id, workspace_id=workspace_id + ) + + user.workspace_roles.append(new_workspace_role) + workspace_user = WorkspaceUser(user, new_workspace_role) + workspace_users.append(workspace_user) + + self.db_session.add(user) + + self.db_session.commit() + + return workspace_users diff --git a/atst/models/workspace_user.py b/atst/models/workspace_user.py new file mode 100644 index 00000000..6faba2d6 --- /dev/null +++ b/atst/models/workspace_user.py @@ -0,0 +1,14 @@ +class WorkspaceUser(object): + def __init__(self, user, workspace_role): + self.user = user + self.workspace_role = workspace_role + + def permissions(self): + atat_permissions = set(self.user.atat_role.permissions) + workspace_permissions = ( + [] if self.workspace_role is None else self.workspace_role.role.permissions + ) + return set(workspace_permissions).union(atat_permissions) + + def workspace_id(self): + return self.workspace_role.workspace_id From 25d3cbac284c8c41210075fd2cb2b957753a9ad7 Mon Sep 17 00:00:00 2001 From: dandds Date: Mon, 30 Jul 2018 14:03:42 -0400 Subject: [PATCH 212/332] add role and perms migrations for authorization --- .../4ea5917e7781_add_default_atat_role.py | 39 ++++ .../96a9f3537996_add_roles_and_permissions.py | 183 ++++++++++++++++++ 2 files changed, 222 insertions(+) create mode 100644 alembic/versions/4ea5917e7781_add_default_atat_role.py create mode 100644 alembic/versions/96a9f3537996_add_roles_and_permissions.py diff --git a/alembic/versions/4ea5917e7781_add_default_atat_role.py b/alembic/versions/4ea5917e7781_add_default_atat_role.py new file mode 100644 index 00000000..78b6ef55 --- /dev/null +++ b/alembic/versions/4ea5917e7781_add_default_atat_role.py @@ -0,0 +1,39 @@ +"""add_default_atat_role + +Revision ID: 4ea5917e7781 +Revises: 96a9f3537996 +Create Date: 2018-07-30 13:51:29.576931 + +""" +from alembic import op +import sqlalchemy as sa +from sqlalchemy.orm.session import Session + + +# revision identifiers, used by Alembic. +revision = '4ea5917e7781' +down_revision = '96a9f3537996' +branch_labels = None +depends_on = None + +from atst.models.role import Role +from atst.models.permissions import Permissions + + +def upgrade(): + session = Session(bind=op.get_bind()) + mission_owner_role = Role( + name='default', + description='', + permissions=[ + Permissions.REQUEST_JEDI_WORKSPACE, + ] + ) + session.add(mission_owner_role) + session.commit() + + +def downgrade(): + db = op.get_bind() + db.execute("DELETE FROM roles WHERE name = 'default'") + diff --git a/alembic/versions/96a9f3537996_add_roles_and_permissions.py b/alembic/versions/96a9f3537996_add_roles_and_permissions.py new file mode 100644 index 00000000..4380208a --- /dev/null +++ b/alembic/versions/96a9f3537996_add_roles_and_permissions.py @@ -0,0 +1,183 @@ +"""add_roles_and_permissions + +Revision ID: 96a9f3537996 +Revises: 4ede1e3e50d1 +Create Date: 2018-07-30 13:48:31.325234 + +""" +import os +import sys +from alembic import op +import sqlalchemy as sa + +from sqlalchemy.orm.session import Session + +from atst.models.role import Role +from atst.models.permissions import Permissions + +# revision identifiers, used by Alembic. +revision = '96a9f3537996' +down_revision = '4ede1e3e50d1' +branch_labels = None +depends_on = None + + +def upgrade(): + session = Session(bind=op.get_bind()) + roles = [ + Role( + name='ccpo', + description='', + permissions=[ + Permissions.VIEW_ORIGINAL_JEDI_REQEUST, + Permissions.REVIEW_AND_APPROVE_JEDI_WORKSPACE_REQUEST, + Permissions.MODIFY_ATAT_ROLE_PERMISSIONS, + Permissions.CREATE_CSP_ROLE, + Permissions.DELETE_CSP_ROLE, + Permissions.DEACTIVE_CSP_ROLE, + Permissions.MODIFY_CSP_ROLE_PERMISSIONS, + + Permissions.VIEW_USAGE_REPORT, + Permissions.VIEW_USAGE_DOLLARS, + Permissions.ADD_AND_ASSIGN_CSP_ROLES, + Permissions.REMOVE_CSP_ROLES, + Permissions.REQUEST_NEW_CSP_ROLE, + Permissions.ASSIGN_AND_UNASSIGN_ATAT_ROLE, + + Permissions.VIEW_ASSIGNED_ATAT_ROLE_CONFIGURATIONS, + Permissions.VIEW_ASSIGNED_CSP_ROLE_CONFIGURATIONS, + + Permissions.DEACTIVATE_WORKSPACE, + Permissions.VIEW_ATAT_PERMISSIONS, + Permissions.TRANSFER_OWNERSHIP_OF_WORKSPACE, + + Permissions.ADD_APPLICATION_IN_WORKSPACE, + Permissions.DELETE_APPLICATION_IN_WORKSPACE, + Permissions.DEACTIVATE_APPLICATION_IN_WORKSPACE, + Permissions.VIEW_APPLICATION_IN_WORKSPACE, + Permissions.RENAME_APPLICATION_IN_WORKSPACE, + + Permissions.ADD_ENVIRONMENT_IN_APPLICATION, + Permissions.DELETE_ENVIRONMENT_IN_APPLICATION, + Permissions.DEACTIVATE_ENVIRONMENT_IN_APPLICATION, + Permissions.VIEW_ENVIRONMENT_IN_APPLICATION, + Permissions.RENAME_ENVIRONMENT_IN_APPLICATION, + + Permissions.ADD_TAG_TO_WORKSPACE, + Permissions.REMOVE_TAG_FROM_WORKSPACE + ] + ), + Role( + name='owner', + description='', + permissions=[ + Permissions.REQUEST_JEDI_WORKSPACE, + Permissions.VIEW_ORIGINAL_JEDI_REQEUST, + + Permissions.VIEW_USAGE_REPORT, + Permissions.VIEW_USAGE_DOLLARS, + Permissions.ADD_AND_ASSIGN_CSP_ROLES, + Permissions.REMOVE_CSP_ROLES, + Permissions.REQUEST_NEW_CSP_ROLE, + Permissions.ASSIGN_AND_UNASSIGN_ATAT_ROLE, + + Permissions.VIEW_ASSIGNED_ATAT_ROLE_CONFIGURATIONS, + Permissions.VIEW_ASSIGNED_CSP_ROLE_CONFIGURATIONS, + + Permissions.DEACTIVATE_WORKSPACE, + Permissions.VIEW_ATAT_PERMISSIONS, + + Permissions.ADD_APPLICATION_IN_WORKSPACE, + Permissions.DELETE_APPLICATION_IN_WORKSPACE, + Permissions.DEACTIVATE_APPLICATION_IN_WORKSPACE, + Permissions.VIEW_APPLICATION_IN_WORKSPACE, + Permissions.RENAME_APPLICATION_IN_WORKSPACE, + + Permissions.ADD_ENVIRONMENT_IN_APPLICATION, + Permissions.DELETE_ENVIRONMENT_IN_APPLICATION, + Permissions.DEACTIVATE_ENVIRONMENT_IN_APPLICATION, + Permissions.VIEW_ENVIRONMENT_IN_APPLICATION, + Permissions.RENAME_ENVIRONMENT_IN_APPLICATION, + ] + ), + Role( + name='admin', + description='', + permissions=[ + Permissions.VIEW_USAGE_REPORT, + Permissions.ADD_AND_ASSIGN_CSP_ROLES, + Permissions.REMOVE_CSP_ROLES, + Permissions.REQUEST_NEW_CSP_ROLE, + Permissions.ASSIGN_AND_UNASSIGN_ATAT_ROLE, + + Permissions.VIEW_ASSIGNED_ATAT_ROLE_CONFIGURATIONS, + Permissions.VIEW_ASSIGNED_CSP_ROLE_CONFIGURATIONS, + + Permissions.ADD_APPLICATION_IN_WORKSPACE, + Permissions.DELETE_APPLICATION_IN_WORKSPACE, + Permissions.DEACTIVATE_APPLICATION_IN_WORKSPACE, + Permissions.VIEW_APPLICATION_IN_WORKSPACE, + Permissions.RENAME_APPLICATION_IN_WORKSPACE, + + Permissions.ADD_ENVIRONMENT_IN_APPLICATION, + Permissions.DELETE_ENVIRONMENT_IN_APPLICATION, + Permissions.DEACTIVATE_ENVIRONMENT_IN_APPLICATION, + Permissions.VIEW_ENVIRONMENT_IN_APPLICATION, + Permissions.RENAME_ENVIRONMENT_IN_APPLICATION, + ] + ), + Role( + name='developer', + description='', + permissions=[ + Permissions.VIEW_USAGE_REPORT, + Permissions.VIEW_USAGE_DOLLARS, + Permissions.VIEW_APPLICATION_IN_WORKSPACE, + Permissions.VIEW_ENVIRONMENT_IN_APPLICATION + ] + ), + Role( + name='billing_auditor', + description='', + permissions=[ + Permissions.VIEW_USAGE_REPORT, + Permissions.VIEW_USAGE_DOLLARS, + + Permissions.VIEW_APPLICATION_IN_WORKSPACE, + + Permissions.VIEW_ENVIRONMENT_IN_APPLICATION, + ] + ), + Role( + name='security_auditor', + description='', + permissions=[ + Permissions.VIEW_ASSIGNED_ATAT_ROLE_CONFIGURATIONS, + Permissions.VIEW_ASSIGNED_CSP_ROLE_CONFIGURATIONS, + + Permissions.VIEW_ATAT_PERMISSIONS, + + Permissions.VIEW_APPLICATION_IN_WORKSPACE, + + Permissions.VIEW_ENVIRONMENT_IN_APPLICATION, + ] + ), + ] + + session.add_all(roles) + session.commit() + + +def downgrade(): + db = op.get_bind() + db.execute(""" + DELETE FROM roles + WHERE name IN ( + 'ccpo', + 'owner', + 'admin', + 'developer', + 'billing_auditor', + 'security_auditor' + ); + """) From 232b8192f54798485ba648b09aa6dd88eb59dd37 Mon Sep 17 00:00:00 2001 From: dandds Date: Mon, 30 Jul 2018 14:04:05 -0400 Subject: [PATCH 213/332] update handlers to user Users repo for managing authorization --- atst/app.py | 11 +++-------- atst/domain/roles.py | 13 +++++++------ atst/domain/users.py | 18 ++++++++---------- atst/handler.py | 21 +++++++-------------- atst/handlers/dev.py | 12 +++++------- atst/handlers/login_redirect.py | 4 ++-- atst/handlers/request.py | 1 + atst/handlers/request_submit.py | 1 + atst/handlers/workspaces.py | 4 ++-- tests/conftest.py | 1 - 10 files changed, 36 insertions(+), 50 deletions(-) diff --git a/atst/app.py b/atst/app.py index a488b4bf..830b7169 100644 --- a/atst/app.py +++ b/atst/app.py @@ -35,7 +35,7 @@ def make_app(config, deps, **kwargs): { "sessions": deps["sessions"], "authnid_client": deps["authnid_client"], - "authz_client": deps["authz_client"], + "db_session": deps["db_session"], }, name="login_redirect", ), @@ -50,7 +50,7 @@ def make_app(config, deps, **kwargs): url( r"/workspaces", Workspaces, - {"page": "workspaces", "authz_client": deps["authz_client"]}, + {"page": "workspaces", "db_session": deps["db_session"]}, name="workspaces", ), url( @@ -137,7 +137,7 @@ def make_app(config, deps, **kwargs): { "action": "login", "sessions": deps["sessions"], - "authz_client": deps["authz_client"], + "db_session": deps["db_session"], }, name="dev-login", ) @@ -168,11 +168,6 @@ def make_deps(config): return { "db_session": make_db(config), - "authz_client": ApiClient( - config["default"]["AUTHZ_BASE_URL"], - api_version="v1", - validate_cert=validate_cert, - ), "authnid_client": ApiClient( config["default"]["AUTHNID_BASE_URL"], api_version="v1", diff --git a/atst/domain/roles.py b/atst/domain/roles.py index 1b5f66c0..87a36961 100644 --- a/atst/domain/roles.py +++ b/atst/domain/roles.py @@ -5,15 +5,16 @@ from .exceptions import NotFoundError class Roles(object): - @classmethod - def get(cls, role_name): + def __init__(self, db_session): + self.db_session = db_session + + def get(self, role_name): try: - role = Role.query.filter_by(name=role_name).one() + role = self.db_session.query(Role).filter_by(name=role_name).one() except NoResultFound: raise NotFoundError("role") return role - @classmethod - def get_all(cls): - return Role.query.all() + def get_all(self): + return self.db_session.query(Role).all() diff --git a/atst/domain/users.py b/atst/domain/users.py index ace13eb5..94e99056 100644 --- a/atst/domain/users.py +++ b/atst/domain/users.py @@ -11,18 +11,19 @@ class Users(object): def __init__(self, db_session): self.db_session = db_session + self.roles_repo = Roles(db_session) def get(self, user_id): try: - user = User.query.filter_by(id=user_id).one() + user = self.db_session.query(User).filter_by(id=user_id).one() except NoResultFound: raise NotFoundError("user") return user def create(self, user_id, atat_role_name): - atat_role = Roles.get(atat_role_name) + atat_role = self.roles_repo.get(atat_role_name) try: user = User(id=user_id, atat_role=atat_role) @@ -34,22 +35,19 @@ class Users(object): return user def get_or_create(self, user_id, *args, **kwargs): - created = False - try: - user = Users.get(user_id) + user = self.get(user_id) except NotFoundError: - user = Users.create(user_id, *args, **kwargs) + user = self.create(user_id, *args, **kwargs) self.db_session.add(user) self.db_session.commit() - created = True - return user, created + return user def update(self, user_id, atat_role_name): - user = Users.get(user_id) - atat_role = Roles.get(atat_role_name) + user = self.get(user_id) + atat_role = self.roles_repo.get(atat_role_name) user.atat_role = atat_role self.db_session.add(user) diff --git a/atst/handler.py b/atst/handler.py index 3766aa95..bcbcf879 100644 --- a/atst/handler.py +++ b/atst/handler.py @@ -1,6 +1,7 @@ import tornado.web from atst.assets import environment from atst.sessions import SessionNotFoundError +from atst.domain.users import Users helpers = {"assets": environment} @@ -15,26 +16,18 @@ class BaseHandler(tornado.web.RequestHandler): @tornado.gen.coroutine def login(self, user): - user_permissions = yield self._get_user_permissions(user["id"]) - user["atat_permissions"] = user_permissions["atat_permissions"] - user["atat_role"] = user_permissions["atat_role"] + db_user = yield self._get_user_permissions(user["id"]) + user["atat_permissions"] = db_user.atat_permissions + user["atat_role"] = db_user.atat_role.name session_id = self.sessions.start_session(user) self.set_secure_cookie("atat", session_id) return self.redirect("/home") @tornado.gen.coroutine def _get_user_permissions(self, user_id): - response = yield self.authz_client.get( - "/users/{}".format(user_id), raise_error=False - ) - if response.code == 404: - response = yield self.authz_client.post( - "/users", json={"id": user_id, "atat_role": "developer"} - ) - return response.json - - else: - return response.json + user_repo = Users(self.db_session) + user = user_repo.get_or_create(user_id, atat_role_name="developer") + return user def get_current_user(self): cookie = self.get_secure_cookie("atat") diff --git a/atst/handlers/dev.py b/atst/handlers/dev.py index 878aca11..4394936b 100644 --- a/atst/handlers/dev.py +++ b/atst/handlers/dev.py @@ -1,6 +1,7 @@ import tornado.gen from atst.handler import BaseHandler +from atst.domain.users import Users _DEV_USERS = { "sam": { @@ -9,7 +10,6 @@ _DEV_USERS = { "last_name": "Seeceepio", "atat_role": "ccpo" }, - "amanda": { "id": "cce17030-4109-4719-b958-ed109dbb87c8", "first_name": "Amanda", @@ -44,10 +44,11 @@ _DEV_USERS = { class Dev(BaseHandler): - def initialize(self, action, sessions, authz_client): + def initialize(self, action, sessions, db_session): + self.db_session = db_session self.action = action self.sessions = sessions - self.authz_client = authz_client + self.users_repo = Users(db_session) @tornado.gen.coroutine def get(self): @@ -58,7 +59,4 @@ class Dev(BaseHandler): @tornado.gen.coroutine def _set_user_permissions(self, user_id, role): - response = yield self.authz_client.post( - "/users", json={"id": user_id, "atat_role": role} - ) - return response.json + return self.users_repo.get_or_create(user_id, atat_role_name=role) diff --git a/atst/handlers/login_redirect.py b/atst/handlers/login_redirect.py index 59fb8751..7746e934 100644 --- a/atst/handlers/login_redirect.py +++ b/atst/handlers/login_redirect.py @@ -3,10 +3,10 @@ from atst.handler import BaseHandler class LoginRedirect(BaseHandler): - def initialize(self, authnid_client, sessions, authz_client): + def initialize(self, authnid_client, sessions, db_session): + self.db_session = db_session self.authnid_client = authnid_client self.sessions = sessions - self.authz_client = authz_client @tornado.gen.coroutine def get(self): diff --git a/atst/handlers/request.py b/atst/handlers/request.py index 1373280a..6918526e 100644 --- a/atst/handlers/request.py +++ b/atst/handlers/request.py @@ -22,6 +22,7 @@ def map_request(user, request): class Request(BaseHandler): def initialize(self, page, db_session): self.page = page + self.db_session = db_session self.requests = Requests(db_session) @tornado.web.authenticated diff --git a/atst/handlers/request_submit.py b/atst/handlers/request_submit.py index ff27803b..116e996a 100644 --- a/atst/handlers/request_submit.py +++ b/atst/handlers/request_submit.py @@ -6,6 +6,7 @@ from atst.domain.requests import Requests class RequestsSubmit(BaseHandler): def initialize(self, db_session): + self.db_session = db_session self.requests_repo = Requests(db_session) @tornado.web.authenticated diff --git a/atst/handlers/workspaces.py b/atst/handlers/workspaces.py index c7e06451..b6fa1dbe 100644 --- a/atst/handlers/workspaces.py +++ b/atst/handlers/workspaces.py @@ -12,9 +12,9 @@ mock_workspaces = [ class Workspaces(BaseHandler): - def initialize(self, page, authz_client): + def initialize(self, page, db_session): self.page = page - self.authz_client = authz_client + self.db_session = db_session @tornado.gen.coroutine @tornado.web.authenticated diff --git a/tests/conftest.py b/tests/conftest.py index a0ed8550..555e1f79 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -10,7 +10,6 @@ from atst.sessions import DictSessions @pytest.fixture def app(db): TEST_DEPS = { - "authz_client": MockAuthzClient("authz"), "authnid_client": MockApiClient("authnid"), "fundz_client": MockFundzClient("fundz"), "sessions": DictSessions(), From be29c5804fe9420957384160d1c74146fa69b146 Mon Sep 17 00:00:00 2001 From: dandds Date: Mon, 30 Jul 2018 14:19:38 -0400 Subject: [PATCH 214/332] add WorkspaceUser tests from authz --- atst/domain/workspace_users.py | 18 ++++++++---- tests/domain/test_workspace_users.py | 43 ++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 6 deletions(-) create mode 100644 tests/domain/test_workspace_users.py diff --git a/atst/domain/workspace_users.py b/atst/domain/workspace_users.py index 9ff139cd..857be057 100644 --- a/atst/domain/workspace_users.py +++ b/atst/domain/workspace_users.py @@ -1,17 +1,23 @@ from sqlalchemy.orm.exc import NoResultFound from sqlalchemy.dialects.postgresql import insert -from atst.models import User, WorkspaceRole, Role +from atst.models.workspace_role import WorkspaceRole +from atst.models.workspace_user import WorkspaceUser +from atst.models.user import User +from .roles import Roles +from .users import Users from .exceptions import NotFoundError class WorkspaceUsers(object): def __init__(self, db_session): self.db_session = db_session + self.roles_repo = Roles(db_session) + self.users_repo = Users(db_session) def get(self, workspace_id, user_id): try: - user = User.query.filter_by(id=user_id).one() + user = self.users_repo.get(user_id) except NoResultFound: raise NotFoundError("user") @@ -31,18 +37,18 @@ class WorkspaceUsers(object): for user_dict in workspace_user_dicts: try: - user = User.query.filter_by(id=user_dict["id"]).one() + user = self.users_repo.get(user_dict["id"]) except NoResultFound: - default_role = Role.query.filter_by(name="developer").one_or_none() + default_role = self.roles_repo.get("developer") user = User(id=user_dict["id"], atat_role=default_role) try: - role = Role.query.filter_by(name=user_dict["workspace_role"]).one() + role = self.roles_repo.get(user_dict["workspace_role"]) except NoResultFound: raise NotFoundError("role") try: - existing_workspace_role = WorkspaceRole.query.filter( + existing_workspace_role = self.db_session.query(WorkspaceRole).filter( WorkspaceRole.user == user, WorkspaceRole.workspace_id == workspace_id, ).one() diff --git a/tests/domain/test_workspace_users.py b/tests/domain/test_workspace_users.py new file mode 100644 index 00000000..e86662f3 --- /dev/null +++ b/tests/domain/test_workspace_users.py @@ -0,0 +1,43 @@ +import pytest +from uuid import uuid4 + +from atst.domain.workspace_users import WorkspaceUsers +from atst.domain.users import Users + + +@pytest.fixture() +def users_repo(db): + return Users(db) + +@pytest.fixture() +def workspace_users_repo(db): + return WorkspaceUsers(db) + +def test_can_create_new_workspace_user(users_repo, workspace_users_repo): + workspace_id = uuid4() + user = users_repo.create(uuid4(), "developer") + + workspace_user_dicts = [ + {"id": user.id, "workspace_role": "owner"} + ] + + workspace_users = workspace_users_repo.add_many(workspace_id, workspace_user_dicts) + + assert workspace_users[0].user.id == user.id + assert workspace_users[0].user.atat_role.name == "developer" + assert workspace_users[0].workspace_role.role.name == "owner" + + +def test_can_update_existing_workspace_user(users_repo, workspace_users_repo): + workspace_id = uuid4() + user = users_repo.create(uuid4(), "developer") + + workspace_users_repo.add_many(workspace_id, [ + {"id": user.id, "workspace_role": "owner"} + ]) + workspace_users = workspace_users_repo.add_many(workspace_id, [ + {"id": user.id, "workspace_role": "developer"} + ]) + + assert workspace_users[0].user.id == user.id + assert workspace_users[0].workspace_role.role.name == "developer" From c4039de861486fe2ffd5451ceb74f9fc806604ff Mon Sep 17 00:00:00 2001 From: richard-dds Date: Mon, 30 Jul 2018 15:31:14 -0400 Subject: [PATCH 215/332] Add domain tests for all of authz --- tests/domain/test_roles.py | 23 ++++++++++++ tests/domain/test_users.py | 72 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 tests/domain/test_roles.py create mode 100644 tests/domain/test_users.py diff --git a/tests/domain/test_roles.py b/tests/domain/test_roles.py new file mode 100644 index 00000000..1280292f --- /dev/null +++ b/tests/domain/test_roles.py @@ -0,0 +1,23 @@ +import pytest +from atst.domain.roles import Roles +from atst.domain.exceptions import NotFoundError + + +@pytest.fixture() +def roles_repo(db): + return Roles(db) + + +def test_get_all_roles(roles_repo): + roles = roles_repo.get_all() + assert roles + + +def test_get_existing_role(roles_repo): + role = roles_repo.get("developer") + assert role.name == "developer" + + +def test_get_nonexistent_role(roles_repo): + with pytest.raises(NotFoundError): + roles_repo.get("nonexistent") diff --git a/tests/domain/test_users.py b/tests/domain/test_users.py new file mode 100644 index 00000000..921463f8 --- /dev/null +++ b/tests/domain/test_users.py @@ -0,0 +1,72 @@ +import pytest +from uuid import uuid4, UUID + +from atst.domain.users import Users +from atst.domain.exceptions import NotFoundError, AlreadyExistsError + +@pytest.fixture() +def users_repo(db) -> Users: + return Users(db) + + +@pytest.fixture(scope="function") +def user_id(): + return uuid4() + + +def test_create_user(users_repo, user_id): + user = users_repo.create(user_id, "developer") + assert user.id == user_id + + +def test_create_user_with_nonexistent_role(users_repo, user_id): + with pytest.raises(NotFoundError): + users_repo.create(user_id, "nonexistent") + + +def test_create_already_existing_user(users_repo, user_id): + users_repo.create(user_id, "developer") + with pytest.raises(AlreadyExistsError): + users_repo.create(user_id, "developer") + + +def test_get_or_create_nonexistent_user(users_repo, user_id): + user = users_repo.get_or_create(user_id, atat_role_name="developer") + assert user.id == user_id + + +def test_get_or_create_existing_user(users_repo, user_id): + users_repo.get_or_create(user_id, atat_role_name="developer") + user = users_repo.get_or_create(user_id, atat_role_name="developer") + assert user + + +def test_get_user(users_repo, user_id): + users_repo.create(user_id, "developer") + user = users_repo.get(user_id) + assert user.id == user_id + + +def test_get_nonexistent_user(users_repo, user_id): + users_repo.create(user_id, "developer") + with pytest.raises(NotFoundError): + users_repo.get(uuid4()) + + +def test_update_user(users_repo, user_id): + users_repo.create(user_id, "developer") + updated_user = users_repo.update(user_id, "ccpo") + + assert updated_user.atat_role.name == "ccpo" + + +def test_update_nonexistent_user(users_repo, user_id): + users_repo.create(user_id, "developer") + with pytest.raises(NotFoundError): + users_repo.update(uuid4(), "ccpo") + + +def test_update_existing_user_with_nonexistent_role(users_repo, user_id): + users_repo.create(user_id, "developer") + with pytest.raises(NotFoundError): + users_repo.update(user_id, "nonexistent") From 8fdf3ec20f60e502760931b6312d739e374f574c Mon Sep 17 00:00:00 2001 From: richard-dds Date: Mon, 30 Jul 2018 15:33:19 -0400 Subject: [PATCH 216/332] Formatting --- atst/domain/users.py | 2 -- atst/domain/workspace_users.py | 14 +++++++++----- atst/domain/workspaces.py | 2 -- tests/domain/test_users.py | 1 + tests/domain/test_workspace_users.py | 18 +++++++++--------- 5 files changed, 19 insertions(+), 18 deletions(-) diff --git a/atst/domain/users.py b/atst/domain/users.py index 94e99056..76385228 100644 --- a/atst/domain/users.py +++ b/atst/domain/users.py @@ -8,12 +8,10 @@ from .exceptions import NotFoundError, AlreadyExistsError class Users(object): - def __init__(self, db_session): self.db_session = db_session self.roles_repo = Roles(db_session) - def get(self, user_id): try: user = self.db_session.query(User).filter_by(id=user_id).one() diff --git a/atst/domain/workspace_users.py b/atst/domain/workspace_users.py index 857be057..e4d93c19 100644 --- a/atst/domain/workspace_users.py +++ b/atst/domain/workspace_users.py @@ -8,8 +8,8 @@ from .roles import Roles from .users import Users from .exceptions import NotFoundError -class WorkspaceUsers(object): +class WorkspaceUsers(object): def __init__(self, db_session): self.db_session = db_session self.roles_repo = Roles(db_session) @@ -48,10 +48,14 @@ class WorkspaceUsers(object): raise NotFoundError("role") try: - existing_workspace_role = self.db_session.query(WorkspaceRole).filter( - WorkspaceRole.user == user, - WorkspaceRole.workspace_id == workspace_id, - ).one() + existing_workspace_role = ( + self.db_session.query(WorkspaceRole) + .filter( + WorkspaceRole.user == user, + WorkspaceRole.workspace_id == workspace_id, + ) + .one() + ) new_workspace_role = existing_workspace_role new_workspace_role.role = role except NoResultFound: diff --git a/atst/domain/workspaces.py b/atst/domain/workspaces.py index b4cc85b8..6ec0b856 100644 --- a/atst/domain/workspaces.py +++ b/atst/domain/workspaces.py @@ -1,5 +1,4 @@ class Projects(object): - def __init__(self): pass @@ -47,7 +46,6 @@ class Projects(object): class Members(object): - def __init__(self): pass diff --git a/tests/domain/test_users.py b/tests/domain/test_users.py index 921463f8..a76a9ae8 100644 --- a/tests/domain/test_users.py +++ b/tests/domain/test_users.py @@ -4,6 +4,7 @@ from uuid import uuid4, UUID from atst.domain.users import Users from atst.domain.exceptions import NotFoundError, AlreadyExistsError + @pytest.fixture() def users_repo(db) -> Users: return Users(db) diff --git a/tests/domain/test_workspace_users.py b/tests/domain/test_workspace_users.py index e86662f3..f76bdf3e 100644 --- a/tests/domain/test_workspace_users.py +++ b/tests/domain/test_workspace_users.py @@ -9,17 +9,17 @@ from atst.domain.users import Users def users_repo(db): return Users(db) + @pytest.fixture() def workspace_users_repo(db): return WorkspaceUsers(db) + def test_can_create_new_workspace_user(users_repo, workspace_users_repo): workspace_id = uuid4() user = users_repo.create(uuid4(), "developer") - workspace_user_dicts = [ - {"id": user.id, "workspace_role": "owner"} - ] + workspace_user_dicts = [{"id": user.id, "workspace_role": "owner"}] workspace_users = workspace_users_repo.add_many(workspace_id, workspace_user_dicts) @@ -32,12 +32,12 @@ def test_can_update_existing_workspace_user(users_repo, workspace_users_repo): workspace_id = uuid4() user = users_repo.create(uuid4(), "developer") - workspace_users_repo.add_many(workspace_id, [ - {"id": user.id, "workspace_role": "owner"} - ]) - workspace_users = workspace_users_repo.add_many(workspace_id, [ - {"id": user.id, "workspace_role": "developer"} - ]) + workspace_users_repo.add_many( + workspace_id, [{"id": user.id, "workspace_role": "owner"}] + ) + workspace_users = workspace_users_repo.add_many( + workspace_id, [{"id": user.id, "workspace_role": "developer"}] + ) assert workspace_users[0].user.id == user.id assert workspace_users[0].workspace_role.role.name == "developer" From d23975ad028db2f192fe5c85c5c8fc8d82d8d0fb Mon Sep 17 00:00:00 2001 From: richard-dds Date: Mon, 30 Jul 2018 15:37:31 -0400 Subject: [PATCH 217/332] Fix linting errors --- atst/domain/workspace_users.py | 1 - tests/conftest.py | 2 +- tests/domain/test_users.py | 2 +- tests/factories.py | 2 +- tests/mocks.py | 49 ---------------------------------- 5 files changed, 3 insertions(+), 53 deletions(-) diff --git a/atst/domain/workspace_users.py b/atst/domain/workspace_users.py index e4d93c19..ef51b78d 100644 --- a/atst/domain/workspace_users.py +++ b/atst/domain/workspace_users.py @@ -1,5 +1,4 @@ from sqlalchemy.orm.exc import NoResultFound -from sqlalchemy.dialects.postgresql import insert from atst.models.workspace_role import WorkspaceRole from atst.models.workspace_user import WorkspaceUser diff --git a/tests/conftest.py b/tests/conftest.py index 555e1f79..04510f1b 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -3,7 +3,7 @@ from sqlalchemy.orm import sessionmaker, scoped_session from atst.app import make_app, make_deps, make_config from atst.database import make_db -from tests.mocks import MockApiClient, MockFundzClient, MockAuthzClient +from tests.mocks import MockApiClient, MockFundzClient from atst.sessions import DictSessions diff --git a/tests/domain/test_users.py b/tests/domain/test_users.py index a76a9ae8..f136e3bd 100644 --- a/tests/domain/test_users.py +++ b/tests/domain/test_users.py @@ -1,5 +1,5 @@ import pytest -from uuid import uuid4, UUID +from uuid import uuid4 from atst.domain.users import Users from atst.domain.exceptions import NotFoundError, AlreadyExistsError diff --git a/tests/factories.py b/tests/factories.py index b07b36fa..1c870308 100644 --- a/tests/factories.py +++ b/tests/factories.py @@ -1,7 +1,7 @@ import factory from uuid import uuid4 -from atst.models import Request, RequestStatusEvent +from atst.models import Request class RequestFactory(factory.Factory): diff --git a/tests/mocks.py b/tests/mocks.py index 96c22e4a..3a277b0f 100644 --- a/tests/mocks.py +++ b/tests/mocks.py @@ -70,52 +70,3 @@ class MockFundzClient(MockApiClient): return self._get_response("GET", path, 200) else: return self._get_response("GET", path, 404) - - -class MockAuthzClient(MockApiClient): - _json = { - "atat_permissions": [ - "view_original_jedi_request", - "review_and_approve_jedi_workspace_request", - "modify_atat_role_permissions", - "create_csp_role", - "delete_csp_role", - "deactivate_csp_role", - "modify_csp_role_permissions", - "view_usage_report", - "view_usage_dollars", - "add_and_assign_csp_roles", - "remove_csp_roles", - "request_new_csp_role", - "assign_and_unassign_atat_role", - "view_assigned_atat_role_configurations", - "view_assigned_csp_role_configurations", - "deactivate_workspace", - "view_atat_permissions", - "transfer_ownership_of_workspace", - "add_application_in_workspace", - "delete_application_in_workspace", - "deactivate_application_in_workspace", - "view_application_in_workspace", - "rename_application_in_workspace", - "add_environment_in_application", - "delete_environment_in_application", - "deactivate_environment_in_application", - "view_environment_in_application", - "rename_environment_in_application", - "add_tag_to_workspace", - "remove_tag_from_workspace", - ], - "atat_role": "ccpo", - "id": "164497f6-c1ea-4f42-a5ef-101da278c012", - "username": None, - "workspace_roles": [], - } - - @tornado.gen.coroutine - def post(self, path, **kwargs): - return self._get_response("POST", path, 200, json=self._json) - - @tornado.gen.coroutine - def get(self, path, **kwargs): - return self._get_response("POST", path, 200, json=self._json) From 4742957f6d153404e7897c23d105da241f044069 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Mon, 30 Jul 2018 15:40:37 -0400 Subject: [PATCH 218/332] Remove unnecessary type hint --- tests/domain/test_users.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/domain/test_users.py b/tests/domain/test_users.py index f136e3bd..9a2245b9 100644 --- a/tests/domain/test_users.py +++ b/tests/domain/test_users.py @@ -6,7 +6,7 @@ from atst.domain.exceptions import NotFoundError, AlreadyExistsError @pytest.fixture() -def users_repo(db) -> Users: +def users_repo(db): return Users(db) From e14aac24c40ce6df50d7bfd4593d0efd0c53421f Mon Sep 17 00:00:00 2001 From: dandds Date: Tue, 31 Jul 2018 10:50:22 -0400 Subject: [PATCH 219/332] remove authz url reference in config --- config/base.ini | 1 - 1 file changed, 1 deletion(-) diff --git a/config/base.ini b/config/base.ini index 78d56c36..285eb11f 100644 --- a/config/base.ini +++ b/config/base.ini @@ -2,7 +2,6 @@ PORT=8000 ENVIRONMENT = dev DEBUG = true -AUTHZ_BASE_URL = http://localhost:8002 AUTHNID_BASE_URL= https://localhost:8001 FUNDZ_BASE_URL= http://localhost:8004 COOKIE_SECRET = some-secret-please-replace From c02a95d00a686daf26aff0e1000a4d43df24381b Mon Sep 17 00:00:00 2001 From: dandds Date: Mon, 30 Jul 2018 14:46:37 -0400 Subject: [PATCH 220/332] import fundz models --- .../versions/55ba973d08b9_add_fundz_models.py | 38 +++++++++++++++++++ atst/models/__init__.py | 2 + atst/models/pe_number.py | 13 +++++++ atst/models/task_order.py | 9 +++++ 4 files changed, 62 insertions(+) create mode 100644 alembic/versions/55ba973d08b9_add_fundz_models.py create mode 100644 atst/models/pe_number.py create mode 100644 atst/models/task_order.py diff --git a/alembic/versions/55ba973d08b9_add_fundz_models.py b/alembic/versions/55ba973d08b9_add_fundz_models.py new file mode 100644 index 00000000..097532f4 --- /dev/null +++ b/alembic/versions/55ba973d08b9_add_fundz_models.py @@ -0,0 +1,38 @@ +"""add_fundz_models + +Revision ID: 55ba973d08b9 +Revises: 4ea5917e7781 +Create Date: 2018-07-30 14:43:34.099799 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '55ba973d08b9' +down_revision = '4ea5917e7781' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('pe_number', + sa.Column('number', sa.String(), nullable=False), + sa.Column('description', sa.String(), nullable=True), + sa.PrimaryKeyConstraint('number') + ) + op.create_table('task_order', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('number', sa.String(), nullable=True), + sa.PrimaryKeyConstraint('id') + ) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('task_order') + op.drop_table('pe_number') + # ### end Alembic commands ### diff --git a/atst/models/__init__.py b/atst/models/__init__.py index fef82003..1d6daae1 100644 --- a/atst/models/__init__.py +++ b/atst/models/__init__.py @@ -8,3 +8,5 @@ from .permissions import Permissions from .role import Role from .user import User from .workspace_role import WorkspaceRole +from .pe_number import PENumber +from .task_order import TaskOrder diff --git a/atst/models/pe_number.py b/atst/models/pe_number.py new file mode 100644 index 00000000..61a0755e --- /dev/null +++ b/atst/models/pe_number.py @@ -0,0 +1,13 @@ +from sqlalchemy import String, Column + +from atst.models import Base + +class PENumber(Base): + __tablename__ = "pe_number" + + number = Column(String, primary_key=True) + description = Column(String) + + def __repr__(self): + return "".format( + self.number, self.description) diff --git a/atst/models/task_order.py b/atst/models/task_order.py new file mode 100644 index 00000000..7a7879a7 --- /dev/null +++ b/atst/models/task_order.py @@ -0,0 +1,9 @@ +from sqlalchemy import Column, Integer, String + +from atst.models import Base + +class TaskOrder(Base): + __tablename__ = "task_order" + + id = Column(Integer, primary_key=True) + number = Column(String) From 2e13c4772b5cf73c6c0b51cec707bc0ff81645a4 Mon Sep 17 00:00:00 2001 From: dandds Date: Mon, 30 Jul 2018 15:50:33 -0400 Subject: [PATCH 221/332] domain repos for PE numbers and task orders --- atst/domain/pe_numbers.py | 15 ++++++++++++++ atst/domain/task_orders.py | 18 +++++++++++++++++ tests/domain/test_pe_numbers.py | 34 ++++++++++++++++++++++++++++++++ tests/domain/test_task_orders.py | 34 ++++++++++++++++++++++++++++++++ tests/factories.py | 12 ++++++++++- 5 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 atst/domain/pe_numbers.py create mode 100644 atst/domain/task_orders.py create mode 100644 tests/domain/test_pe_numbers.py create mode 100644 tests/domain/test_task_orders.py diff --git a/atst/domain/pe_numbers.py b/atst/domain/pe_numbers.py new file mode 100644 index 00000000..07d79585 --- /dev/null +++ b/atst/domain/pe_numbers.py @@ -0,0 +1,15 @@ +from atst.models.pe_number import PENumber +from .exceptions import NotFoundError + + +class PENumbers(object): + + def __init__(self, db_session): + self.db_session = db_session + + def get(self, number): + pe_number = self.db_session.query(PENumber).get(number) + if not pe_number: + raise NotFoundError("pe_number") + + return pe_number diff --git a/atst/domain/task_orders.py b/atst/domain/task_orders.py new file mode 100644 index 00000000..cbc4cc4e --- /dev/null +++ b/atst/domain/task_orders.py @@ -0,0 +1,18 @@ +from sqlalchemy.orm.exc import NoResultFound + +from atst.models.task_order import TaskOrder +from .exceptions import NotFoundError + + +class TaskOrders(object): + + def __init__(self, db_session): + self.db_session = db_session + + def get(self, order_number): + try: + task_order = self.db_session.query(TaskOrder).filter_by(number=order_number).one() + except NoResultFound: + raise NotFoundError("task_order") + + return task_order diff --git a/tests/domain/test_pe_numbers.py b/tests/domain/test_pe_numbers.py new file mode 100644 index 00000000..ba9025be --- /dev/null +++ b/tests/domain/test_pe_numbers.py @@ -0,0 +1,34 @@ +import pytest + +from atst.domain.exceptions import NotFoundError +from atst.domain.pe_numbers import PENumbers + +from tests.factories import PENumberFactory + + +@pytest.fixture() +def pe_numbers(db): + return PENumbers(db) + +@pytest.fixture(scope="function") +def new_pe_number(db): + def make_pe_number(**kwargs): + pen = PENumberFactory.create(**kwargs) + db.add(pen) + db.commit() + + return pen + + return make_pe_number + + +def test_can_get_pe_number(pe_numbers, new_pe_number): + new_pen = new_pe_number(number="0101969F", description="Combat Support - Offensive") + pen = pe_numbers.get(new_pen.number) + + assert pen.number == new_pen.number + + +def test_nonexistent_pe_number_raises(pe_numbers): + with pytest.raises(NotFoundError): + pe_numbers.get("some fake number") diff --git a/tests/domain/test_task_orders.py b/tests/domain/test_task_orders.py new file mode 100644 index 00000000..9b7c0882 --- /dev/null +++ b/tests/domain/test_task_orders.py @@ -0,0 +1,34 @@ +import pytest + +from atst.domain.exceptions import NotFoundError +from atst.domain.task_orders import TaskOrders + +from tests.factories import TaskOrderFactory + + +@pytest.fixture() +def task_orders(db): + return TaskOrders(db) + +@pytest.fixture(scope="function") +def new_task_order(db): + def make_task_order(**kwargs): + to = TaskOrderFactory.create(**kwargs) + db.add(to) + db.commit() + + return to + + return make_task_order + + +def test_can_get_task_order(task_orders, new_task_order): + new_to = new_task_order(number="0101969F") + to = task_orders.get(new_to.number) + + assert to.id == to.id + + +def test_nonexistent_task_order_raises(task_orders): + with pytest.raises(NotFoundError): + task_orders.get("some fake number") diff --git a/tests/factories.py b/tests/factories.py index 1c870308..582ce461 100644 --- a/tests/factories.py +++ b/tests/factories.py @@ -1,7 +1,9 @@ import factory from uuid import uuid4 -from atst.models import Request +from atst.models import Request, RequestStatusEvent +from atst.models.pe_number import PENumber +from atst.models.task_order import TaskOrder class RequestFactory(factory.Factory): @@ -9,3 +11,11 @@ class RequestFactory(factory.Factory): model = Request id = factory.Sequence(lambda x: uuid4()) + +class PENumberFactory(factory.Factory): + class Meta: + model = PENumber + +class TaskOrderFactory(factory.Factory): + class Meta: + model = TaskOrder From c2d5c52577ef2f23a7edf4e2c7af31376e2c1c19 Mon Sep 17 00:00:00 2001 From: dandds Date: Mon, 30 Jul 2018 16:25:15 -0400 Subject: [PATCH 222/332] remove fundz_client in favor of pe numbers repo --- atst/app.py | 7 ------- atst/forms/financial.py | 16 ++++++++-------- atst/handlers/request_financial_verification.py | 7 ++++--- atst/handlers/request_new.py | 15 ++++++++------- tests/conftest.py | 1 - tests/handlers/test_financial_verification.py | 10 +++++++--- 6 files changed, 27 insertions(+), 29 deletions(-) diff --git a/atst/app.py b/atst/app.py index 830b7169..a94a93ec 100644 --- a/atst/app.py +++ b/atst/app.py @@ -65,7 +65,6 @@ def make_app(config, deps, **kwargs): { "page": "requests_new", "db_session": deps["db_session"], - "fundz_client": deps["fundz_client"], }, name="request_new", ), @@ -75,7 +74,6 @@ def make_app(config, deps, **kwargs): { "page": "requests_new", "db_session": deps["db_session"], - "fundz_client": deps["fundz_client"], }, name="request_form_new", ), @@ -85,7 +83,6 @@ def make_app(config, deps, **kwargs): { "page": "requests_new", "db_session": deps["db_session"], - "fundz_client": deps["fundz_client"], }, name="request_form_update", ), @@ -108,7 +105,6 @@ def make_app(config, deps, **kwargs): { "page": "financial_verification", "db_session": deps["db_session"], - "fundz_client": deps["fundz_client"], }, name="financial_verification", ), @@ -173,9 +169,6 @@ def make_deps(config): api_version="v1", validate_cert=validate_cert, ), - "fundz_client": ApiClient( - config["default"]["FUNDZ_BASE_URL"], validate_cert=validate_cert - ), "sessions": RedisSessions( redis_client, config["default"]["SESSION_TTL_SECONDS"] ), diff --git a/atst/forms/financial.py b/atst/forms/financial.py index 9c2a669c..52b4ef28 100644 --- a/atst/forms/financial.py +++ b/atst/forms/financial.py @@ -6,6 +6,8 @@ from wtforms.fields import StringField, SelectField from wtforms.form import Form from wtforms.validators import Required, Email +from atst.domain.exceptions import NotFoundError + from .fields import NewlineListField from .forms import ValidatedForm @@ -35,12 +37,10 @@ def suggest_pe_id(pe_id): @tornado.gen.coroutine -def validate_pe_id(field, existing_request, fundz_client): - response = yield fundz_client.get( - "/pe-number/{}".format(field.data), - raise_error=False, - ) - if not response.ok: +def validate_pe_id(field, existing_request, pe_numbers_repo): + try: + pe_number = pe_numbers_repo.get(field.data) + except NotFoundError: suggestion = suggest_pe_id(field.data) error_str = ( "We couldn't find that PE number. {}" @@ -56,10 +56,10 @@ def validate_pe_id(field, existing_request, fundz_client): class FinancialForm(ValidatedForm): @tornado.gen.coroutine - def perform_extra_validation(self, existing_request, fundz_client): + def perform_extra_validation(self, existing_request, pe_numbers_repo): valid = True if not existing_request or existing_request.get('pe_id') != self.pe_id.data: - valid = yield validate_pe_id(self.pe_id, existing_request, fundz_client) + valid = yield validate_pe_id(self.pe_id, existing_request, pe_numbers_repo) raise Return(valid) task_order_id = StringField( diff --git a/atst/handlers/request_financial_verification.py b/atst/handlers/request_financial_verification.py index a063692c..e93f999c 100644 --- a/atst/handlers/request_financial_verification.py +++ b/atst/handlers/request_financial_verification.py @@ -3,13 +3,14 @@ import tornado from atst.handler import BaseHandler from atst.forms.financial import FinancialForm from atst.domain.requests import Requests +from atst.domain.pe_numbers import PENumbers class RequestFinancialVerification(BaseHandler): - def initialize(self, page, db_session, fundz_client): + def initialize(self, page, db_session): self.page = page self.requests_repo = Requests(db_session) - self.fundz_client = fundz_client + self.pe_numbers_repo = PENumbers(db_session) def get_existing_request(self, request_id): return self.requests_repo.get(request_id) @@ -48,7 +49,7 @@ class RequestFinancialVerification(BaseHandler): yield self.update_request(request_id, form.data) valid = yield form.perform_extra_validation( existing_request.body.get('financial_verification'), - self.fundz_client + self.pe_numbers_repo ) if valid: self.redirect( diff --git a/atst/handlers/request_new.py b/atst/handlers/request_new.py index 67c24585..1d33daa0 100644 --- a/atst/handlers/request_new.py +++ b/atst/handlers/request_new.py @@ -7,13 +7,14 @@ from atst.forms.org import OrgForm from atst.forms.poc import POCForm from atst.forms.review import ReviewForm from atst.domain.requests import Requests +from atst.domain.pe_numbers import PENumbers class RequestNew(BaseHandler): - def initialize(self, page, db_session, fundz_client): + def initialize(self, page, db_session): self.page = page self.requests_repo = Requests(db_session) - self.fundz_client = fundz_client + self.pe_numbers_repo = PENumbers(db_session) def get_existing_request(self, request_id): if request_id is None: @@ -31,7 +32,7 @@ class RequestNew(BaseHandler): existing_request = self.get_existing_request(request_id) jedi_flow = JEDIRequestFlow( self.requests_repo, - self.fundz_client, + self.pe_numbers_repo, screen, post_data=post_data, request_id=request_id, @@ -81,7 +82,7 @@ class RequestNew(BaseHandler): request = self.requests_repo.get(request_id) jedi_flow = JEDIRequestFlow( - self.requests_repo, self.fundz_client, screen, request, request_id=request_id + self.requests_repo, self.pe_numbers_repo, screen, request, request_id=request_id ) self.render( @@ -101,7 +102,7 @@ class JEDIRequestFlow(object): def __init__( self, requests_repo, - fundz_client, + pe_numbers_repo, current_step, request=None, post_data=None, @@ -110,7 +111,7 @@ class JEDIRequestFlow(object): existing_request=None, ): self.requests_repo = requests_repo - self.fundz_client = fundz_client + self.pe_numbers_repo = pe_numbers_repo self.current_step = current_step self.request = request @@ -144,7 +145,7 @@ class JEDIRequestFlow(object): valid = yield self.form.perform_extra_validation( existing_request_data, - self.fundz_client, + self.pe_numbers_repo, ) return valid diff --git a/tests/conftest.py b/tests/conftest.py index 04510f1b..92da1bce 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -11,7 +11,6 @@ from atst.sessions import DictSessions def app(db): TEST_DEPS = { "authnid_client": MockApiClient("authnid"), - "fundz_client": MockFundzClient("fundz"), "sessions": DictSessions(), "db_session": db } diff --git a/tests/handlers/test_financial_verification.py b/tests/handlers/test_financial_verification.py index 57b8851d..d84f76bd 100644 --- a/tests/handlers/test_financial_verification.py +++ b/tests/handlers/test_financial_verification.py @@ -2,7 +2,8 @@ import re import pytest import tornado import urllib -from tests.mocks import MOCK_REQUEST, MOCK_USER, MOCK_VALID_PE_ID +from tests.mocks import MOCK_REQUEST, MOCK_USER +from tests.factories import PENumberFactory class TestPENumberInForm: @@ -73,11 +74,14 @@ class TestPENumberInForm: assert response.headers.get("Location") == "/requests/financial_verification_submitted" @pytest.mark.gen_test - def test_submit_request_form_with_new_valid_pe_id(self, monkeypatch, http_client, base_url): + def test_submit_request_form_with_new_valid_pe_id(self, db, monkeypatch, http_client, base_url): self._set_monkeypatches(monkeypatch) + pe = PENumberFactory.create(number="8675309U", description="sample PE number") + db.add(pe) + db.commit() data = dict(self.required_data) - data['pe_id'] = MOCK_VALID_PE_ID + data['pe_id'] = pe.number response = yield self.submit_data(http_client, base_url, data) From 5f1db135c3189c130aea42cdb0baeeb519b8e6b4 Mon Sep 17 00:00:00 2001 From: dandds Date: Tue, 31 Jul 2018 09:21:33 -0400 Subject: [PATCH 223/332] add script for ingesting PE numbers and necessary script config for database --- config/base.ini | 1 + script/ingest_pe_numbers.py | 40 +++++++++++++++++++++++++++++++++++++ script/setup | 3 +++ script/update | 3 +++ 4 files changed, 47 insertions(+) create mode 100644 script/ingest_pe_numbers.py diff --git a/config/base.ini b/config/base.ini index 285eb11f..8b3a6881 100644 --- a/config/base.ini +++ b/config/base.ini @@ -7,6 +7,7 @@ FUNDZ_BASE_URL= http://localhost:8004 COOKIE_SECRET = some-secret-please-replace SECRET = change_me_into_something_secret CAC_URL = https://localhost:8001 +PE_NUMBER_CSV_URL = http://c95e1ebb198426ee57b8-174bb05a294821bedbf46b6384fe9b1f.r31.cf5.rackcdn.com/penumbers.csv REDIS_URI = redis://localhost:6379 SESSION_TTL_SECONDS = 600 PGAPPNAME = atst diff --git a/script/ingest_pe_numbers.py b/script/ingest_pe_numbers.py new file mode 100644 index 00000000..1df5b132 --- /dev/null +++ b/script/ingest_pe_numbers.py @@ -0,0 +1,40 @@ +from urllib.request import urlopen +import csv + +from sqlalchemy.dialects.postgresql import insert + +# Add root project dir to the python path +import os +import sys +parent_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) +sys.path.append(parent_dir) + +from atst.app import make_deps, make_config +from atst.models import PENumber + + +def get_pe_numbers(url): + response = urlopen(url) + t = response.read().decode("utf-8") + return list(csv.reader(t.split("\r\n"))) + + +def insert_pe_numbers(db, list_of_pe_numbers): + stmt = insert(PENumber).values(list_of_pe_numbers) + do_update = stmt.on_conflict_do_update( + index_elements=["number"], + set_=dict(description=stmt.excluded.description) + ) + db.execute(do_update) + db.commit() + + +if __name__ == "__main__": + config = make_config() + deps = make_deps(config) + db = deps["db_session"] + url = config["default"]['PE_NUMBER_CSV_URL'] + print("Fetching PE numbers from {}".format(url)) + pe_numbers = get_pe_numbers(url) + print("Inserting {} PE numbers".format(len(pe_numbers))) + insert_pe_numbers(db, pe_numbers) diff --git a/script/setup b/script/setup index 5cd11461..bf83b19a 100755 --- a/script/setup +++ b/script/setup @@ -16,3 +16,6 @@ RESET_DB="true" # Run the shared setup script source ./script/include/run_setup + +# Fetch and import the PE numbers +run_command "python script/ingest_pe_numbers.py" diff --git a/script/update b/script/update index 1baef9a8..46d5d549 100755 --- a/script/update +++ b/script/update @@ -9,3 +9,6 @@ MIGRATE_DB="true" # Run the shared update script source ./script/include/run_update + +# Fetch and import/update the PE numbers +run_command "python script/ingest_pe_numbers.py" From 080d48dc388688fd24d576675ec778152c187fa5 Mon Sep 17 00:00:00 2001 From: dandds Date: Tue, 31 Jul 2018 11:19:29 -0400 Subject: [PATCH 224/332] fix pe number test to add non-existent pe number --- tests/domain/test_pe_numbers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/domain/test_pe_numbers.py b/tests/domain/test_pe_numbers.py index ba9025be..332ae688 100644 --- a/tests/domain/test_pe_numbers.py +++ b/tests/domain/test_pe_numbers.py @@ -23,7 +23,7 @@ def new_pe_number(db): def test_can_get_pe_number(pe_numbers, new_pe_number): - new_pen = new_pe_number(number="0101969F", description="Combat Support - Offensive") + new_pen = new_pe_number(number="0701367F", description="Combat Support - Offensive") pen = pe_numbers.get(new_pen.number) assert pen.number == new_pen.number From a37711b47aa7726ad7a3454ad6c117b9cc38d345 Mon Sep 17 00:00:00 2001 From: dandds Date: Tue, 31 Jul 2018 11:21:48 -0400 Subject: [PATCH 225/332] remove reference to fundz in config and api mocks --- config/base.ini | 1 - tests/conftest.py | 2 +- tests/mocks.py | 9 --------- 3 files changed, 1 insertion(+), 11 deletions(-) diff --git a/config/base.ini b/config/base.ini index 8b3a6881..e8be9197 100644 --- a/config/base.ini +++ b/config/base.ini @@ -3,7 +3,6 @@ PORT=8000 ENVIRONMENT = dev DEBUG = true AUTHNID_BASE_URL= https://localhost:8001 -FUNDZ_BASE_URL= http://localhost:8004 COOKIE_SECRET = some-secret-please-replace SECRET = change_me_into_something_secret CAC_URL = https://localhost:8001 diff --git a/tests/conftest.py b/tests/conftest.py index 92da1bce..0921f2bf 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -3,7 +3,7 @@ from sqlalchemy.orm import sessionmaker, scoped_session from atst.app import make_app, make_deps, make_config from atst.database import make_db -from tests.mocks import MockApiClient, MockFundzClient +from tests.mocks import MockApiClient from atst.sessions import DictSessions diff --git a/tests/mocks.py b/tests/mocks.py index 3a277b0f..c8903099 100644 --- a/tests/mocks.py +++ b/tests/mocks.py @@ -61,12 +61,3 @@ class MockApiClient(ApiClient): MOCK_VALID_PE_ID = "8675309U" - -class MockFundzClient(MockApiClient): - - @tornado.gen.coroutine - def get(self, path, **kwargs): - if path.endswith(MOCK_VALID_PE_ID): - return self._get_response("GET", path, 200) - else: - return self._get_response("GET", path, 404) From 5f27ae2015b097233006c415493dfc2c3409928e Mon Sep 17 00:00:00 2001 From: dandds Date: Tue, 31 Jul 2018 11:43:09 -0400 Subject: [PATCH 226/332] move logic for creating many PE Numbers to the domain repo --- atst/domain/pe_numbers.py | 11 +++++++++++ script/ingest_pe_numbers.py | 23 +++++++---------------- tests/domain/test_pe_numbers.py | 7 +++++++ 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/atst/domain/pe_numbers.py b/atst/domain/pe_numbers.py index 07d79585..a80e10ef 100644 --- a/atst/domain/pe_numbers.py +++ b/atst/domain/pe_numbers.py @@ -1,3 +1,5 @@ +from sqlalchemy.dialects.postgresql import insert + from atst.models.pe_number import PENumber from .exceptions import NotFoundError @@ -13,3 +15,12 @@ class PENumbers(object): raise NotFoundError("pe_number") return pe_number + + def create_many(self, list_of_pe_numbers): + stmt = insert(PENumber).values(list_of_pe_numbers) + do_update = stmt.on_conflict_do_update( + index_elements=["number"], + set_=dict(description=stmt.excluded.description) + ) + self.db_session.execute(do_update) + self.db_session.commit() diff --git a/script/ingest_pe_numbers.py b/script/ingest_pe_numbers.py index 1df5b132..e3bbecb0 100644 --- a/script/ingest_pe_numbers.py +++ b/script/ingest_pe_numbers.py @@ -1,8 +1,6 @@ from urllib.request import urlopen import csv -from sqlalchemy.dialects.postgresql import insert - # Add root project dir to the python path import os import sys @@ -10,7 +8,7 @@ parent_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) sys.path.append(parent_dir) from atst.app import make_deps, make_config -from atst.models import PENumber +from atst.domain.pe_numbers import PENumbers def get_pe_numbers(url): @@ -18,23 +16,16 @@ def get_pe_numbers(url): t = response.read().decode("utf-8") return list(csv.reader(t.split("\r\n"))) - -def insert_pe_numbers(db, list_of_pe_numbers): - stmt = insert(PENumber).values(list_of_pe_numbers) - do_update = stmt.on_conflict_do_update( - index_elements=["number"], - set_=dict(description=stmt.excluded.description) - ) - db.execute(do_update) - db.commit() - +def make_pe_number_repo(config): + deps = make_deps(config) + db = deps["db_session"] + return PENumbers(db) if __name__ == "__main__": config = make_config() - deps = make_deps(config) - db = deps["db_session"] url = config["default"]['PE_NUMBER_CSV_URL'] print("Fetching PE numbers from {}".format(url)) pe_numbers = get_pe_numbers(url) print("Inserting {} PE numbers".format(len(pe_numbers))) - insert_pe_numbers(db, pe_numbers) + pe_numbers_repo = make_pe_number_repo(config) + pe_numbers_repo.create_many(pe_numbers) diff --git a/tests/domain/test_pe_numbers.py b/tests/domain/test_pe_numbers.py index 332ae688..028aa712 100644 --- a/tests/domain/test_pe_numbers.py +++ b/tests/domain/test_pe_numbers.py @@ -32,3 +32,10 @@ def test_can_get_pe_number(pe_numbers, new_pe_number): def test_nonexistent_pe_number_raises(pe_numbers): with pytest.raises(NotFoundError): pe_numbers.get("some fake number") + +def test_create_many(pe_numbers): + pen_list = [['123456', 'Land Speeder'], ['7891011', 'Lightsaber']] + pe_numbers.create_many(pen_list) + + assert pe_numbers.get(pen_list[0][0]) + assert pe_numbers.get(pen_list[1][0]) From 63e3db7d511af8b5b12192780ac4e3f112a399a7 Mon Sep 17 00:00:00 2001 From: dandds Date: Wed, 1 Aug 2018 09:06:48 -0400 Subject: [PATCH 227/332] fix missing import from rebase --- tests/handlers/test_request_new.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/handlers/test_request_new.py b/tests/handlers/test_request_new.py index 3373c867..8409fc13 100644 --- a/tests/handlers/test_request_new.py +++ b/tests/handlers/test_request_new.py @@ -3,6 +3,7 @@ import pytest import tornado import urllib from tests.mocks import MOCK_USER +from tests.factories import RequestFactory ERROR_CLASS = "alert--error" MOCK_REQUEST = RequestFactory.create( From 1af0f5e579a460232919ff18875f07df5cd4fa01 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Wed, 1 Aug 2018 10:51:14 -0400 Subject: [PATCH 228/332] Flask setup --- Pipfile | 13 +- Pipfile.lock | 196 ++++++++++++++++++++------- app.py | 12 +- atst/app.py | 290 ++++++++++++++++++++-------------------- atst/assets.py | 11 +- atst/database.py | 9 +- atst/handler.py | 3 +- atst/routes/__init__.py | 7 + 8 files changed, 318 insertions(+), 223 deletions(-) create mode 100644 atst/routes/__init__.py diff --git a/Pipfile b/Pipfile index 81cadd0d..4110ccbf 100644 --- a/Pipfile +++ b/Pipfile @@ -4,20 +4,23 @@ verify_ssl = true name = "pypi" [packages] -tornado = "==5.0.2" -webassets = "==0.12.1" -Unipath = "==1.1" +tornado = "*" +webassets = "*" +Unipath = "*" wtforms-tornado = "*" pendulum = "*" redis = "*" sqlalchemy = "*" alembic = "*" "psycopg2-binary" = "*" +flask = "*" +flask-sqlalchemy = "*" +flask-assets = "*" [dev-packages] bandit = "*" -pytest = "==3.6.0" -pytest-tornado = "==0.5.0" +pytest = "*" +pytest-tornado = "*" ipython = "*" ipdb = "*" pylint = "*" diff --git a/Pipfile.lock b/Pipfile.lock index d87dfa97..d6e5cf64 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "7cd87f2c2c42bc776a6aa6f72fcbb8b30d4e703e50b6480ce1c8ace6ae6dd0a4" + "sha256": "2ee6dd90ff3784e7b1781c680d690ac59118b4e3d72e8da3adf9e93d6e512bc7" }, "pipfile-spec": 6, "requires": { @@ -24,6 +24,49 @@ "index": "pypi", "version": "==1.0.0" }, + "click": { + "hashes": [ + "sha256:29f99fc6125fbc931b758dc053b3114e55c77a6e4c6c3a2674a2dc986016381d", + "sha256:f15516df478d5a56180fbf80e68f206010e6d160fc39fa508b65e035fd75130b" + ], + "version": "==6.7" + }, + "flask": { + "hashes": [ + "sha256:2271c0070dbcb5275fad4a82e29f23ab92682dc45f9dfbc22c02ba9b9322ce48", + "sha256:a080b744b7e345ccfcbc77954861cb05b3c63786e93f2b3875e0913d44b43f05" + ], + "index": "pypi", + "version": "==1.0.2" + }, + "flask-assets": { + "hashes": [ + "sha256:6031527b89fb3509d1581d932affa5a79dd348cfffb58d0aef99a43461d47847" + ], + "index": "pypi", + "version": "==0.12" + }, + "flask-sqlalchemy": { + "hashes": [ + "sha256:3bc0fac969dd8c0ace01b32060f0c729565293302f0c4269beed154b46bec50b", + "sha256:5971b9852b5888655f11db634e87725a9031e170f37c0ce7851cf83497f56e53" + ], + "index": "pypi", + "version": "==2.3.2" + }, + "itsdangerous": { + "hashes": [ + "sha256:cbb3fcf8d3e33df861709ecaf89d9e6629cff0a217bc2848f1b41cd30d360519" + ], + "version": "==0.24" + }, + "jinja2": { + "hashes": [ + "sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd", + "sha256:f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4" + ], + "version": "==2.10" + }, "mako": { "hashes": [ "sha256:4e02fde57bd4abb5ec400181e4c314f56ac3e49ba4fb8b0d50bba18cb27d25ae" @@ -38,19 +81,22 @@ }, "pendulum": { "hashes": [ - "sha256:0643d45824e6789b88187728337dfa6075a0233f6976c2abefba00d064156309", - "sha256:3cc271195d8054bec06f54ff7d56ea6c2e2b5ad5dd6b532d787b34d2cabe6a65", - "sha256:544e44d8a92954e5ef4db4fa8b662d3282f2ac7b7c2cbf4227dc193ba78b9e1e", - "sha256:846478ab5f7480b3d850a09e44fe03830d448633c84f0b1066615ff6c34293aa", - "sha256:8bb523f759daeecfc0649369f198cbeb27a6608347354f4f847d21d579003db6", - "sha256:a449142063100f1b3c1119453c7569667c9ba79897305a1c50ca83a8c790f1e4", - "sha256:b7ff156b3d7cccbdeeb63465578d9a4e6f57d463f6ff6d4474254208d08f8353", - "sha256:d8822a592bbc16576c44ec4625bff9187ed9b649d47714e4905a55adc5b25339", - "sha256:dd45c7b349faab69714df9835cdf8bf8bce50bf6fc471419d3b23ba33e1915a5", - "sha256:fac088b637b5db5a047a0e89194d8c3c9e9e9ce1665089240003bb7c05b92536" + "sha256:0ec5371949e147753661e1e98721273170638034dfceb578f29d69d93d3d474b", + "sha256:10ccdc8c6d004ba97883dd0f57503963ddf6cb83e849a16c4675ba18da657564", + "sha256:37bb54bcbb9d7fccd725f3fda69702e51ab3de9971b4c1c986505fbb3bc58bed", + "sha256:51803352e40778f914ff7af3494788b404260b415d9a9d607a8cf73e5e120994", + "sha256:5de295ca85761d9adf4020e6f3bed6eb933846ccf23b74e04b071f6d677f11a4", + "sha256:73f850265adcf0986fcc0af83ae9c8c5a7ca3c4a2525184110478a8bfd1a77b3", + "sha256:8fe289356322f6b0f4510082b4c412a1496a64054a37ae86b24411868a1901c6", + "sha256:c0401482dfa9fbd7005f2dfbf54ec61fd2c8130df37651ac2a3722d1f049ae4e", + "sha256:c358ee65ddb99c2b1bf301458e43ed09ff6d40465bcc9928265246912fad4d0f", + "sha256:d07962450e808556b3e6209a5830e2bbf8c7747129580c3b5b09e641f72617ab", + "sha256:dc05e6186c9c3b9969326aded9cba7a796744918581b25457f5148a5e3475d55", + "sha256:ee9466eea403e8e308c284d3055e285b97905a5ffb1566df0ef200b4f39c0f15", + "sha256:f7fa6220251a636112721e8158b9dd59018d818ec121047900934d80864eca62" ], "index": "pypi", - "version": "==2.0.2" + "version": "==2.0.3" }, "psycopg2-binary": { "hashes": [ @@ -106,7 +152,7 @@ "sha256:1d936da41ee06216d89fdc7ead1ee9a5da2811a8787515a976b646e110c3f622", "sha256:e4ef42e82b0b493c5849eed98b5ab49d6767caf982127e9a33167f1153b36cc5" ], - "markers": "python_version != '3.1.*' and python_version != '3.2.*' and python_version != '3.0.*' and python_version != '3.3.*' and python_version >= '2.7'", + "markers": "python_version != '3.0.*' and python_version != '3.1.*' and python_version != '3.2.*' and python_version >= '2.7' and python_version != '3.3.*'", "version": "==2018.5" }, "redis": { @@ -133,14 +179,16 @@ }, "tornado": { "hashes": [ - "sha256:1b83d5c10550f2653380b4c77331d6f8850f287c4f67d7ce1e1c639d9222fbc7", - "sha256:408d129e9d13d3c55aa73f8084aa97d5f90ed84132e38d6932e63a67d5bec563", - "sha256:88ce0282cce70df9045e515f578c78f1ebc35dcabe1d70f800c3583ebda7f5f5", - "sha256:ba9fbb249ac5390bff8a1d6aa4b844fd400701069bda7d2e380dfe2217895101", - "sha256:c050089173c2e9272244bccfb6a8615fb9e53b79420a5551acfa76094ecc3111" + "sha256:1c0816fc32b7d31b98781bd8ebc7a9726d7dce67407dc353a2e66e697e138448", + "sha256:4f66a2172cb947387193ca4c2c3e19131f1c70fa8be470ddbbd9317fd0801582", + "sha256:5327ba1a6c694e0149e7d9126426b3704b1d9d520852a3e4aa9fc8fe989e4046", + "sha256:6a7e8657618268bb007646b9eae7661d0b57f13efc94faa33cd2588eae5912c9", + "sha256:a9b14804783a1d77c0bd6c66f7a9b1196cbddfbdf8bceb64683c5ae60bd1ec6f", + "sha256:c58757e37c4a3172949c99099d4d5106e4d7b63aa0617f9bb24bfbff712c7866", + "sha256:d8984742ce86c0855cccecd5c6f54a9f7532c983947cff06f3a0e2115b47f85c" ], "index": "pypi", - "version": "==5.0.2" + "version": "==5.1" }, "unipath": { "hashes": [ @@ -157,6 +205,13 @@ "index": "pypi", "version": "==0.12.1" }, + "werkzeug": { + "hashes": [ + "sha256:c3fd7a7d41976d9f44db327260e263132466836cef6f91512889ed60ad26557c", + "sha256:d5da73735293558eb1651ee2fddc4d0dedcfa06538b8813a2e20011583c9e49b" + ], + "version": "==0.14.1" + }, "wtforms": { "hashes": [ "sha256:0cdbac3e7f6878086c334aa25dc5a33869a3954e9d1e015130d65a69309b3b61", @@ -197,10 +252,10 @@ }, "astroid": { "hashes": [ - "sha256:0a0c484279a5f08c9bcedd6fa9b42e378866a7dcc695206b92d59dc9f2d9760d", - "sha256:218e36cf8d98a42f16214e8670819ce307fa707d1dcf7f9af84c7aede1febc7f" + "sha256:a48b57ede295c3188ef5c84273bc2a8eadc46e4cbb001eae0d49fb5d1fabbb19", + "sha256:d066cdeec5faeb51a4be5010da612680653d844b57afd86a5c8315f2f801b4cc" ], - "version": "==2.0.1" + "version": "==2.0.2" }, "atomicwrites": { "hashes": [ @@ -279,7 +334,7 @@ "sha256:0e9a1227a3a0f3297a485715e72ee6eb77081b17b629367042b586e38c03c867", "sha256:b4840807a94a3bad0217d6ed3f9b65a1cc6e1db1c99e1184673056ae2c0a4c4d" ], - "markers": "python_version != '3.2.*' and python_version != '3.0.*' and python_version >= '2.7' and python_version != '3.1.*'", + "markers": "python_version != '3.1.*' and python_version != '3.2.*' and python_version >= '2.7' and python_version != '3.0.*'", "version": "==0.8.17" }, "gitdb2": { @@ -305,11 +360,11 @@ }, "ipython": { "hashes": [ - "sha256:a0c96853549b246991046f32d19db7140f5b1a644cc31f0dc1edc86713b7676f", - "sha256:eca537aa61592aca2fef4adea12af8e42f5c335004dfa80c78caf80e8b525e5c" + "sha256:007dcd929c14631f83daff35df0147ea51d1af420da303fd078343878bd5fb62", + "sha256:b0f2ef9eada4a68ef63ee10b6dde4f35c840035c50fd24265f8052c98947d5a4" ], "index": "pypi", - "version": "==6.4.0" + "version": "==6.5.0" }, "ipython-genutils": { "hashes": [ @@ -324,7 +379,7 @@ "sha256:b9c40e9750f3d77e6e4d441d8b0266cf555e7cdabdcff33c4fd06366ca761ef8", "sha256:ec9ef8f4a9bc6f71eec99e1806bfa2de401650d996c59330782b89a5555c1497" ], - "markers": "python_version >= '2.7' and python_version != '3.1.*' and python_version != '3.3.*' and python_version != '3.0.*' and python_version != '3.2.*'", + "markers": "python_version != '3.3.*' and python_version >= '2.7' and python_version != '3.1.*' and python_version != '3.0.*' and python_version != '3.2.*'", "version": "==4.3.4" }, "jedi": { @@ -377,11 +432,11 @@ }, "more-itertools": { "hashes": [ - "sha256:2b6b9893337bfd9166bee6a62c2b0c9fe7735dcf85948b387ec8cba30e85d8e8", - "sha256:6703844a52d3588f951883005efcf555e49566a48afd4db4e965d69b883980d3", - "sha256:a18d870ef2ffca2b8463c0070ad17b5978056f403fb64e3f15fe62a52db21cc0" + "sha256:c187a73da93e7a8acc0001572aebc7e3c69daf7bf6881a2cea10650bd4420092", + "sha256:c476b5d3a34e12d40130bc2f935028b5f636df8f372dc2c1c01dc19681b2039e", + "sha256:fcbfeaea0be121980e15bc97b3817b5202ca73d0eae185b4550cbfce2a3ebb3d" ], - "version": "==4.2.0" + "version": "==4.3.0" }, "parso": { "hashes": [ @@ -398,10 +453,10 @@ }, "pbr": { "hashes": [ - "sha256:754e766b4f4bad3aa68cfd532456298da1aa39375da8748392dbae90860d5f18", - "sha256:c6bddbad814f23c7faaf88d8a186e9965243cc6206a23361b73023648e645794" + "sha256:1b8be50d938c9bb75d0eaf7eda111eec1bf6dc88a62a6412e33bf077457e0f45", + "sha256:b486975c0cafb6beeb50ca0e17ba047647f229087bd74e37f4a7e2cac17d2caa" ], - "version": "==4.1.1" + "version": "==4.2.0" }, "pexpect": { "hashes": [ @@ -420,12 +475,11 @@ }, "pluggy": { "hashes": [ - "sha256:7f8ae7f5bdf75671a718d2daf0a64b7885f74510bcd98b1a0bb420eb9a9d0cff", - "sha256:d345c8fe681115900d6da8d048ba67c25df42973bda370783cd58826442dcd7c", - "sha256:e160a7fcf25762bb60efc7e171d4497ff1d8d2d75a3d0df7a21b76821ecbf5c5" + "sha256:6e3836e39f4d36ae72840833db137f7b7d35105079aee6ec4a62d9f80d594dd1", + "sha256:95eb8364a4708392bae89035f45341871286a333f749c3141c20573d2b3876e1" ], - "markers": "python_version >= '2.7' and python_version != '3.1.*' and python_version != '3.3.*' and python_version != '3.0.*' and python_version != '3.2.*'", - "version": "==0.6.0" + "markers": "python_version != '3.3.*' and python_version >= '2.7' and python_version != '3.1.*' and python_version != '3.0.*' and python_version != '3.2.*'", + "version": "==0.7.1" }, "prompt-toolkit": { "hashes": [ @@ -447,7 +501,7 @@ "sha256:3fd59af7435864e1a243790d322d763925431213b6b8529c6ca71081ace3bbf7", "sha256:e31fb2767eb657cbde86c454f02e99cb846d3cd9d61b318525140214fdc0e98e" ], - "markers": "python_version >= '2.7' and python_version != '3.1.*' and python_version != '3.3.*' and python_version != '3.0.*' and python_version != '3.2.*'", + "markers": "python_version != '3.3.*' and python_version >= '2.7' and python_version != '3.1.*' and python_version != '3.0.*' and python_version != '3.2.*'", "version": "==1.5.4" }, "pygments": { @@ -459,19 +513,19 @@ }, "pylint": { "hashes": [ - "sha256:2c90a24bee8fae22ac98061c896e61f45c5b73c2e0511a4bf53f99ba56e90434", - "sha256:454532779425098969b8f54ab0f056000b883909f69d05905ea114df886e3251" + "sha256:0edfec21270725c5aa8e8d8d06ef5666f766e0e748ed2f1ab23624727303b935", + "sha256:4cadcaa4f1fb19123d4baa758d9fbe6286c5b3aa513af6ea42a2d51d405db205" ], "index": "pypi", - "version": "==2.0.1" + "version": "==2.1.0" }, "pytest": { "hashes": [ - "sha256:39555d023af3200d004d09e51b4dd9fdd828baa863cded3fd6ba2f29f757ae2d", - "sha256:c76e93f3145a44812955e8d46cdd302d8a45fbfc7bf22be24fe231f9d8d8853a" + "sha256:8214ab8446104a1d0c17fbd218ec6aac743236c6ffbe23abc038e40213c60b88", + "sha256:e2b2c6e1560b8f9dc8dd600b0923183fbd68ba3d9bdecde04467be6dd296a384" ], "index": "pypi", - "version": "==3.6.0" + "version": "==3.7.0" }, "pytest-tornado": { "hashes": [ @@ -547,14 +601,16 @@ }, "tornado": { "hashes": [ - "sha256:1b83d5c10550f2653380b4c77331d6f8850f287c4f67d7ce1e1c639d9222fbc7", - "sha256:408d129e9d13d3c55aa73f8084aa97d5f90ed84132e38d6932e63a67d5bec563", - "sha256:88ce0282cce70df9045e515f578c78f1ebc35dcabe1d70f800c3583ebda7f5f5", - "sha256:ba9fbb249ac5390bff8a1d6aa4b844fd400701069bda7d2e380dfe2217895101", - "sha256:c050089173c2e9272244bccfb6a8615fb9e53b79420a5551acfa76094ecc3111" + "sha256:1c0816fc32b7d31b98781bd8ebc7a9726d7dce67407dc353a2e66e697e138448", + "sha256:4f66a2172cb947387193ca4c2c3e19131f1c70fa8be470ddbbd9317fd0801582", + "sha256:5327ba1a6c694e0149e7d9126426b3704b1d9d520852a3e4aa9fc8fe989e4046", + "sha256:6a7e8657618268bb007646b9eae7661d0b57f13efc94faa33cd2588eae5912c9", + "sha256:a9b14804783a1d77c0bd6c66f7a9b1196cbddfbdf8bceb64683c5ae60bd1ec6f", + "sha256:c58757e37c4a3172949c99099d4d5106e4d7b63aa0617f9bb24bfbff712c7866", + "sha256:d8984742ce86c0855cccecd5c6f54a9f7532c983947cff06f3a0e2115b47f85c" ], "index": "pypi", - "version": "==5.0.2" + "version": "==5.1" }, "traitlets": { "hashes": [ @@ -563,6 +619,42 @@ ], "version": "==4.3.2" }, + "typed-ast": { + "hashes": [ + "sha256:0948004fa228ae071054f5208840a1e88747a357ec1101c17217bfe99b299d58", + "sha256:10703d3cec8dcd9eef5a630a04056bbc898abc19bac5691612acba7d1325b66d", + "sha256:1f6c4bd0bdc0f14246fd41262df7dfc018d65bb05f6e16390b7ea26ca454a291", + "sha256:25d8feefe27eb0303b73545416b13d108c6067b846b543738a25ff304824ed9a", + "sha256:29464a177d56e4e055b5f7b629935af7f49c196be47528cc94e0a7bf83fbc2b9", + "sha256:2e214b72168ea0275efd6c884b114ab42e316de3ffa125b267e732ed2abda892", + "sha256:3e0d5e48e3a23e9a4d1a9f698e32a542a4a288c871d33ed8df1b092a40f3a0f9", + "sha256:519425deca5c2b2bdac49f77b2c5625781abbaf9a809d727d3a5596b30bb4ded", + "sha256:57fe287f0cdd9ceaf69e7b71a2e94a24b5d268b35df251a88fef5cc241bf73aa", + "sha256:668d0cec391d9aed1c6a388b0d5b97cd22e6073eaa5fbaa6d2946603b4871efe", + "sha256:68ba70684990f59497680ff90d18e756a47bf4863c604098f10de9716b2c0bdd", + "sha256:6de012d2b166fe7a4cdf505eee3aaa12192f7ba365beeefaca4ec10e31241a85", + "sha256:79b91ebe5a28d349b6d0d323023350133e927b4de5b651a8aa2db69c761420c6", + "sha256:8550177fa5d4c1f09b5e5f524411c44633c80ec69b24e0e98906dd761941ca46", + "sha256:898f818399cafcdb93cbbe15fc83a33d05f18e29fb498ddc09b0214cdfc7cd51", + "sha256:94b091dc0f19291adcb279a108f5d38de2430411068b219f41b343c03b28fb1f", + "sha256:a26863198902cda15ab4503991e8cf1ca874219e0118cbf07c126bce7c4db129", + "sha256:a8034021801bc0440f2e027c354b4eafd95891b573e12ff0418dec385c76785c", + "sha256:bc978ac17468fe868ee589c795d06777f75496b1ed576d308002c8a5756fb9ea", + "sha256:c05b41bc1deade9f90ddc5d988fe506208019ebba9f2578c622516fd201f5863", + "sha256:c9b060bd1e5a26ab6e8267fd46fc9e02b54eb15fffb16d112d4c7b1c12987559", + "sha256:edb04bdd45bfd76c8292c4d9654568efaedf76fe78eb246dde69bdb13b2dad87", + "sha256:f19f2a4f547505fe9072e15f6f4ae714af51b5a681a97f187971f50c283193b6" + ], + "version": "==1.1.0" + }, + "typing": { + "hashes": [ + "sha256:3a887b021a77b292e151afb75323dea88a7bc1b3dfa92176cff8e44c8b68bddf", + "sha256:b2c689d54e1144bbcfd191b0832980a21c2dbcf7b5ff7a66248a60c90e951eb8", + "sha256:d400a9344254803a2368533e4533a4200d21eb7b6b729c173bc38201a74db3f2" + ], + "version": "==3.6.4" + }, "watchdog": { "hashes": [ "sha256:7e65882adb7746039b6f3876ee174952f8eaaa34491ba34333ddf1fe35de4162" diff --git a/app.py b/app.py index b6d66f53..6d786f34 100755 --- a/app.py +++ b/app.py @@ -1,15 +1,11 @@ #!/usr/bin/env python -import tornado.ioloop - -from atst.app import make_app, make_deps, make_config +from atst.app import make_app, make_config config = make_config() -deps = make_deps(config) -app = make_app(config, deps) +app = make_app(config) if __name__ == "__main__": - port = int(config["default"]["PORT"]) - app.listen(port) + port = int(config["PORT"]) + app.run(port=port) print("Listening on http://localhost:%i" % port) - tornado.ioloop.IOLoop.current().start() diff --git a/atst/app.py b/atst/app.py index a94a93ec..5128117f 100644 --- a/atst/app.py +++ b/atst/app.py @@ -1,160 +1,166 @@ import os from configparser import ConfigParser -import tornado.web -from tornado.web import url from redis import StrictRedis +from flask import Flask +from unipath import Path -from atst.handlers.main import Main -from atst.handlers.root import Root -from atst.handlers.login_redirect import LoginRedirect -from atst.handlers.workspaces import Workspaces -from atst.handlers.workspace import Workspace -from atst.handlers.workspace_members import WorkspaceMembers -from atst.handlers.request import Request -from atst.handlers.request_financial_verification import RequestFinancialVerification -from atst.handlers.request_new import RequestNew -from atst.handlers.request_submit import RequestsSubmit -from atst.handlers.dev import Dev -from atst.home import home from atst.api_client import ApiClient from atst.sessions import RedisSessions -from atst import ui_modules -from atst import ui_methods -from atst.database import make_db +from atst.database import db +from atst.assets import assets +from atst.routes import bp ENV = os.getenv("TORNADO_ENV", "dev") -def make_app(config, deps, **kwargs): +def make_app(config): - routes = [ - url(r"/", Root, {"page": "root"}, name="root"), - url( - r"/login-redirect", - LoginRedirect, - { - "sessions": deps["sessions"], - "authnid_client": deps["authnid_client"], - "db_session": deps["db_session"], - }, - name="login_redirect", - ), - url(r"/home", Main, {"page": "home"}, name="home"), - url(r"/styleguide", Main, {"page": "styleguide"}, name="styleguide"), - url( - r"/workspaces/blank", - Main, - {"page": "workspaces_blank"}, - name="workspaces_blank", - ), - url( - r"/workspaces", - Workspaces, - {"page": "workspaces", "db_session": deps["db_session"]}, - name="workspaces", - ), - url( - r"/requests", - Request, - {"page": "requests", "db_session": deps["db_session"]}, - name="requests", - ), - url( - r"/requests/new", - RequestNew, - { - "page": "requests_new", - "db_session": deps["db_session"], - }, - name="request_new", - ), - url( - r"/requests/new/([0-9])", - RequestNew, - { - "page": "requests_new", - "db_session": deps["db_session"], - }, - name="request_form_new", - ), - url( - r"/requests/new/([0-9])/(\S+)", - RequestNew, - { - "page": "requests_new", - "db_session": deps["db_session"], - }, - name="request_form_update", - ), - url( - r"/requests/submit/(\S+)", - RequestsSubmit, - {"db_session": deps["db_session"]}, - name="requests_submit", - ), - # Dummy request/approval screen - url( - r"/request/approval", - Main, - {"page": "request_approval"}, - name="request_approval", - ), - url( - r"/requests/verify/(\S+)", - RequestFinancialVerification, - { - "page": "financial_verification", - "db_session": deps["db_session"], - }, - name="financial_verification", - ), - url( - r"/requests/financial_verification_submitted", - Main, - {"page": "requests/financial_verification_submitted"}, - name="financial_verification_submitted", - ), - url(r"/users", Main, {"page": "users"}, name="users"), - url(r"/reports", Main, {"page": "reports"}, name="reports"), - url(r"/calculator", Main, {"page": "calculator"}, name="calculator"), - url( - r"/workspaces/(\S+)/members", WorkspaceMembers, {}, name="workspace_members" - ), - url(r"/workspaces/(\S+)/projects", Workspace, {}, name="workspace_projects"), - url(r"/workspaces/123456/projects/789/edit", Main, {"page": "project_edit"}, name="project_edit"), - url(r"/workspaces/123456/members/789/edit", Main, {"page": "member_edit"}, name="member_edit"), - ] + parent_dir = Path().parent - if not ENV == "production": - routes += [ - url( - r"/login-dev", - Dev, - { - "action": "login", - "sessions": deps["sessions"], - "db_session": deps["db_session"], - }, - name="dev-login", - ) - ] - - app = tornado.web.Application( - routes, - login_url="/", - template_path=home.child("templates"), - static_path=home.child("static"), - cookie_secret=config["default"]["COOKIE_SECRET"], - debug=config["default"].getboolean("DEBUG"), - ui_modules=ui_modules, - ui_methods=ui_methods, - **kwargs + app = Flask( + __name__, + template_folder=parent_dir.child("templates").absolute(), + static_folder=parent_dir.child("static").absolute() ) - app.config = config - app.sessions = deps["sessions"] + app.config.update(config) + + db.init_app(app) + assets.init_app(app) + + app.register_blueprint(bp) + return app +# def make_app(config, deps, **kwargs): +# routes = [ +# url(r"/", Root, {"page": "root"}, name="root"), +# url( +# r"/login-redirect", +# LoginRedirect, +# { +# "sessions": deps["sessions"], +# "authnid_client": deps["authnid_client"], +# "db_session": deps["db_session"], +# }, +# name="login_redirect", +# ), +# url(r"/home", Main, {"page": "home"}, name="home"), +# url(r"/styleguide", Main, {"page": "styleguide"}, name="styleguide"), +# url( +# r"/workspaces/blank", +# Main, +# {"page": "workspaces_blank"}, +# name="workspaces_blank", +# ), +# url( +# r"/workspaces", +# Workspaces, +# {"page": "workspaces", "db_session": deps["db_session"]}, +# name="workspaces", +# ), +# url( +# r"/requests", +# Request, +# {"page": "requests", "db_session": deps["db_session"]}, +# name="requests", +# ), +# url( +# r"/requests/new", +# RequestNew, +# { +# "page": "requests_new", +# "db_session": deps["db_session"], +# }, +# name="request_new", +# ), +# url( +# r"/requests/new/([0-9])", +# RequestNew, +# { +# "page": "requests_new", +# "db_session": deps["db_session"], +# }, +# name="request_form_new", +# ), +# url( +# r"/requests/new/([0-9])/(\S+)", +# RequestNew, +# { +# "page": "requests_new", +# "db_session": deps["db_session"], +# }, +# name="request_form_update", +# ), +# url( +# r"/requests/submit/(\S+)", +# RequestsSubmit, +# {"db_session": deps["db_session"]}, +# name="requests_submit", +# ), +# # Dummy request/approval screen +# url( +# r"/request/approval", +# Main, +# {"page": "request_approval"}, +# name="request_approval", +# ), +# url( +# r"/requests/verify/(\S+)", +# RequestFinancialVerification, +# { +# "page": "financial_verification", +# "db_session": deps["db_session"], +# }, +# name="financial_verification", +# ), +# url( +# r"/requests/financial_verification_submitted", +# Main, +# {"page": "requests/financial_verification_submitted"}, +# name="financial_verification_submitted", +# ), +# url(r"/users", Main, {"page": "users"}, name="users"), +# url(r"/reports", Main, {"page": "reports"}, name="reports"), +# url(r"/calculator", Main, {"page": "calculator"}, name="calculator"), +# url( +# r"/workspaces/(\S+)/members", WorkspaceMembers, {}, name="workspace_members" +# ), +# url(r"/workspaces/(\S+)/projects", Workspace, {}, name="workspace_projects"), +# url(r"/workspaces/123456/projects/789/edit", Main, {"page": "project_edit"}, name="project_edit"), +# url(r"/workspaces/123456/members/789/edit", Main, {"page": "member_edit"}, name="member_edit"), +# ] + +# if not ENV == "production": +# routes += [ +# url( +# r"/login-dev", +# Dev, +# { +# "action": "login", +# "sessions": deps["sessions"], +# "db_session": deps["db_session"], +# }, +# name="dev-login", +# ) +# ] + +# app = tornado.web.Application( +# routes, +# login_url="/", +# template_path=home.child("templates"), +# static_path=home.child("static"), +# cookie_secret=config["default"]["COOKIE_SECRET"], +# debug=config["default"].getboolean("DEBUG"), +# ui_modules=ui_modules, +# ui_methods=ui_methods, +# **kwargs +# ) +# app.config = config +# app.sessions = deps["sessions"] +# return app + + def make_deps(config): # we do not want to do SSL verify services in test and development validate_cert = ENV == "production" @@ -206,4 +212,4 @@ def make_config(): ) config.set("default", "DATABASE_URI", database_uri) - return config + return config["default"] diff --git a/atst/assets.py b/atst/assets.py index 7f723f75..bed898ac 100644 --- a/atst/assets.py +++ b/atst/assets.py @@ -1,16 +1,13 @@ -from webassets import Environment, Bundle +from flask_assets import Environment, Bundle from atst.home import home -environment = Environment( - directory=home.child("scss"), - url="/static" -) +assets = Environment() css = Bundle( - "atat.scss", + "../scss/atat.scss", filters="scss", output="../static/assets/out.%(version)s.css", depends=("**/*.scss"), ) -environment.register("css", css) +assets.register("css", css) diff --git a/atst/database.py b/atst/database.py index 6191f62e..f0b13d6f 100644 --- a/atst/database.py +++ b/atst/database.py @@ -1,8 +1,3 @@ -from sqlalchemy import create_engine -from sqlalchemy.orm import sessionmaker, scoped_session +from flask_sqlalchemy import SQLAlchemy - -def make_db(config): - engine = create_engine(config['default']['DATABASE_URI']) - session = scoped_session(sessionmaker(bind=engine)) - return session +db = SQLAlchemy() diff --git a/atst/handler.py b/atst/handler.py index bcbcf879..bc931a8d 100644 --- a/atst/handler.py +++ b/atst/handler.py @@ -1,9 +1,8 @@ import tornado.web -from atst.assets import environment from atst.sessions import SessionNotFoundError from atst.domain.users import Users -helpers = {"assets": environment} +helpers = {"assets": None} class BaseHandler(tornado.web.RequestHandler): diff --git a/atst/routes/__init__.py b/atst/routes/__init__.py new file mode 100644 index 00000000..c6b03baf --- /dev/null +++ b/atst/routes/__init__.py @@ -0,0 +1,7 @@ +from flask import Blueprint, render_template + +bp = Blueprint("atst", __name__) + +@bp.route("/") +def home(): + return render_template("home.html") From 9d9c980eb02d4732cc73701d2509c46ef8b0ac80 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Wed, 1 Aug 2018 11:22:21 -0400 Subject: [PATCH 229/332] Convert ui methods into Flask globals --- atst/app.py | 31 +++++++++++++++++++++++++-- atst/routes/__init__.py | 2 +- templates/{base.html.to => base.html} | 22 +++++++++---------- templates/{home.html.to => home.html} | 4 ++-- 4 files changed, 42 insertions(+), 17 deletions(-) rename templates/{base.html.to => base.html} (60%) rename templates/{home.html.to => home.html} (68%) diff --git a/atst/app.py b/atst/app.py index 5128117f..f4cfe183 100644 --- a/atst/app.py +++ b/atst/app.py @@ -1,7 +1,8 @@ import os +import re from configparser import ConfigParser from redis import StrictRedis -from flask import Flask +from flask import Flask, request, g from unipath import Path from atst.api_client import ApiClient @@ -24,6 +25,8 @@ def make_app(config): ) app.config.update(config) + make_flask_callbacks(app) + db.init_app(app) assets.init_app(app) @@ -32,6 +35,21 @@ def make_app(config): return app +def make_flask_callbacks(app): + @app.before_request + def set_globals(): + g.navigationContext = 'workspace' if re.match('\/workspaces\/[A-Za-z0-9]*', request.url) else 'global' + g.dev = os.getenv("TORNADO_ENV", "dev") == "dev" + g.matchesPath = lambda href: re.match('^'+href, request.url) + g.modalOpen = request.args.get("modal", False) + + # TODO: Make me a macro + def modal(self, body): + return self.render_string( + "components/modal.html.to", + body=body) + + # def make_app(config, deps, **kwargs): # routes = [ # url(r"/", Root, {"page": "root"}, name="root"), @@ -180,6 +198,15 @@ def make_deps(config): ), } +def map_config(config): + return { + "ENV": config["default"]["ENVIRONMENT"], + "DEBUG": config["default"]["DEBUG"], + "PORT": int(config["default"]["PORT"]), + "SQLALCHEMY_DATABASE_URI": config["default"]["DATABASE_URI"], + "SQLALCHEMY_TRACK_MODIFICATIONS": False, + **config["default"] + } def make_config(): BASE_CONFIG_FILENAME = os.path.join(os.path.dirname(__file__), "../config/base.ini") @@ -212,4 +239,4 @@ def make_config(): ) config.set("default", "DATABASE_URI", database_uri) - return config["default"] + return map_config(config) diff --git a/atst/routes/__init__.py b/atst/routes/__init__.py index c6b03baf..93fde8e2 100644 --- a/atst/routes/__init__.py +++ b/atst/routes/__init__.py @@ -1,4 +1,4 @@ -from flask import Blueprint, render_template +from flask import Blueprint, render_template, g bp = Blueprint("atst", __name__) diff --git a/templates/base.html.to b/templates/base.html similarity index 60% rename from templates/base.html.to rename to templates/base.html index 3f0d5995..58c804cb 100644 --- a/templates/base.html.to +++ b/templates/base.html @@ -1,21 +1,21 @@ {# TODO: set this context elsewhere #} {# set context='workspace' #} -{% set context=navigationContext() %} +{% set context=g.navigationContext %} - {% block title %}JEDI{% end %} - {% for url in assets['css'].urls() %} - - {% end %} + {% block title %}JEDI{% endblock %} + {% assets "css" %} + + {% endassets %} - + - {% block template_vars %}{% end %} + {% block template_vars %}{% endblock %} {% include 'navigation/topbar.html.to' %} @@ -23,18 +23,16 @@ {% include 'navigation/global_navigation.html.to' %}
      - {% block sidenav %}{% end %} + {% block sidenav %}{% endblock %} {% block content %} these are not the droids you are looking for - {% end %} + {% endblock %}
    {% include 'footer.html.to' %} - {% block modal %}{% end %} + {% block modal %}{% endblock %} - - diff --git a/templates/home.html.to b/templates/home.html similarity index 68% rename from templates/home.html.to rename to templates/home.html index eb789f28..0df70037 100644 --- a/templates/home.html.to +++ b/templates/home.html @@ -1,4 +1,4 @@ -{% extends "base.html.to" %} +{% extends "base.html" %} {% block content %} @@ -8,7 +8,7 @@ -{% end %} +{% endblock %} From 9c024e382a5cb95d59c222e6b53c544f9450efaa Mon Sep 17 00:00:00 2001 From: richard-dds Date: Wed, 1 Aug 2018 11:40:07 -0400 Subject: [PATCH 230/332] home.html is rendering - Converted Icon and SidenavItem into macros - Setting a mock user on g.current_user --- atst/app.py | 6 ++++ templates/components.html | 32 +++++++++++++++++++ .../navigation/global_navigation.html.to | 25 ++++++++------- templates/navigation/topbar.html.to | 9 +++--- 4 files changed, 56 insertions(+), 16 deletions(-) create mode 100644 templates/components.html diff --git a/atst/app.py b/atst/app.py index f4cfe183..23ad724b 100644 --- a/atst/app.py +++ b/atst/app.py @@ -42,6 +42,12 @@ def make_flask_callbacks(app): g.dev = os.getenv("TORNADO_ENV", "dev") == "dev" g.matchesPath = lambda href: re.match('^'+href, request.url) g.modalOpen = request.args.get("modal", False) + g.current_user = { + "id": "cce17030-4109-4719-b958-ed109dbb87c8", + "first_name": "Amanda", + "last_name": "Adamson", + "atat_role": "default" + } # TODO: Make me a macro def modal(self, body): diff --git a/templates/components.html b/templates/components.html new file mode 100644 index 00000000..06d487ea --- /dev/null +++ b/templates/components.html @@ -0,0 +1,32 @@ +{% macro Icon(name, classes="") -%} + {% autoescape false %} + + {% endautoescape %} +{%- endmacro %} + +{% macro SidenavItem(label, href, active=False, icon=None, subnav=None) -%} +
  • + + {% if icon %} + {{ Icon(icon, classes="sidenav__link-icon") }} + {% endif %} + + {{label}} + + + {% if subnav and active %} + + {% endif %} +
  • +{%- endmacro %} diff --git a/templates/navigation/global_navigation.html.to b/templates/navigation/global_navigation.html.to index 60991d47..594bf574 100644 --- a/templates/navigation/global_navigation.html.to +++ b/templates/navigation/global_navigation.html.to @@ -1,24 +1,25 @@ +{% from "components.html" import SidenavItem %} diff --git a/templates/navigation/topbar.html.to b/templates/navigation/topbar.html.to index 9af26690..10fc0c6d 100644 --- a/templates/navigation/topbar.html.to +++ b/templates/navigation/topbar.html.to @@ -1,18 +1,19 @@ +{% from "components.html" import Icon %}
    From 494a91979718bd7acb9ba6f94def445950f8bb58 Mon Sep 17 00:00:00 2001 From: dandds Date: Wed, 1 Aug 2018 13:15:07 -0400 Subject: [PATCH 231/332] switch workspace routes and templates to Flask and Jinja --- atst/app.py | 2 ++ atst/routes/workspaces.py | 31 ++++++++++++++++++ ..._workspace.html.to => base_workspace.html} | 6 ++-- templates/components.html | 12 +++++++ .../navigation/workspace_navigation.html.to | 32 ++++++++++--------- ...members.html.to => workspace_members.html} | 16 ++++++---- ...ojects.html.to => workspace_projects.html} | 16 ++++++---- .../{workspaces.html.to => workspaces.html} | 6 ++-- 8 files changed, 86 insertions(+), 35 deletions(-) create mode 100644 atst/routes/workspaces.py rename templates/{base_workspace.html.to => base_workspace.html} (70%) rename templates/{workspace_members.html.to => workspace_members.html} (92%) rename templates/{workspace_projects.html.to => workspace_projects.html} (72%) rename templates/{workspaces.html.to => workspaces.html} (91%) diff --git a/atst/app.py b/atst/app.py index 23ad724b..087277fc 100644 --- a/atst/app.py +++ b/atst/app.py @@ -10,6 +10,7 @@ from atst.sessions import RedisSessions from atst.database import db from atst.assets import assets from atst.routes import bp +from atst.routes.workspaces import bp as workspace_routes ENV = os.getenv("TORNADO_ENV", "dev") @@ -31,6 +32,7 @@ def make_app(config): assets.init_app(app) app.register_blueprint(bp) + app.register_blueprint(workspace_routes) return app diff --git a/atst/routes/workspaces.py b/atst/routes/workspaces.py new file mode 100644 index 00000000..1f3b47f2 --- /dev/null +++ b/atst/routes/workspaces.py @@ -0,0 +1,31 @@ +from flask import Blueprint, render_template + +from atst.domain.workspaces import Projects, Members +from atst.database import db + +bp = Blueprint("workspaces", __name__) + +mock_workspaces = [ + { + "name": "Unclassified IaaS and PaaS for Defense Digital Service (DDS)", + "id": "5966187a-eff9-44c3-aa15-4de7a65ac7ff", + "task_order": {"number": 123456}, + "user_count": 23, + } +] + +@bp.route("/workspaces") +def workspaces(): + return render_template("workspaces.html", page=5, workspaces=mock_workspaces) + +@bp.route("/workspaces//projects") +def workspace_projects(workspace_id): + projects_repo = Projects() + projects = projects_repo.get_many(workspace_id) + return render_template("workspace_projects.html", workspace_id=workspace_id, projects=projects) + +@bp.route("/workspaces//members") +def workspace_members(workspace_id): + members_repo = Members() + members = members_repo.get_many(workspace_id) + return render_template("workspace_members.html", workspace_id=workspace_id, members=members) diff --git a/templates/base_workspace.html.to b/templates/base_workspace.html similarity index 70% rename from templates/base_workspace.html.to rename to templates/base_workspace.html index 7803ace8..0ccad5ba 100644 --- a/templates/base_workspace.html.to +++ b/templates/base_workspace.html @@ -1,4 +1,4 @@ -{% extends "base.html.to" %} +{% extends "base.html" %} {% block content %} @@ -8,8 +8,8 @@
    - {% block workspace_content %}{% end %} + {% block workspace_content %}{% endblock %}
    -{% end %} +{% endblock %} diff --git a/templates/components.html b/templates/components.html index 06d487ea..0bc83991 100644 --- a/templates/components.html +++ b/templates/components.html @@ -30,3 +30,15 @@ {% endif %} {%- endmacro %} + +{% macro EmptyState(self, message, actionLabel, actionHref, icon=None) -%} +
    +

    {{ message }}

    + + {% if icon %} + {{ Icon(icon) }} + {% endif %} + + {{ actionLabel }} +
    +{%- endmacro %} diff --git a/templates/navigation/workspace_navigation.html.to b/templates/navigation/workspace_navigation.html.to index 65a9525b..d516c1b0 100644 --- a/templates/navigation/workspace_navigation.html.to +++ b/templates/navigation/workspace_navigation.html.to @@ -1,42 +1,44 @@ +{% from "components.html" import SidenavItem %} + diff --git a/templates/workspace_members.html.to b/templates/workspace_members.html similarity index 92% rename from templates/workspace_members.html.to rename to templates/workspace_members.html index 0f538b05..989d1d0e 100644 --- a/templates/workspace_members.html.to +++ b/templates/workspace_members.html @@ -1,15 +1,17 @@ -{% extends "base_workspace.html.to" %} +{% from "components.html" import EmptyState %} + +{% extends "base_workspace.html" %} {% block workspace_content %} {% if not members %} - {% module EmptyState( + {{ EmptyState( 'There are currently no members in this Workspace.', actionLabel='Invite a new Member', actionHref='/members/new', icon='avatar' - )%} + )}} {% else %} @@ -59,17 +61,17 @@ {% for m in members %} {{ m['first_name'] }} {{ m['last_name'] }} - {% if m['num_projects'] == '0' %} No Project Access {% end %} + {% if m['num_projects'] == '0' %} No Project Access {% endif %} {{ m['status'] }} {{ m['workspace_role'] }} - {% end %} + {% endfor %}
    -{% end %} +{% endif %} -{% end %} +{% endblock %} diff --git a/templates/workspace_projects.html.to b/templates/workspace_projects.html similarity index 72% rename from templates/workspace_projects.html.to rename to templates/workspace_projects.html index a9f1a8aa..91826bb6 100644 --- a/templates/workspace_projects.html.to +++ b/templates/workspace_projects.html @@ -1,13 +1,15 @@ -{% extends "base_workspace.html.to" %} +{% from "components.html" import Icon %} + +{% extends "base_workspace.html" %} {% block workspace_content %} {% for project in projects %}
    -

    {{ project['name'] }} ({{ len(project['environments'])}} environments)

    +

    {{ project['name'] }} ({{ project['environments']|length }} environments)

    - {% module Icon('edit') %} + {{ Icon('edit') }} edit
    @@ -15,7 +17,7 @@ {% for environment in project['environments'] %}
  • - {% module Icon('link') %} + {{ Icon('link') }} {{ environment["name"]}} @@ -24,10 +26,10 @@ members
  • - {% end %} + {% endfor %}
    -{% end %} +{% endfor %} -{% end %} +{% endblock %} diff --git a/templates/workspaces.html.to b/templates/workspaces.html similarity index 91% rename from templates/workspaces.html.to rename to templates/workspaces.html index 21bbad7d..5f407766 100644 --- a/templates/workspaces.html.to +++ b/templates/workspaces.html @@ -1,4 +1,4 @@ -{% extends "base.html.to" %} +{% extends "base.html" %} {% block content %}
    @@ -23,9 +23,9 @@ {{ w['user_count'] }}Users - {% end %} + {% endfor %}
    -{% end %} +{% endblock %} From fbe5137188c5e8c3c7aff7cac8cd97b97af161ba Mon Sep 17 00:00:00 2001 From: richard-dds Date: Wed, 1 Aug 2018 14:17:43 -0400 Subject: [PATCH 232/332] Requests index rendering --- Pipfile | 1 + Pipfile.lock | 10 +++- atst/app.py | 9 +++- atst/domain/requests.py | 45 ++++++++-------- atst/routes/__init__.py | 3 ++ atst/routes/requests.py | 52 +++++++++++++++++++ templates/components.html | 50 +++++++++++++++++- templates/{requests.html.to => requests.html} | 36 +++++++------ 8 files changed, 164 insertions(+), 42 deletions(-) create mode 100644 atst/routes/requests.py rename templates/{requests.html.to => requests.html} (81%) diff --git a/Pipfile b/Pipfile index 4110ccbf..620553f1 100644 --- a/Pipfile +++ b/Pipfile @@ -16,6 +16,7 @@ alembic = "*" flask = "*" flask-sqlalchemy = "*" flask-assets = "*" +flask-session = "*" [dev-packages] bandit = "*" diff --git a/Pipfile.lock b/Pipfile.lock index d6e5cf64..d55c6fcf 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "2ee6dd90ff3784e7b1781c680d690ac59118b4e3d72e8da3adf9e93d6e512bc7" + "sha256": "f097384512537988c799b892830b52e78bcc19133327213e9c6e2876210d62d3" }, "pipfile-spec": 6, "requires": { @@ -46,6 +46,14 @@ "index": "pypi", "version": "==0.12" }, + "flask-session": { + "hashes": [ + "sha256:a31c27e0c3287f00c825b3d9625aba585f4df4cccedb1e7dd5a69a215881a731", + "sha256:b9b32126bfc52c3169089f2ed9a40e34b589527bda48b633428e07d39d9c8792" + ], + "index": "pypi", + "version": "==0.3.1" + }, "flask-sqlalchemy": { "hashes": [ "sha256:3bc0fac969dd8c0ace01b32060f0c729565293302f0c4269beed154b46bec50b", diff --git a/atst/app.py b/atst/app.py index 087277fc..7dac78b7 100644 --- a/atst/app.py +++ b/atst/app.py @@ -2,15 +2,18 @@ import os import re from configparser import ConfigParser from redis import StrictRedis -from flask import Flask, request, g +from flask import Flask, request, g, session from unipath import Path from atst.api_client import ApiClient from atst.sessions import RedisSessions from atst.database import db from atst.assets import assets + from atst.routes import bp from atst.routes.workspaces import bp as workspace_routes +from atst.routes.requests import requests_bp + ENV = os.getenv("TORNADO_ENV", "dev") @@ -33,6 +36,7 @@ def make_app(config): app.register_blueprint(bp) app.register_blueprint(workspace_routes) + app.register_blueprint(requests_bp) return app @@ -48,7 +52,8 @@ def make_flask_callbacks(app): "id": "cce17030-4109-4719-b958-ed109dbb87c8", "first_name": "Amanda", "last_name": "Adamson", - "atat_role": "default" + "atat_role": "default", + "atat_permissions": [] } # TODO: Make me a macro diff --git a/atst/domain/requests.py b/atst/domain/requests.py index aa37b932..a513d660 100644 --- a/atst/domain/requests.py +++ b/atst/domain/requests.py @@ -4,6 +4,8 @@ from sqlalchemy.orm.exc import NoResultFound from sqlalchemy.orm.attributes import flag_modified from atst.models import Request, RequestStatusEvent +from atst.database import db + from .exceptions import NotFoundError @@ -28,67 +30,68 @@ def deep_merge(source, destination: dict): class Requests(object): AUTO_APPROVE_THRESHOLD = 1000000 - def __init__(self, db_session): - self.db_session = db_session - - def create(self, creator_id, body): + @classmethod + def create(cls, creator_id, body): request = Request(creator=creator_id, body=body) status_event = RequestStatusEvent(new_status="incomplete") request.status_events.append(status_event) - self.db_session.add(request) - self.db_session.commit() + db.session.add(request) + db.session.commit() return request - def exists(self, request_id, creator_id): - return self.db_session.query( + @classmethod + def exists(cls, request_id, creator_id): + return db.session.query( exists().where( and_(Request.id == request_id, Request.creator == creator_id) ) ).scalar() - def get(self, request_id): + @classmethod + def get(cls, request_id): try: - request = self.db_session.query(Request).filter_by(id=request_id).one() + request = db.session.query(Request).filter_by(id=request_id).one() except NoResultFound: raise NotFoundError("request") return request - def get_many(self, creator_id=None): + @classmethod + def get_many(cls, creator_id=None): filters = [] if creator_id: filters.append(Request.creator == creator_id) requests = ( - self.db_session.query(Request) + db.session.query(Request) .filter(*filters) .order_by(Request.time_created.desc()) .all() ) return requests - @tornado.gen.coroutine - def submit(self, request): + @classmethod + def submit(cls, request): request.status_events.append(RequestStatusEvent(new_status="submitted")) if Requests.should_auto_approve(request): request.status_events.append(RequestStatusEvent(new_status="approved")) - self.db_session.add(request) - self.db_session.commit() + db.session.add(request) + db.session.commit() return request - @tornado.gen.coroutine - def update(self, request_id, request_delta): + @classmethod + def update(cls, request_id, request_delta): try: # Query for request matching id, acquiring a row-level write lock. # https://www.postgresql.org/docs/10/static/sql-select.html#SQL-FOR-UPDATE-SHARE request = ( - self.db_session.query(Request) + db.session.query(Request) .filter_by(id=request_id) .with_for_update(of=Request) .one() @@ -105,8 +108,8 @@ class Requests(object): # since it doesn't track dictionary mutations by default. flag_modified(request, "body") - self.db_session.add(request) - self.db_session.commit() + db.session.add(request) + db.session.commit() @classmethod def should_auto_approve(cls, request): diff --git a/atst/routes/__init__.py b/atst/routes/__init__.py index 93fde8e2..de181ce2 100644 --- a/atst/routes/__init__.py +++ b/atst/routes/__init__.py @@ -1,4 +1,7 @@ from flask import Blueprint, render_template, g +import pendulum + +from atst.domain.requests import Requests bp = Blueprint("atst", __name__) diff --git a/atst/routes/requests.py b/atst/routes/requests.py new file mode 100644 index 00000000..6c37344d --- /dev/null +++ b/atst/routes/requests.py @@ -0,0 +1,52 @@ +from flask import Blueprint, g, render_template +import pendulum + +from atst.domain.requests import Requests + +requests_bp = Blueprint("requests", __name__) + +def map_request(user, request): + time_created = pendulum.instance(request.time_created) + is_new = time_created.add(days=1) > pendulum.now() + + return { + "order_id": request.id, + "is_new": is_new, + "status": request.status, + "app_count": 1, + "date": time_created.format("M/DD/YYYY"), + "full_name": "{} {}".format(user["first_name"], user["last_name"]), + } + + +@requests_bp.route("/requests", methods=["GET"]) +def requests_index(): + requests = [] + if "review_and_approve_jedi_workspace_request" in g.current_user["atat_permissions"]: + requests = Requests.get_many() + else: + requests = Requests.get_many(creator_id=g.current_user["id"]) + + mapped_requests = [map_request(g.current_user, r) for r in requests] + + return render_template("requests.html", requests=mapped_requests) + + +@requests_bp.route("/requests/new/", methods=["GET"]) +def requests_new(): + pass + + +@requests_bp.route("/requests/new//", methods=["GET"]) +def requests_form_update(): + pass + + +@requests_bp.route("/requests/verify/", methods=["GET"]) +def financial_verification(): + pass + + +@requests_bp.route("/requests/verify/", methods=["POST"]) +def update_financial_verification(): + pass diff --git a/templates/components.html b/templates/components.html index 0bc83991..04f6be36 100644 --- a/templates/components.html +++ b/templates/components.html @@ -31,7 +31,17 @@ {%- endmacro %} -{% macro EmptyState(self, message, actionLabel, actionHref, icon=None) -%} +{% macro Modal() -%} + +{%- endmacro %} + +{% macro EmptyState(message, actionLabel, actionHref, icon=None) -%}

    {{ message }}

    @@ -42,3 +52,41 @@ {{ actionLabel }}
    {%- endmacro %} + +{% macro Alert(title, message=None, actions=None, level='info') -%} +{% set role = 'alertdialog' if actions else 'alert' %} +{% set levels = { + 'warning': { + 'icon': 'alert', + 'tone': 'assertive' + }, + 'error': { + 'icon': 'alert', + 'tone': 'assertive' + }, + 'info': { + 'icon': 'info', + 'tone': 'polite' + }, + 'success': { + 'icon': 'ok', + 'tone': 'polite' + } +} %} + +
    + {{ Icon(levels.get(level).get('icon'), classes='alert__icon icon--large') }} + +
    +

    {{title}}

    + + {% if message %} +
    {{ message | safe }}
    + {% endif %} + + {% if actions %} +
    {{ actions | safe }}
    + {% endif %} +
    +
    +{%- endmacro %} diff --git a/templates/requests.html.to b/templates/requests.html similarity index 81% rename from templates/requests.html.to rename to templates/requests.html index bd0c9e8c..5d27ff1e 100644 --- a/templates/requests.html.to +++ b/templates/requests.html @@ -1,8 +1,10 @@ -{% extends "base.html.to" %} +{% extends "base.html" %} + +{% from "components.html" import Modal, Alert, EmptyState %} {% block modal %} - {% if modalOpen() %} - {% apply modal %} + {% if g.modalOpen %} + {% call Modal() %}

    Your request is now approved!

    @@ -17,34 +19,34 @@ usage in sync with your budget.

    - {% module Alert("You'll need these details: ", + {{ Alert("You'll need these details: ", message="

    Task Order Number

    Contracting Officer: Name, E-mail and Office

    " - ) %} + ) }} - {% end %} - {% end %} -{% end %} + {% endcall %} + {% endif %} +{% endblock %} {% block content %} {% if not requests %} - {% module EmptyState( + {{ EmptyState( 'There are currently no active requests for you to see.', actionLabel='Create a new JEDI Cloud Request', actionHref='/requests/new', icon='document' - )%} + ) }} {% else %} - {% module Alert('Pending Financial Verification', + {{ Alert('Pending Financial Verification', message="

    Your next step is to create a Task Order (T.O.) associated with JEDI Cloud. Please consult a Contracting Officer (KO) or Contracting Officer Representative (COR) to help with this step.

    " - ) %} + ) }}
    @@ -84,10 +86,10 @@ {% for r in requests %} - {{ r['order_id'] }} + {{ r['order_id'] }} {% if r['is_new'] %}New - {% end %} + {% endif %} {{ r['date'] }} {{ r['full_name'] }} {{ r['app_count'] }} @@ -97,13 +99,13 @@ Approval - {% end %} + {% endfor %}
    -{% end %} +{% endif %} -{% end %} +{% endblock %} From 2618d92e12589bb29546dbe43ef21c68ae568df1 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Wed, 1 Aug 2018 16:25:08 -0400 Subject: [PATCH 233/332] Financial verification form rendering --- Pipfile | 1 + Pipfile.lock | 10 ++- atst/app.py | 1 + atst/forms/forms.py | 4 +- atst/routes/requests.py | 7 ++- config/base.ini | 1 + ...on.html.to => financial_verification.html} | 61 ++++++++++--------- templates/requests_new.html.to | 2 +- 8 files changed, 51 insertions(+), 36 deletions(-) rename templates/requests/{financial_verification.html.to => financial_verification.html} (87%) diff --git a/Pipfile b/Pipfile index 620553f1..04e23572 100644 --- a/Pipfile +++ b/Pipfile @@ -17,6 +17,7 @@ flask = "*" flask-sqlalchemy = "*" flask-assets = "*" flask-session = "*" +flask-wtf = "*" [dev-packages] bandit = "*" diff --git a/Pipfile.lock b/Pipfile.lock index d55c6fcf..5dcf8f6b 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "f097384512537988c799b892830b52e78bcc19133327213e9c6e2876210d62d3" + "sha256": "e04e11d9bd5c1dcc725de48b20902f5c416417e73774e557e45af7bd0c147ff5" }, "pipfile-spec": 6, "requires": { @@ -62,6 +62,14 @@ "index": "pypi", "version": "==2.3.2" }, + "flask-wtf": { + "hashes": [ + "sha256:5d14d55cfd35f613d99ee7cba0fc3fbbe63ba02f544d349158c14ca15561cc36", + "sha256:d9a9e366b32dcbb98ef17228e76be15702cd2600675668bca23f63a7947fd5ac" + ], + "index": "pypi", + "version": "==0.14.2" + }, "itsdangerous": { "hashes": [ "sha256:cbb3fcf8d3e33df861709ecaf89d9e6629cff0a217bc2848f1b41cd30d360519" diff --git a/atst/app.py b/atst/app.py index 7dac78b7..babaff7a 100644 --- a/atst/app.py +++ b/atst/app.py @@ -229,6 +229,7 @@ def make_config(): OVERRIDE_CONFIG_FILENAME = os.getenv("OVERRIDE_CONFIG_FULLPATH") config = ConfigParser() + config.optionxform = str config_files = [BASE_CONFIG_FILENAME, ENV_CONFIG_FILENAME] if OVERRIDE_CONFIG_FILENAME: diff --git a/atst/forms/forms.py b/atst/forms/forms.py index c3ea02c4..48f03295 100644 --- a/atst/forms/forms.py +++ b/atst/forms/forms.py @@ -1,9 +1,9 @@ import tornado from tornado.gen import Return -from wtforms_tornado import Form +from flask_wtf import FlaskForm -class ValidatedForm(Form): +class ValidatedForm(FlaskForm): @tornado.gen.coroutine def perform_extra_validation(self, *args, **kwargs): diff --git a/atst/routes/requests.py b/atst/routes/requests.py index 6c37344d..5903524c 100644 --- a/atst/routes/requests.py +++ b/atst/routes/requests.py @@ -2,6 +2,7 @@ from flask import Blueprint, g, render_template import pendulum from atst.domain.requests import Requests +from atst.forms.financial import FinancialForm requests_bp = Blueprint("requests", __name__) @@ -43,8 +44,10 @@ def requests_form_update(): @requests_bp.route("/requests/verify/", methods=["GET"]) -def financial_verification(): - pass +def financial_verification(request_id=None): + request = Requests.get(request_id) + form = FinancialForm(data=request.body.get('financial_verification')) + return render_template("requests/financial_verification.html", f=form) @requests_bp.route("/requests/verify/", methods=["POST"]) diff --git a/config/base.ini b/config/base.ini index e8be9197..fddfa26f 100644 --- a/config/base.ini +++ b/config/base.ini @@ -5,6 +5,7 @@ DEBUG = true AUTHNID_BASE_URL= https://localhost:8001 COOKIE_SECRET = some-secret-please-replace SECRET = change_me_into_something_secret +SECRET_KEY = change_me_into_something_secret CAC_URL = https://localhost:8001 PE_NUMBER_CSV_URL = http://c95e1ebb198426ee57b8-174bb05a294821bedbf46b6384fe9b1f.r31.cf5.rackcdn.com/penumbers.csv REDIS_URI = redis://localhost:6379 diff --git a/templates/requests/financial_verification.html.to b/templates/requests/financial_verification.html similarity index 87% rename from templates/requests/financial_verification.html.to rename to templates/requests/financial_verification.html index df5b12ab..0f0d8110 100644 --- a/templates/requests/financial_verification.html.to +++ b/templates/requests/financial_verification.html @@ -1,4 +1,4 @@ -{% extends "../base.html.to" %} +{% extends "base.html" %} {% block content %} @@ -14,15 +14,15 @@ {% block form_action %} -
    - {% end %} + + {% endblock %} - {% module xsrf_form_html() %} + {{ f.csrf_token }} {% block form %} - {% autoescape None %} + {% autoescape false %} {% if f.errors %} There were some errors, see below. - {% end %} + {% endif %}

    In order to get you access to the JEDI Cloud, we will need you to enter the details below that will help us verify and account for your Task Order.

    @@ -32,7 +32,7 @@
    {{ e }}
    - {% end %} + {% endfor %} {{ f.uii_ids.label }} {{ f.uii_ids(placeholder="Example: \nDI 0CVA5786950 \nUN1945326361234786950") }} @@ -40,7 +40,7 @@
    {{ e }}
    - {% end %} + {% endfor %} {{ f.pe_id.label }} {{ f.pe_id(placeholder="Example: 0203752A") }} @@ -48,7 +48,7 @@
    {{ e }}
    - {% end %} + {% endfor %} {{ f.treasury_code.label }} {{ f.treasury_code(placeholder="Example: 1200") }} @@ -56,7 +56,7 @@
    {{ e }}
    - {% end %} + {% endfor %} {{ f.ba_code.label }} {{ f.ba_code(placeholder="Example: 02") }} @@ -64,7 +64,7 @@
    {{ e }}
    - {% end %} + {% endfor %} @@ -76,7 +76,7 @@
    {{ e }}
    - {% end %} + {% endfor %} {{ f.lname_co.label }} {{ f.lname_co(placeholder="Contracting Officer last name") }} @@ -84,7 +84,7 @@
    {{ e }}
    - {% end %} + {% endfor %} {{ f.email_co.label }} {{ f.email_co(placeholder="jane@mail.mil") }} @@ -92,7 +92,7 @@
    {{ e }}
    - {% end %} + {% endfor %} {{ f.office_co.label }} {{ f.office_co(placeholder="Example: WHS") }} @@ -100,7 +100,7 @@
    {{ e }}
    - {% end %} + {% endfor %} @@ -113,7 +113,7 @@
    {{ e }}
    - {% end %} + {% endfor %} {{ f.lname_cor.label }} {{ f.lname_cor(placeholder="Contracting Officer Representative last name") }} @@ -121,7 +121,7 @@
    {{ e }}
    - {% end %} + {% endfor %} {{ f.email_cor.label }} {{ f.email_cor(placeholder="jane@mail.mil") }} @@ -129,7 +129,7 @@
    {{ e }}
    - {% end %} + {% endfor %} {{ f.office_cor.label }} {{ f.office_cor(placeholder="Example: WHS") }} @@ -137,7 +137,7 @@
    {{ e }}
    - {% end %} + {% endfor %}

    ↓ FIELDS NEEDED FOR MANUAL ENTRY OF TASK ORDER INFORMATION (only necessary if EDA info not available) @@ -149,7 +149,7 @@
    {{ e }}
    - {% end %} + {% endfor %} {{ f.funding_type_other.label }} {{ f.funding_type_other(placeholder="") }} @@ -157,7 +157,7 @@
    {{ e }}
    - {% end %} + {% endfor %} {{ f.clin_0001.label }} {{ f.clin_0001(placeholder="50,000") }} @@ -165,7 +165,7 @@
    {{ e }}
    - {% end %} + {% endfor %} {{ f.clin_0003.label }} {{ f.clin_0003(placeholder="13,000") }} @@ -173,7 +173,7 @@
    {{ e }}
    - {% end %} + {% endfor %} {{ f.clin_1001.label }} {{ f.clin_1001(placeholder="30,000") }} @@ -181,7 +181,7 @@
    {{ e }}
    - {% end %} + {% endfor %} {{ f.clin_1003.label }} {{ f.clin_1003(placeholder="7,000") }} @@ -189,7 +189,7 @@
    {{ e }}
    - {% end %} + {% endfor %} {{ f.clin_2001.label }} {{ f.clin_2001(placeholder="30,000") }} @@ -197,7 +197,7 @@
    {{ e }}
    - {% end %} + {% endfor %} {{ f.clin_2003.label }} {{ f.clin_2003(placeholder="7,000") }} @@ -205,15 +205,16 @@
    {{ e }}
    - {% end %} - {% end %} + {% endfor %} + {% endautoescape %} + {% endblock form %} {% block next %} - {% end %} + {% endblock %}
    -{% end %} +{% endblock %} diff --git a/templates/requests_new.html.to b/templates/requests_new.html.to index 5a309f26..c5f96ed5 100644 --- a/templates/requests_new.html.to +++ b/templates/requests_new.html.to @@ -22,7 +22,7 @@ {% end %} {% end %} - {% module xsrf_form_html() %} + {{ form.csrf_token }} {% block form %} form goes here {% end %} From f15fc19eafbce87af87dc54b1d76fc5f629f51a8 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Thu, 2 Aug 2018 10:21:26 -0400 Subject: [PATCH 234/332] First page of request form rendering, but flow is still WIP --- atst/handlers/request_new.py | 3 +- atst/routes/requests.py | 199 +++++++++++++++++- templates/components.html | 53 +++++ templates/requests/menu.html | 13 ++ templates/requests/menu.html.to | 13 -- templates/requests/screen-0.html | 12 ++ templates/requests/screen-0.html.to | 12 -- templates/requests/screen-1.html | 46 ++++ templates/requests/screen-1.html.to | 45 ---- templates/requests/screen-2.html | 32 +++ templates/requests/screen-2.html.to | 31 --- .../{screen-3.html.to => screen-3.html} | 0 .../{screen-4.html.to => screen-4.html} | 0 .../{screen-5.html.to => screen-5.html} | 0 .../{sidebar.html.to => sidebar.html} | 0 templates/requests_new.html | 45 ++++ templates/requests_new.html.to | 46 ---- 17 files changed, 398 insertions(+), 152 deletions(-) create mode 100644 templates/requests/menu.html delete mode 100644 templates/requests/menu.html.to create mode 100644 templates/requests/screen-0.html delete mode 100644 templates/requests/screen-0.html.to create mode 100644 templates/requests/screen-1.html delete mode 100644 templates/requests/screen-1.html.to create mode 100644 templates/requests/screen-2.html delete mode 100644 templates/requests/screen-2.html.to rename templates/requests/{screen-3.html.to => screen-3.html} (100%) rename templates/requests/{screen-4.html.to => screen-4.html} (100%) rename templates/requests/{screen-5.html.to => screen-5.html} (100%) rename templates/requests/{sidebar.html.to => sidebar.html} (100%) create mode 100644 templates/requests_new.html delete mode 100644 templates/requests_new.html.to diff --git a/atst/handlers/request_new.py b/atst/handlers/request_new.py index 1d33daa0..30549e63 100644 --- a/atst/handlers/request_new.py +++ b/atst/handlers/request_new.py @@ -101,7 +101,6 @@ class RequestNew(BaseHandler): class JEDIRequestFlow(object): def __init__( self, - requests_repo, pe_numbers_repo, current_step, request=None, @@ -110,6 +109,8 @@ class JEDIRequestFlow(object): current_user=None, existing_request=None, ): + self.pe_numbers_repo = pe_numbers_repo + self.requests_repo = requests_repo self.pe_numbers_repo = pe_numbers_repo diff --git a/atst/routes/requests.py b/atst/routes/requests.py index 5903524c..565c268e 100644 --- a/atst/routes/requests.py +++ b/atst/routes/requests.py @@ -1,8 +1,14 @@ -from flask import Blueprint, g, render_template +from flask import Blueprint, g, render_template, url_for, redirect, request import pendulum +from collections import defaultdict from atst.domain.requests import Requests from atst.forms.financial import FinancialForm +from atst.forms.request import RequestForm +from atst.forms.org import OrgForm +from atst.forms.poc import POCForm +from atst.forms.review import ReviewForm + requests_bp = Blueprint("requests", __name__) @@ -34,13 +40,72 @@ def requests_index(): @requests_bp.route("/requests/new/", methods=["GET"]) -def requests_new(): +def requests_form_new(): pass @requests_bp.route("/requests/new//", methods=["GET"]) -def requests_form_update(): - pass +def requests_form_update(screen=1, request_id=None): + request = Requests.get(request_id) if request_id is not None else None + jedi_flow = JEDIRequestFlow(screen, request, request_id=request_id) + + return render_template( + "requests/screen-%d.html" % int(screen), + f=jedi_flow.form, + data=jedi_flow.current_step_data, + screens=jedi_flow.screens, + current=screen, + next_screen=screen + 1, + request_id=request_id, + can_submit=jedi_flow.can_submit + ) + +@requests_bp.route("/requests/new//", methods=["POST"]) +def requests_update(screen=1, request_id=None): + screen = int(screen) + post_data = str(request.data) + current_user = g.current_user + existing_request = Requests.get(request_id) if request_id is not None else None + jedi_flow = JEDIRequestFlow( + screen, + post_data=post_data, + request_id=request_id, + current_user=current_user, + existing_request=existing_request, + ) + + rerender_args = dict( + f=jedi_flow.form, + data=post_data, + screens=jedi_flow.screens, + current=screen, + next_screen=jedi_flow.next_screen, + request_id=jedi_flow.request_id, + ) + + if jedi_flow.validate(): + jedi_flow.create_or_update_request() + valid = jedi_flow.validate_warnings() + if valid: + if jedi_flow.next_screen > len(jedi_flow.screens): + where = "/requests" + else: + where = url_for( + "requests.requests_Form_update", screen=jedi_flow.next_screen, request_id=jedi_flow.request_id + ) + return redirect(where) + else: + return render_template( + "requests/screen-%d.html" % int(screen), + **rerender_args + ) + else: + return render_template( + "requests/screen-%d.html" % int(screen), + **rerender_args + ) + + @requests_bp.route("/requests/verify/", methods=["GET"]) @@ -53,3 +118,129 @@ def financial_verification(request_id=None): @requests_bp.route("/requests/verify/", methods=["POST"]) def update_financial_verification(): pass + + +class JEDIRequestFlow(object): + def __init__( + self, + current_step, + request=None, + post_data=None, + request_id=None, + current_user=None, + existing_request=None, + ): + self.current_step = current_step + self.request = request + + self.post_data = post_data + self.is_post = self.post_data is not None + + self.request_id = request_id + self.form = self._form() + + self.current_user = current_user + self.existing_request = existing_request + + def _form(self): + if self.is_post: + return self.form_class()(self.post_data) + elif self.request: + return self.form_class()(data=self.current_step_data) + else: + return self.form_class()() + + def validate(self): + return self.form.validate() + + def validate_warnings(self): + existing_request_data = ( + self.existing_request + and self.existing_request.body.get(self.form_section) + ) or None + + valid = self.form.perform_extra_validation( + existing_request_data, + ) + return valid + + @property + def current_screen(self): + return self.screens[self.current_step - 1] + + @property + def form_section(self): + return self.current_screen["section"] + + def form_class(self): + return self.current_screen["form"] + + @property + def current_step_data(self): + data = {} + + if self.is_post: + data = self.post_data + + if self.request: + if self.form_section == "review_submit": + data = self.request.body + else: + data = self.request.body.get(self.form_section, {}) + + return defaultdict(lambda: defaultdict(lambda: 'Input required'), data) + + @property + def can_submit(self): + return self.request and self.request.status != "incomplete" + + @property + def next_screen(self): + return self.current_step + 1 + + @property + def screens(self): + return [ + { + "title": "Details of Use", + "section": "details_of_use", + "form": RequestForm, + "subitems": [ + { + "title": "Overall request details", + "id": "overall-request-details", + }, + {"title": "Cloud Resources", "id": "cloud-resources"}, + {"title": "Support Staff", "id": "support-staff"}, + ], + "show": True, + }, + { + "title": "Information About You", + "section": "information_about_you", + "form": OrgForm, + "show": True, + }, + { + "title": "Primary Point of Contact", + "section": "primary_poc", + "form": POCForm, + "show": True, + }, + { + "title": "Review & Submit", + "section": "review_submit", + "form": ReviewForm, + "show":True, + }, + ] + + def create_or_update_request(self): + request_data = { + self.form_section: self.form.data + } + if self.request_id: + Requests.update(request_id, request_data) + else: + request = Requests.create(self.current_user["id"], request_data) + self.request_id = request.id diff --git a/templates/components.html b/templates/components.html index 04f6be36..027ede6f 100644 --- a/templates/components.html +++ b/templates/components.html @@ -90,3 +90,56 @@ {%- endmacro %} + +{% macro TextInput(field, placeholder='') -%} +
    + + + {{ field(placeholder=placeholder) | safe }} + + {% if field.errors %} + {% for error in field.errors %} + {{ error }} + {% endfor %} + {% endif %} +
    +{%- endmacro %} + +{% macro OptionsInput(field, inline=False) -%} +
    + +
    + + {{ field.label }} + + {% if field.description %} + {{ field.description | safe }} + {% endif %} + + {% if field.errors %} + {{ Icon('alert') }} + {% endif %} + + + {{ field() }} + + {% if field.errors %} + {% for error in field.errors %} + {{ error }} + {% endfor %} + {% endif %} + +
    +
    + +{%- endmacro %} diff --git a/templates/requests/menu.html b/templates/requests/menu.html new file mode 100644 index 00000000..f1642e46 --- /dev/null +++ b/templates/requests/menu.html @@ -0,0 +1,13 @@ +
    + +
    diff --git a/templates/requests/menu.html.to b/templates/requests/menu.html.to deleted file mode 100644 index 4bc77431..00000000 --- a/templates/requests/menu.html.to +++ /dev/null @@ -1,13 +0,0 @@ -
    - -
    \ No newline at end of file diff --git a/templates/requests/screen-0.html b/templates/requests/screen-0.html new file mode 100644 index 00000000..19f57d2e --- /dev/null +++ b/templates/requests/screen-0.html @@ -0,0 +1,12 @@ +{% extends '../requests_new.html.to' %} + +{% block form %} +

    New JEDI Request

    + +

    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Natus error omnis a, tenetur similique quo officiis voluptates eum recusandae dolorem minus dignissimos, magni consequatur, maxime debitis reprehenderit sint non iusto?

    + +New Application +Existing Application +Sandbox Environment + +{% endblock %} diff --git a/templates/requests/screen-0.html.to b/templates/requests/screen-0.html.to deleted file mode 100644 index 6fe78374..00000000 --- a/templates/requests/screen-0.html.to +++ /dev/null @@ -1,12 +0,0 @@ -{% extends '../requests_new.html.to' %} - -{% block form %} -

    New JEDI Request

    - -

    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Natus error omnis a, tenetur similique quo officiis voluptates eum recusandae dolorem minus dignissimos, magni consequatur, maxime debitis reprehenderit sint non iusto?

    - -New Application -Existing Application -Sandbox Environment - -{% end %} diff --git a/templates/requests/screen-1.html b/templates/requests/screen-1.html new file mode 100644 index 00000000..da6c5ae0 --- /dev/null +++ b/templates/requests/screen-1.html @@ -0,0 +1,46 @@ +{% extends 'requests_new.html' %} + +{% from "components.html" import Alert, TextInput, OptionsInput %} + +{% block subtitle %} +

    Details of Use

    +{% endblock %} + +{% block form %} + +{% if f.errors %} + {{ Alert('There were some errors', + message="

    Please see below.

    ", + level='error' + ) }} +{% endif %} + + +

    We’d like to know a little about how you plan to use JEDI Cloud services to process your request. Please answer the following questions to the best of your ability. Note that the CCPO does not directly help with migrating systems to JEDI Cloud. These questions are for learning about your cloud readiness and financial usage of the JEDI Cloud; your estimates will not be used for any department level reporting.

    +

    All fields are required, unless specified optional.

    + +

    General

    +{{ TextInput(f.dod_component) }} +{{ TextInput(f.jedi_usage,placeholder="e.g. We are migrating XYZ application to the cloud so that...") }} + +

    Cloud Readiness

    +{{ TextInput(f.num_software_systems,placeholder="Number of systems") }} +{{ OptionsInput(f.jedi_migration) }} +{{ OptionsInput(f.rationalization_software_systems) }} +{{ OptionsInput(f.technical_support_team) }} +{{ OptionsInput(f.organization_providing_assistance) }} +{{ OptionsInput(f.engineering_assessment) }} +{{ TextInput(f.data_transfers) }} +{{ TextInput(f.expected_completion_date) }} +{{ OptionsInput(f.cloud_native) }} + +

    Financial Usage

    +{{ TextInput(f.estimated_monthly_spend) }} +

    So this means you are spending approximately $X annually

    +{{ TextInput(f.dollar_value) }} +{{ TextInput(f.number_user_sessions) }} +{{ TextInput(f.average_daily_traffic) }} +{{ TextInput(f.start_date) }} + + +{% endblock %} diff --git a/templates/requests/screen-1.html.to b/templates/requests/screen-1.html.to deleted file mode 100644 index a8ed7887..00000000 --- a/templates/requests/screen-1.html.to +++ /dev/null @@ -1,45 +0,0 @@ -{% extends '../requests_new.html.to' %} - -{% block subtitle %} -

    Details of Use

    -{% end %} - -{% block form %} - -{% autoescape None %} -{% if f.errors %} - {% module Alert('There were some errors', - message="

    Please see below.

    ", - level='error' - ) %} -{% end %} - - -

    We’d like to know a little about how you plan to use JEDI Cloud services to process your request. Please answer the following questions to the best of your ability. Note that the CCPO does not directly help with migrating systems to JEDI Cloud. These questions are for learning about your cloud readiness and financial usage of the JEDI Cloud; your estimates will not be used for any department level reporting.

    -

    All fields are required, unless specified optional.

    - -

    General

    -{% module TextInput(f.dod_component) %} -{% module TextInput(f.jedi_usage,placeholder="e.g. We are migrating XYZ application to the cloud so that...") %} - -

    Cloud Readiness

    -{% module TextInput(f.num_software_systems,placeholder="Number of systems") %} -{% module OptionsInput(f.jedi_migration) %} -{% module OptionsInput(f.rationalization_software_systems) %} -{% module OptionsInput(f.technical_support_team) %} -{% module OptionsInput(f.organization_providing_assistance) %} -{% module OptionsInput(f.engineering_assessment) %} -{% module TextInput(f.data_transfers) %} -{% module TextInput(f.expected_completion_date) %} -{% module OptionsInput(f.cloud_native) %} - -

    Financial Usage

    -{% module TextInput(f.estimated_monthly_spend) %} -

    So this means you are spending approximately $X annually

    -{% module TextInput(f.dollar_value) %} -{% module TextInput(f.number_user_sessions) %} -{% module TextInput(f.average_daily_traffic) %} -{% module TextInput(f.start_date) %} - - -{% end %} diff --git a/templates/requests/screen-2.html b/templates/requests/screen-2.html new file mode 100644 index 00000000..24c8f749 --- /dev/null +++ b/templates/requests/screen-2.html @@ -0,0 +1,32 @@ +{% extends 'requests_new.html' %} + +{% from "components.html" import Alert, TextInput, OptionsInput %} + +{% block subtitle %} +

    Information About You

    +{% endblock %} + +{% block form %} + +{% if f.errors %} + {{ Alert('There were some errors', + message="

    Please see below.

    ", + level='error' + ) }} +{% endif %} + +

    Please tell us more about you.

    + +{{ TextInput(f.fname_request,placeholder='First Name') }} +{{ TextInput(f.lname_request,placeholder='Last Name') }} +{{ TextInput(f.email_request,placeholder='jane@mail.mil') }} +{{ TextInput(f.phone_number,placeholder='(123) 456-7890') }} + +

    We want to collect the following information from you for security auditing and determining priviledged user access

    + +{{ TextInput(f.service_branch,placeholder='e.g. US Air Force, US Army, US Navy, Marine Corps, Defense Media Agency') }} +{{ OptionsInput(f.citizenship) }} +{{ OptionsInput(f.designation) }} +{{ TextInput(f.date_latest_training) }} + +{% endblock %} diff --git a/templates/requests/screen-2.html.to b/templates/requests/screen-2.html.to deleted file mode 100644 index fb667dc5..00000000 --- a/templates/requests/screen-2.html.to +++ /dev/null @@ -1,31 +0,0 @@ -{% extends '../requests_new.html.to' %} - -{% block subtitle %} -

    Information About You

    -{% end %} - -{% block form %} - -{% autoescape None %} -{% if f.errors %} - {% module Alert('There were some errors', - message="

    Please see below.

    ", - level='error' - ) %} -{% end %} - -

    Please tell us more about you.

    - -{% module TextInput(f.fname_request,placeholder='First Name') %} -{% module TextInput(f.lname_request,placeholder='Last Name') %} -{% module TextInput(f.email_request,placeholder='jane@mail.mil') %} -{% module TextInput(f.phone_number,placeholder='(123) 456-7890') %} - -

    We want to collect the following information from you for security auditing and determining priviledged user access

    - -{% module TextInput(f.service_branch,placeholder='e.g. US Air Force, US Army, US Navy, Marine Corps, Defense Media Agency') %} -{% module OptionsInput(f.citizenship) %} -{% module OptionsInput(f.designation) %} -{% module TextInput(f.date_latest_training) %} - -{% end %} \ No newline at end of file diff --git a/templates/requests/screen-3.html.to b/templates/requests/screen-3.html similarity index 100% rename from templates/requests/screen-3.html.to rename to templates/requests/screen-3.html diff --git a/templates/requests/screen-4.html.to b/templates/requests/screen-4.html similarity index 100% rename from templates/requests/screen-4.html.to rename to templates/requests/screen-4.html diff --git a/templates/requests/screen-5.html.to b/templates/requests/screen-5.html similarity index 100% rename from templates/requests/screen-5.html.to rename to templates/requests/screen-5.html diff --git a/templates/requests/sidebar.html.to b/templates/requests/sidebar.html similarity index 100% rename from templates/requests/sidebar.html.to rename to templates/requests/sidebar.html diff --git a/templates/requests_new.html b/templates/requests_new.html new file mode 100644 index 00000000..559c2355 --- /dev/null +++ b/templates/requests_new.html @@ -0,0 +1,45 @@ +{% extends "base.html" %} + +{% block content %} + +
    + + {% include 'requests/menu.html' %} + +
    + +
    +

    New Request

    +
    {% block subtitle %}{% endblock %}
    +
    + +
    + {% block form_action %} + {% if request_id %} +
    + {% else %} + + {% endif %} + {% endblock %} + + {{ f.csrf_token }} + {% block form %} + form goes here + {% endblock %} + +
    + +
    + + {% block next %} + +
    + +
    + + {% endblock %} + + +
    + +{% endblock %} diff --git a/templates/requests_new.html.to b/templates/requests_new.html.to deleted file mode 100644 index c5f96ed5..00000000 --- a/templates/requests_new.html.to +++ /dev/null @@ -1,46 +0,0 @@ -{% extends "base.html.to" %} - -{% block content %} - -
    - - {% include 'requests/menu.html.to' %} - -
    - -
    -

    New Request

    -
    {% block subtitle %}{% end %}
    -
    - -
    - {% block form_action %} - {% if request_id %} -
    - {% else %} - - {% end %} - {% end %} - - {{ form.csrf_token }} - {% block form %} - form goes here - {% end %} - -
    - -
    - - {% block next %} - -
    - -
    - - {% end %} - - -
    - -{% end %} - From a032ccd5b012fa49c043c6749a48a8e15adf1149 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Thu, 2 Aug 2018 10:36:25 -0400 Subject: [PATCH 235/332] Converted all form pages. Flow still not working --- atst/forms/financial.py | 4 +-- atst/forms/forms.py | 5 ++-- atst/routes/requests.py | 11 +++++-- templates/requests/screen-3.html | 23 +++++++------- templates/requests/screen-4.html | 33 +++++++++++---------- templates/requests/screen-5.html | 51 ++++++++++++++++---------------- 6 files changed, 65 insertions(+), 62 deletions(-) diff --git a/atst/forms/financial.py b/atst/forms/financial.py index 52b4ef28..fb66282b 100644 --- a/atst/forms/financial.py +++ b/atst/forms/financial.py @@ -36,7 +36,6 @@ def suggest_pe_id(pe_id): return None -@tornado.gen.coroutine def validate_pe_id(field, existing_request, pe_numbers_repo): try: pe_number = pe_numbers_repo.get(field.data) @@ -55,12 +54,11 @@ def validate_pe_id(field, existing_request, pe_numbers_repo): class FinancialForm(ValidatedForm): - @tornado.gen.coroutine def perform_extra_validation(self, existing_request, pe_numbers_repo): valid = True if not existing_request or existing_request.get('pe_id') != self.pe_id.data: valid = yield validate_pe_id(self.pe_id, existing_request, pe_numbers_repo) - raise Return(valid) + return valid task_order_id = StringField( "Task Order Number associated with this request.", validators=[Required()] diff --git a/atst/forms/forms.py b/atst/forms/forms.py index 48f03295..d60e3a2c 100644 --- a/atst/forms/forms.py +++ b/atst/forms/forms.py @@ -5,8 +5,7 @@ from flask_wtf import FlaskForm class ValidatedForm(FlaskForm): - @tornado.gen.coroutine def perform_extra_validation(self, *args, **kwargs): - """A coroutine that performs any applicable extra validation. Must + """Performs any applicable extra validation. Must return True if the form is valid or False otherwise.""" - raise Return(True) + return True diff --git a/atst/routes/requests.py b/atst/routes/requests.py index 565c268e..0c225a7f 100644 --- a/atst/routes/requests.py +++ b/atst/routes/requests.py @@ -63,7 +63,7 @@ def requests_form_update(screen=1, request_id=None): @requests_bp.route("/requests/new//", methods=["POST"]) def requests_update(screen=1, request_id=None): screen = int(screen) - post_data = str(request.data) + post_data = request.form current_user = g.current_user existing_request = Requests.get(request_id) if request_id is not None else None jedi_flow = JEDIRequestFlow( @@ -91,7 +91,7 @@ def requests_update(screen=1, request_id=None): where = "/requests" else: where = url_for( - "requests.requests_Form_update", screen=jedi_flow.next_screen, request_id=jedi_flow.request_id + "requests.requests_form_update", screen=jedi_flow.next_screen, request_id=jedi_flow.request_id ) return redirect(where) else: @@ -120,6 +120,11 @@ def update_financial_verification(): pass +@requests_bp.route("/requests/submit/", methods=["POST"]) +def requests_submit(request_id=None): + pass + + class JEDIRequestFlow(object): def __init__( self, @@ -240,7 +245,7 @@ class JEDIRequestFlow(object): self.form_section: self.form.data } if self.request_id: - Requests.update(request_id, request_data) + Requests.update(self.request_id, request_data) else: request = Requests.create(self.current_user["id"], request_data) self.request_id = request.id diff --git a/templates/requests/screen-3.html b/templates/requests/screen-3.html index af4ea66f..5bdbaf43 100644 --- a/templates/requests/screen-3.html +++ b/templates/requests/screen-3.html @@ -1,18 +1,19 @@ -{% extends '../requests_new.html.to' %} +{% extends 'requests_new.html' %} + +{% from "components.html" import Alert, TextInput %} {% block subtitle %}

    Primary Government/Military
    Point of Contact (POC)

    -{% end %} +{% endblock %} {% block form %} -{% autoescape None %} {% if f.errors %} - {% module Alert('There were some errors', + {{ Alert('There were some errors', message="

    Please see below.

    ", level='error' - ) %} -{% end %} + ) }} +{% endif %}

    Please designate a Primary Point of Contact that will be responsible for owning the workspace in the JEDI Cloud.

    The Point of Contact will become the primary owner of the workspace created to use the JEDI Cloud. As a workspace owner, this person will have the ability to: @@ -26,9 +27,9 @@ This POC may be you.

    -{% module TextInput(f.fname_poc,placeholder='First Name') %} -{% module TextInput(f.lname_poc,placeholder='Last Name') %} -{% module TextInput(f.email_poc,placeholder='jane@mail.mil') %} -{% module TextInput(f.dodid_poc,placeholder='10-digit number on the back of the CAC') %} +{{ TextInput(f.fname_poc,placeholder='First Name') }} +{{ TextInput(f.lname_poc,placeholder='Last Name') }} +{{ TextInput(f.email_poc,placeholder='jane@mail.mil') }} +{{ TextInput(f.dodid_poc,placeholder='10-digit number on the back of the CAC') }} -{% end %} \ No newline at end of file +{% endblock %} diff --git a/templates/requests/screen-4.html b/templates/requests/screen-4.html index 60dd06ac..37cfc5de 100644 --- a/templates/requests/screen-4.html +++ b/templates/requests/screen-4.html @@ -1,27 +1,28 @@ -{% extends '../requests_new.html.to' %} +{% extends 'requests_new.html' %} + +{% from "components.html" import Alert, TextInput %} {% block subtitle %}

    Review & Submit

    -{% end %} +{% endblock %} {% block form_action %} -
    - {% end %} + +{% endblock %} {% block form %} - {% autoescape None %} {% if f.errors %} - {% module Alert('There were some errors', + {{ Alert('There were some errors', message="

    Please complete all required fields before submitting.

    ", level='error' - ) %} - {% end %} + ) }} + {% endif %}

    Before you can submit your request, please take a moment to review the information entered in the form. You may make changes by clicking the edit link on each section. When all information looks right, go ahead and submit.

    -

    Details of Use Edit

    +

    Details of Use Edit

    @@ -107,7 +108,7 @@
    -

    Information About You Edit

    +

    Information About You Edit

    @@ -152,7 +153,7 @@
    -

    Primary Point of Contact Edit

    +

    Primary Point of Contact Edit

    @@ -178,15 +179,15 @@ -{% end %} +{% endblock %} {% block next %} {% if not can_submit %} - {% module Alert('There were some errors', + {{ Alert('There were some errors', message="

    Please complete all required fields before submitting.

    ", level='error' - ) %} -{% end %} + ) }} +{% endif %}
    @@ -194,4 +195,4 @@ -{% end %} +{% endblock %} diff --git a/templates/requests/screen-5.html b/templates/requests/screen-5.html index e8642f1e..845ed133 100644 --- a/templates/requests/screen-5.html +++ b/templates/requests/screen-5.html @@ -2,13 +2,12 @@ {% block form %} -{% autoescape None %} {% if f.errors %} - {% module Alert('There were some errors', + {{ Alert('There were some errors', message="

    Please complete all the fields before submitting.

    ", level='error' - ) %} -{% end %} + ) }} +{% endif %}

    Financial Verification

    @@ -20,7 +19,7 @@
    {{ e }}
    -{% end %} +{% endfor %} {{ f.uii_ids.label }} {{ f.uii_ids(placeholder="Example: \nDI 0CVA5786950 \nUN1945326361234786950") }} @@ -28,7 +27,7 @@
    {{ e }}
    -{% end %} +{% endfor %} {{ f.pe_id.label }} {{ f.pe_id(placeholder="Example: 0203752A") }} @@ -36,7 +35,7 @@
    {{ e }}
    -{% end %} +{% endfor %} {{ f.treasury_code.label }} {{ f.treasury_code(placeholder="Example: 1200") }} @@ -44,7 +43,7 @@
    {{ e }}
    -{% end %} +{% endfor %} {{ f.ba_code.label }} {{ f.ba_code(placeholder="Example: 02") }} @@ -52,7 +51,7 @@
    {{ e }}
    -{% end %} +{% endfor %} @@ -64,7 +63,7 @@
    {{ e }}
    -{% end %} +{% endfor %} {{ f.lname_co.label }} {{ f.lname_co(placeholder="Contracting Officer last name") }} @@ -72,7 +71,7 @@
    {{ e }}
    -{% end %} +{% endfor %} {{ f.email_co.label }} {{ f.email_co(placeholder="jane@mail.mil") }} @@ -80,7 +79,7 @@
    {{ e }}
    -{% end %} +{% endfor %} {{ f.office_co.label }} {{ f.office_co(placeholder="Example: WHS") }} @@ -88,7 +87,7 @@
    {{ e }}
    -{% end %} +{% endfor %} @@ -101,7 +100,7 @@
    {{ e }}
    -{% end %} +{% endfor %} {{ f.lname_cor.label }} {{ f.lname_cor(placeholder="Contracting Officer Representative last name") }} @@ -109,7 +108,7 @@
    {{ e }}
    -{% end %} +{% endfor %} {{ f.email_cor.label }} {{ f.email_cor(placeholder="jane@mail.mil") }} @@ -117,7 +116,7 @@
    {{ e }}
    -{% end %} +{% endfor %} {{ f.office_cor.label }} {{ f.office_cor(placeholder="Example: WHS") }} @@ -125,7 +124,7 @@
    {{ e }}
    -{% end %} +{% endfor %}

    ↓ FIELDS NEEDED FOR MANUAL ENTRY OF TASK ORDER INFORMATION (only necessary if EDA info not available) @@ -137,7 +136,7 @@
    {{ e }}
    -{% end %} +{% endfor %} {{ f.funding_type_other.label }} {{ f.funding_type_other(placeholder="") }} @@ -145,7 +144,7 @@
    {{ e }}
    -{% end %} +{% endfor %} {{ f.clin_0001.label }} {{ f.clin_0001(placeholder="50,000") }} @@ -153,7 +152,7 @@
    {{ e }}
    -{% end %} +{% endfor %} {{ f.clin_0003.label }} {{ f.clin_0003(placeholder="13,000") }} @@ -161,7 +160,7 @@
    {{ e }}
    -{% end %} +{% endfor %} {{ f.clin_1001.label }} {{ f.clin_1001(placeholder="30,000") }} @@ -169,7 +168,7 @@
    {{ e }}
    -{% end %} +{% endfor %} {{ f.clin_1003.label }} {{ f.clin_1003(placeholder="7,000") }} @@ -177,7 +176,7 @@
    {{ e }}
    -{% end %} +{% endfor %} {{ f.clin_2001.label }} {{ f.clin_2001(placeholder="30,000") }} @@ -185,7 +184,7 @@
    {{ e }}
    -{% end %} +{% endfor %} {{ f.clin_2003.label }} {{ f.clin_2003(placeholder="7,000") }} @@ -193,7 +192,7 @@
    {{ e }}
    -{% end %} +{% endfor %} -{% end %} +{% endblock %} From 46e3bf1643a404bcd82f4b17f2426458c5248a9b Mon Sep 17 00:00:00 2001 From: richard-dds Date: Thu, 2 Aug 2018 10:59:05 -0400 Subject: [PATCH 236/332] Request flow seems to be working --- atst/app.py | 2 +- atst/routes/requests/__init__.py | 126 ++++++++++++++++++++ atst/routes/requests/jedi_request_flow.py | 135 ++++++++++++++++++++++ templates/components.html | 6 +- templates/requests/menu.html | 2 +- 5 files changed, 266 insertions(+), 5 deletions(-) create mode 100644 atst/routes/requests/__init__.py create mode 100644 atst/routes/requests/jedi_request_flow.py diff --git a/atst/app.py b/atst/app.py index babaff7a..cd432ea9 100644 --- a/atst/app.py +++ b/atst/app.py @@ -46,7 +46,7 @@ def make_flask_callbacks(app): def set_globals(): g.navigationContext = 'workspace' if re.match('\/workspaces\/[A-Za-z0-9]*', request.url) else 'global' g.dev = os.getenv("TORNADO_ENV", "dev") == "dev" - g.matchesPath = lambda href: re.match('^'+href, request.url) + g.matchesPath = lambda href: re.match('^'+href, request.path) g.modalOpen = request.args.get("modal", False) g.current_user = { "id": "cce17030-4109-4719-b958-ed109dbb87c8", diff --git a/atst/routes/requests/__init__.py b/atst/routes/requests/__init__.py new file mode 100644 index 00000000..aa747e71 --- /dev/null +++ b/atst/routes/requests/__init__.py @@ -0,0 +1,126 @@ +from flask import Blueprint, g, render_template, url_for, redirect, request +import pendulum + +from atst.routes.requests.jedi_request_flow import JEDIRequestFlow +from atst.domain.requests import Requests + + +requests_bp = Blueprint("requests", __name__) + +def map_request(user, request): + time_created = pendulum.instance(request.time_created) + is_new = time_created.add(days=1) > pendulum.now() + + return { + "order_id": request.id, + "is_new": is_new, + "status": request.status, + "app_count": 1, + "date": time_created.format("M/DD/YYYY"), + "full_name": "{} {}".format(user["first_name"], user["last_name"]), + } + + +@requests_bp.route("/requests", methods=["GET"]) +def requests_index(): + requests = [] + if "review_and_approve_jedi_workspace_request" in g.current_user["atat_permissions"]: + requests = Requests.get_many() + else: + requests = Requests.get_many(creator_id=g.current_user["id"]) + + mapped_requests = [map_request(g.current_user, r) for r in requests] + + return render_template("requests.html", requests=mapped_requests) + + +@requests_bp.route("/requests/new/", methods=["GET"]) +def requests_form_new(): + pass + + +@requests_bp.route("/requests/new//", methods=["GET"]) +def requests_form_update(screen=1, request_id=None): + request = Requests.get(request_id) if request_id is not None else None + jedi_flow = JEDIRequestFlow(screen, request, request_id=request_id) + + return render_template( + "requests/screen-%d.html" % int(screen), + f=jedi_flow.form, + data=jedi_flow.current_step_data, + screens=jedi_flow.screens, + current=screen, + next_screen=screen + 1, + request_id=request_id, + can_submit=jedi_flow.can_submit + ) + +@requests_bp.route("/requests/new//", methods=["POST"]) +def requests_update(screen=1, request_id=None): + screen = int(screen) + post_data = request.form + current_user = g.current_user + existing_request = Requests.get(request_id) if request_id is not None else None + jedi_flow = JEDIRequestFlow( + screen, + post_data=post_data, + request_id=request_id, + current_user=current_user, + existing_request=existing_request, + ) + + rerender_args = dict( + f=jedi_flow.form, + data=post_data, + screens=jedi_flow.screens, + current=screen, + next_screen=jedi_flow.next_screen, + request_id=jedi_flow.request_id, + ) + + if jedi_flow.validate(): + jedi_flow.create_or_update_request() + valid = jedi_flow.validate_warnings() + if valid: + if jedi_flow.next_screen > len(jedi_flow.screens): + where = "/requests" + else: + where = url_for( + "requests.requests_form_update", screen=jedi_flow.next_screen, request_id=jedi_flow.request_id + ) + return redirect(where) + else: + return render_template( + "requests/screen-%d.html" % int(screen), + **rerender_args + ) + else: + return render_template( + "requests/screen-%d.html" % int(screen), + **rerender_args + ) + + + + +@requests_bp.route("/requests/verify/", methods=["GET"]) +def financial_verification(request_id=None): + request = Requests.get(request_id) + form = FinancialForm(data=request.body.get('financial_verification')) + return render_template("requests/financial_verification.html", f=form) + + +@requests_bp.route("/requests/verify/", methods=["POST"]) +def update_financial_verification(): + pass + + +@requests_bp.route("/requests/submit/", methods=["POST"]) +def requests_submit(request_id=None): + request = Requests.get(request_id) + Requests.submit(request) + + if request.status == "approved": + return redirect("/requests?modal=True") + else: + return redirect("/requests") diff --git a/atst/routes/requests/jedi_request_flow.py b/atst/routes/requests/jedi_request_flow.py new file mode 100644 index 00000000..4befe5f5 --- /dev/null +++ b/atst/routes/requests/jedi_request_flow.py @@ -0,0 +1,135 @@ +from collections import defaultdict + +from atst.domain.requests import Requests +from atst.forms.financial import FinancialForm +from atst.forms.request import RequestForm +from atst.forms.org import OrgForm +from atst.forms.poc import POCForm +from atst.forms.review import ReviewForm + + + +class JEDIRequestFlow(object): + def __init__( + self, + current_step, + request=None, + post_data=None, + request_id=None, + current_user=None, + existing_request=None, + ): + self.current_step = current_step + self.request = request + + self.post_data = post_data + self.is_post = self.post_data is not None + + self.request_id = request_id + self.form = self._form() + + self.current_user = current_user + self.existing_request = existing_request + + def _form(self): + if self.is_post: + return self.form_class()(self.post_data) + elif self.request: + return self.form_class()(data=self.current_step_data) + else: + return self.form_class()() + + def validate(self): + return self.form.validate() + + def validate_warnings(self): + existing_request_data = ( + self.existing_request + and self.existing_request.body.get(self.form_section) + ) or None + + valid = self.form.perform_extra_validation( + existing_request_data, + ) + return valid + + @property + def current_screen(self): + return self.screens[self.current_step - 1] + + @property + def form_section(self): + return self.current_screen["section"] + + def form_class(self): + return self.current_screen["form"] + + @property + def current_step_data(self): + data = {} + + if self.is_post: + data = self.post_data + + if self.request: + if self.form_section == "review_submit": + data = self.request.body + else: + data = self.request.body.get(self.form_section, {}) + + return defaultdict(lambda: defaultdict(lambda: 'Input required'), data) + + @property + def can_submit(self): + return self.request and self.request.status != "incomplete" + + @property + def next_screen(self): + return self.current_step + 1 + + @property + def screens(self): + return [ + { + "title": "Details of Use", + "section": "details_of_use", + "form": RequestForm, + "subitems": [ + { + "title": "Overall request details", + "id": "overall-request-details", + }, + {"title": "Cloud Resources", "id": "cloud-resources"}, + {"title": "Support Staff", "id": "support-staff"}, + ], + "show": True, + }, + { + "title": "Information About You", + "section": "information_about_you", + "form": OrgForm, + "show": True, + }, + { + "title": "Primary Point of Contact", + "section": "primary_poc", + "form": POCForm, + "show": True, + }, + { + "title": "Review & Submit", + "section": "review_submit", + "form": ReviewForm, + "show":True, + }, + ] + + def create_or_update_request(self): + request_data = { + self.form_section: self.form.data + } + if self.request_id: + Requests.update(self.request_id, request_data) + else: + request = Requests.create(self.current_user["id"], request_data) + self.request_id = request.id diff --git a/templates/components.html b/templates/components.html index 027ede6f..ea214631 100644 --- a/templates/components.html +++ b/templates/components.html @@ -7,11 +7,11 @@ {% macro SidenavItem(label, href, active=False, icon=None, subnav=None) -%}
  • - {% if icon %} + {% if icon %} {{ Icon(icon, classes="sidenav__link-icon") }} - {% endif %} + {% endif %} - {{label}} + {{label}} {% if subnav and active %} diff --git a/templates/requests/menu.html b/templates/requests/menu.html index f1642e46..24b28d4f 100644 --- a/templates/requests/menu.html +++ b/templates/requests/menu.html @@ -2,7 +2,7 @@
  • - {% end %} - {% end %} -{% end %} + {% endcall %} + {% endif %} +{% endblock %} {% block content %} -{% module Alert('A Warning Alert', +{{ Alert('A Warning Alert', message="\

    This is a message. It is a very important message. Please note, proper semantic markup is required here, such as paragraph tags. Don't omit paragraph tags!

    \

    Also note the same for actions below. You'll need to include the full link markup.

    \ ", actions="Open a Modal Dialog", level='warning' -) %} +) }} -{% module Alert('A Success Alert', +{{ Alert('A Success Alert', message="

    Congratulations! You did a thing.

    ", level='success' -) %} +) }} -{% module Alert('An Error Alert', +{{ Alert('An Error Alert', message="

    Booooo. You're the worst.

    ", level='error' -) %} +) }} -{% module Alert('An Info Alert', +{{ Alert('An Info Alert', message="

    The more you know.

    " -) %} +) }}
    @@ -214,7 +216,7 @@
    - Inline Checkboxes {% module Icon('alert') %} + Inline Checkboxes {{ Icon('alert') }} @@ -234,7 +236,7 @@
    - Problem Radio Buttons {% module Icon('alert') %} + Problem Radio Buttons {{ Icon('alert') }} @@ -279,30 +281,30 @@
    Icons
    - {% module Icon('trash') %} 'trash'    - {% module Icon('document') %} 'document'    - {% module Icon('cloud') %} 'cloud'    - {% module Icon('chart') %} 'chart'    - {% module Icon('caret_up') %} 'caret_up'    - {% module Icon('caret_down') %} 'caret_down'    - {% module Icon('caret_right') %} 'caret_right'    - {% module Icon('caret_left') %} 'caret_left'    - {% module Icon('x') %} 'x'    - {% module Icon('search') %} 'search'    - {% module Icon('avatar') %} 'avatar'    - {% module Icon('download') %} 'download'    - {% module Icon('briefcase') %} 'briefcase'    - {% module Icon('bell') %} 'bell'    - {% module Icon('folder') %} 'folder'    - {% module Icon('help') %} 'help'    - {% module Icon('shield') %} 'shield'    - {% module Icon('info') %} 'info'    - {% module Icon('alert') %} 'alert'    - {% module Icon('link') %} 'link'    - {% module Icon('ok') %} 'ok'    - {% module Icon('checkmark') %} 'checkmark'    - {% module Icon('arrow-right') %} 'arrow-right'    - {% module Icon('arrow-down') %} 'arrow-down'    + {{ Icon('trash') }} 'trash'    + {{ Icon('document') }} 'document'    + {{ Icon('cloud') }} 'cloud'    + {{ Icon('chart') }} 'chart'    + {{ Icon('caret_up') }} 'caret_up'    + {{ Icon('caret_down') }} 'caret_down'    + {{ Icon('caret_right') }} 'caret_right'    + {{ Icon('caret_left') }} 'caret_left'    + {{ Icon('x') }} 'x'    + {{ Icon('search') }} 'search'    + {{ Icon('avatar') }} 'avatar'    + {{ Icon('download') }} 'download'    + {{ Icon('briefcase') }} 'briefcase'    + {{ Icon('bell') }} 'bell'    + {{ Icon('folder') }} 'folder'    + {{ Icon('help') }} 'help'    + {{ Icon('shield') }} 'shield'    + {{ Icon('info') }} 'info'    + {{ Icon('alert') }} 'alert'    + {{ Icon('link') }} 'link'    + {{ Icon('ok') }} 'ok'    + {{ Icon('checkmark') }} 'checkmark'    + {{ Icon('arrow-right') }} 'arrow-right'    + {{ Icon('arrow-down') }} 'arrow-down'   
    @@ -360,4 +362,4 @@ Action group link
    -{% end %} +{% endblock %} From a9d13907044f509981b8d076e264d6a354668840 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Thu, 2 Aug 2018 13:44:01 -0400 Subject: [PATCH 245/332] Rename assets environment to play nicely with script/setup --- atst/app.py | 4 ++-- atst/assets.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/atst/app.py b/atst/app.py index cd54f15d..46b017bb 100644 --- a/atst/app.py +++ b/atst/app.py @@ -5,7 +5,7 @@ from flask import Flask, request, g from unipath import Path from atst.database import db -from atst.assets import assets +from atst.assets import environment as assets_environment from atst.routes import bp from atst.routes.workspaces import bp as workspace_routes @@ -29,7 +29,7 @@ def make_app(config): make_flask_callbacks(app) db.init_app(app) - assets.init_app(app) + assets_environment.init_app(app) app.register_blueprint(bp) app.register_blueprint(workspace_routes) diff --git a/atst/assets.py b/atst/assets.py index bed898ac..aef6b35e 100644 --- a/atst/assets.py +++ b/atst/assets.py @@ -1,7 +1,7 @@ from flask_assets import Environment, Bundle from atst.home import home -assets = Environment() +environment = Environment() css = Bundle( "../scss/atat.scss", @@ -10,4 +10,4 @@ css = Bundle( depends=("**/*.scss"), ) -assets.register("css", css) +environment.register("css", css) From 3ddc76c3307ab49ba1c2f38548f1154cea03aae2 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Thu, 2 Aug 2018 13:44:54 -0400 Subject: [PATCH 246/332] Formatting --- atst/routes/requests/financial_verification.py | 5 ++++- atst/routes/requests/requests_form.py | 9 ++++++--- atst/routes/workspaces.py | 11 +++++++++-- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/atst/routes/requests/financial_verification.py b/atst/routes/requests/financial_verification.py index e0d08a37..4471b524 100644 --- a/atst/routes/requests/financial_verification.py +++ b/atst/routes/requests/financial_verification.py @@ -4,6 +4,7 @@ from . import requests_bp from atst.domain.requests import Requests from atst.forms.financial import FinancialForm + @requests_bp.route("/requests/verify/", methods=["GET"]) def financial_verification(request_id=None): request = Requests.get(request_id) @@ -30,7 +31,9 @@ def update_financial_verification(request_id): if valid: redirect(url_for("requests.financial_verification_submitted")) else: - return render_template("requests/financial_verification.html", **rerender_args) + return render_template( + "requests/financial_verification.html", **rerender_args + ) else: return render_template("requests/financial_verification.html", **rerender_args) diff --git a/atst/routes/requests/requests_form.py b/atst/routes/requests/requests_form.py index 4e9b5018..cd12fbcd 100644 --- a/atst/routes/requests/requests_form.py +++ b/atst/routes/requests/requests_form.py @@ -21,7 +21,9 @@ def requests_form_new(screen): ) -@requests_bp.route("/requests/new/", methods=["GET"], defaults={"request_id": None}) +@requests_bp.route( + "/requests/new/", methods=["GET"], defaults={"request_id": None} +) @requests_bp.route("/requests/new//", methods=["GET"]) def requests_form_update(screen=1, request_id=None): request = Requests.get(request_id) if request_id is not None else None @@ -39,7 +41,9 @@ def requests_form_update(screen=1, request_id=None): ) -@requests_bp.route("/requests/new/", methods=["POST"], defaults={"request_id": None}) +@requests_bp.route( + "/requests/new/", methods=["POST"], defaults={"request_id": None} +) @requests_bp.route("/requests/new//", methods=["POST"]) def requests_update(screen=1, request_id=None): screen = int(screen) @@ -84,7 +88,6 @@ def requests_update(screen=1, request_id=None): return render_template("requests/screen-%d.html" % int(screen), **rerender_args) - @requests_bp.route("/requests/submit/", methods=["POST"]) def requests_submit(request_id=None): request = Requests.get(request_id) diff --git a/atst/routes/workspaces.py b/atst/routes/workspaces.py index 1f3b47f2..43b3b050 100644 --- a/atst/routes/workspaces.py +++ b/atst/routes/workspaces.py @@ -14,18 +14,25 @@ mock_workspaces = [ } ] + @bp.route("/workspaces") def workspaces(): return render_template("workspaces.html", page=5, workspaces=mock_workspaces) + @bp.route("/workspaces//projects") def workspace_projects(workspace_id): projects_repo = Projects() projects = projects_repo.get_many(workspace_id) - return render_template("workspace_projects.html", workspace_id=workspace_id, projects=projects) + return render_template( + "workspace_projects.html", workspace_id=workspace_id, projects=projects + ) + @bp.route("/workspaces//members") def workspace_members(workspace_id): members_repo = Members() members = members_repo.get_many(workspace_id) - return render_template("workspace_members.html", workspace_id=workspace_id, members=members) + return render_template( + "workspace_members.html", workspace_id=workspace_id, members=members + ) From 89bde5fb2cd22f3c6f2da4c18ce4a8f36c317987 Mon Sep 17 00:00:00 2001 From: Luis Cielak Date: Mon, 30 Jul 2018 17:26:07 -0400 Subject: [PATCH 247/332] Add member placeholder info --- templates/member_edit.html.to | 73 ++++++++----------- .../navigation/workspace_navigation.html.to | 32 ++++---- templates/workspace_members.html | 16 ++-- 3 files changed, 51 insertions(+), 70 deletions(-) diff --git a/templates/member_edit.html.to b/templates/member_edit.html.to index 24893bf2..d454152c 100644 --- a/templates/member_edit.html.to +++ b/templates/member_edit.html.to @@ -16,40 +16,39 @@ level="info" ) %} -
    -
    -

    {{ member_name }}

    -
    Workspace Role
    {{member_workspace_role}}
    -
    -
    -
    -
    -
    DOD ID:
    -
    {{ member_id }}
    -
    -
    -
    Email:
    -
    {{ member_email }}
    -
    -
    - edit account details + +
    +
    +

    + {% if is_new_member %} + Add new member + {% else %} + {{ member_name }} + {% end %} +

    +
    Workspace Role {{member_workspace_role}}
    -
    {%- endmacro %} - -{% macro TextInput(field, placeholder='') -%} -
    - - - {{ field(placeholder=placeholder) | safe }} - - {% if field.errors %} - {% for error in field.errors %} - {{ error }} - {% endfor %} - {% endif %} -
    -{%- endmacro %} - -{% macro OptionsInput(field, inline=False) -%} -
    - -
    - - {{ field.label }} - - {% if field.description %} - {{ field.description | safe }} - {% endif %} - - {% if field.errors %} - {{ Icon('alert') }} - {% endif %} - - - {{ field() }} - - {% if field.errors %} - {% for error in field.errors %} - {{ error }} - {% endfor %} - {% endif %} - -
    -
    - -{%- endmacro %} From cd2f17e0849123827aebdd0a740209c9142a9e14 Mon Sep 17 00:00:00 2001 From: Patrick Smith Date: Thu, 2 Aug 2018 10:47:31 -0400 Subject: [PATCH 250/332] Update alembic/env to work with flask app --- alembic/env.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/alembic/env.py b/alembic/env.py index 6a9d9749..91b96364 100644 --- a/alembic/env.py +++ b/alembic/env.py @@ -30,11 +30,10 @@ sys.path.append(parent_dir) from atst.app import make_config app_config = make_config() -config.set_main_option('sqlalchemy.url', app_config['default']['DATABASE_URI']) +config.set_main_option('sqlalchemy.url', app_config['DATABASE_URI']) -from atst.database import make_db +from atst.database import db from atst.models import * -db = make_db(app_config) target_metadata = Base.metadata From ccf4108665afeea7083271ae13e6c110d0c3c6e4 Mon Sep 17 00:00:00 2001 From: Patrick Smith Date: Thu, 2 Aug 2018 10:51:12 -0400 Subject: [PATCH 251/332] Add parcel/vue js deps --- package.json | 4 +- yarn.lock | 6585 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 6588 insertions(+), 1 deletion(-) create mode 100644 yarn.lock diff --git a/package.json b/package.json index 5e9a5920..9a474e0d 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,8 @@ "license": "MIT", "dependencies": { "npm": "^6.0.1", - "uswds": "^1.6.3" + "parcel": "^1.9.7", + "uswds": "^1.6.3", + "vue": "^2.5.17" } } diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 00000000..ca8a5e51 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,6585 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@mrmlnc/readdir-enhanced@^2.2.1": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde" + dependencies: + call-me-maybe "^1.0.1" + glob-to-regexp "^0.3.0" + +"@nodelib/fs.stat@^1.0.1": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.0.tgz#50c1e2260ac0ed9439a181de3725a0168d59c48a" + +"@types/node@^8.5.5": + version "8.10.23" + resolved "https://registry.yarnpkg.com/@types/node/-/node-8.10.23.tgz#e5ccfdafff42af5397c29669b6d7d65f7d629a00" + +JSONStream@^1.0.3, JSONStream@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.3.tgz#27b4b8fbbfeab4e71bcf551e7f27be8d952239bf" + dependencies: + jsonparse "^1.2.0" + through ">=2.2.7 <3" + +abbrev@1, abbrev@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + +acorn-dynamic-import@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-3.0.0.tgz#901ceee4c7faaef7e07ad2a47e890675da50a278" + dependencies: + acorn "^5.0.0" + +acorn-node@^1.2.0, acorn-node@^1.3.0, acorn-node@^1.5.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/acorn-node/-/acorn-node-1.5.2.tgz#2ca723df19d997b05824b69f6c7fb091fc42c322" + dependencies: + acorn "^5.7.1" + acorn-dynamic-import "^3.0.0" + xtend "^4.0.1" + +acorn@^5.0.0, acorn@^5.2.1, acorn@^5.7.1: + version "5.7.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.1.tgz#f095829297706a7c9776958c0afc8930a9b9d9d8" + +agent-base@4, agent-base@^4.1.0, agent-base@~4.2.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9" + dependencies: + es6-promisify "^5.0.0" + +agentkeepalive@^3.4.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-3.5.1.tgz#4eba75cf2ad258fc09efd506cdb8d8c2971d35a4" + dependencies: + humanize-ms "^1.2.1" + +ajv@^4.9.1: + version "4.11.8" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" + dependencies: + co "^4.6.0" + json-stable-stringify "^1.0.1" + +ajv@^5.1.0: + version "5.5.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" + dependencies: + co "^4.6.0" + fast-deep-equal "^1.0.0" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.3.0" + +alphanum-sort@^1.0.0, alphanum-sort@^1.0.1, alphanum-sort@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" + +ansi-align@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-2.0.0.tgz#c36aeccba563b89ceb556f3690f0b1d9e3547f7f" + dependencies: + string-width "^2.0.0" + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + dependencies: + color-convert "^1.9.0" + +ansi-to-html@^0.6.4: + version "0.6.6" + resolved "https://registry.yarnpkg.com/ansi-to-html/-/ansi-to-html-0.6.6.tgz#58a8d04b87ec9a85e3ad273c12a5fbc7147b9c42" + dependencies: + entities "^1.1.1" + +ansicolors@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.3.2.tgz#665597de86a9ffe3aa9bfbe6cae5c6ea426b4979" + +ansistyles@~0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/ansistyles/-/ansistyles-0.1.3.tgz#5de60415bda071bb37127854c864f41b23254539" + +anymatch@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + dependencies: + micromatch "^3.1.4" + normalize-path "^2.1.1" + +aproba@^1.0.3, aproba@^1.1.1, aproba@^1.1.2, aproba@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + +"aproba@^1.1.2 || 2": + version "2.0.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" + +archy@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" + +are-we-there-yet@~1.1.2: + version "1.1.5" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + dependencies: + sprintf-js "~1.0.2" + +arr-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + +arr-flatten@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + +arr-union@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + +array-filter@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-1.0.0.tgz#baf79e62e6ef4c2a4c0b831232daffec251f9d83" + +array-filter@~0.0.0: + version "0.0.1" + resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-0.0.1.tgz#7da8cf2e26628ed732803581fd21f67cacd2eeec" + +array-foreach@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-foreach/-/array-foreach-1.0.2.tgz#cd36e42f0f482108c406b35c3612a8970b2fccea" + +array-map@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/array-map/-/array-map-0.0.0.tgz#88a2bab73d1cf7bcd5c1b118a003f66f665fa662" + +array-reduce@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/array-reduce/-/array-reduce-0.0.0.tgz#173899d3ffd1c7d9383e4479525dbe278cab5f2b" + +array-unique@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + +asap@^2.0.0: + version "2.0.6" + resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" + +asn1.js@^4.0.0: + version "4.10.1" + resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0" + dependencies: + bn.js "^4.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +asn1@~0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + +assert-plus@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" + +assert@^1.1.1, assert@^1.4.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91" + dependencies: + util "0.10.3" + +assign-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + +async-each@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" + +async-limiter@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + +atob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.1.tgz#ae2d5a729477f289d60dd7f96a6314a22dd6c22a" + +autoprefixer@^6.3.1: + version "6.7.7" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-6.7.7.tgz#1dbd1c835658e35ce3f9984099db00585c782014" + dependencies: + browserslist "^1.7.6" + caniuse-db "^1.0.30000634" + normalize-range "^0.1.2" + num2fraction "^1.2.2" + postcss "^5.2.16" + postcss-value-parser "^3.2.3" + +aws-sign2@~0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" + +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + +aws4@^1.2.1, aws4@^1.6.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.7.0.tgz#d4d0e9b9dbfca77bf08eeb0a8a471550fe39e289" + +babel-code-frame@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" + dependencies: + chalk "^1.1.3" + esutils "^2.0.2" + js-tokens "^3.0.2" + +babel-core@^6.25.0, babel-core@^6.26.0: + version "6.26.3" + resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.3.tgz#b2e2f09e342d0f0c88e2f02e067794125e75c207" + dependencies: + babel-code-frame "^6.26.0" + babel-generator "^6.26.0" + babel-helpers "^6.24.1" + babel-messages "^6.23.0" + babel-register "^6.26.0" + babel-runtime "^6.26.0" + babel-template "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + convert-source-map "^1.5.1" + debug "^2.6.9" + json5 "^0.5.1" + lodash "^4.17.4" + minimatch "^3.0.4" + path-is-absolute "^1.0.1" + private "^0.1.8" + slash "^1.0.0" + source-map "^0.5.7" + +babel-generator@^6.25.0, babel-generator@^6.26.0: + version "6.26.1" + resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90" + dependencies: + babel-messages "^6.23.0" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + detect-indent "^4.0.0" + jsesc "^1.3.0" + lodash "^4.17.4" + source-map "^0.5.7" + trim-right "^1.0.1" + +babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664" + dependencies: + babel-helper-explode-assignable-expression "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-builder-react-jsx@^6.24.1: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.26.0.tgz#39ff8313b75c8b65dceff1f31d383e0ff2a408a0" + dependencies: + babel-runtime "^6.26.0" + babel-types "^6.26.0" + esutils "^2.0.2" + +babel-helper-call-delegate@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" + dependencies: + babel-helper-hoist-variables "^6.24.1" + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-define-map@^6.24.1: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz#a5f56dab41a25f97ecb498c7ebaca9819f95be5f" + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" + +babel-helper-explode-assignable-expression@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz#f25b82cf7dc10433c55f70592d5746400ac22caa" + dependencies: + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-function-name@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9" + dependencies: + babel-helper-get-function-arity "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-get-function-arity@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-hoist-variables@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz#1ecb27689c9d25513eadbc9914a73f5408be7a76" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-optimise-call-expression@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-regex@^6.24.1: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz#325c59f902f82f24b74faceed0363954f6495e72" + dependencies: + babel-runtime "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" + +babel-helper-remap-async-to-generator@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz#5ec581827ad723fecdd381f1c928390676e4551b" + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-replace-supers@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a" + dependencies: + babel-helper-optimise-call-expression "^6.24.1" + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helpers@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" + dependencies: + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-messages@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-check-es2015-constants@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-syntax-async-functions@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" + +babel-plugin-syntax-exponentiation-operator@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" + +babel-plugin-syntax-jsx@^6.8.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946" + +babel-plugin-syntax-trailing-function-commas@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" + +babel-plugin-transform-async-to-generator@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761" + dependencies: + babel-helper-remap-async-to-generator "^6.24.1" + babel-plugin-syntax-async-functions "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-arrow-functions@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-block-scoping@^6.23.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f" + dependencies: + babel-runtime "^6.26.0" + babel-template "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" + +babel-plugin-transform-es2015-classes@^6.23.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db" + dependencies: + babel-helper-define-map "^6.24.1" + babel-helper-function-name "^6.24.1" + babel-helper-optimise-call-expression "^6.24.1" + babel-helper-replace-supers "^6.24.1" + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-computed-properties@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3" + dependencies: + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-destructuring@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-duplicate-keys@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-for-of@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-function-name@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b" + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-literals@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015-modules-amd@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154" + dependencies: + babel-plugin-transform-es2015-modules-commonjs "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-es2015-modules-commonjs@^6.24.1, babel-plugin-transform-es2015-modules-commonjs@^6.26.0: + version "6.26.2" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz#58a793863a9e7ca870bdc5a881117ffac27db6f3" + dependencies: + babel-plugin-transform-strict-mode "^6.24.1" + babel-runtime "^6.26.0" + babel-template "^6.26.0" + babel-types "^6.26.0" + +babel-plugin-transform-es2015-modules-systemjs@^6.23.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23" + dependencies: + babel-helper-hoist-variables "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-modules-umd@^6.23.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468" + dependencies: + babel-plugin-transform-es2015-modules-amd "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-object-super@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d" + dependencies: + babel-helper-replace-supers "^6.24.1" + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-parameters@^6.23.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b" + dependencies: + babel-helper-call-delegate "^6.24.1" + babel-helper-get-function-arity "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-shorthand-properties@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-spread@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-sticky-regex@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc" + dependencies: + babel-helper-regex "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-template-literals@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-typeof-symbol@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-unicode-regex@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9" + dependencies: + babel-helper-regex "^6.24.1" + babel-runtime "^6.22.0" + regexpu-core "^2.0.0" + +babel-plugin-transform-exponentiation-operator@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz#2ab0c9c7f3098fa48907772bb813fe41e8de3a0e" + dependencies: + babel-helper-builder-binary-assignment-operator-visitor "^6.24.1" + babel-plugin-syntax-exponentiation-operator "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-react-jsx@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx/-/babel-plugin-transform-react-jsx-6.24.1.tgz#840a028e7df460dfc3a2d29f0c0d91f6376e66a3" + dependencies: + babel-helper-builder-react-jsx "^6.24.1" + babel-plugin-syntax-jsx "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-regenerator@^6.22.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f" + dependencies: + regenerator-transform "^0.10.0" + +babel-plugin-transform-strict-mode@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-preset-env@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.7.0.tgz#dea79fa4ebeb883cd35dab07e260c1c9c04df77a" + dependencies: + babel-plugin-check-es2015-constants "^6.22.0" + babel-plugin-syntax-trailing-function-commas "^6.22.0" + babel-plugin-transform-async-to-generator "^6.22.0" + babel-plugin-transform-es2015-arrow-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoped-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoping "^6.23.0" + babel-plugin-transform-es2015-classes "^6.23.0" + babel-plugin-transform-es2015-computed-properties "^6.22.0" + babel-plugin-transform-es2015-destructuring "^6.23.0" + babel-plugin-transform-es2015-duplicate-keys "^6.22.0" + babel-plugin-transform-es2015-for-of "^6.23.0" + babel-plugin-transform-es2015-function-name "^6.22.0" + babel-plugin-transform-es2015-literals "^6.22.0" + babel-plugin-transform-es2015-modules-amd "^6.22.0" + babel-plugin-transform-es2015-modules-commonjs "^6.23.0" + babel-plugin-transform-es2015-modules-systemjs "^6.23.0" + babel-plugin-transform-es2015-modules-umd "^6.23.0" + babel-plugin-transform-es2015-object-super "^6.22.0" + babel-plugin-transform-es2015-parameters "^6.23.0" + babel-plugin-transform-es2015-shorthand-properties "^6.22.0" + babel-plugin-transform-es2015-spread "^6.22.0" + babel-plugin-transform-es2015-sticky-regex "^6.22.0" + babel-plugin-transform-es2015-template-literals "^6.22.0" + babel-plugin-transform-es2015-typeof-symbol "^6.23.0" + babel-plugin-transform-es2015-unicode-regex "^6.22.0" + babel-plugin-transform-exponentiation-operator "^6.22.0" + babel-plugin-transform-regenerator "^6.22.0" + browserslist "^3.2.6" + invariant "^2.2.2" + semver "^5.3.0" + +babel-register@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" + dependencies: + babel-core "^6.26.0" + babel-runtime "^6.26.0" + core-js "^2.5.0" + home-or-tmp "^2.0.0" + lodash "^4.17.4" + mkdirp "^0.5.1" + source-map-support "^0.4.15" + +babel-runtime@^6.11.6, babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.11.0" + +babel-template@^6.24.1, babel-template@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" + dependencies: + babel-runtime "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + lodash "^4.17.4" + +babel-traverse@^6.24.1, babel-traverse@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" + dependencies: + babel-code-frame "^6.26.0" + babel-messages "^6.23.0" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + debug "^2.6.8" + globals "^9.18.0" + invariant "^2.2.2" + lodash "^4.17.4" + +babel-types@^6.15.0, babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" + dependencies: + babel-runtime "^6.26.0" + esutils "^2.0.2" + lodash "^4.17.4" + to-fast-properties "^1.0.3" + +babylon-walk@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/babylon-walk/-/babylon-walk-1.0.2.tgz#3b15a5ddbb482a78b4ce9c01c8ba181702d9d6ce" + dependencies: + babel-runtime "^6.11.6" + babel-types "^6.15.0" + lodash.clone "^4.5.0" + +babylon@^6.17.4, babylon@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" + +balanced-match@^0.4.2: + version "0.4.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + +base64-js@^1.0.2: + version "1.3.0" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3" + +base@^0.11.1: + version "0.11.2" + resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + dependencies: + cache-base "^1.0.1" + class-utils "^0.3.5" + component-emitter "^1.2.1" + define-property "^1.0.0" + isobject "^3.0.1" + mixin-deep "^1.2.0" + pascalcase "^0.1.1" + +bcrypt-pbkdf@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + dependencies: + tweetnacl "^0.14.3" + +bin-links@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/bin-links/-/bin-links-1.1.2.tgz#fb74bd54bae6b7befc6c6221f25322ac830d9757" + dependencies: + bluebird "^3.5.0" + cmd-shim "^2.0.2" + gentle-fs "^2.0.0" + graceful-fs "^4.1.11" + write-file-atomic "^2.3.0" + +binary-extensions@^1.0.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205" + +bindings@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.2.1.tgz#14ad6113812d2d37d72e67b4cacb4bb726505f11" + +block-stream@*: + version "0.0.9" + resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" + dependencies: + inherits "~2.0.0" + +bluebird@^3.0.5, bluebird@^3.5.0, bluebird@^3.5.1, bluebird@~3.5.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" + +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: + version "4.11.8" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" + +boolbase@^1.0.0, boolbase@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" + +boom@2.x.x: + version "2.10.1" + resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" + dependencies: + hoek "2.x.x" + +boxen@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/boxen/-/boxen-1.3.0.tgz#55c6c39a8ba58d9c61ad22cd877532deb665a20b" + dependencies: + ansi-align "^2.0.0" + camelcase "^4.0.0" + chalk "^2.0.1" + cli-boxes "^1.0.0" + string-width "^2.0.0" + term-size "^1.2.0" + widest-line "^2.0.0" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^2.3.0, braces@^2.3.1: + version "2.3.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + dependencies: + arr-flatten "^1.1.0" + array-unique "^0.3.2" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.0.1" + +brfs@^1.2.0: + version "1.6.1" + resolved "https://registry.yarnpkg.com/brfs/-/brfs-1.6.1.tgz#b78ce2336d818e25eea04a0947cba6d4fb8849c3" + dependencies: + quote-stream "^1.0.1" + resolve "^1.1.5" + static-module "^2.2.0" + through2 "^2.0.0" + +brorand@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + +browser-pack@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/browser-pack/-/browser-pack-6.1.0.tgz#c34ba10d0b9ce162b5af227c7131c92c2ecd5774" + dependencies: + JSONStream "^1.0.3" + combine-source-map "~0.8.0" + defined "^1.0.0" + safe-buffer "^5.1.1" + through2 "^2.0.0" + umd "^3.0.0" + +browser-resolve@^1.11.0, browser-resolve@^1.7.0: + version "1.11.3" + resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.3.tgz#9b7cbb3d0f510e4cb86bdbd796124d28b5890af6" + dependencies: + resolve "1.1.7" + +browserify-aes@^1.0.0, browserify-aes@^1.0.4: + version "1.2.0" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" + dependencies: + buffer-xor "^1.0.3" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.3" + inherits "^2.0.1" + safe-buffer "^5.0.1" + +browserify-cipher@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" + dependencies: + browserify-aes "^1.0.4" + browserify-des "^1.0.0" + evp_bytestokey "^1.0.0" + +browserify-des@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" + dependencies: + cipher-base "^1.0.1" + des.js "^1.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +browserify-rsa@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524" + dependencies: + bn.js "^4.1.0" + randombytes "^2.0.1" + +browserify-sign@^4.0.0: + version "4.0.4" + resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.4.tgz#aa4eb68e5d7b658baa6bf6a57e630cbd7a93d298" + dependencies: + bn.js "^4.1.1" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.2" + elliptic "^6.0.0" + inherits "^2.0.1" + parse-asn1 "^5.0.0" + +browserify-zlib@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" + dependencies: + pako "~1.0.5" + +browserify-zlib@~0.1.2: + version "0.1.4" + resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.1.4.tgz#bb35f8a519f600e0fa6b8485241c979d0141fb2d" + dependencies: + pako "~0.2.0" + +browserify@^13.0.0: + version "13.3.0" + resolved "https://registry.yarnpkg.com/browserify/-/browserify-13.3.0.tgz#b5a9c9020243f0c70e4675bec8223bc627e415ce" + dependencies: + JSONStream "^1.0.3" + assert "^1.4.0" + browser-pack "^6.0.1" + browser-resolve "^1.11.0" + browserify-zlib "~0.1.2" + buffer "^4.1.0" + cached-path-relative "^1.0.0" + concat-stream "~1.5.1" + console-browserify "^1.1.0" + constants-browserify "~1.0.0" + crypto-browserify "^3.0.0" + defined "^1.0.0" + deps-sort "^2.0.0" + domain-browser "~1.1.0" + duplexer2 "~0.1.2" + events "~1.1.0" + glob "^7.1.0" + has "^1.0.0" + htmlescape "^1.1.0" + https-browserify "~0.0.0" + inherits "~2.0.1" + insert-module-globals "^7.0.0" + labeled-stream-splicer "^2.0.0" + module-deps "^4.0.8" + os-browserify "~0.1.1" + parents "^1.0.1" + path-browserify "~0.0.0" + process "~0.11.0" + punycode "^1.3.2" + querystring-es3 "~0.2.0" + read-only-stream "^2.0.0" + readable-stream "^2.0.2" + resolve "^1.1.4" + shasum "^1.0.0" + shell-quote "^1.6.1" + stream-browserify "^2.0.0" + stream-http "^2.0.0" + string_decoder "~0.10.0" + subarg "^1.0.0" + syntax-error "^1.1.1" + through2 "^2.0.0" + timers-browserify "^1.0.1" + tty-browserify "~0.0.0" + url "~0.11.0" + util "~0.10.1" + vm-browserify "~0.0.1" + xtend "^4.0.0" + +browserslist@^1.3.6, browserslist@^1.5.2, browserslist@^1.7.6: + version "1.7.7" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-1.7.7.tgz#0bd76704258be829b2398bb50e4b62d1a166b0b9" + dependencies: + caniuse-db "^1.0.30000639" + electron-to-chromium "^1.2.7" + +browserslist@^3.2.6: + version "3.2.8" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-3.2.8.tgz#b0005361d6471f0f5952797a76fc985f1f978fc6" + dependencies: + caniuse-lite "^1.0.30000844" + electron-to-chromium "^1.3.47" + +browserslist@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.0.1.tgz#61c05ce2a5843c7d96166408bc23d58b5416e818" + dependencies: + caniuse-lite "^1.0.30000865" + electron-to-chromium "^1.3.52" + node-releases "^1.0.0-alpha.10" + +buffer-equal@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/buffer-equal/-/buffer-equal-0.0.1.tgz#91bc74b11ea405bc916bc6aa908faafa5b4aac4b" + +buffer-from@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" + +buffer-xor@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + +buffer@^4.1.0, buffer@^4.3.0: + version "4.9.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + isarray "^1.0.0" + +builtin-modules@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" + +builtin-status-codes@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" + +builtins@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88" + +byline@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/byline/-/byline-5.0.0.tgz#741c5216468eadc457b03410118ad77de8c1ddb1" + +byte-size@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/byte-size/-/byte-size-4.0.3.tgz#b7c095efc68eadf82985fccd9a2df43a74fa2ccd" + +cacache@^10.0.4: + version "10.0.4" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-10.0.4.tgz#6452367999eff9d4188aefd9a14e9d7c6a263460" + dependencies: + bluebird "^3.5.1" + chownr "^1.0.1" + glob "^7.1.2" + graceful-fs "^4.1.11" + lru-cache "^4.1.1" + mississippi "^2.0.0" + mkdirp "^0.5.1" + move-concurrently "^1.0.1" + promise-inflight "^1.0.1" + rimraf "^2.6.2" + ssri "^5.2.4" + unique-filename "^1.1.0" + y18n "^4.0.0" + +cacache@^11.0.1, cacache@^11.0.2, cacache@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-11.1.0.tgz#3d76dbc2e9da413acaad2557051960a4dad3e1a4" + dependencies: + bluebird "^3.5.1" + chownr "^1.0.1" + figgy-pudding "^3.1.0" + glob "^7.1.2" + graceful-fs "^4.1.11" + lru-cache "^4.1.3" + mississippi "^3.0.0" + mkdirp "^0.5.1" + move-concurrently "^1.0.1" + promise-inflight "^1.0.1" + rimraf "^2.6.2" + ssri "^6.0.0" + unique-filename "^1.1.0" + y18n "^4.0.0" + +cache-base@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + dependencies: + collection-visit "^1.0.0" + component-emitter "^1.2.1" + get-value "^2.0.6" + has-value "^1.0.0" + isobject "^3.0.1" + set-value "^2.0.0" + to-object-path "^0.3.0" + union-value "^1.0.0" + unset-value "^1.0.0" + +cached-path-relative@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cached-path-relative/-/cached-path-relative-1.0.1.tgz#d09c4b52800aa4c078e2dd81a869aac90d2e54e7" + +call-limit@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/call-limit/-/call-limit-1.1.0.tgz#6fd61b03f3da42a2cd0ec2b60f02bd0e71991fea" + +call-me-maybe@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b" + +camelcase@^4.0.0, camelcase@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" + +caniuse-api@^1.5.2: + version "1.6.1" + resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-1.6.1.tgz#b534e7c734c4f81ec5fbe8aca2ad24354b962c6c" + dependencies: + browserslist "^1.3.6" + caniuse-db "^1.0.30000529" + lodash.memoize "^4.1.2" + lodash.uniq "^4.5.0" + +caniuse-api@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0" + dependencies: + browserslist "^4.0.0" + caniuse-lite "^1.0.0" + lodash.memoize "^4.1.2" + lodash.uniq "^4.5.0" + +caniuse-db@^1.0.30000529, caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639: + version "1.0.30000872" + resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000872.tgz#3f6e53b63d373768bf99e896133d66ef89c49999" + +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000844, caniuse-lite@^1.0.30000865: + version "1.0.30000865" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000865.tgz#70026616e8afe6e1442f8bb4e1092987d81a2f25" + +capture-stack-trace@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz#4a6fa07399c26bba47f0b2496b4d0fb408c5550d" + +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + +chalk@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.1, chalk@^2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e" + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chokidar@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.4.tgz#356ff4e2b0e8e43e322d18a372460bbcf3accd26" + dependencies: + anymatch "^2.0.0" + async-each "^1.0.0" + braces "^2.3.0" + glob-parent "^3.1.0" + inherits "^2.0.1" + is-binary-path "^1.0.0" + is-glob "^4.0.0" + lodash.debounce "^4.0.8" + normalize-path "^2.1.1" + path-is-absolute "^1.0.0" + readdirp "^2.0.0" + upath "^1.0.5" + optionalDependencies: + fsevents "^1.2.2" + +chownr@^1.0.1, chownr@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" + +ci-info@^1.0.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.1.3.tgz#710193264bb05c77b8c90d02f5aaf22216a667b2" + +cidr-regex@^2.0.8: + version "2.0.9" + resolved "https://registry.yarnpkg.com/cidr-regex/-/cidr-regex-2.0.9.tgz#9c17bb2b18e15af07f7d0c3b994b961d687ed1c9" + dependencies: + ip-regex "^2.1.0" + +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +clap@^1.0.9: + version "1.2.3" + resolved "https://registry.yarnpkg.com/clap/-/clap-1.2.3.tgz#4f36745b32008492557f46412d66d50cb99bce51" + dependencies: + chalk "^1.1.3" + +class-utils@^0.3.5: + version "0.3.6" + resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + +classlist-polyfill@^1.0.3: + version "1.2.0" + resolved "https://registry.yarnpkg.com/classlist-polyfill/-/classlist-polyfill-1.2.0.tgz#935bc2dfd9458a876b279617514638bcaa964a2e" + +cli-boxes@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143" + +cli-columns@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/cli-columns/-/cli-columns-3.1.2.tgz#6732d972979efc2ae444a1f08e08fa139c96a18e" + dependencies: + string-width "^2.0.0" + strip-ansi "^3.0.1" + +cli-cursor@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" + dependencies: + restore-cursor "^2.0.0" + +cli-spinners@^1.1.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-1.3.1.tgz#002c1990912d0d59580c93bd36c056de99e4259a" + +cli-table3@^0.5.0: + version "0.5.1" + resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.5.1.tgz#0252372d94dfc40dbd8df06005f48f31f656f202" + dependencies: + object-assign "^4.1.0" + string-width "^2.1.1" + optionalDependencies: + colors "^1.1.2" + +cliui@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + wrap-ansi "^2.0.0" + +cliui@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" + dependencies: + string-width "^2.1.1" + strip-ansi "^4.0.0" + wrap-ansi "^2.0.0" + +clone@^1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" + +clone@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" + +clones@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/clones/-/clones-1.1.0.tgz#87e904132d6140c5c0b72006c08c0d05bd7b63b3" + +cmd-shim@^2.0.2, cmd-shim@~2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/cmd-shim/-/cmd-shim-2.0.2.tgz#6fcbda99483a8fd15d7d30a196ca69d688a2efdb" + dependencies: + graceful-fs "^4.1.2" + mkdirp "~0.5.0" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + +coa@~1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/coa/-/coa-1.0.4.tgz#a9ef153660d6a86a8bdec0289a5c684d217432fd" + dependencies: + q "^1.1.2" + +coa@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/coa/-/coa-2.0.1.tgz#f3f8b0b15073e35d70263fb1042cb2c023db38af" + dependencies: + q "^1.1.2" + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + +collection-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + dependencies: + map-visit "^1.0.0" + object-visit "^1.0.0" + +color-convert@^1.3.0, color-convert@^1.9.0, color-convert@^1.9.1: + version "1.9.2" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.2.tgz#49881b8fba67df12a96bdf3f56c0aab9e7913147" + dependencies: + color-name "1.1.1" + +color-name@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.1.tgz#4b1415304cf50028ea81643643bd82ea05803689" + +color-name@^1.0.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + +color-string@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-0.3.0.tgz#27d46fb67025c5c2fa25993bfbf579e47841b991" + dependencies: + color-name "^1.0.0" + +color-string@^1.5.2: + version "1.5.3" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.5.3.tgz#c9bbc5f01b58b5492f3d6857459cb6590ce204cc" + dependencies: + color-name "^1.0.0" + simple-swizzle "^0.2.2" + +color@^0.11.0: + version "0.11.4" + resolved "https://registry.yarnpkg.com/color/-/color-0.11.4.tgz#6d7b5c74fb65e841cd48792ad1ed5e07b904d764" + dependencies: + clone "^1.0.2" + color-convert "^1.3.0" + color-string "^0.3.0" + +color@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/color/-/color-3.0.0.tgz#d920b4328d534a3ac8295d68f7bd4ba6c427be9a" + dependencies: + color-convert "^1.9.1" + color-string "^1.5.2" + +colormin@^1.0.5: + version "1.1.2" + resolved "https://registry.yarnpkg.com/colormin/-/colormin-1.1.2.tgz#ea2f7420a72b96881a38aae59ec124a6f7298133" + dependencies: + color "^0.11.0" + css-color-names "0.0.4" + has "^1.0.1" + +colors@^1.1.2: + version "1.3.1" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.3.1.tgz#4accdb89cf2cabc7f982771925e9468784f32f3d" + +colors@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" + +columnify@~1.5.4: + version "1.5.4" + resolved "https://registry.yarnpkg.com/columnify/-/columnify-1.5.4.tgz#4737ddf1c7b69a8a7c340570782e947eec8e78bb" + dependencies: + strip-ansi "^3.0.0" + wcwidth "^1.0.0" + +combine-source-map@^0.8.0, combine-source-map@~0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/combine-source-map/-/combine-source-map-0.8.0.tgz#a58d0df042c186fcf822a8e8015f5450d2d79a8b" + dependencies: + convert-source-map "~1.1.0" + inline-source-map "~0.6.0" + lodash.memoize "~3.0.3" + source-map "~0.5.3" + +combined-stream@1.0.6, combined-stream@^1.0.5, combined-stream@~1.0.5: + version "1.0.6" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.6.tgz#723e7df6e801ac5613113a7e445a9b69cb632818" + dependencies: + delayed-stream "~1.0.0" + +command-exists@^1.2.6: + version "1.2.7" + resolved "https://registry.yarnpkg.com/command-exists/-/command-exists-1.2.7.tgz#16828f0c3ff2b0c58805861ef211b64fc15692a8" + +commander@^2.11.0, commander@^2.9.0, commander@~2.16.0: + version "2.16.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.16.0.tgz#f16390593996ceb4f3eeb020b31d78528f7f8a50" + +commander@~2.14.1: + version "2.14.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.14.1.tgz#2235123e37af8ca3c65df45b026dbd357b01b9aa" + +component-emitter@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + +concat-stream@^1.5.0, concat-stream@^1.5.2, concat-stream@^1.6.1, concat-stream@~1.6.0: + version "1.6.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + dependencies: + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + +concat-stream@~1.5.0, concat-stream@~1.5.1: + version "1.5.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.5.2.tgz#708978624d856af41a5a741defdd261da752c266" + dependencies: + inherits "~2.0.1" + readable-stream "~2.0.0" + typedarray "~0.0.5" + +config-chain@~1.1.11, config-chain@~1.1.5: + version "1.1.11" + resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.11.tgz#aba09747dfbe4c3e70e766a6e41586e1859fc6f2" + dependencies: + ini "^1.3.4" + proto-list "~1.2.1" + +configstore@^3.0.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/configstore/-/configstore-3.1.2.tgz#c6f25defaeef26df12dd33414b001fe81a543f8f" + dependencies: + dot-prop "^4.1.0" + graceful-fs "^4.1.2" + make-dir "^1.0.0" + unique-string "^1.0.0" + write-file-atomic "^2.0.0" + xdg-basedir "^3.0.0" + +console-browserify@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" + dependencies: + date-now "^0.1.4" + +console-control-strings@^1.0.0, console-control-strings@^1.1.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + +constants-browserify@^1.0.0, constants-browserify@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" + +convert-source-map@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5" + +convert-source-map@~1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.1.3.tgz#4829c877e9fe49b3161f3bf3673888e204699860" + +copy-concurrently@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0" + dependencies: + aproba "^1.1.1" + fs-write-stream-atomic "^1.0.8" + iferr "^0.1.5" + mkdirp "^0.5.1" + rimraf "^2.5.4" + run-queue "^1.0.0" + +copy-descriptor@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + +core-js@^2.4.0, core-js@^2.5.0: + version "2.5.7" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e" + +core-util-is@1.0.2, core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + +cosmiconfig@^5.0.0: + version "5.0.5" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.0.5.tgz#a809e3c2306891ce17ab70359dc8bdf661fe2cd0" + dependencies: + is-directory "^0.3.1" + js-yaml "^3.9.0" + parse-json "^4.0.0" + +create-ecdh@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff" + dependencies: + bn.js "^4.1.0" + elliptic "^6.0.0" + +create-error-class@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/create-error-class/-/create-error-class-3.0.2.tgz#06be7abef947a3f14a30fd610671d401bca8b7b6" + dependencies: + capture-stack-trace "^1.0.0" + +create-hash@^1.1.0, create-hash@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + md5.js "^1.3.4" + ripemd160 "^2.0.1" + sha.js "^2.4.0" + +create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: + version "1.1.7" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +cross-spawn@^5.0.1: + version "5.1.0" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" + dependencies: + lru-cache "^4.0.1" + shebang-command "^1.2.0" + which "^1.2.9" + +cross-spawn@^6.0.4: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + +cryptiles@2.x.x: + version "2.0.5" + resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" + dependencies: + boom "2.x.x" + +crypto-browserify@^3.0.0, crypto-browserify@^3.11.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" + dependencies: + browserify-cipher "^1.0.0" + browserify-sign "^4.0.0" + create-ecdh "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.0" + diffie-hellman "^5.0.0" + inherits "^2.0.1" + pbkdf2 "^3.0.3" + public-encrypt "^4.0.0" + randombytes "^2.0.0" + randomfill "^1.0.3" + +crypto-random-string@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" + +css-color-names@0.0.4, css-color-names@^0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0" + +css-declaration-sorter@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-3.0.1.tgz#d0e3056b0fd88dc1ea9dceff435adbe9c702a7f8" + dependencies: + postcss "^6.0.0" + timsort "^0.3.0" + +css-select-base-adapter@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/css-select-base-adapter/-/css-select-base-adapter-0.1.0.tgz#0102b3d14630df86c3eb9fa9f5456270106cf990" + +css-select@~1.3.0-rc0: + version "1.3.0-rc0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.3.0-rc0.tgz#6f93196aaae737666ea1036a8cb14a8fcb7a9231" + dependencies: + boolbase "^1.0.0" + css-what "2.1" + domutils "1.5.1" + nth-check "^1.0.1" + +css-tree@1.0.0-alpha.29: + version "1.0.0-alpha.29" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.29.tgz#3fa9d4ef3142cbd1c301e7664c1f352bd82f5a39" + dependencies: + mdn-data "~1.1.0" + source-map "^0.5.3" + +css-tree@1.0.0-alpha25: + version "1.0.0-alpha25" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha25.tgz#1bbfabfbf6eeef4f01d9108ff2edd0be2fe35597" + dependencies: + mdn-data "^1.0.0" + source-map "^0.5.3" + +css-unit-converter@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/css-unit-converter/-/css-unit-converter-1.1.1.tgz#d9b9281adcfd8ced935bdbaba83786897f64e996" + +css-url-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/css-url-regex/-/css-url-regex-1.1.0.tgz#83834230cc9f74c457de59eebd1543feeb83b7ec" + +css-what@2.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.0.tgz#9467d032c38cfaefb9f2d79501253062f87fa1bd" + +cssnano-preset-default@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-4.0.0.tgz#c334287b4f7d49fb2d170a92f9214655788e3b6b" + dependencies: + css-declaration-sorter "^3.0.0" + cssnano-util-raw-cache "^4.0.0" + postcss "^6.0.0" + postcss-calc "^6.0.0" + postcss-colormin "^4.0.0" + postcss-convert-values "^4.0.0" + postcss-discard-comments "^4.0.0" + postcss-discard-duplicates "^4.0.0" + postcss-discard-empty "^4.0.0" + postcss-discard-overridden "^4.0.0" + postcss-merge-longhand "^4.0.0" + postcss-merge-rules "^4.0.0" + postcss-minify-font-values "^4.0.0" + postcss-minify-gradients "^4.0.0" + postcss-minify-params "^4.0.0" + postcss-minify-selectors "^4.0.0" + postcss-normalize-charset "^4.0.0" + postcss-normalize-display-values "^4.0.0" + postcss-normalize-positions "^4.0.0" + postcss-normalize-repeat-style "^4.0.0" + postcss-normalize-string "^4.0.0" + postcss-normalize-timing-functions "^4.0.0" + postcss-normalize-unicode "^4.0.0" + postcss-normalize-url "^4.0.0" + postcss-normalize-whitespace "^4.0.0" + postcss-ordered-values "^4.0.0" + postcss-reduce-initial "^4.0.0" + postcss-reduce-transforms "^4.0.0" + postcss-svgo "^4.0.0" + postcss-unique-selectors "^4.0.0" + +cssnano-util-get-arguments@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz#ed3a08299f21d75741b20f3b81f194ed49cc150f" + +cssnano-util-get-match@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz#c0e4ca07f5386bb17ec5e52250b4f5961365156d" + +cssnano-util-raw-cache@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.0.tgz#be0a2856e25f185f5f7a2bcc0624e28b7f179a9f" + dependencies: + postcss "^6.0.0" + +cssnano-util-same-parent@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.0.tgz#d2a3de1039aa98bc4ec25001fa050330c2a16dac" + +cssnano@^3.4.0: + version "3.10.0" + resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-3.10.0.tgz#4f38f6cea2b9b17fa01490f23f1dc68ea65c1c38" + dependencies: + autoprefixer "^6.3.1" + decamelize "^1.1.2" + defined "^1.0.0" + has "^1.0.1" + object-assign "^4.0.1" + postcss "^5.0.14" + postcss-calc "^5.2.0" + postcss-colormin "^2.1.8" + postcss-convert-values "^2.3.4" + postcss-discard-comments "^2.0.4" + postcss-discard-duplicates "^2.0.1" + postcss-discard-empty "^2.0.1" + postcss-discard-overridden "^0.1.1" + postcss-discard-unused "^2.2.1" + postcss-filter-plugins "^2.0.0" + postcss-merge-idents "^2.1.5" + postcss-merge-longhand "^2.0.1" + postcss-merge-rules "^2.0.3" + postcss-minify-font-values "^1.0.2" + postcss-minify-gradients "^1.0.1" + postcss-minify-params "^1.0.4" + postcss-minify-selectors "^2.0.4" + postcss-normalize-charset "^1.1.0" + postcss-normalize-url "^3.0.7" + postcss-ordered-values "^2.1.0" + postcss-reduce-idents "^2.2.2" + postcss-reduce-initial "^1.0.0" + postcss-reduce-transforms "^1.0.3" + postcss-svgo "^2.1.1" + postcss-unique-selectors "^2.0.2" + postcss-value-parser "^3.2.3" + postcss-zindex "^2.0.1" + +cssnano@^4.0.0: + version "4.0.5" + resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-4.0.5.tgz#8789b5fdbe7be05d8a0f7e45c4c789ebe712f5aa" + dependencies: + cosmiconfig "^5.0.0" + cssnano-preset-default "^4.0.0" + is-resolvable "^1.0.0" + postcss "^6.0.0" + +csso@^3.5.0: + version "3.5.1" + resolved "https://registry.yarnpkg.com/csso/-/csso-3.5.1.tgz#7b9eb8be61628973c1b261e169d2f024008e758b" + dependencies: + css-tree "1.0.0-alpha.29" + +csso@~2.3.1: + version "2.3.2" + resolved "https://registry.yarnpkg.com/csso/-/csso-2.3.2.tgz#ddd52c587033f49e94b71fc55569f252e8ff5f85" + dependencies: + clap "^1.0.9" + source-map "^0.5.3" + +cyclist@~0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640" + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + dependencies: + assert-plus "^1.0.0" + +date-now@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" + +deasync@^0.1.13: + version "0.1.13" + resolved "https://registry.yarnpkg.com/deasync/-/deasync-0.1.13.tgz#815c2b69bbd1117cae570152cd895661c09f20ea" + dependencies: + bindings "~1.2.1" + nan "^2.0.7" + +debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + dependencies: + ms "2.0.0" + +debug@3.1.0, debug@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + dependencies: + ms "2.0.0" + +debuglog@*, debuglog@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" + +decamelize@^1.1.1, decamelize@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + +deep-extend@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + +deep-is@~0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + +defaults@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" + dependencies: + clone "^1.0.2" + +define-properties@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94" + dependencies: + foreach "^2.0.5" + object-keys "^1.0.8" + +define-property@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + dependencies: + is-descriptor "^1.0.0" + +define-property@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" + +defined@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + +deps-sort@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/deps-sort/-/deps-sort-2.0.0.tgz#091724902e84658260eb910748cccd1af6e21fb5" + dependencies: + JSONStream "^1.0.3" + shasum "^1.0.0" + subarg "^1.0.0" + through2 "^2.0.0" + +des.js@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc" + dependencies: + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + +detect-indent@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" + dependencies: + repeating "^2.0.0" + +detect-indent@~5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-5.0.0.tgz#3871cc0a6a002e8c3e5b3cf7f336264675f06b9d" + +detect-libc@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + +detect-newline@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-2.1.0.tgz#f41f1c10be4b00e87b5f13da680759f2c5bfd3e2" + +detective@^4.0.0: + version "4.7.1" + resolved "https://registry.yarnpkg.com/detective/-/detective-4.7.1.tgz#0eca7314338442febb6d65da54c10bb1c82b246e" + dependencies: + acorn "^5.2.1" + defined "^1.0.0" + +dezalgo@^1.0.0, dezalgo@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456" + dependencies: + asap "^2.0.0" + wrappy "1" + +diffie-hellman@^5.0.0: + version "5.0.3" + resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" + dependencies: + bn.js "^4.1.0" + miller-rabin "^4.0.0" + randombytes "^2.0.0" + +dom-serializer@0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82" + dependencies: + domelementtype "~1.1.1" + entities "~1.1.1" + +domain-browser@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" + +domain-browser@~1.1.0: + version "1.1.7" + resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.1.7.tgz#867aa4b093faa05f1de08c06f4d7b21fdf8698bc" + +domelementtype@1, domelementtype@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.0.tgz#b17aed82e8ab59e52dd9c19b1756e0fc187204c2" + +domelementtype@~1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.1.3.tgz#bd28773e2642881aec51544924299c5cd822185b" + +domhandler@^2.3.0: + version "2.4.2" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.2.tgz#8805097e933d65e85546f726d60f5eb88b44f803" + dependencies: + domelementtype "1" + +domready@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/domready/-/domready-1.0.8.tgz#91f252e597b65af77e745ae24dd0185d5e26d58c" + +domutils@1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf" + dependencies: + dom-serializer "0" + domelementtype "1" + +domutils@^1.5.1: + version "1.7.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" + dependencies: + dom-serializer "0" + domelementtype "1" + +dot-prop@^4.1.0, dot-prop@^4.1.1: + version "4.2.0" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57" + dependencies: + is-obj "^1.0.0" + +dotenv@^5.0.0, dotenv@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-5.0.1.tgz#a5317459bd3d79ab88cff6e44057a6a3fbb1fcef" + +duplexer2@^0.1.2, duplexer2@~0.1.0, duplexer2@~0.1.2, duplexer2@~0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1" + dependencies: + readable-stream "^2.0.2" + +duplexer3@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" + +duplexify@^3.4.2, duplexify@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.6.0.tgz#592903f5d80b38d037220541264d69a198fb3410" + dependencies: + end-of-stream "^1.0.0" + inherits "^2.0.1" + readable-stream "^2.0.0" + stream-shift "^1.0.0" + +ecc-jsbn@~0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" + dependencies: + jsbn "~0.1.0" + safer-buffer "^2.1.0" + +editor@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/editor/-/editor-1.0.0.tgz#60c7f87bd62bcc6a894fa8ccd6afb7823a24f742" + +editorconfig@^0.13.2: + version "0.13.3" + resolved "https://registry.yarnpkg.com/editorconfig/-/editorconfig-0.13.3.tgz#e5219e587951d60958fd94ea9a9a008cdeff1b34" + dependencies: + bluebird "^3.0.5" + commander "^2.9.0" + lru-cache "^3.2.0" + semver "^5.1.0" + sigmund "^1.0.1" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + +electron-to-chromium@^1.2.7, electron-to-chromium@^1.3.47, electron-to-chromium@^1.3.52: + version "1.3.55" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.55.tgz#f150e10b20b77d9d41afcca312efe0c3b1a7fdce" + +elem-dataset@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/elem-dataset/-/elem-dataset-1.1.1.tgz#18f07fa7fc71ebd49b0f9f63819cb03c8276577a" + +element-closest@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/element-closest/-/element-closest-2.0.2.tgz#72a740a107453382e28df9ce5dbb5a8df0f966ec" + +elliptic@^6.0.0: + version "6.4.0" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.0.tgz#cac9af8762c85836187003c8dfe193e5e2eae5df" + dependencies: + bn.js "^4.4.0" + brorand "^1.0.1" + hash.js "^1.0.0" + hmac-drbg "^1.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.0" + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + +encoding@^0.1.11: + version "0.1.12" + resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" + dependencies: + iconv-lite "~0.4.13" + +end-of-stream@^1.0.0, end-of-stream@^1.1.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" + dependencies: + once "^1.4.0" + +entities@^1.1.1, entities@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" + +err-code@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/err-code/-/err-code-1.1.2.tgz#06e0116d3028f6aef4806849eb0ea6a748ae6960" + +errno@~0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618" + dependencies: + prr "~1.0.1" + +error-ex@^1.2.0, error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + dependencies: + is-arrayish "^0.2.1" + +es-abstract@^1.5.1, es-abstract@^1.6.1: + version "1.12.0" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.12.0.tgz#9dbbdd27c6856f0001421ca18782d786bf8a6165" + dependencies: + es-to-primitive "^1.1.1" + function-bind "^1.1.1" + has "^1.0.1" + is-callable "^1.1.3" + is-regex "^1.0.4" + +es-to-primitive@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.1.1.tgz#45355248a88979034b6792e19bb81f2b7975dd0d" + dependencies: + is-callable "^1.1.1" + is-date-object "^1.0.1" + is-symbol "^1.0.1" + +es6-promise@^4.0.3: + version "4.2.4" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.4.tgz#dc4221c2b16518760bd8c39a52d8f356fc00ed29" + +es6-promisify@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" + dependencies: + es6-promise "^4.0.3" + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + +escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + +escodegen@^1.8.1: + version "1.11.0" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.11.0.tgz#b27a9389481d5bfd5bec76f7bb1eb3f8f4556589" + dependencies: + esprima "^3.1.3" + estraverse "^4.2.0" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.6.1" + +escodegen@~1.9.0: + version "1.9.1" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.9.1.tgz#dbae17ef96c8e4bedb1356f4504fa4cc2f7cb7e2" + dependencies: + esprima "^3.1.3" + estraverse "^4.2.0" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.6.1" + +esprima@^2.6.0: + version "2.7.3" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" + +esprima@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + +estraverse@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" + +esutils@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + +events@^1.0.0, events@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" + +evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" + dependencies: + md5.js "^1.3.4" + safe-buffer "^5.1.1" + +execa@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" + dependencies: + cross-spawn "^5.0.1" + get-stream "^3.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +expand-brackets@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + dependencies: + debug "^2.3.3" + define-property "^0.2.5" + extend-shallow "^2.0.1" + posix-character-classes "^0.1.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + dependencies: + is-extendable "^0.1.0" + +extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + +extend@~3.0.0, extend@~3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + +extglob@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + dependencies: + array-unique "^0.3.2" + define-property "^1.0.0" + expand-brackets "^2.1.4" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + +extsprintf@^1.2.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" + +falafel@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/falafel/-/falafel-2.1.0.tgz#96bb17761daba94f46d001738b3cedf3a67fe06c" + dependencies: + acorn "^5.0.0" + foreach "^2.0.5" + isarray "0.0.1" + object-keys "^1.0.6" + +fast-deep-equal@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" + +fast-glob@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.2.tgz#71723338ac9b4e0e2fff1d6748a2a13d5ed352bf" + dependencies: + "@mrmlnc/readdir-enhanced" "^2.2.1" + "@nodelib/fs.stat" "^1.0.1" + glob-parent "^3.1.0" + is-glob "^4.0.0" + merge2 "^1.2.1" + micromatch "^3.1.10" + +fast-json-stable-stringify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" + +fast-levenshtein@~2.0.4: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + +figgy-pudding@^3.0.0, figgy-pudding@^3.1.0, figgy-pudding@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.2.0.tgz#464626b73d7b0fc045a99753d191b0785957ff73" + +filesize@^3.6.0: + version "3.6.1" + resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.6.1.tgz#090bb3ee01b6f801a8a8be99d31710b3422bb317" + +fill-range@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + +find-npm-prefix@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/find-npm-prefix/-/find-npm-prefix-1.0.2.tgz#8d8ce2c78b3b4b9e66c8acc6a37c231eb841cfdf" + +find-up@^2.0.0, find-up@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + dependencies: + locate-path "^2.0.0" + +flatten@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782" + +flush-write-stream@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.0.3.tgz#c5d586ef38af6097650b49bc41b55fabb19f35bd" + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.4" + +for-in@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + +foreach@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + +form-data@~2.1.1: + version "2.1.4" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1" + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.5" + mime-types "^2.1.12" + +form-data@~2.3.1: + version "2.3.2" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.2.tgz#4970498be604c20c005d4f5c23aecd21d6b49099" + dependencies: + asynckit "^0.4.0" + combined-stream "1.0.6" + mime-types "^2.1.12" + +fragment-cache@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + dependencies: + map-cache "^0.2.2" + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + +from2@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/from2/-/from2-1.3.0.tgz#88413baaa5f9a597cfde9221d86986cd3c061dfd" + dependencies: + inherits "~2.0.1" + readable-stream "~1.1.10" + +from2@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.0" + +fs-minipass@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d" + dependencies: + minipass "^2.2.1" + +fs-vacuum@^1.2.10, fs-vacuum@~1.2.10: + version "1.2.10" + resolved "https://registry.yarnpkg.com/fs-vacuum/-/fs-vacuum-1.2.10.tgz#b7629bec07a4031a2548fdf99f5ecf1cc8b31e36" + dependencies: + graceful-fs "^4.1.2" + path-is-inside "^1.0.1" + rimraf "^2.5.2" + +fs-write-stream-atomic@^1.0.8, fs-write-stream-atomic@~1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" + dependencies: + graceful-fs "^4.1.2" + iferr "^0.1.5" + imurmurhash "^0.1.4" + readable-stream "1 || 2" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + +fsevents@^1.2.2: + version "1.2.4" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.4.tgz#f41dcb1af2582af3692da36fc55cbd8e1041c426" + dependencies: + nan "^2.9.2" + node-pre-gyp "^0.10.0" + +fstream@^1.0.0, fstream@^1.0.2: + version "1.0.11" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" + dependencies: + graceful-fs "^4.1.2" + inherits "~2.0.0" + mkdirp ">=0.5 0" + rimraf "2" + +fswatcher-child@^1.0.3: + version "1.0.5" + resolved "https://registry.yarnpkg.com/fswatcher-child/-/fswatcher-child-1.0.5.tgz#134d012ffa74918975617e00e56e4139f36cb140" + dependencies: + chokidar "^2.0.3" + +function-bind@^1.1.0, function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + +gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + +genfun@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/genfun/-/genfun-4.0.1.tgz#ed10041f2e4a7f1b0a38466d17a5c3e27df1dfc1" + +gentle-fs@^2.0.0, gentle-fs@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/gentle-fs/-/gentle-fs-2.0.1.tgz#585cfd612bfc5cd52471fdb42537f016a5ce3687" + dependencies: + aproba "^1.1.2" + fs-vacuum "^1.2.10" + graceful-fs "^4.1.11" + iferr "^0.1.5" + mkdirp "^0.5.1" + path-is-inside "^1.0.2" + read-cmd-shim "^1.0.1" + slide "^1.1.6" + +get-assigned-identifiers@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/get-assigned-identifiers/-/get-assigned-identifiers-1.2.0.tgz#6dbf411de648cbaf8d9169ebb0d2d576191e2ff1" + +get-caller-file@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" + +get-port@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/get-port/-/get-port-3.2.0.tgz#dd7ce7de187c06c8bf353796ac71e099f0980ebc" + +get-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + +get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + dependencies: + assert-plus "^1.0.0" + +glob-parent@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" + dependencies: + is-glob "^3.1.0" + path-dirname "^1.0.0" + +glob-to-regexp@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab" + +glob@^7.0.3, glob@^7.0.5, glob@^7.1.0, glob@^7.1.1, glob@^7.1.2, glob@~7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +global-dirs@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445" + dependencies: + ini "^1.3.4" + +globals@^9.18.0: + version "9.18.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" + +got@^6.7.1: + version "6.7.1" + resolved "https://registry.yarnpkg.com/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0" + dependencies: + create-error-class "^3.0.0" + duplexer3 "^0.1.4" + get-stream "^3.0.0" + is-redirect "^1.0.0" + is-retry-allowed "^1.0.0" + is-stream "^1.0.0" + lowercase-keys "^1.0.0" + safe-buffer "^5.0.1" + timed-out "^4.0.0" + unzip-response "^2.0.1" + url-parse-lax "^1.0.0" + +graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@~4.1.11: + version "4.1.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" + +grapheme-breaker@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/grapheme-breaker/-/grapheme-breaker-0.3.2.tgz#5b9e6b78c3832452d2ba2bb1cb830f96276410ac" + dependencies: + brfs "^1.2.0" + unicode-trie "^0.3.1" + +har-schema@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e" + +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + +har-validator@~4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a" + dependencies: + ajv "^4.9.1" + har-schema "^1.0.5" + +har-validator@~5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.0.3.tgz#ba402c266194f15956ef15e0fcf242993f6a7dfd" + dependencies: + ajv "^5.1.0" + har-schema "^2.0.0" + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + dependencies: + ansi-regex "^2.0.0" + +has-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + +has-unicode@^2.0.0, has-unicode@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + +has-value@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + dependencies: + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" + +has-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + dependencies: + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + +has-values@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + +has-values@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + +has@^1.0.0, has@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + dependencies: + function-bind "^1.1.1" + +hash-base@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918" + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +hash.js@^1.0.0, hash.js@^1.0.3: + version "1.1.5" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.5.tgz#e38ab4b85dfb1e0c40fe9265c0e9b54854c23812" + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + +hawk@~3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" + dependencies: + boom "2.x.x" + cryptiles "2.x.x" + hoek "2.x.x" + sntp "1.x.x" + +hex-color-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e" + +hmac-drbg@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + +hoek@2.x.x: + version "2.16.3" + resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" + +home-or-tmp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.1" + +hosted-git-info@^2.1.4, hosted-git-info@^2.6.0: + version "2.7.1" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047" + +hsl-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/hsl-regex/-/hsl-regex-1.0.0.tgz#d49330c789ed819e276a4c0d272dffa30b18fe6e" + +hsla-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/hsla-regex/-/hsla-regex-1.0.0.tgz#c1ce7a3168c8c6614033a4b5f7877f3b225f9c38" + +html-comment-regex@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.1.tgz#668b93776eaae55ebde8f3ad464b307a4963625e" + +htmlescape@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/htmlescape/-/htmlescape-1.1.1.tgz#3a03edc2214bca3b66424a3e7959349509cb0351" + +htmlnano@^0.1.9: + version "0.1.9" + resolved "https://registry.yarnpkg.com/htmlnano/-/htmlnano-0.1.9.tgz#e6137aea84d20311a3875c42eb2799a1ff352627" + dependencies: + cssnano "^3.4.0" + object-assign "^4.0.1" + posthtml "^0.11.3" + posthtml-render "^1.1.3" + svgo "^1.0.5" + uglify-es "^3.3.9" + +htmlparser2@^3.9.2: + version "3.9.2" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.9.2.tgz#1bdf87acca0f3f9e53fa4fcceb0f4b4cbb00b338" + dependencies: + domelementtype "^1.3.0" + domhandler "^2.3.0" + domutils "^1.5.1" + entities "^1.1.1" + inherits "^2.0.1" + readable-stream "^2.0.2" + +http-cache-semantics@^3.8.1: + version "3.8.1" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" + +http-errors@~1.6.2: + version "1.6.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.0" + statuses ">= 1.4.0 < 2" + +http-proxy-agent@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz#e4821beef5b2142a2026bd73926fe537631c5405" + dependencies: + agent-base "4" + debug "3.1.0" + +http-signature@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" + dependencies: + assert-plus "^0.2.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + dependencies: + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +https-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" + +https-browserify@~0.0.0: + version "0.0.1" + resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-0.0.1.tgz#3f91365cabe60b77ed0ebba24b454e3e09d95a82" + +https-proxy-agent@^2.2.0, https-proxy-agent@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz#51552970fa04d723e04c56d04178c3f92592bbc0" + dependencies: + agent-base "^4.1.0" + debug "^3.1.0" + +humanize-ms@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" + dependencies: + ms "^2.0.0" + +iconv-lite@^0.4.4, iconv-lite@~0.4.13: + version "0.4.23" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" + dependencies: + safer-buffer ">= 2.1.2 < 3" + +ieee754@^1.1.4: + version "1.1.12" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.12.tgz#50bf24e5b9c8bb98af4964c941cdb0918da7b60b" + +iferr@^0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" + +iferr@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/iferr/-/iferr-1.0.2.tgz#e9fde49a9da06dc4a4194c6c9ed6d08305037a6d" + +ignore-walk@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8" + dependencies: + minimatch "^3.0.4" + +import-lazy@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" + +imurmurhash@*, imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + +indexes-of@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607" + +indexof@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" + +inflight@^1.0.4, inflight@~1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + +inherits@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" + +ini@^1.3.4, ini@^1.3.5, ini@~1.3.0: + version "1.3.5" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" + +init-package-json@^1.10.3: + version "1.10.3" + resolved "https://registry.yarnpkg.com/init-package-json/-/init-package-json-1.10.3.tgz#45ffe2f610a8ca134f2bd1db5637b235070f6cbe" + dependencies: + glob "^7.1.1" + npm-package-arg "^4.0.0 || ^5.0.0 || ^6.0.0" + promzard "^0.3.0" + read "~1.0.1" + read-package-json "1 || 2" + semver "2.x || 3.x || 4 || 5" + validate-npm-package-license "^3.0.1" + validate-npm-package-name "^3.0.0" + +inline-source-map@~0.6.0: + version "0.6.2" + resolved "https://registry.yarnpkg.com/inline-source-map/-/inline-source-map-0.6.2.tgz#f9393471c18a79d1724f863fa38b586370ade2a5" + dependencies: + source-map "~0.5.3" + +insert-module-globals@^7.0.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/insert-module-globals/-/insert-module-globals-7.2.0.tgz#ec87e5b42728479e327bd5c5c71611ddfb4752ba" + dependencies: + JSONStream "^1.0.3" + acorn-node "^1.5.2" + combine-source-map "^0.8.0" + concat-stream "^1.6.1" + is-buffer "^1.1.0" + path-is-absolute "^1.0.1" + process "~0.11.0" + through2 "^2.0.0" + undeclared-identifiers "^1.1.2" + xtend "^4.0.0" + +invariant@^2.2.2: + version "2.2.4" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" + dependencies: + loose-envify "^1.0.0" + +invert-kv@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" + +ip-regex@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" + +ip@^1.1.4, ip@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" + +is-absolute-url@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.1.0.tgz#50530dfb84fcc9aa7dbe7852e83a37b93b9f2aa6" + +is-accessor-descriptor@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + dependencies: + kind-of "^3.0.2" + +is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + dependencies: + kind-of "^6.0.0" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + +is-arrayish@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" + +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + dependencies: + binary-extensions "^1.0.0" + +is-buffer@^1.1.0, is-buffer@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + +is-builtin-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" + dependencies: + builtin-modules "^1.0.0" + +is-callable@^1.1.1, is-callable@^1.1.3: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" + +is-ci@^1.0.10: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.1.0.tgz#247e4162e7860cebbdaf30b774d6b0ac7dcfe7a5" + dependencies: + ci-info "^1.0.0" + +is-cidr@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/is-cidr/-/is-cidr-2.0.6.tgz#4b01c9693d8e18399dacd18a4f3d60ea5871ac60" + dependencies: + cidr-regex "^2.0.8" + +is-color-stop@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-color-stop/-/is-color-stop-1.1.0.tgz#cfff471aee4dd5c9e158598fbe12967b5cdad345" + dependencies: + css-color-names "^0.0.4" + hex-color-regex "^1.1.0" + hsl-regex "^1.0.0" + hsla-regex "^1.0.0" + rgb-regex "^1.0.1" + rgba-regex "^1.0.0" + +is-data-descriptor@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + dependencies: + kind-of "^3.0.2" + +is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + dependencies: + kind-of "^6.0.0" + +is-date-object@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" + +is-descriptor@^0.1.0: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + +is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + +is-directory@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" + +is-extendable@^0.1.0, is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + +is-extendable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + dependencies: + is-plain-object "^2.0.4" + +is-extglob@^2.1.0, is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + +is-finite@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + +is-glob@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" + dependencies: + is-extglob "^2.1.0" + +is-glob@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.0.tgz#9521c76845cc2610a85203ddf080a958c2ffabc0" + dependencies: + is-extglob "^2.1.1" + +is-installed-globally@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.1.0.tgz#0dfd98f5a9111716dd535dda6492f67bf3d25a80" + dependencies: + global-dirs "^0.1.0" + is-path-inside "^1.0.0" + +is-npm@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-1.0.0.tgz#f2fb63a65e4905b406c86072765a1a4dc793b9f4" + +is-number@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + dependencies: + kind-of "^3.0.2" + +is-obj@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" + +is-path-inside@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" + dependencies: + path-is-inside "^1.0.1" + +is-plain-obj@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" + +is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + dependencies: + isobject "^3.0.1" + +is-redirect@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24" + +is-regex@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" + dependencies: + has "^1.0.1" + +is-resolvable@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" + +is-retry-allowed@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34" + +is-stream@^1.0.0, is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + +is-svg@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-svg/-/is-svg-2.1.0.tgz#cf61090da0d9efbcab8722deba6f032208dbb0e9" + dependencies: + html-comment-regex "^1.1.0" + +is-svg@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-svg/-/is-svg-3.0.0.tgz#9321dbd29c212e5ca99c4fa9794c714bcafa2f75" + dependencies: + html-comment-regex "^1.1.0" + +is-symbol@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.1.tgz#3cc59f00025194b6ab2e38dbae6689256b660572" + +is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + +is-url@^1.2.2: + version "1.2.4" + resolved "https://registry.yarnpkg.com/is-url/-/is-url-1.2.4.tgz#04a4df46d28c4cff3d73d01ff06abeb318a1aa52" + +is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + +is-wsl@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" + +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + +isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + +isarray@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.4.tgz#38e7bcbb0f3ba1b7933c86ba1894ddfc3781bbb7" + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + +isobject@^2.0.0, isobject@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + dependencies: + isarray "1.0.0" + +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + +js-base64@^2.1.9: + version "2.4.8" + resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.4.8.tgz#57a9b130888f956834aa40c5b165ba59c758f033" + +js-beautify@^1.7.5: + version "1.7.5" + resolved "https://registry.yarnpkg.com/js-beautify/-/js-beautify-1.7.5.tgz#69d9651ef60dbb649f65527b53674950138a7919" + dependencies: + config-chain "~1.1.5" + editorconfig "^0.13.2" + mkdirp "~0.5.0" + nopt "~3.0.1" + +"js-tokens@^3.0.0 || ^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + +js-tokens@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" + +js-yaml@^3.10.0, js-yaml@^3.9.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1" + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +js-yaml@~3.10.0: + version "3.10.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.10.0.tgz#2e78441646bd4682e963f22b6e92823c309c62dc" + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +js-yaml@~3.7.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.7.0.tgz#5c967ddd837a9bfdca5f2de84253abe8a1c03b80" + dependencies: + argparse "^1.0.7" + esprima "^2.6.0" + +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + +jsesc@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + +json-parse-better-errors@^1.0.0, json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" + +json-schema-traverse@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" + +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + +json-stable-stringify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" + dependencies: + jsonify "~0.0.0" + +json-stable-stringify@~0.0.0: + version "0.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-0.0.1.tgz#611c23e814db375527df851193db59dd2af27f45" + dependencies: + jsonify "~0.0.0" + +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + +json5@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" + +json5@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" + dependencies: + minimist "^1.2.0" + +jsonify@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" + +jsonparse@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" + +jsprim@^1.2.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.2.3" + verror "1.10.0" + +keyboardevent-key-polyfill@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/keyboardevent-key-polyfill/-/keyboardevent-key-polyfill-1.1.0.tgz#8a319d8e45a13172fca56286372f90c1d4c7014c" + +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + dependencies: + is-buffer "^1.1.5" + +kind-of@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + +kind-of@^6.0.0, kind-of@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" + +labeled-stream-splicer@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/labeled-stream-splicer/-/labeled-stream-splicer-2.0.1.tgz#9cffa32fd99e1612fd1d86a8db962416d5292926" + dependencies: + inherits "^2.0.1" + isarray "^2.0.4" + stream-splicer "^2.0.0" + +latest-version@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-3.1.0.tgz#a205383fea322b33b5ae3b18abee0dc2f356ee15" + dependencies: + package-json "^4.0.0" + +lazy-property@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lazy-property/-/lazy-property-1.0.0.tgz#84ddc4b370679ba8bd4cdcfa4c06b43d57111147" + +lcid@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" + dependencies: + invert-kv "^1.0.0" + +levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +libcipm@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/libcipm/-/libcipm-2.0.1.tgz#2f4ebf8562e0fc6e46f415373674e4cf3ac4b9ba" + dependencies: + bin-links "^1.1.2" + bluebird "^3.5.1" + find-npm-prefix "^1.0.2" + graceful-fs "^4.1.11" + lock-verify "^2.0.2" + mkdirp "^0.5.1" + npm-lifecycle "^2.0.3" + npm-logical-tree "^1.2.1" + npm-package-arg "^6.1.0" + pacote "^8.1.6" + protoduck "^5.0.0" + read-package-json "^2.0.13" + rimraf "^2.6.2" + worker-farm "^1.6.0" + +libnpmhook@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/libnpmhook/-/libnpmhook-4.0.1.tgz#63641654de772cbeb96a88527a7fd5456ec3c2d7" + dependencies: + figgy-pudding "^3.1.0" + npm-registry-fetch "^3.0.0" + +libnpx@^10.2.0: + version "10.2.0" + resolved "https://registry.yarnpkg.com/libnpx/-/libnpx-10.2.0.tgz#1bf4a1c9f36081f64935eb014041da10855e3102" + dependencies: + dotenv "^5.0.1" + npm-package-arg "^6.0.0" + rimraf "^2.6.2" + safe-buffer "^5.1.0" + update-notifier "^2.3.0" + which "^1.3.0" + y18n "^4.0.0" + yargs "^11.0.0" + +load-json-file@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + strip-bom "^3.0.0" + +locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + dependencies: + p-locate "^2.0.0" + path-exists "^3.0.0" + +lock-verify@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/lock-verify/-/lock-verify-2.0.2.tgz#148e4f85974915c9e3c34d694b7de9ecb18ee7a8" + dependencies: + npm-package-arg "^5.1.2 || 6" + semver "^5.4.1" + +lockfile@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/lockfile/-/lockfile-1.0.4.tgz#07f819d25ae48f87e538e6578b6964a4981a5609" + dependencies: + signal-exit "^3.0.2" + +lodash._baseindexof@*: + version "3.1.0" + resolved "https://registry.yarnpkg.com/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz#fe52b53a1c6761e42618d654e4a25789ed61822c" + +lodash._baseuniq@~4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz#0ebb44e456814af7905c6212fa2c9b2d51b841e8" + dependencies: + lodash._createset "~4.0.0" + lodash._root "~3.0.0" + +lodash._bindcallback@*: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" + +lodash._cacheindexof@*: + version "3.0.2" + resolved "https://registry.yarnpkg.com/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz#3dc69ac82498d2ee5e3ce56091bafd2adc7bde92" + +lodash._createcache@*: + version "3.1.2" + resolved "https://registry.yarnpkg.com/lodash._createcache/-/lodash._createcache-3.1.2.tgz#56d6a064017625e79ebca6b8018e17440bdcf093" + dependencies: + lodash._getnative "^3.0.0" + +lodash._createset@~4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/lodash._createset/-/lodash._createset-4.0.3.tgz#0f4659fbb09d75194fa9e2b88a6644d363c9fe26" + +lodash._getnative@*, lodash._getnative@^3.0.0: + version "3.9.1" + resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" + +lodash._root@~3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692" + +lodash.clone@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.clone/-/lodash.clone-4.5.0.tgz#195870450f5a13192478df4bc3d23d2dea1907b6" + +lodash.clonedeep@~4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" + +lodash.debounce@^4.0.7, lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + +lodash.memoize@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + +lodash.memoize@~3.0.3: + version "3.0.4" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-3.0.4.tgz#2dcbd2c287cbc0a55cc42328bd0c736150d53e3f" + +lodash.restparam@*: + version "3.6.1" + resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" + +lodash.union@~4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88" + +lodash.uniq@^4.5.0, lodash.uniq@~4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + +lodash.without@~4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.without/-/lodash.without-4.4.0.tgz#3cd4574a00b67bae373a94b748772640507b7aac" + +lodash@^4.17.4: + version "4.17.10" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" + +log-symbols@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" + dependencies: + chalk "^2.0.1" + +loose-envify@^1.0.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +lowercase-keys@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" + +lru-cache@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-3.2.0.tgz#71789b3b7f5399bec8565dda38aa30d2a097efee" + dependencies: + pseudomap "^1.0.1" + +lru-cache@^4.0.1, lru-cache@^4.1.1, lru-cache@^4.1.2, lru-cache@^4.1.3: + version "4.1.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.3.tgz#a1175cf3496dfc8436c156c334b4955992bce69c" + dependencies: + pseudomap "^1.0.2" + yallist "^2.1.2" + +magic-string@^0.22.4: + version "0.22.5" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.22.5.tgz#8e9cf5afddf44385c1da5bc2a6a0dbd10b03657e" + dependencies: + vlq "^0.2.2" + +make-dir@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" + dependencies: + pify "^3.0.0" + +"make-fetch-happen@^2.5.0 || 3 || 4", make-fetch-happen@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-4.0.1.tgz#141497cb878f243ba93136c83d8aba12c216c083" + dependencies: + agentkeepalive "^3.4.1" + cacache "^11.0.1" + http-cache-semantics "^3.8.1" + http-proxy-agent "^2.1.0" + https-proxy-agent "^2.2.1" + lru-cache "^4.1.2" + mississippi "^3.0.0" + node-fetch-npm "^2.0.2" + promise-retry "^1.1.1" + socks-proxy-agent "^4.0.0" + ssri "^6.0.0" + +make-fetch-happen@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-3.0.0.tgz#7b661d2372fc4710ab5cc8e1fa3c290eea69a961" + dependencies: + agentkeepalive "^3.4.1" + cacache "^10.0.4" + http-cache-semantics "^3.8.1" + http-proxy-agent "^2.1.0" + https-proxy-agent "^2.2.0" + lru-cache "^4.1.2" + mississippi "^3.0.0" + node-fetch-npm "^2.0.2" + promise-retry "^1.1.1" + socks-proxy-agent "^3.0.1" + ssri "^5.2.4" + +map-cache@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + +map-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + dependencies: + object-visit "^1.0.0" + +matches-selector@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/matches-selector/-/matches-selector-1.2.0.tgz#d1814e7e8f43e69d22ac33c9af727dc884ecf12a" + +math-expression-evaluator@^1.2.14: + version "1.2.17" + resolved "https://registry.yarnpkg.com/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz#de819fdbcd84dccd8fae59c6aeb79615b9d266ac" + +md5.js@^1.3.4: + version "1.3.4" + resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.4.tgz#e9bdbde94a20a5ac18b04340fc5764d5b09d901d" + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + +mdn-data@^1.0.0, mdn-data@~1.1.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-1.1.4.tgz#50b5d4ffc4575276573c4eedb8780812a8419f01" + +meant@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/meant/-/meant-1.0.1.tgz#66044fea2f23230ec806fb515efea29c44d2115d" + +mem@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/mem/-/mem-1.1.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76" + dependencies: + mimic-fn "^1.0.0" + +merge-source-map@1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/merge-source-map/-/merge-source-map-1.0.4.tgz#a5de46538dae84d4114cc5ea02b4772a6346701f" + dependencies: + source-map "^0.5.6" + +merge2@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.2.2.tgz#03212e3da8d86c4d8523cebd6318193414f94e34" + +micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4: + version "3.1.10" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.2" + +miller-rabin@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" + dependencies: + bn.js "^4.0.0" + brorand "^1.0.1" + +mime-db@~1.35.0: + version "1.35.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.35.0.tgz#0569d657466491283709663ad379a99b90d9ab47" + +mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.7: + version "2.1.19" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.19.tgz#71e464537a7ef81c15f2db9d97e913fc0ff606f0" + dependencies: + mime-db "~1.35.0" + +mime@1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" + +mimic-fn@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" + +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + +minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + +minimatch@^3.0.2, minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + dependencies: + brace-expansion "^1.1.7" + +minimist@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + +minimist@^1.1.0, minimist@^1.1.3, minimist@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + +minipass@^2.2.1, minipass@^2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.3.tgz#a7dcc8b7b833f5d368759cce544dccb55f50f233" + dependencies: + safe-buffer "^5.1.2" + yallist "^3.0.0" + +minizlib@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.1.0.tgz#11e13658ce46bc3a70a267aac58359d1e0c29ceb" + dependencies: + minipass "^2.2.1" + +mississippi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-2.0.0.tgz#3442a508fafc28500486feea99409676e4ee5a6f" + dependencies: + concat-stream "^1.5.0" + duplexify "^3.4.2" + end-of-stream "^1.1.0" + flush-write-stream "^1.0.0" + from2 "^2.1.0" + parallel-transform "^1.1.0" + pump "^2.0.1" + pumpify "^1.3.3" + stream-each "^1.1.0" + through2 "^2.0.0" + +mississippi@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022" + dependencies: + concat-stream "^1.5.0" + duplexify "^3.4.2" + end-of-stream "^1.1.0" + flush-write-stream "^1.0.0" + from2 "^2.1.0" + parallel-transform "^1.1.0" + pump "^3.0.0" + pumpify "^1.3.3" + stream-each "^1.1.0" + through2 "^2.0.0" + +mixin-deep@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + +"mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + dependencies: + minimist "0.0.8" + +module-deps@^4.0.8: + version "4.1.1" + resolved "https://registry.yarnpkg.com/module-deps/-/module-deps-4.1.1.tgz#23215833f1da13fd606ccb8087b44852dcb821fd" + dependencies: + JSONStream "^1.0.3" + browser-resolve "^1.7.0" + cached-path-relative "^1.0.0" + concat-stream "~1.5.0" + defined "^1.0.0" + detective "^4.0.0" + duplexer2 "^0.1.2" + inherits "^2.0.1" + parents "^1.0.0" + readable-stream "^2.0.2" + resolve "^1.1.3" + stream-combiner2 "^1.1.1" + subarg "^1.0.0" + through2 "^2.0.0" + xtend "^4.0.0" + +move-concurrently@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" + dependencies: + aproba "^1.1.1" + copy-concurrently "^1.0.0" + fs-write-stream-atomic "^1.0.8" + mkdirp "^0.5.1" + rimraf "^2.5.4" + run-queue "^1.0.3" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + +ms@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + +mute-stream@~0.0.4: + version "0.0.7" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" + +nan@^2.0.7, nan@^2.9.2: + version "2.10.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f" + +nanomatch@^1.2.9: + version "1.2.13" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + define-property "^2.0.2" + extend-shallow "^3.0.2" + fragment-cache "^0.2.1" + is-windows "^1.0.2" + kind-of "^6.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +needle@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.1.tgz#b5e325bd3aae8c2678902fa296f729455d1d3a7d" + dependencies: + debug "^2.1.2" + iconv-lite "^0.4.4" + sax "^1.2.4" + +nice-try@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.4.tgz#d93962f6c52f2c1558c0fbda6d512819f1efe1c4" + +node-fetch-npm@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/node-fetch-npm/-/node-fetch-npm-2.0.2.tgz#7258c9046182dca345b4208eda918daf33697ff7" + dependencies: + encoding "^0.1.11" + json-parse-better-errors "^1.0.0" + safe-buffer "^5.1.1" + +node-forge@^0.7.1: + version "0.7.5" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.7.5.tgz#6c152c345ce11c52f465c2abd957e8639cd674df" + +node-gyp@^3.6.2, node-gyp@^3.7.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.7.0.tgz#789478e8f6c45e277aa014f3e28f958f286f9203" + dependencies: + fstream "^1.0.0" + glob "^7.0.3" + graceful-fs "^4.1.2" + mkdirp "^0.5.0" + nopt "2 || 3" + npmlog "0 || 1 || 2 || 3 || 4" + osenv "0" + request ">=2.9.0 <2.82.0" + rimraf "2" + semver "~5.3.0" + tar "^2.0.0" + which "1" + +node-libs-browser@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.1.0.tgz#5f94263d404f6e44767d726901fff05478d600df" + dependencies: + assert "^1.1.1" + browserify-zlib "^0.2.0" + buffer "^4.3.0" + console-browserify "^1.1.0" + constants-browserify "^1.0.0" + crypto-browserify "^3.11.0" + domain-browser "^1.1.1" + events "^1.0.0" + https-browserify "^1.0.0" + os-browserify "^0.3.0" + path-browserify "0.0.0" + process "^0.11.10" + punycode "^1.2.4" + querystring-es3 "^0.2.0" + readable-stream "^2.3.3" + stream-browserify "^2.0.1" + stream-http "^2.7.2" + string_decoder "^1.0.0" + timers-browserify "^2.0.4" + tty-browserify "0.0.0" + url "^0.11.0" + util "^0.10.3" + vm-browserify "0.0.4" + +node-pre-gyp@^0.10.0: + version "0.10.3" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz#3070040716afdc778747b61b6887bf78880b80fc" + dependencies: + detect-libc "^1.0.2" + mkdirp "^0.5.1" + needle "^2.2.1" + nopt "^4.0.1" + npm-packlist "^1.1.6" + npmlog "^4.0.2" + rc "^1.2.7" + rimraf "^2.6.1" + semver "^5.3.0" + tar "^4" + +node-releases@^1.0.0-alpha.10: + version "1.0.0-alpha.10" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.0.0-alpha.10.tgz#61c8d5f9b5b2e05d84eba941d05b6f5202f68a2a" + dependencies: + semver "^5.3.0" + +"nopt@2 || 3", nopt@~3.0.1: + version "3.0.6" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" + dependencies: + abbrev "1" + +nopt@^4.0.1, nopt@~4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" + dependencies: + abbrev "1" + osenv "^0.1.4" + +normalize-package-data@^2.0.0, normalize-package-data@^2.3.2, normalize-package-data@^2.4.0, "normalize-package-data@~1.0.1 || ^2.0.0", normalize-package-data@~2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" + dependencies: + hosted-git-info "^2.1.4" + is-builtin-module "^1.0.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + +normalize-path@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + dependencies: + remove-trailing-separator "^1.0.1" + +normalize-range@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" + +normalize-url@^1.4.0: + version "1.9.1" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-1.9.1.tgz#2cc0d66b31ea23036458436e3620d85954c66c3c" + dependencies: + object-assign "^4.0.1" + prepend-http "^1.0.0" + query-string "^4.1.0" + sort-keys "^1.0.0" + +normalize-url@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-3.2.0.tgz#98d0948afc82829f374320f405fe9ca55a5f8567" + +npm-audit-report@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/npm-audit-report/-/npm-audit-report-1.3.1.tgz#e79ea1fcb5ffaf3031102b389d5222c2b0459632" + dependencies: + cli-table3 "^0.5.0" + console-control-strings "^1.1.0" + +npm-bundled@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.3.tgz#7e71703d973af3370a9591bafe3a63aca0be2308" + +npm-cache-filename@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/npm-cache-filename/-/npm-cache-filename-1.0.2.tgz#ded306c5b0bfc870a9e9faf823bc5f283e05ae11" + +npm-install-checks@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/npm-install-checks/-/npm-install-checks-3.0.0.tgz#d4aecdfd51a53e3723b7b2f93b2ee28e307bc0d7" + dependencies: + semver "^2.3.0 || 3.x || 4 || 5" + +npm-lifecycle@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/npm-lifecycle/-/npm-lifecycle-2.0.3.tgz#696bedf1143371163e9cc16fe872357e25d8d90e" + dependencies: + byline "^5.0.0" + graceful-fs "^4.1.11" + node-gyp "^3.6.2" + resolve-from "^4.0.0" + slide "^1.1.6" + uid-number "0.0.6" + umask "^1.1.0" + which "^1.3.0" + +npm-logical-tree@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/npm-logical-tree/-/npm-logical-tree-1.2.1.tgz#44610141ca24664cad35d1e607176193fd8f5b88" + +"npm-package-arg@^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0", "npm-package-arg@^4.0.0 || ^5.0.0 || ^6.0.0", "npm-package-arg@^5.1.2 || 6", npm-package-arg@^6.0.0, npm-package-arg@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-6.1.0.tgz#15ae1e2758a5027efb4c250554b85a737db7fcc1" + dependencies: + hosted-git-info "^2.6.0" + osenv "^0.1.5" + semver "^5.5.0" + validate-npm-package-name "^3.0.0" + +npm-packlist@^1.1.10, npm-packlist@^1.1.6, npm-packlist@~1.1.10: + version "1.1.11" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.1.11.tgz#84e8c683cbe7867d34b1d357d893ce29e28a02de" + dependencies: + ignore-walk "^3.0.1" + npm-bundled "^1.0.1" + +npm-pick-manifest@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/npm-pick-manifest/-/npm-pick-manifest-2.1.0.tgz#dc381bdd670c35d81655e1d5a94aa3dd4d87fce5" + dependencies: + npm-package-arg "^6.0.0" + semver "^5.4.1" + +npm-profile@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/npm-profile/-/npm-profile-3.0.2.tgz#58d568f1b56ef769602fd0aed8c43fa0e0de0f57" + dependencies: + aproba "^1.1.2 || 2" + make-fetch-happen "^2.5.0 || 3 || 4" + +npm-registry-client@^8.5.1: + version "8.6.0" + resolved "https://registry.yarnpkg.com/npm-registry-client/-/npm-registry-client-8.6.0.tgz#7f1529f91450732e89f8518e0f21459deea3e4c4" + dependencies: + concat-stream "^1.5.2" + graceful-fs "^4.1.6" + normalize-package-data "~1.0.1 || ^2.0.0" + npm-package-arg "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0" + once "^1.3.3" + request "^2.74.0" + retry "^0.10.0" + safe-buffer "^5.1.1" + semver "2 >=2.2.1 || 3.x || 4 || 5" + slide "^1.1.3" + ssri "^5.2.4" + optionalDependencies: + npmlog "2 || ^3.1.0 || ^4.0.0" + +npm-registry-fetch@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-1.1.1.tgz#710bc5947d9ee2c549375072dab6d5d17baf2eb2" + dependencies: + bluebird "^3.5.1" + figgy-pudding "^3.0.0" + lru-cache "^4.1.2" + make-fetch-happen "^3.0.0" + npm-package-arg "^6.0.0" + safe-buffer "^5.1.1" + +npm-registry-fetch@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-3.2.0.tgz#94ec859c4dd395f924e575cee471da6fd3906d53" + dependencies: + bluebird "^3.5.1" + figgy-pudding "^3.2.0" + lru-cache "^4.1.3" + make-fetch-happen "^4.0.1" + npm-package-arg "^6.1.0" + +npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + dependencies: + path-key "^2.0.0" + +npm-user-validate@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/npm-user-validate/-/npm-user-validate-1.0.0.tgz#8ceca0f5cea04d4e93519ef72d0557a75122e951" + +npm@^6.0.1: + version "6.3.0" + resolved "https://registry.yarnpkg.com/npm/-/npm-6.3.0.tgz#de7df51f6d1b05b088486097cf7993dbbcac752f" + dependencies: + JSONStream "^1.3.3" + abbrev "~1.1.1" + ansicolors "~0.3.2" + ansistyles "~0.1.3" + aproba "~1.2.0" + archy "~1.0.0" + bin-links "^1.1.2" + bluebird "~3.5.1" + byte-size "^4.0.3" + cacache "^11.1.0" + call-limit "~1.1.0" + chownr "~1.0.1" + cli-columns "^3.1.2" + cli-table3 "^0.5.0" + cmd-shim "~2.0.2" + columnify "~1.5.4" + config-chain "~1.1.11" + detect-indent "~5.0.0" + detect-newline "^2.1.0" + dezalgo "~1.0.3" + editor "~1.0.0" + figgy-pudding "^3.2.0" + find-npm-prefix "^1.0.2" + fs-vacuum "~1.2.10" + fs-write-stream-atomic "~1.0.10" + gentle-fs "^2.0.1" + glob "~7.1.2" + graceful-fs "~4.1.11" + has-unicode "~2.0.1" + hosted-git-info "^2.6.0" + iferr "^1.0.0" + inflight "~1.0.6" + inherits "~2.0.3" + ini "^1.3.5" + init-package-json "^1.10.3" + is-cidr "^2.0.6" + json-parse-better-errors "^1.0.2" + lazy-property "~1.0.0" + libcipm "^2.0.0" + libnpmhook "^4.0.1" + libnpx "^10.2.0" + lock-verify "^2.0.2" + lockfile "^1.0.4" + lodash._baseuniq "~4.6.0" + lodash.clonedeep "~4.5.0" + lodash.union "~4.6.0" + lodash.uniq "~4.5.0" + lodash.without "~4.4.0" + lru-cache "^4.1.3" + meant "~1.0.1" + mississippi "^3.0.0" + mkdirp "~0.5.1" + move-concurrently "^1.0.1" + node-gyp "^3.7.0" + nopt "~4.0.1" + normalize-package-data "~2.4.0" + npm-audit-report "^1.3.1" + npm-cache-filename "~1.0.2" + npm-install-checks "~3.0.0" + npm-lifecycle "^2.0.3" + npm-package-arg "^6.1.0" + npm-packlist "~1.1.10" + npm-pick-manifest "^2.1.0" + npm-profile "^3.0.2" + npm-registry-client "^8.5.1" + npm-registry-fetch "^1.1.0" + npm-user-validate "~1.0.0" + npmlog "~4.1.2" + once "~1.4.0" + opener "~1.4.3" + osenv "^0.1.5" + pacote "^8.1.6" + path-is-inside "~1.0.2" + promise-inflight "~1.0.1" + qrcode-terminal "^0.12.0" + query-string "^6.1.0" + qw "~1.0.1" + read "~1.0.7" + read-cmd-shim "~1.0.1" + read-installed "~4.0.3" + read-package-json "^2.0.13" + read-package-tree "^5.2.1" + readable-stream "^2.3.6" + request "^2.81.0" + retry "^0.12.0" + rimraf "~2.6.2" + safe-buffer "^5.1.2" + semver "^5.5.0" + sha "~2.0.1" + slide "~1.1.6" + sorted-object "~2.0.1" + sorted-union-stream "~2.1.3" + ssri "^6.0.0" + stringify-package "^1.0.0" + tar "^4.4.4" + text-table "~0.2.0" + tiny-relative-date "^1.3.0" + uid-number "0.0.6" + umask "~1.1.0" + unique-filename "~1.1.0" + unpipe "~1.0.0" + update-notifier "^2.5.0" + uuid "^3.3.2" + validate-npm-package-license "^3.0.3" + validate-npm-package-name "~3.0.0" + which "^1.3.1" + worker-farm "^1.6.0" + write-file-atomic "^2.3.0" + +"npmlog@0 || 1 || 2 || 3 || 4", "npmlog@2 || ^3.1.0 || ^4.0.0", npmlog@^4.0.2, npmlog@~4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + +nth-check@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.1.tgz#9929acdf628fc2c41098deab82ac580cf149aae4" + dependencies: + boolbase "~1.0.0" + +num2fraction@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + +oauth-sign@~0.8.1, oauth-sign@~0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" + +object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + +object-copy@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + +object-inspect@~1.4.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.4.1.tgz#37ffb10e71adaf3748d05f713b4c9452f402cbc4" + +object-keys@^1.0.6, object-keys@^1.0.8: + version "1.0.12" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.12.tgz#09c53855377575310cca62f55bb334abff7b3ed2" + +object-visit@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + dependencies: + isobject "^3.0.0" + +object.getownpropertydescriptors@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz#8758c846f5b407adab0f236e0986f14b051caa16" + dependencies: + define-properties "^1.1.2" + es-abstract "^1.5.1" + +object.pick@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + dependencies: + isobject "^3.0.1" + +object.values@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.0.4.tgz#e524da09b4f66ff05df457546ec72ac99f13069a" + dependencies: + define-properties "^1.1.2" + es-abstract "^1.6.1" + function-bind "^1.1.0" + has "^1.0.1" + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + dependencies: + ee-first "1.1.1" + +once@^1.3.0, once@^1.3.1, once@^1.3.3, once@^1.4.0, once@~1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + dependencies: + wrappy "1" + +onetime@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" + dependencies: + mimic-fn "^1.0.0" + +opener@~1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/opener/-/opener-1.4.3.tgz#5c6da2c5d7e5831e8ffa3964950f8d6674ac90b8" + +opn@^5.1.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/opn/-/opn-5.3.0.tgz#64871565c863875f052cfdf53d3e3cb5adb53b1c" + dependencies: + is-wsl "^1.1.0" + +optionator@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.4" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + wordwrap "~1.0.0" + +ora@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/ora/-/ora-2.1.0.tgz#6caf2830eb924941861ec53a173799e008b51e5b" + dependencies: + chalk "^2.3.1" + cli-cursor "^2.1.0" + cli-spinners "^1.1.0" + log-symbols "^2.2.0" + strip-ansi "^4.0.0" + wcwidth "^1.0.1" + +os-browserify@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" + +os-browserify@~0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.1.2.tgz#49ca0293e0b19590a5f5de10c7f265a617d8fe54" + +os-homedir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + +os-locale@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2" + dependencies: + execa "^0.7.0" + lcid "^1.0.0" + mem "^1.1.0" + +os-tmpdir@^1.0.0, os-tmpdir@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + +osenv@0, osenv@^0.1.4, osenv@^0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" + +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + +p-limit@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" + dependencies: + p-try "^1.0.0" + +p-locate@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + dependencies: + p-limit "^1.1.0" + +p-try@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + +package-json@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/package-json/-/package-json-4.0.1.tgz#8869a0401253661c4c4ca3da6c2121ed555f5eed" + dependencies: + got "^6.7.1" + registry-auth-token "^3.0.1" + registry-url "^3.0.3" + semver "^5.1.0" + +pacote@^8.1.6: + version "8.1.6" + resolved "https://registry.yarnpkg.com/pacote/-/pacote-8.1.6.tgz#8e647564d38156367e7a9dc47a79ca1ab278d46e" + dependencies: + bluebird "^3.5.1" + cacache "^11.0.2" + get-stream "^3.0.0" + glob "^7.1.2" + lru-cache "^4.1.3" + make-fetch-happen "^4.0.1" + minimatch "^3.0.4" + minipass "^2.3.3" + mississippi "^3.0.0" + mkdirp "^0.5.1" + normalize-package-data "^2.4.0" + npm-package-arg "^6.1.0" + npm-packlist "^1.1.10" + npm-pick-manifest "^2.1.0" + osenv "^0.1.5" + promise-inflight "^1.0.1" + promise-retry "^1.1.1" + protoduck "^5.0.0" + rimraf "^2.6.2" + safe-buffer "^5.1.2" + semver "^5.5.0" + ssri "^6.0.0" + tar "^4.4.3" + unique-filename "^1.1.0" + which "^1.3.0" + +pako@^0.2.5, pako@~0.2.0: + version "0.2.9" + resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75" + +pako@~1.0.5: + version "1.0.6" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.6.tgz#0101211baa70c4bca4a0f63f2206e97b7dfaf258" + +parallel-transform@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.1.0.tgz#d410f065b05da23081fcd10f28854c29bda33b06" + dependencies: + cyclist "~0.2.2" + inherits "^2.0.3" + readable-stream "^2.1.5" + +parcel@^1.9.7: + version "1.9.7" + resolved "https://registry.yarnpkg.com/parcel/-/parcel-1.9.7.tgz#77ca0cdb305d8e9365ded4762ee39ca760b0c219" + dependencies: + ansi-to-html "^0.6.4" + babel-code-frame "^6.26.0" + babel-core "^6.25.0" + babel-generator "^6.25.0" + babel-plugin-transform-es2015-modules-commonjs "^6.26.0" + babel-plugin-transform-react-jsx "^6.24.1" + babel-preset-env "^1.7.0" + babel-template "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + babylon "^6.17.4" + babylon-walk "^1.0.2" + browserslist "^3.2.6" + chalk "^2.1.0" + clone "^2.1.1" + command-exists "^1.2.6" + commander "^2.11.0" + cross-spawn "^6.0.4" + cssnano "^4.0.0" + deasync "^0.1.13" + dotenv "^5.0.0" + fast-glob "^2.2.2" + filesize "^3.6.0" + fswatcher-child "^1.0.3" + get-port "^3.2.0" + grapheme-breaker "^0.3.2" + htmlnano "^0.1.9" + is-glob "^4.0.0" + is-url "^1.2.2" + js-yaml "^3.10.0" + json5 "^1.0.1" + micromatch "^3.0.4" + mkdirp "^0.5.1" + node-forge "^0.7.1" + node-libs-browser "^2.0.0" + opn "^5.1.0" + ora "^2.1.0" + physical-cpu-count "^2.0.0" + postcss "^6.0.19" + postcss-value-parser "^3.3.0" + posthtml "^0.11.2" + posthtml-parser "^0.4.0" + posthtml-render "^1.1.3" + resolve "^1.4.0" + semver "^5.4.1" + serialize-to-js "^1.1.1" + serve-static "^1.12.4" + source-map "0.6.1" + strip-ansi "^4.0.0" + terser "^3.7.3" + toml "^2.3.3" + tomlify-j0.4 "^3.0.0" + v8-compile-cache "^2.0.0" + ws "^5.1.1" + +parents@^1.0.0, parents@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parents/-/parents-1.0.1.tgz#fedd4d2bf193a77745fe71e371d73c3307d9c751" + dependencies: + path-platform "~0.11.15" + +parse-asn1@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.1.tgz#f6bf293818332bd0dab54efb16087724745e6ca8" + dependencies: + asn1.js "^4.0.0" + browserify-aes "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.0" + pbkdf2 "^3.0.3" + +parse-json@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" + dependencies: + error-ex "^1.2.0" + +parse-json@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" + dependencies: + error-ex "^1.3.1" + json-parse-better-errors "^1.0.1" + +parseurl@~1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" + +pascalcase@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + +path-browserify@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a" + +path-browserify@~0.0.0: + version "0.0.1" + resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a" + +path-dirname@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + +path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + +path-is-inside@^1.0.1, path-is-inside@^1.0.2, path-is-inside@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + +path-key@^2.0.0, path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + +path-parse@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" + +path-platform@~0.11.15: + version "0.11.15" + resolved "https://registry.yarnpkg.com/path-platform/-/path-platform-0.11.15.tgz#e864217f74c36850f0852b78dc7bf7d4a5721bf2" + +path-type@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" + dependencies: + pify "^2.0.0" + +pbkdf2@^3.0.3: + version "3.0.16" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.16.tgz#7404208ec6b01b62d85bf83853a8064f8d9c2a5c" + dependencies: + create-hash "^1.1.2" + create-hmac "^1.1.4" + ripemd160 "^2.0.1" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +performance-now@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" + +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + +physical-cpu-count@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/physical-cpu-count/-/physical-cpu-count-2.0.0.tgz#18de2f97e4bf7a9551ad7511942b5496f7aba660" + +pify@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + +pify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" + +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + +postcss-calc@^5.2.0: + version "5.3.1" + resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-5.3.1.tgz#77bae7ca928ad85716e2fda42f261bf7c1d65b5e" + dependencies: + postcss "^5.0.2" + postcss-message-helpers "^2.0.0" + reduce-css-calc "^1.2.6" + +postcss-calc@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-6.0.1.tgz#3d24171bbf6e7629d422a436ebfe6dd9511f4330" + dependencies: + css-unit-converter "^1.1.1" + postcss "^6.0.0" + postcss-selector-parser "^2.2.2" + reduce-css-calc "^2.0.0" + +postcss-colormin@^2.1.8: + version "2.2.2" + resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-2.2.2.tgz#6631417d5f0e909a3d7ec26b24c8a8d1e4f96e4b" + dependencies: + colormin "^1.0.5" + postcss "^5.0.13" + postcss-value-parser "^3.2.3" + +postcss-colormin@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-4.0.1.tgz#6f1c18a0155bc69613f2ff13843e2e4ae8ff0bbe" + dependencies: + browserslist "^4.0.0" + color "^3.0.0" + has "^1.0.0" + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + +postcss-convert-values@^2.3.4: + version "2.6.1" + resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-2.6.1.tgz#bbd8593c5c1fd2e3d1c322bb925dcae8dae4d62d" + dependencies: + postcss "^5.0.11" + postcss-value-parser "^3.1.2" + +postcss-convert-values@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-4.0.0.tgz#77d77d9aed1dc4e6956e651cc349d53305876f62" + dependencies: + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + +postcss-discard-comments@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-2.0.4.tgz#befe89fafd5b3dace5ccce51b76b81514be00e3d" + dependencies: + postcss "^5.0.14" + +postcss-discard-comments@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-4.0.0.tgz#9684a299e76b3e93263ef8fd2adbf1a1c08fd88d" + dependencies: + postcss "^6.0.0" + +postcss-discard-duplicates@^2.0.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-2.1.0.tgz#b9abf27b88ac188158a5eb12abcae20263b91932" + dependencies: + postcss "^5.0.4" + +postcss-discard-duplicates@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.0.tgz#42f3c267f85fa909e042c35767ecfd65cb2bd72c" + dependencies: + postcss "^6.0.0" + +postcss-discard-empty@^2.0.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-2.1.0.tgz#d2b4bd9d5ced5ebd8dcade7640c7d7cd7f4f92b5" + dependencies: + postcss "^5.0.14" + +postcss-discard-empty@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-4.0.0.tgz#55e18a59c74128e38c7d2804bcfa4056611fb97f" + dependencies: + postcss "^6.0.0" + +postcss-discard-overridden@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-0.1.1.tgz#8b1eaf554f686fb288cd874c55667b0aa3668d58" + dependencies: + postcss "^5.0.16" + +postcss-discard-overridden@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-4.0.0.tgz#4a0bf85978784cf1f81ed2c1c1fd9d964a1da1fa" + dependencies: + postcss "^6.0.0" + +postcss-discard-unused@^2.2.1: + version "2.2.3" + resolved "https://registry.yarnpkg.com/postcss-discard-unused/-/postcss-discard-unused-2.2.3.tgz#bce30b2cc591ffc634322b5fb3464b6d934f4433" + dependencies: + postcss "^5.0.14" + uniqs "^2.0.0" + +postcss-filter-plugins@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/postcss-filter-plugins/-/postcss-filter-plugins-2.0.3.tgz#82245fdf82337041645e477114d8e593aa18b8ec" + dependencies: + postcss "^5.0.4" + +postcss-merge-idents@^2.1.5: + version "2.1.7" + resolved "https://registry.yarnpkg.com/postcss-merge-idents/-/postcss-merge-idents-2.1.7.tgz#4c5530313c08e1d5b3bbf3d2bbc747e278eea270" + dependencies: + has "^1.0.1" + postcss "^5.0.10" + postcss-value-parser "^3.1.1" + +postcss-merge-longhand@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-2.0.2.tgz#23d90cd127b0a77994915332739034a1a4f3d658" + dependencies: + postcss "^5.0.4" + +postcss-merge-longhand@^4.0.0: + version "4.0.4" + resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-4.0.4.tgz#bffc7c6ffa146591c993a0bb8373d65f9a06d4d0" + dependencies: + css-color-names "0.0.4" + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + stylehacks "^4.0.0" + +postcss-merge-rules@^2.0.3: + version "2.1.2" + resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-2.1.2.tgz#d1df5dfaa7b1acc3be553f0e9e10e87c61b5f721" + dependencies: + browserslist "^1.5.2" + caniuse-api "^1.5.2" + postcss "^5.0.4" + postcss-selector-parser "^2.2.2" + vendors "^1.0.0" + +postcss-merge-rules@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-4.0.1.tgz#430fd59b3f2ed2e8afcd0b31278eda39854abb10" + dependencies: + browserslist "^4.0.0" + caniuse-api "^3.0.0" + cssnano-util-same-parent "^4.0.0" + postcss "^6.0.0" + postcss-selector-parser "^3.0.0" + vendors "^1.0.0" + +postcss-message-helpers@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-message-helpers/-/postcss-message-helpers-2.0.0.tgz#a4f2f4fab6e4fe002f0aed000478cdf52f9ba60e" + +postcss-minify-font-values@^1.0.2: + version "1.0.5" + resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-1.0.5.tgz#4b58edb56641eba7c8474ab3526cafd7bbdecb69" + dependencies: + object-assign "^4.0.1" + postcss "^5.0.4" + postcss-value-parser "^3.0.2" + +postcss-minify-font-values@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-4.0.0.tgz#4cc33d283d6a81759036e757ef981d92cbd85bed" + dependencies: + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + +postcss-minify-gradients@^1.0.1: + version "1.0.5" + resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-1.0.5.tgz#5dbda11373703f83cfb4a3ea3881d8d75ff5e6e1" + dependencies: + postcss "^5.0.12" + postcss-value-parser "^3.3.0" + +postcss-minify-gradients@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-4.0.0.tgz#3fc3916439d27a9bb8066db7cdad801650eb090e" + dependencies: + cssnano-util-get-arguments "^4.0.0" + is-color-stop "^1.0.0" + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + +postcss-minify-params@^1.0.4: + version "1.2.2" + resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-1.2.2.tgz#ad2ce071373b943b3d930a3fa59a358c28d6f1f3" + dependencies: + alphanum-sort "^1.0.1" + postcss "^5.0.2" + postcss-value-parser "^3.0.2" + uniqs "^2.0.0" + +postcss-minify-params@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-4.0.0.tgz#05e9166ee48c05af651989ce84d39c1b4d790674" + dependencies: + alphanum-sort "^1.0.0" + cssnano-util-get-arguments "^4.0.0" + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + uniqs "^2.0.0" + +postcss-minify-selectors@^2.0.4: + version "2.1.1" + resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-2.1.1.tgz#b2c6a98c0072cf91b932d1a496508114311735bf" + dependencies: + alphanum-sort "^1.0.2" + has "^1.0.1" + postcss "^5.0.14" + postcss-selector-parser "^2.0.0" + +postcss-minify-selectors@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-4.0.0.tgz#b1e9f6c463416d3fcdcb26e7b785d95f61578aad" + dependencies: + alphanum-sort "^1.0.0" + has "^1.0.0" + postcss "^6.0.0" + postcss-selector-parser "^3.0.0" + +postcss-normalize-charset@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-1.1.1.tgz#ef9ee71212d7fe759c78ed162f61ed62b5cb93f1" + dependencies: + postcss "^5.0.5" + +postcss-normalize-charset@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-4.0.0.tgz#24527292702d5e8129eafa3d1de49ed51a6ab730" + dependencies: + postcss "^6.0.0" + +postcss-normalize-display-values@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.0.tgz#950e0c7be3445770a160fffd6b6644c3c0cd8f89" + dependencies: + cssnano-util-get-match "^4.0.0" + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-positions@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-positions/-/postcss-normalize-positions-4.0.0.tgz#ee9343ab981b822c63ab72615ecccd08564445a3" + dependencies: + cssnano-util-get-arguments "^4.0.0" + has "^1.0.0" + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-repeat-style@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.0.tgz#b711c592cf16faf9ff575e42fa100b6799083eff" + dependencies: + cssnano-util-get-arguments "^4.0.0" + cssnano-util-get-match "^4.0.0" + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-string/-/postcss-normalize-string-4.0.0.tgz#718cb6d30a6fac6ac6a830e32c06c07dbc66fe5d" + dependencies: + has "^1.0.0" + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-timing-functions@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.0.tgz#0351f29886aa981d43d91b2c2bd1aea6d0af6d23" + dependencies: + cssnano-util-get-match "^4.0.0" + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-unicode@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.0.tgz#5acd5d47baea5d17674b2ccc4ae5166fa88cdf97" + dependencies: + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-url@^3.0.7: + version "3.0.8" + resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-3.0.8.tgz#108f74b3f2fcdaf891a2ffa3ea4592279fc78222" + dependencies: + is-absolute-url "^2.0.0" + normalize-url "^1.4.0" + postcss "^5.0.14" + postcss-value-parser "^3.2.3" + +postcss-normalize-url@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-4.0.0.tgz#b7a9c8ad26cf26694c146eb2d68bd0cf49956f0d" + dependencies: + is-absolute-url "^2.0.0" + normalize-url "^3.0.0" + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-whitespace@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.0.tgz#1da7e76b10ae63c11827fa04fc3bb4a1efe99cc0" + dependencies: + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + +postcss-ordered-values@^2.1.0: + version "2.2.3" + resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-2.2.3.tgz#eec6c2a67b6c412a8db2042e77fe8da43f95c11d" + dependencies: + postcss "^5.0.4" + postcss-value-parser "^3.0.1" + +postcss-ordered-values@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-4.0.0.tgz#58b40c74f72e022eb34152c12e4b0f9354482fc2" + dependencies: + cssnano-util-get-arguments "^4.0.0" + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + +postcss-reduce-idents@^2.2.2: + version "2.4.0" + resolved "https://registry.yarnpkg.com/postcss-reduce-idents/-/postcss-reduce-idents-2.4.0.tgz#c2c6d20cc958284f6abfbe63f7609bf409059ad3" + dependencies: + postcss "^5.0.4" + postcss-value-parser "^3.0.2" + +postcss-reduce-initial@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-1.0.1.tgz#68f80695f045d08263a879ad240df8dd64f644ea" + dependencies: + postcss "^5.0.4" + +postcss-reduce-initial@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-4.0.1.tgz#f2d58f50cea2b0c5dc1278d6ea5ed0ff5829c293" + dependencies: + browserslist "^4.0.0" + caniuse-api "^3.0.0" + has "^1.0.0" + postcss "^6.0.0" + +postcss-reduce-transforms@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-1.0.4.tgz#ff76f4d8212437b31c298a42d2e1444025771ae1" + dependencies: + has "^1.0.1" + postcss "^5.0.8" + postcss-value-parser "^3.0.1" + +postcss-reduce-transforms@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.0.tgz#f645fc7440c35274f40de8104e14ad7163edf188" + dependencies: + cssnano-util-get-match "^4.0.0" + has "^1.0.0" + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + +postcss-selector-parser@^2.0.0, postcss-selector-parser@^2.2.2: + version "2.2.3" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-2.2.3.tgz#f9437788606c3c9acee16ffe8d8b16297f27bb90" + dependencies: + flatten "^1.0.2" + indexes-of "^1.0.1" + uniq "^1.0.1" + +postcss-selector-parser@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-3.1.1.tgz#4f875f4afb0c96573d5cf4d74011aee250a7e865" + dependencies: + dot-prop "^4.1.1" + indexes-of "^1.0.1" + uniq "^1.0.1" + +postcss-svgo@^2.1.1: + version "2.1.6" + resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-2.1.6.tgz#b6df18aa613b666e133f08adb5219c2684ac108d" + dependencies: + is-svg "^2.0.0" + postcss "^5.0.14" + postcss-value-parser "^3.2.3" + svgo "^0.7.0" + +postcss-svgo@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-4.0.0.tgz#c0bbad02520fc636c9d78b0e8403e2e515c32285" + dependencies: + is-svg "^3.0.0" + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + svgo "^1.0.0" + +postcss-unique-selectors@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-2.0.2.tgz#981d57d29ddcb33e7b1dfe1fd43b8649f933ca1d" + dependencies: + alphanum-sort "^1.0.1" + postcss "^5.0.4" + uniqs "^2.0.0" + +postcss-unique-selectors@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-4.0.0.tgz#04c1e9764c75874261303402c41f0e9769fc5501" + dependencies: + alphanum-sort "^1.0.0" + postcss "^6.0.0" + uniqs "^2.0.0" + +postcss-value-parser@^3.0.0, postcss-value-parser@^3.0.1, postcss-value-parser@^3.0.2, postcss-value-parser@^3.1.1, postcss-value-parser@^3.1.2, postcss-value-parser@^3.2.3, postcss-value-parser@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz#87f38f9f18f774a4ab4c8a232f5c5ce8872a9d15" + +postcss-zindex@^2.0.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/postcss-zindex/-/postcss-zindex-2.2.0.tgz#d2109ddc055b91af67fc4cb3b025946639d2af22" + dependencies: + has "^1.0.1" + postcss "^5.0.4" + uniqs "^2.0.0" + +postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0.13, postcss@^5.0.14, postcss@^5.0.16, postcss@^5.0.2, postcss@^5.0.4, postcss@^5.0.5, postcss@^5.0.8, postcss@^5.2.16: + version "5.2.18" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-5.2.18.tgz#badfa1497d46244f6390f58b319830d9107853c5" + dependencies: + chalk "^1.1.3" + js-base64 "^2.1.9" + source-map "^0.5.6" + supports-color "^3.2.3" + +postcss@^6.0.0, postcss@^6.0.19: + version "6.0.23" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.23.tgz#61c82cc328ac60e677645f979054eb98bc0e3324" + dependencies: + chalk "^2.4.1" + source-map "^0.6.1" + supports-color "^5.4.0" + +posthtml-parser@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/posthtml-parser/-/posthtml-parser-0.3.3.tgz#3fe986fca9f00c0f109d731ba590b192f26e776d" + dependencies: + htmlparser2 "^3.9.2" + isobject "^2.1.0" + object-assign "^4.1.1" + +posthtml-parser@^0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/posthtml-parser/-/posthtml-parser-0.4.1.tgz#95b78fef766fbbe0a6f861b6e95582bc3d1ff933" + dependencies: + htmlparser2 "^3.9.2" + object-assign "^4.1.1" + +posthtml-render@^1.1.0, posthtml-render@^1.1.3: + version "1.1.4" + resolved "https://registry.yarnpkg.com/posthtml-render/-/posthtml-render-1.1.4.tgz#95dac09892f4f183fad5ac823f08f42c0256551e" + +posthtml@^0.11.2, posthtml@^0.11.3: + version "0.11.3" + resolved "https://registry.yarnpkg.com/posthtml/-/posthtml-0.11.3.tgz#17ea2921b0555b7455f33c977bd16d8b8cb74f27" + dependencies: + object-assign "^4.1.1" + posthtml-parser "^0.3.3" + posthtml-render "^1.1.0" + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + +prepend-http@^1.0.0, prepend-http@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" + +private@^0.1.6, private@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" + +process-nextick-args@~1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" + +process-nextick-args@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" + +process@^0.11.10, process@~0.11.0: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + +promise-inflight@^1.0.1, promise-inflight@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" + +promise-retry@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-1.1.1.tgz#6739e968e3051da20ce6497fb2b50f6911df3d6d" + dependencies: + err-code "^1.0.0" + retry "^0.10.0" + +promzard@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/promzard/-/promzard-0.3.0.tgz#26a5d6ee8c7dee4cb12208305acfb93ba382a9ee" + dependencies: + read "1" + +proto-list@~1.2.1: + version "1.2.4" + resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" + +protoduck@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/protoduck/-/protoduck-5.0.0.tgz#752145e6be0ad834cb25716f670a713c860dce70" + dependencies: + genfun "^4.0.1" + +prr@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" + +pseudomap@^1.0.1, pseudomap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + +public-encrypt@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.2.tgz#46eb9107206bf73489f8b85b69d91334c6610994" + dependencies: + bn.js "^4.1.0" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + parse-asn1 "^5.0.0" + randombytes "^2.0.1" + +pump@^2.0.0, pump@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pumpify@^1.3.3: + version "1.5.1" + resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce" + dependencies: + duplexify "^3.6.0" + inherits "^2.0.3" + pump "^2.0.0" + +punycode@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + +punycode@^1.2.4, punycode@^1.3.2, punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + +q@^1.1.2: + version "1.5.1" + resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" + +qrcode-terminal@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/qrcode-terminal/-/qrcode-terminal-0.12.0.tgz#bb5b699ef7f9f0505092a3748be4464fe71b5819" + +qs@~6.4.0: + version "6.4.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" + +qs@~6.5.1: + version "6.5.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" + +query-string@^4.1.0: + version "4.3.4" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.4.tgz#bbb693b9ca915c232515b228b1a02b609043dbeb" + dependencies: + object-assign "^4.1.0" + strict-uri-encode "^1.0.0" + +query-string@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-6.1.0.tgz#01e7d69f6a0940dac67a937d6c6325647aa4532a" + dependencies: + decode-uri-component "^0.2.0" + strict-uri-encode "^2.0.0" + +querystring-es3@^0.2.0, querystring-es3@~0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" + +querystring@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + +quote-stream@^1.0.1, quote-stream@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/quote-stream/-/quote-stream-1.0.2.tgz#84963f8c9c26b942e153feeb53aae74652b7e0b2" + dependencies: + buffer-equal "0.0.1" + minimist "^1.1.3" + through2 "^2.0.0" + +qw@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/qw/-/qw-1.0.1.tgz#efbfdc740f9ad054304426acb183412cc8b996d4" + +randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: + version "2.0.6" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.6.tgz#d302c522948588848a8d300c932b44c24231da80" + dependencies: + safe-buffer "^5.1.0" + +randomfill@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" + dependencies: + randombytes "^2.0.5" + safe-buffer "^5.1.0" + +range-parser@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" + +rc@^1.0.1, rc@^1.1.6, rc@^1.2.7: + version "1.2.8" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + dependencies: + deep-extend "^0.6.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + +read-cmd-shim@^1.0.1, read-cmd-shim@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/read-cmd-shim/-/read-cmd-shim-1.0.1.tgz#2d5d157786a37c055d22077c32c53f8329e91c7b" + dependencies: + graceful-fs "^4.1.2" + +read-installed@~4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/read-installed/-/read-installed-4.0.3.tgz#ff9b8b67f187d1e4c29b9feb31f6b223acd19067" + dependencies: + debuglog "^1.0.1" + read-package-json "^2.0.0" + readdir-scoped-modules "^1.0.0" + semver "2 || 3 || 4 || 5" + slide "~1.1.3" + util-extend "^1.0.1" + optionalDependencies: + graceful-fs "^4.1.2" + +read-only-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-only-stream/-/read-only-stream-2.0.0.tgz#2724fd6a8113d73764ac288d4386270c1dbf17f0" + dependencies: + readable-stream "^2.0.2" + +"read-package-json@1 || 2", read-package-json@^2.0.0, read-package-json@^2.0.13: + version "2.0.13" + resolved "https://registry.yarnpkg.com/read-package-json/-/read-package-json-2.0.13.tgz#2e82ebd9f613baa6d2ebe3aa72cefe3f68e41f4a" + dependencies: + glob "^7.1.1" + json-parse-better-errors "^1.0.1" + normalize-package-data "^2.0.0" + slash "^1.0.0" + optionalDependencies: + graceful-fs "^4.1.2" + +read-package-tree@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/read-package-tree/-/read-package-tree-5.2.1.tgz#6218b187d6fac82289ce4387bbbaf8eef536ad63" + dependencies: + debuglog "^1.0.1" + dezalgo "^1.0.0" + once "^1.3.0" + read-package-json "^2.0.0" + readdir-scoped-modules "^1.0.0" + +read-pkg-up@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" + dependencies: + find-up "^2.0.0" + read-pkg "^2.0.0" + +read-pkg@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" + dependencies: + load-json-file "^2.0.0" + normalize-package-data "^2.3.2" + path-type "^2.0.0" + +read@1, read@~1.0.1, read@~1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/read/-/read-1.0.7.tgz#b3da19bd052431a97671d44a42634adf710b40c4" + dependencies: + mute-stream "~0.0.4" + +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.3: + version "2.3.6" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@~1.1.10: + version "1.1.14" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +readable-stream@~2.0.0: + version "2.0.6" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + string_decoder "~0.10.x" + util-deprecate "~1.0.1" + +readdir-scoped-modules@*, readdir-scoped-modules@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/readdir-scoped-modules/-/readdir-scoped-modules-1.0.2.tgz#9fafa37d286be5d92cbaebdee030dc9b5f406747" + dependencies: + debuglog "^1.0.1" + dezalgo "^1.0.0" + graceful-fs "^4.1.2" + once "^1.3.0" + +readdirp@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" + dependencies: + graceful-fs "^4.1.2" + minimatch "^3.0.2" + readable-stream "^2.0.2" + set-immediate-shim "^1.0.1" + +receptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/receptor/-/receptor-1.0.0.tgz#bf54477e0387e44bebf3855120bbda5adea08f8b" + dependencies: + element-closest "^2.0.1" + keyboardevent-key-polyfill "^1.0.2" + matches-selector "^1.0.0" + object-assign "^4.1.0" + +reduce-css-calc@^1.2.6: + version "1.3.0" + resolved "https://registry.yarnpkg.com/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz#747c914e049614a4c9cfbba629871ad1d2927716" + dependencies: + balanced-match "^0.4.2" + math-expression-evaluator "^1.2.14" + reduce-function-call "^1.0.1" + +reduce-css-calc@^2.0.0: + version "2.1.4" + resolved "https://registry.yarnpkg.com/reduce-css-calc/-/reduce-css-calc-2.1.4.tgz#c20e9cda8445ad73d4ff4bea960c6f8353791708" + dependencies: + css-unit-converter "^1.1.1" + postcss-value-parser "^3.3.0" + +reduce-function-call@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/reduce-function-call/-/reduce-function-call-1.0.2.tgz#5a200bf92e0e37751752fe45b0ab330fd4b6be99" + dependencies: + balanced-match "^0.4.2" + +regenerate@^1.2.1: + version "1.4.0" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" + +regenerator-runtime@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" + +regenerator-transform@^0.10.0: + version "0.10.1" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd" + dependencies: + babel-runtime "^6.18.0" + babel-types "^6.19.0" + private "^0.1.6" + +regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + +regexpu-core@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" + dependencies: + regenerate "^1.2.1" + regjsgen "^0.2.0" + regjsparser "^0.1.4" + +registry-auth-token@^3.0.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.3.2.tgz#851fd49038eecb586911115af845260eec983f20" + dependencies: + rc "^1.1.6" + safe-buffer "^5.0.1" + +registry-url@^3.0.3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942" + dependencies: + rc "^1.0.1" + +regjsgen@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" + +regjsparser@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" + dependencies: + jsesc "~0.5.0" + +remove-trailing-separator@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + +repeat-element@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" + +repeat-string@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + +repeating@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" + dependencies: + is-finite "^1.0.0" + +"request@>=2.9.0 <2.82.0": + version "2.81.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" + dependencies: + aws-sign2 "~0.6.0" + aws4 "^1.2.1" + caseless "~0.12.0" + combined-stream "~1.0.5" + extend "~3.0.0" + forever-agent "~0.6.1" + form-data "~2.1.1" + har-validator "~4.2.1" + hawk "~3.1.3" + http-signature "~1.1.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.7" + oauth-sign "~0.8.1" + performance-now "^0.2.0" + qs "~6.4.0" + safe-buffer "^5.0.1" + stringstream "~0.0.4" + tough-cookie "~2.3.0" + tunnel-agent "^0.6.0" + uuid "^3.0.0" + +request@^2.74.0, request@^2.81.0: + version "2.87.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.87.0.tgz#32f00235cd08d482b4d0d68db93a829c0ed5756e" + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.6.0" + caseless "~0.12.0" + combined-stream "~1.0.5" + extend "~3.0.1" + forever-agent "~0.6.1" + form-data "~2.3.1" + har-validator "~5.0.3" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.17" + oauth-sign "~0.8.2" + performance-now "^2.1.0" + qs "~6.5.1" + safe-buffer "^5.1.1" + tough-cookie "~2.3.3" + tunnel-agent "^0.6.0" + uuid "^3.1.0" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + +require-main-filename@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + +resolve-id-refs@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/resolve-id-refs/-/resolve-id-refs-0.1.0.tgz#3126624b887489da8fc0ae889632f8413ac6c3ec" + +resolve-url@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + +resolve@1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" + +resolve@^1.1.3, resolve@^1.1.4, resolve@^1.1.5, resolve@^1.4.0: + version "1.8.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.8.1.tgz#82f1ec19a423ac1fbd080b0bab06ba36e84a7a26" + dependencies: + path-parse "^1.0.5" + +restore-cursor@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" + dependencies: + onetime "^2.0.0" + signal-exit "^3.0.2" + +ret@~0.1.10: + version "0.1.15" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + +retry@^0.10.0: + version "0.10.1" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.10.1.tgz#e76388d217992c252750241d3d3956fed98d8ff4" + +retry@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" + +rgb-regex@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/rgb-regex/-/rgb-regex-1.0.1.tgz#c0e0d6882df0e23be254a475e8edd41915feaeb1" + +rgba-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3" + +rimraf@2, rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@~2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" + dependencies: + glob "^7.0.5" + +ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + +run-queue@^1.0.0, run-queue@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47" + dependencies: + aproba "^1.1.1" + +safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + +safe-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + dependencies: + ret "~0.1.10" + +"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + +safer-eval@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/safer-eval/-/safer-eval-1.2.3.tgz#73ba74a34bc8a07d6a44135c815fd18a8eebe7a0" + dependencies: + clones "^1.1.0" + +sax@^1.2.4, sax@~1.2.1, sax@~1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + +semver-diff@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36" + dependencies: + semver "^5.0.3" + +"semver@2 >=2.2.1 || 3.x || 4 || 5", "semver@2 || 3 || 4 || 5", "semver@2.x || 3.x || 4 || 5", "semver@^2.3.0 || 3.x || 4 || 5", semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" + +semver@~5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" + +send@0.16.2: + version "0.16.2" + resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1" + dependencies: + debug "2.6.9" + depd "~1.1.2" + destroy "~1.0.4" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "~1.6.2" + mime "1.4.1" + ms "2.0.0" + on-finished "~2.3.0" + range-parser "~1.2.0" + statuses "~1.4.0" + +serialize-to-js@^1.1.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/serialize-to-js/-/serialize-to-js-1.2.1.tgz#2e87f61f938826d24c463a7cbd0dd2929ec38008" + dependencies: + js-beautify "^1.7.5" + safer-eval "^1.2.3" + +serve-static@^1.12.4: + version "1.13.2" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1" + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.2" + send "0.16.2" + +set-blocking@^2.0.0, set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + +set-immediate-shim@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" + +set-value@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1" + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.1" + to-object-path "^0.3.0" + +set-value@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274" + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" + +setimmediate@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + +setprototypeof@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" + +sha.js@^2.4.0, sha.js@^2.4.8, sha.js@~2.4.4: + version "2.4.11" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +sha@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/sha/-/sha-2.0.1.tgz#6030822fbd2c9823949f8f72ed6411ee5cf25aae" + dependencies: + graceful-fs "^4.1.2" + readable-stream "^2.0.2" + +shallow-copy@~0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/shallow-copy/-/shallow-copy-0.0.1.tgz#415f42702d73d810330292cc5ee86eae1a11a170" + +shasum@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/shasum/-/shasum-1.0.2.tgz#e7012310d8f417f4deb5712150e5678b87ae565f" + dependencies: + json-stable-stringify "~0.0.0" + sha.js "~2.4.4" + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + dependencies: + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + +shell-quote@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.6.1.tgz#f4781949cce402697127430ea3b3c5476f481767" + dependencies: + array-filter "~0.0.0" + array-map "~0.0.0" + array-reduce "~0.0.0" + jsonify "~0.0.0" + +sigmund@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" + +signal-exit@^3.0.0, signal-exit@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + +simple-concat@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.0.tgz#7344cbb8b6e26fb27d66b2fc86f9f6d5997521c6" + +simple-swizzle@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" + dependencies: + is-arrayish "^0.3.1" + +slash@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" + +slide@^1.1.3, slide@^1.1.6, slide@~1.1.3, slide@~1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" + +smart-buffer@^1.0.13: + version "1.1.15" + resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-1.1.15.tgz#7f114b5b65fab3e2a35aa775bb12f0d1c649bf16" + +smart-buffer@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.0.1.tgz#07ea1ca8d4db24eb4cac86537d7d18995221ace3" + +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + dependencies: + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" + +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + dependencies: + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + dependencies: + base "^0.11.1" + debug "^2.2.0" + define-property "^0.2.5" + extend-shallow "^2.0.1" + map-cache "^0.2.2" + source-map "^0.5.6" + source-map-resolve "^0.5.0" + use "^3.1.0" + +sntp@1.x.x: + version "1.0.9" + resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" + dependencies: + hoek "2.x.x" + +socks-proxy-agent@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-3.0.1.tgz#2eae7cf8e2a82d34565761539a7f9718c5617659" + dependencies: + agent-base "^4.1.0" + socks "^1.1.10" + +socks-proxy-agent@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-4.0.1.tgz#5936bf8b707a993079c6f37db2091821bffa6473" + dependencies: + agent-base "~4.2.0" + socks "~2.2.0" + +socks@^1.1.10: + version "1.1.10" + resolved "https://registry.yarnpkg.com/socks/-/socks-1.1.10.tgz#5b8b7fc7c8f341c53ed056e929b7bf4de8ba7b5a" + dependencies: + ip "^1.1.4" + smart-buffer "^1.0.13" + +socks@~2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/socks/-/socks-2.2.1.tgz#68ad678b3642fbc5d99c64c165bc561eab0215f9" + dependencies: + ip "^1.1.5" + smart-buffer "^4.0.1" + +sort-keys@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad" + dependencies: + is-plain-obj "^1.0.0" + +sorted-object@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/sorted-object/-/sorted-object-2.0.1.tgz#7d631f4bd3a798a24af1dffcfbfe83337a5df5fc" + +sorted-union-stream@~2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/sorted-union-stream/-/sorted-union-stream-2.1.3.tgz#c7794c7e077880052ff71a8d4a2dbb4a9a638ac7" + dependencies: + from2 "^1.3.0" + stream-iterate "^1.1.0" + +source-map-resolve@^0.5.0: + version "0.5.2" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" + dependencies: + atob "^2.1.1" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + +source-map-support@^0.4.15: + version "0.4.18" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" + dependencies: + source-map "^0.5.6" + +source-map-support@~0.5.6: + version "0.5.6" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.6.tgz#4435cee46b1aab62b8e8610ce60f788091c51c13" + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map-url@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" + +source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + +source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.3: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + +spdx-correct@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.0.0.tgz#05a5b4d7153a195bc92c3c425b69f3b2a9524c82" + dependencies: + spdx-expression-parse "^3.0.0" + spdx-license-ids "^3.0.0" + +spdx-exceptions@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz#2c7ae61056c714a5b9b9b2b2af7d311ef5c78fe9" + +spdx-expression-parse@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz#7a7cd28470cc6d3a1cfe6d66886f6bc430d3ac87" + +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + dependencies: + extend-shallow "^3.0.0" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + +sshpk@^1.7.0: + version "1.14.2" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.14.2.tgz#c6fc61648a3d9c4e764fd3fcdf4ea105e492ba98" + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + dashdash "^1.12.0" + getpass "^0.1.1" + safer-buffer "^2.0.2" + optionalDependencies: + bcrypt-pbkdf "^1.0.0" + ecc-jsbn "~0.1.1" + jsbn "~0.1.0" + tweetnacl "~0.14.0" + +ssri@^5.2.4: + version "5.3.0" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-5.3.0.tgz#ba3872c9c6d33a0704a7d71ff045e5ec48999d06" + dependencies: + safe-buffer "^5.1.1" + +ssri@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.0.tgz#fc21bfc90e03275ac3e23d5a42e38b8a1cbc130d" + +stable@~0.1.6: + version "0.1.8" + resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" + +static-eval@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/static-eval/-/static-eval-2.0.0.tgz#0e821f8926847def7b4b50cda5d55c04a9b13864" + dependencies: + escodegen "^1.8.1" + +static-extend@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" + +static-module@^2.2.0: + version "2.2.5" + resolved "https://registry.yarnpkg.com/static-module/-/static-module-2.2.5.tgz#bd40abceae33da6b7afb84a0e4329ff8852bfbbf" + dependencies: + concat-stream "~1.6.0" + convert-source-map "^1.5.1" + duplexer2 "~0.1.4" + escodegen "~1.9.0" + falafel "^2.1.0" + has "^1.0.1" + magic-string "^0.22.4" + merge-source-map "1.0.4" + object-inspect "~1.4.0" + quote-stream "~1.0.2" + readable-stream "~2.3.3" + shallow-copy "~0.0.1" + static-eval "^2.0.0" + through2 "~2.0.3" + +"statuses@>= 1.4.0 < 2": + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + +statuses@~1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" + +stream-browserify@^2.0.0, stream-browserify@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db" + dependencies: + inherits "~2.0.1" + readable-stream "^2.0.2" + +stream-combiner2@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/stream-combiner2/-/stream-combiner2-1.1.1.tgz#fb4d8a1420ea362764e21ad4780397bebcb41cbe" + dependencies: + duplexer2 "~0.1.0" + readable-stream "^2.0.2" + +stream-each@^1.1.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae" + dependencies: + end-of-stream "^1.1.0" + stream-shift "^1.0.0" + +stream-http@^2.0.0, stream-http@^2.7.2: + version "2.8.3" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc" + dependencies: + builtin-status-codes "^3.0.0" + inherits "^2.0.1" + readable-stream "^2.3.6" + to-arraybuffer "^1.0.0" + xtend "^4.0.0" + +stream-iterate@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/stream-iterate/-/stream-iterate-1.2.0.tgz#2bd7c77296c1702a46488b8ad41f79865eecd4e1" + dependencies: + readable-stream "^2.1.5" + stream-shift "^1.0.0" + +stream-shift@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" + +stream-splicer@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/stream-splicer/-/stream-splicer-2.0.0.tgz#1b63be438a133e4b671cc1935197600175910d83" + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.2" + +strict-uri-encode@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" + +strict-uri-encode@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546" + +string-width@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +string_decoder@^1.0.0, string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + dependencies: + safe-buffer "~5.1.0" + +string_decoder@~0.10.0, string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + +stringify-package@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/stringify-package/-/stringify-package-1.0.0.tgz#e02828089333d7d45cd8c287c30aa9a13375081b" + +stringstream@~0.0.4: + version "0.0.6" + resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.6.tgz#7880225b0d4ad10e30927d167a1d6f2fd3b33a72" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + dependencies: + ansi-regex "^3.0.0" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + +strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + +stylehacks@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-4.0.0.tgz#64b323951c4a24e5fc7b2ec06c137bf32d155e8a" + dependencies: + browserslist "^4.0.0" + postcss "^6.0.0" + postcss-selector-parser "^3.0.0" + +subarg@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/subarg/-/subarg-1.0.0.tgz#f62cf17581e996b48fc965699f54c06ae268b8d2" + dependencies: + minimist "^1.1.0" + +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + +supports-color@^3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" + dependencies: + has-flag "^1.0.0" + +supports-color@^5.3.0, supports-color@^5.4.0: + version "5.4.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54" + dependencies: + has-flag "^3.0.0" + +svgo@^0.7.0: + version "0.7.2" + resolved "https://registry.yarnpkg.com/svgo/-/svgo-0.7.2.tgz#9f5772413952135c6fefbf40afe6a4faa88b4bb5" + dependencies: + coa "~1.0.1" + colors "~1.1.2" + csso "~2.3.1" + js-yaml "~3.7.0" + mkdirp "~0.5.1" + sax "~1.2.1" + whet.extend "~0.9.9" + +svgo@^1.0.0, svgo@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/svgo/-/svgo-1.0.5.tgz#7040364c062a0538abacff4401cea6a26a7a389a" + dependencies: + coa "~2.0.1" + colors "~1.1.2" + css-select "~1.3.0-rc0" + css-select-base-adapter "~0.1.0" + css-tree "1.0.0-alpha25" + css-url-regex "^1.1.0" + csso "^3.5.0" + js-yaml "~3.10.0" + mkdirp "~0.5.1" + object.values "^1.0.4" + sax "~1.2.4" + stable "~0.1.6" + unquote "~1.1.1" + util.promisify "~1.0.0" + +syntax-error@^1.1.1: + version "1.4.0" + resolved "https://registry.yarnpkg.com/syntax-error/-/syntax-error-1.4.0.tgz#2d9d4ff5c064acb711594a3e3b95054ad51d907c" + dependencies: + acorn-node "^1.2.0" + +tar@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" + dependencies: + block-stream "*" + fstream "^1.0.2" + inherits "2" + +tar@^4, tar@^4.4.3, tar@^4.4.4: + version "4.4.6" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.6.tgz#63110f09c00b4e60ac8bcfe1bf3c8660235fbc9b" + dependencies: + chownr "^1.0.1" + fs-minipass "^1.2.5" + minipass "^2.3.3" + minizlib "^1.1.0" + mkdirp "^0.5.0" + safe-buffer "^5.1.2" + yallist "^3.0.2" + +term-size@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/term-size/-/term-size-1.2.0.tgz#458b83887f288fc56d6fffbfad262e26638efa69" + dependencies: + execa "^0.7.0" + +terser@^3.7.3: + version "3.8.1" + resolved "https://registry.yarnpkg.com/terser/-/terser-3.8.1.tgz#cb70070ac9e0a71add169dfb63c0a64fca2738ac" + dependencies: + commander "~2.16.0" + source-map "~0.6.1" + source-map-support "~0.5.6" + +text-table@~0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + +through2@^2.0.0, through2@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be" + dependencies: + readable-stream "^2.1.5" + xtend "~4.0.1" + +"through@>=2.2.7 <3": + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + +timed-out@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" + +timers-browserify@^1.0.1: + version "1.4.2" + resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-1.4.2.tgz#c9c58b575be8407375cb5e2462dacee74359f41d" + dependencies: + process "~0.11.0" + +timers-browserify@^2.0.4: + version "2.0.10" + resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.10.tgz#1d28e3d2aadf1d5a5996c4e9f95601cd053480ae" + dependencies: + setimmediate "^1.0.4" + +timsort@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" + +tiny-inflate@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/tiny-inflate/-/tiny-inflate-1.0.2.tgz#93d9decffc8805bd57eae4310f0b745e9b6fb3a7" + +tiny-relative-date@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/tiny-relative-date/-/tiny-relative-date-1.3.0.tgz#fa08aad501ed730f31cc043181d995c39a935e07" + +to-arraybuffer@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" + +to-fast-properties@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" + +to-object-path@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + dependencies: + kind-of "^3.0.2" + +to-regex-range@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + dependencies: + is-number "^3.0.0" + repeat-string "^1.6.1" + +to-regex@^3.0.1, to-regex@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + dependencies: + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" + +toml@^2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/toml/-/toml-2.3.3.tgz#8d683d729577cb286231dfc7a8affe58d31728fb" + +tomlify-j0.4@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/tomlify-j0.4/-/tomlify-j0.4-3.0.0.tgz#99414d45268c3a3b8bf38be82145b7bba34b7473" + +tough-cookie@~2.3.0, tough-cookie@~2.3.3: + version "2.3.4" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.4.tgz#ec60cee38ac675063ffc97a5c18970578ee83655" + dependencies: + punycode "^1.4.1" + +trim-right@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" + +tty-browserify@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" + +tty-browserify@~0.0.0: + version "0.0.1" + resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.1.tgz#3f05251ee17904dfd0677546670db9651682b811" + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + dependencies: + safe-buffer "^5.0.1" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + dependencies: + prelude-ls "~1.1.2" + +typedarray@^0.0.6, typedarray@~0.0.5: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + +typescript@^2.4.1: + version "2.9.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.9.2.tgz#1cbf61d05d6b96269244eb6a3bce4bd914e0f00c" + +uglify-es@^3.3.9: + version "3.3.10" + resolved "https://registry.yarnpkg.com/uglify-es/-/uglify-es-3.3.10.tgz#8b0b7992cebe20edc26de1bf325cef797b8f3fa5" + dependencies: + commander "~2.14.1" + source-map "~0.6.1" + +uid-number@0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" + +umask@^1.1.0, umask@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/umask/-/umask-1.1.0.tgz#f29cebf01df517912bb58ff9c4e50fde8e33320d" + +umd@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/umd/-/umd-3.0.3.tgz#aa9fe653c42b9097678489c01000acb69f0b26cf" + +undeclared-identifiers@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/undeclared-identifiers/-/undeclared-identifiers-1.1.2.tgz#7d850a98887cff4bd0bf64999c014d08ed6d1acc" + dependencies: + acorn-node "^1.3.0" + get-assigned-identifiers "^1.2.0" + simple-concat "^1.0.0" + xtend "^4.0.1" + +unicode-trie@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/unicode-trie/-/unicode-trie-0.3.1.tgz#d671dddd89101a08bac37b6a5161010602052085" + dependencies: + pako "^0.2.5" + tiny-inflate "^1.0.0" + +union-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^0.4.3" + +uniq@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" + +uniqs@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02" + +unique-filename@^1.1.0, unique-filename@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.0.tgz#d05f2fe4032560871f30e93cbe735eea201514f3" + dependencies: + unique-slug "^2.0.0" + +unique-slug@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.0.tgz#db6676e7c7cc0629878ff196097c78855ae9f4ab" + dependencies: + imurmurhash "^0.1.4" + +unique-string@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a" + dependencies: + crypto-random-string "^1.0.0" + +unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + +unquote@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/unquote/-/unquote-1.1.1.tgz#8fded7324ec6e88a0ff8b905e7c098cdc086d544" + +unset-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + +unzip-response@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97" + +upath@^1.0.5: + version "1.1.0" + resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.0.tgz#35256597e46a581db4793d0ce47fa9aebfc9fabd" + +update-notifier@^2.3.0, update-notifier@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-2.5.0.tgz#d0744593e13f161e406acb1d9408b72cad08aff6" + dependencies: + boxen "^1.2.1" + chalk "^2.0.1" + configstore "^3.0.0" + import-lazy "^2.1.0" + is-ci "^1.0.10" + is-installed-globally "^0.1.0" + is-npm "^1.0.0" + latest-version "^3.0.0" + semver-diff "^2.0.0" + xdg-basedir "^3.0.0" + +urix@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + +url-parse-lax@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" + dependencies: + prepend-http "^1.0.1" + +url@^0.11.0, url@~0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" + dependencies: + punycode "1.3.2" + querystring "0.2.0" + +use@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + +uswds@^1.6.3: + version "1.6.7" + resolved "https://registry.yarnpkg.com/uswds/-/uswds-1.6.7.tgz#85ffa94a26da333e7e709b9fbc7292edab04ac82" + dependencies: + "@types/node" "^8.5.5" + array-filter "^1.0.0" + array-foreach "^1.0.2" + browserify "^13.0.0" + classlist-polyfill "^1.0.3" + domready "^1.0.8" + elem-dataset "^1.1.1" + lodash.debounce "^4.0.7" + object-assign "^4.1.1" + receptor "^1.0.0" + resolve-id-refs "^0.1.0" + typescript "^2.4.1" + yargs "^8.0.2" + +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + +util-extend@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/util-extend/-/util-extend-1.0.3.tgz#a7c216d267545169637b3b6edc6ca9119e2ff93f" + +util.promisify@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.0.tgz#440f7165a459c9a16dc145eb8e72f35687097030" + dependencies: + define-properties "^1.1.2" + object.getownpropertydescriptors "^2.0.3" + +util@0.10.3: + version "0.10.3" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" + dependencies: + inherits "2.0.1" + +util@^0.10.3, util@~0.10.1: + version "0.10.4" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.4.tgz#3aa0125bfe668a4672de58857d3ace27ecb76901" + dependencies: + inherits "2.0.3" + +uuid@^3.0.0, uuid@^3.1.0, uuid@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" + +v8-compile-cache@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.0.0.tgz#526492e35fc616864284700b7043e01baee09f0a" + +validate-npm-package-license@^3.0.1, validate-npm-package-license@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz#81643bcbef1bdfecd4623793dc4648948ba98338" + dependencies: + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" + +validate-npm-package-name@^3.0.0, validate-npm-package-name@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz#5fa912d81eb7d0c74afc140de7317f0ca7df437e" + dependencies: + builtins "^1.0.3" + +vendors@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.2.tgz#7fcb5eef9f5623b156bcea89ec37d63676f21801" + +verror@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + +vlq@^0.2.2: + version "0.2.3" + resolved "https://registry.yarnpkg.com/vlq/-/vlq-0.2.3.tgz#8f3e4328cf63b1540c0d67e1b2778386f8975b26" + +vm-browserify@0.0.4, vm-browserify@~0.0.1: + version "0.0.4" + resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73" + dependencies: + indexof "0.0.1" + +vue@^2.5.17: + version "2.5.17" + resolved "https://registry.yarnpkg.com/vue/-/vue-2.5.17.tgz#0f8789ad718be68ca1872629832ed533589c6ada" + +wcwidth@^1.0.0, wcwidth@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" + dependencies: + defaults "^1.0.3" + +whet.extend@~0.9.9: + version "0.9.9" + resolved "https://registry.yarnpkg.com/whet.extend/-/whet.extend-0.9.9.tgz#f877d5bf648c97e5aa542fadc16d6a259b9c11a1" + +which-module@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + +which@1, which@^1.2.9, which@^1.3.0, which@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + dependencies: + isexe "^2.0.0" + +wide-align@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" + dependencies: + string-width "^1.0.2 || 2" + +widest-line@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-2.0.0.tgz#0142a4e8a243f8882c0233aa0e0281aa76152273" + dependencies: + string-width "^2.1.1" + +wordwrap@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + +worker-farm@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.6.0.tgz#aecc405976fab5a95526180846f0dba288f3a4a0" + dependencies: + errno "~0.1.7" + +wrap-ansi@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + +write-file-atomic@^2.0.0, write-file-atomic@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.3.0.tgz#1ff61575c2e2a4e8e510d6fa4e243cce183999ab" + dependencies: + graceful-fs "^4.1.11" + imurmurhash "^0.1.4" + signal-exit "^3.0.2" + +ws@^5.1.1: + version "5.2.2" + resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.2.tgz#dffef14866b8e8dc9133582514d1befaf96e980f" + dependencies: + async-limiter "~1.0.0" + +xdg-basedir@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" + +xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" + +y18n@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" + +y18n@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" + +yallist@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + +yallist@^3.0.0, yallist@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.2.tgz#8452b4bb7e83c7c188d8041c1a837c773d6d8bb9" + +yargs-parser@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-7.0.0.tgz#8d0ac42f16ea55debd332caf4c4038b3e3f5dfd9" + dependencies: + camelcase "^4.1.0" + +yargs-parser@^9.0.2: + version "9.0.2" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-9.0.2.tgz#9ccf6a43460fe4ed40a9bb68f48d43b8a68cc077" + dependencies: + camelcase "^4.1.0" + +yargs@^11.0.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-11.1.0.tgz#90b869934ed6e871115ea2ff58b03f4724ed2d77" + dependencies: + cliui "^4.0.0" + decamelize "^1.1.1" + find-up "^2.1.0" + get-caller-file "^1.0.1" + os-locale "^2.0.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1" + yargs-parser "^9.0.2" + +yargs@^8.0.2: + version "8.0.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-8.0.2.tgz#6299a9055b1cefc969ff7e79c1d918dceb22c360" + dependencies: + camelcase "^4.1.0" + cliui "^3.2.0" + decamelize "^1.1.1" + get-caller-file "^1.0.1" + os-locale "^2.0.0" + read-pkg-up "^2.0.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1" + yargs-parser "^7.0.0" From 630a3b0cd530a7f4581f31af3d358e47ac9396c7 Mon Sep 17 00:00:00 2001 From: Patrick Smith Date: Thu, 2 Aug 2018 13:51:54 -0400 Subject: [PATCH 252/332] Working parcel setup --- package.json | 5 + static/js/index.js | 4 + static/js/thing.js | 7 + {scss => static/scss}/README.md | 0 {scss => static/scss}/atat.scss | 2 +- {scss => static/scss}/components/_alerts.scss | 0 .../scss}/components/_empty_state.scss | 0 {scss => static/scss}/components/_footer.scss | 0 .../scss}/components/_global_layout.scss | 0 .../scss}/components/_global_navigation.scss | 0 {scss => static/scss}/components/_modal.scss | 0 .../scss}/components/_progress_menu.scss | 4 +- .../scss}/components/_search_bar.scss | 2 +- .../scss}/components/_site_action.scss | 0 {scss => static/scss}/components/_topbar.scss | 0 .../scss}/components/_workspace_layout.scss | 0 {scss => static/scss}/core/_grid.scss | 0 {scss => static/scss}/core/_util.scss | 0 {scss => static/scss}/core/_variables.scss | 0 .../scss}/elements/_action_group.scss | 0 .../scss}/elements/_block_lists.scss | 0 {scss => static/scss}/elements/_buttons.scss | 0 {scss => static/scss}/elements/_diff.scss | 0 .../scss}/elements/_icon_link.scss | 0 {scss => static/scss}/elements/_icons.scss | 0 {scss => static/scss}/elements/_inputs.scss | 0 {scss => static/scss}/elements/_labels.scss | 0 {scss => static/scss}/elements/_panels.scss | 0 {scss => static/scss}/elements/_sidenav.scss | 0 {scss => static/scss}/elements/_tables.scss | 0 .../scss}/elements/_typography.scss | 0 {scss => static/scss}/sections/_login.scss | 0 .../scss}/sections/_member_edit.scss | 0 .../scss}/sections/_project_edit.scss | 0 .../scss}/sections/_projects_list.scss | 0 .../scss}/sections/_request_approval.scss | 0 templates/base.html | 5 +- templates/home.html | 1 + yarn.lock | 391 +++++++++++++++--- 39 files changed, 349 insertions(+), 72 deletions(-) create mode 100644 static/js/index.js create mode 100644 static/js/thing.js rename {scss => static/scss}/README.md (100%) rename {scss => static/scss}/atat.scss (94%) rename {scss => static/scss}/components/_alerts.scss (100%) rename {scss => static/scss}/components/_empty_state.scss (100%) rename {scss => static/scss}/components/_footer.scss (100%) rename {scss => static/scss}/components/_global_layout.scss (100%) rename {scss => static/scss}/components/_global_navigation.scss (100%) rename {scss => static/scss}/components/_modal.scss (100%) rename {scss => static/scss}/components/_progress_menu.scss (96%) rename {scss => static/scss}/components/_search_bar.scss (95%) rename {scss => static/scss}/components/_site_action.scss (100%) rename {scss => static/scss}/components/_topbar.scss (100%) rename {scss => static/scss}/components/_workspace_layout.scss (100%) rename {scss => static/scss}/core/_grid.scss (100%) rename {scss => static/scss}/core/_util.scss (100%) rename {scss => static/scss}/core/_variables.scss (100%) rename {scss => static/scss}/elements/_action_group.scss (100%) rename {scss => static/scss}/elements/_block_lists.scss (100%) rename {scss => static/scss}/elements/_buttons.scss (100%) rename {scss => static/scss}/elements/_diff.scss (100%) rename {scss => static/scss}/elements/_icon_link.scss (100%) rename {scss => static/scss}/elements/_icons.scss (100%) rename {scss => static/scss}/elements/_inputs.scss (100%) rename {scss => static/scss}/elements/_labels.scss (100%) rename {scss => static/scss}/elements/_panels.scss (100%) rename {scss => static/scss}/elements/_sidenav.scss (100%) rename {scss => static/scss}/elements/_tables.scss (100%) rename {scss => static/scss}/elements/_typography.scss (100%) rename {scss => static/scss}/sections/_login.scss (100%) rename {scss => static/scss}/sections/_member_edit.scss (100%) rename {scss => static/scss}/sections/_project_edit.scss (100%) rename {scss => static/scss}/sections/_projects_list.scss (100%) rename {scss => static/scss}/sections/_request_approval.scss (100%) diff --git a/package.json b/package.json index 9a474e0d..4d7b794e 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,8 @@ "description": "ATST Stateless Services", "main": "index.js", "scripts": { + "watch": "parcel watch static/js/index.js -d static/assets -o index.js --no-autoinstall", + "build": "parcel build static/js/index.js -d static/assets -o index.js --no-autoinstall", "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", @@ -13,5 +15,8 @@ "parcel": "^1.9.7", "uswds": "^1.6.3", "vue": "^2.5.17" + }, + "devDependencies": { + "node-sass": "^4.9.2" } } diff --git a/static/js/index.js b/static/js/index.js new file mode 100644 index 00000000..9cc49957 --- /dev/null +++ b/static/js/index.js @@ -0,0 +1,4 @@ +import classes from '../scss/atat.scss' + +import './thing' + diff --git a/static/js/thing.js b/static/js/thing.js new file mode 100644 index 00000000..033b8cd3 --- /dev/null +++ b/static/js/thing.js @@ -0,0 +1,7 @@ +console.log('hanlo again') +window.onload = function() { + console.log('boop') + const thing = document.querySelector('#hello') + thing.innerHTML = 'hanlo friendo' +} + diff --git a/scss/README.md b/static/scss/README.md similarity index 100% rename from scss/README.md rename to static/scss/README.md diff --git a/scss/atat.scss b/static/scss/atat.scss similarity index 94% rename from scss/atat.scss rename to static/scss/atat.scss index b4ae7797..040cc201 100644 --- a/scss/atat.scss +++ b/static/scss/atat.scss @@ -1,5 +1,5 @@ @import 'core/variables'; -@import '../node_modules/uswds/src/stylesheets/uswds'; +@import '../../node_modules/uswds/src/stylesheets/uswds'; @import 'core/grid'; @import 'core/util'; diff --git a/scss/components/_alerts.scss b/static/scss/components/_alerts.scss similarity index 100% rename from scss/components/_alerts.scss rename to static/scss/components/_alerts.scss diff --git a/scss/components/_empty_state.scss b/static/scss/components/_empty_state.scss similarity index 100% rename from scss/components/_empty_state.scss rename to static/scss/components/_empty_state.scss diff --git a/scss/components/_footer.scss b/static/scss/components/_footer.scss similarity index 100% rename from scss/components/_footer.scss rename to static/scss/components/_footer.scss diff --git a/scss/components/_global_layout.scss b/static/scss/components/_global_layout.scss similarity index 100% rename from scss/components/_global_layout.scss rename to static/scss/components/_global_layout.scss diff --git a/scss/components/_global_navigation.scss b/static/scss/components/_global_navigation.scss similarity index 100% rename from scss/components/_global_navigation.scss rename to static/scss/components/_global_navigation.scss diff --git a/scss/components/_modal.scss b/static/scss/components/_modal.scss similarity index 100% rename from scss/components/_modal.scss rename to static/scss/components/_modal.scss diff --git a/scss/components/_progress_menu.scss b/static/scss/components/_progress_menu.scss similarity index 96% rename from scss/components/_progress_menu.scss rename to static/scss/components/_progress_menu.scss index 3ca7bb72..a675dfb7 100644 --- a/scss/components/_progress_menu.scss +++ b/static/scss/components/_progress_menu.scss @@ -88,7 +88,7 @@ } &--complete:before { - content: url('/static/icons/checkmark.svg'); + content: url('#{$asset-path}/icons/checkmark.svg'); background-color: $color-blue; border: 2px solid $color-blue; font-size: $h6-font-size; @@ -100,4 +100,4 @@ } } -} \ No newline at end of file +} diff --git a/scss/components/_search_bar.scss b/static/scss/components/_search_bar.scss similarity index 95% rename from scss/components/_search_bar.scss rename to static/scss/components/_search_bar.scss index f5c031f8..dbc795d2 100644 --- a/scss/components/_search_bar.scss +++ b/static/scss/components/_search_bar.scss @@ -62,7 +62,7 @@ text-align: center; &:after { - content: url('/static/icons/search.svg'); + content: url('#{$asset-path}/icons/search.svg'); display: inline-block; width: 1.6rem; height: 1.6rem; diff --git a/scss/components/_site_action.scss b/static/scss/components/_site_action.scss similarity index 100% rename from scss/components/_site_action.scss rename to static/scss/components/_site_action.scss diff --git a/scss/components/_topbar.scss b/static/scss/components/_topbar.scss similarity index 100% rename from scss/components/_topbar.scss rename to static/scss/components/_topbar.scss diff --git a/scss/components/_workspace_layout.scss b/static/scss/components/_workspace_layout.scss similarity index 100% rename from scss/components/_workspace_layout.scss rename to static/scss/components/_workspace_layout.scss diff --git a/scss/core/_grid.scss b/static/scss/core/_grid.scss similarity index 100% rename from scss/core/_grid.scss rename to static/scss/core/_grid.scss diff --git a/scss/core/_util.scss b/static/scss/core/_util.scss similarity index 100% rename from scss/core/_util.scss rename to static/scss/core/_util.scss diff --git a/scss/core/_variables.scss b/static/scss/core/_variables.scss similarity index 100% rename from scss/core/_variables.scss rename to static/scss/core/_variables.scss diff --git a/scss/elements/_action_group.scss b/static/scss/elements/_action_group.scss similarity index 100% rename from scss/elements/_action_group.scss rename to static/scss/elements/_action_group.scss diff --git a/scss/elements/_block_lists.scss b/static/scss/elements/_block_lists.scss similarity index 100% rename from scss/elements/_block_lists.scss rename to static/scss/elements/_block_lists.scss diff --git a/scss/elements/_buttons.scss b/static/scss/elements/_buttons.scss similarity index 100% rename from scss/elements/_buttons.scss rename to static/scss/elements/_buttons.scss diff --git a/scss/elements/_diff.scss b/static/scss/elements/_diff.scss similarity index 100% rename from scss/elements/_diff.scss rename to static/scss/elements/_diff.scss diff --git a/scss/elements/_icon_link.scss b/static/scss/elements/_icon_link.scss similarity index 100% rename from scss/elements/_icon_link.scss rename to static/scss/elements/_icon_link.scss diff --git a/scss/elements/_icons.scss b/static/scss/elements/_icons.scss similarity index 100% rename from scss/elements/_icons.scss rename to static/scss/elements/_icons.scss diff --git a/scss/elements/_inputs.scss b/static/scss/elements/_inputs.scss similarity index 100% rename from scss/elements/_inputs.scss rename to static/scss/elements/_inputs.scss diff --git a/scss/elements/_labels.scss b/static/scss/elements/_labels.scss similarity index 100% rename from scss/elements/_labels.scss rename to static/scss/elements/_labels.scss diff --git a/scss/elements/_panels.scss b/static/scss/elements/_panels.scss similarity index 100% rename from scss/elements/_panels.scss rename to static/scss/elements/_panels.scss diff --git a/scss/elements/_sidenav.scss b/static/scss/elements/_sidenav.scss similarity index 100% rename from scss/elements/_sidenav.scss rename to static/scss/elements/_sidenav.scss diff --git a/scss/elements/_tables.scss b/static/scss/elements/_tables.scss similarity index 100% rename from scss/elements/_tables.scss rename to static/scss/elements/_tables.scss diff --git a/scss/elements/_typography.scss b/static/scss/elements/_typography.scss similarity index 100% rename from scss/elements/_typography.scss rename to static/scss/elements/_typography.scss diff --git a/scss/sections/_login.scss b/static/scss/sections/_login.scss similarity index 100% rename from scss/sections/_login.scss rename to static/scss/sections/_login.scss diff --git a/scss/sections/_member_edit.scss b/static/scss/sections/_member_edit.scss similarity index 100% rename from scss/sections/_member_edit.scss rename to static/scss/sections/_member_edit.scss diff --git a/scss/sections/_project_edit.scss b/static/scss/sections/_project_edit.scss similarity index 100% rename from scss/sections/_project_edit.scss rename to static/scss/sections/_project_edit.scss diff --git a/scss/sections/_projects_list.scss b/static/scss/sections/_projects_list.scss similarity index 100% rename from scss/sections/_projects_list.scss rename to static/scss/sections/_projects_list.scss diff --git a/scss/sections/_request_approval.scss b/static/scss/sections/_request_approval.scss similarity index 100% rename from scss/sections/_request_approval.scss rename to static/scss/sections/_request_approval.scss diff --git a/templates/base.html b/templates/base.html index 2414f6f1..aaae0374 100644 --- a/templates/base.html +++ b/templates/base.html @@ -8,9 +8,7 @@ {% block title %}JEDI{% endblock %} - {% assets "css" %} - - {% endassets %} + @@ -34,5 +32,6 @@ {% include 'footer.html' %} {% block modal %}{% endblock %} + diff --git a/templates/home.html b/templates/home.html index 0df70037..056d62b8 100644 --- a/templates/home.html +++ b/templates/home.html @@ -5,6 +5,7 @@

    Home

    +
    diff --git a/yarn.lock b/yarn.lock index ca8a5e51..b8e561fc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -78,6 +78,10 @@ alphanum-sort@^1.0.0, alphanum-sort@^1.0.1, alphanum-sort@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" +amdefine@>=0.0.4: + version "1.0.1" + resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" + ansi-align@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-2.0.0.tgz#c36aeccba563b89ceb556f3690f0b1d9e3547f7f" @@ -168,6 +172,10 @@ array-filter@~0.0.0: version "0.0.1" resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-0.0.1.tgz#7da8cf2e26628ed732803581fd21f67cacd2eeec" +array-find-index@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" + array-foreach@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/array-foreach/-/array-foreach-1.0.2.tgz#cd36e42f0f482108c406b35c3612a8970b2fccea" @@ -222,6 +230,10 @@ async-each@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" +async-foreach@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/async-foreach/-/async-foreach-0.1.3.tgz#36121f845c0578172de419a97dbeb1d16ec34542" + async-limiter@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" @@ -1115,6 +1127,21 @@ call-me-maybe@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b" +camelcase-keys@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" + dependencies: + camelcase "^2.0.0" + map-obj "^1.0.0" + +camelcase@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" + +camelcase@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" + camelcase@^4.0.0, camelcase@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" @@ -1153,7 +1180,7 @@ caseless@~0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" -chalk@^1.1.3: +chalk@^1.1.1, chalk@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" dependencies: @@ -1544,6 +1571,13 @@ create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: safe-buffer "^5.0.1" sha.js "^2.4.8" +cross-spawn@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-3.0.1.tgz#1256037ecb9f0c5f79e3d6ef135e30770184b982" + dependencies: + lru-cache "^4.0.1" + which "^1.2.9" + cross-spawn@^5.0.1: version "5.1.0" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" @@ -1750,6 +1784,12 @@ csso@~2.3.1: clap "^1.0.9" source-map "^0.5.3" +currently-unhandled@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" + dependencies: + array-find-index "^1.0.1" + cyclist@~0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640" @@ -1783,7 +1823,7 @@ debug@3.1.0, debug@^3.1.0: dependencies: ms "2.0.0" -debuglog@*, debuglog@^1.0.1: +debuglog@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" @@ -2280,6 +2320,13 @@ find-npm-prefix@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/find-npm-prefix/-/find-npm-prefix-1.0.2.tgz#8d8ce2c78b3b4b9e66c8acc6a37c231eb841cfdf" +find-up@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" + dependencies: + path-exists "^2.0.0" + pinkie-promise "^2.0.0" + find-up@^2.0.0, find-up@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" @@ -2415,6 +2462,12 @@ gauge@~2.7.3: strip-ansi "^3.0.1" wide-align "^1.1.0" +gaze@^1.0.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/gaze/-/gaze-1.1.3.tgz#c441733e13b927ac8c0ff0b4c3b033f28812924a" + dependencies: + globule "^1.0.0" + genfun@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/genfun/-/genfun-4.0.1.tgz#ed10041f2e4a7f1b0a38466d17a5c3e27df1dfc1" @@ -2444,6 +2497,10 @@ get-port@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/get-port/-/get-port-3.2.0.tgz#dd7ce7de187c06c8bf353796ac71e099f0980ebc" +get-stdin@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" + get-stream@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" @@ -2469,7 +2526,17 @@ glob-to-regexp@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab" -glob@^7.0.3, glob@^7.0.5, glob@^7.1.0, glob@^7.1.1, glob@^7.1.2, glob@~7.1.2: +glob@^6.0.4: + version "6.0.4" + resolved "https://registry.yarnpkg.com/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22" + dependencies: + inflight "^1.0.4" + inherits "2" + minimatch "2 || 3" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.0, glob@^7.1.1, glob@^7.1.2, glob@~7.1.1, glob@~7.1.2: version "7.1.2" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" dependencies: @@ -2490,6 +2557,14 @@ globals@^9.18.0: version "9.18.0" resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" +globule@^1.0.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/globule/-/globule-1.2.1.tgz#5dffb1b191f22d20797a9369b49eab4e9839696d" + dependencies: + glob "~7.1.1" + lodash "~4.17.10" + minimatch "~3.0.2" + got@^6.7.1: version "6.7.1" resolved "https://registry.yarnpkg.com/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0" @@ -2763,10 +2838,20 @@ import-lazy@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" -imurmurhash@*, imurmurhash@^0.1.4: +imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" +in-publish@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/in-publish/-/in-publish-2.0.0.tgz#e20ff5e3a2afc2690320b6dc552682a9c7fadf51" + +indent-string@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" + dependencies: + repeating "^2.0.0" + indexes-of@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607" @@ -3074,6 +3159,10 @@ is-url@^1.2.2: version "1.2.4" resolved "https://registry.yarnpkg.com/is-url/-/is-url-1.2.4.tgz#04a4df46d28c4cff3d73d01ff06abeb318a1aa52" +is-utf8@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" + is-windows@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" @@ -3112,7 +3201,7 @@ isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" -js-base64@^2.1.9: +js-base64@^2.1.8, js-base64@^2.1.9: version "2.4.8" resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.4.8.tgz#57a9b130888f956834aa40c5b165ba59c758f033" @@ -3315,6 +3404,16 @@ libnpx@^10.2.0: y18n "^4.0.0" yargs "^11.0.0" +load-json-file@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + pinkie-promise "^2.0.0" + strip-bom "^2.0.0" + load-json-file@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" @@ -3344,10 +3443,6 @@ lockfile@^1.0.4: dependencies: signal-exit "^3.0.2" -lodash._baseindexof@*: - version "3.1.0" - resolved "https://registry.yarnpkg.com/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz#fe52b53a1c6761e42618d654e4a25789ed61822c" - lodash._baseuniq@~4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz#0ebb44e456814af7905c6212fa2c9b2d51b841e8" @@ -3355,37 +3450,23 @@ lodash._baseuniq@~4.6.0: lodash._createset "~4.0.0" lodash._root "~3.0.0" -lodash._bindcallback@*: - version "3.0.1" - resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" - -lodash._cacheindexof@*: - version "3.0.2" - resolved "https://registry.yarnpkg.com/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz#3dc69ac82498d2ee5e3ce56091bafd2adc7bde92" - -lodash._createcache@*: - version "3.1.2" - resolved "https://registry.yarnpkg.com/lodash._createcache/-/lodash._createcache-3.1.2.tgz#56d6a064017625e79ebca6b8018e17440bdcf093" - dependencies: - lodash._getnative "^3.0.0" - lodash._createset@~4.0.0: version "4.0.3" resolved "https://registry.yarnpkg.com/lodash._createset/-/lodash._createset-4.0.3.tgz#0f4659fbb09d75194fa9e2b88a6644d363c9fe26" -lodash._getnative@*, lodash._getnative@^3.0.0: - version "3.9.1" - resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" - lodash._root@~3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692" +lodash.assign@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" + lodash.clone@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.clone/-/lodash.clone-4.5.0.tgz#195870450f5a13192478df4bc3d23d2dea1907b6" -lodash.clonedeep@~4.5.0: +lodash.clonedeep@^4.3.2, lodash.clonedeep@~4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" @@ -3401,9 +3482,9 @@ lodash.memoize@~3.0.3: version "3.0.4" resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-3.0.4.tgz#2dcbd2c287cbc0a55cc42328bd0c736150d53e3f" -lodash.restparam@*: - version "3.6.1" - resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" +lodash.mergewith@^4.6.0: + version "4.6.1" + resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.1.tgz#639057e726c3afbdb3e7d42741caa8d6e4335927" lodash.union@~4.6.0: version "4.6.0" @@ -3417,7 +3498,7 @@ lodash.without@~4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.without/-/lodash.without-4.4.0.tgz#3cd4574a00b67bae373a94b748772640507b7aac" -lodash@^4.17.4: +lodash@^4.0.0, lodash@^4.17.4, lodash@~4.17.10: version "4.17.10" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" @@ -3433,6 +3514,13 @@ loose-envify@^1.0.0: dependencies: js-tokens "^3.0.0 || ^4.0.0" +loud-rejection@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" + dependencies: + currently-unhandled "^0.4.1" + signal-exit "^3.0.0" + lowercase-keys@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" @@ -3498,6 +3586,10 @@ map-cache@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" +map-obj@^1.0.0, map-obj@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" + map-visit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" @@ -3533,6 +3625,21 @@ mem@^1.1.0: dependencies: mimic-fn "^1.0.0" +meow@^3.7.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" + dependencies: + camelcase-keys "^2.0.0" + decamelize "^1.1.2" + loud-rejection "^1.0.0" + map-obj "^1.0.1" + minimist "^1.1.3" + normalize-package-data "^2.3.4" + object-assign "^4.0.1" + read-pkg-up "^1.0.1" + redent "^1.0.0" + trim-newlines "^1.0.0" + merge-source-map@1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/merge-source-map/-/merge-source-map-1.0.4.tgz#a5de46538dae84d4114cc5ea02b4772a6346701f" @@ -3594,7 +3701,7 @@ minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" -minimatch@^3.0.2, minimatch@^3.0.4: +"minimatch@2 || 3", minimatch@^3.0.2, minimatch@^3.0.4, minimatch@~3.0.2: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" dependencies: @@ -3707,7 +3814,7 @@ mute-stream@~0.0.4: version "0.0.7" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" -nan@^2.0.7, nan@^2.9.2: +nan@^2.0.7, nan@^2.10.0, nan@^2.9.2: version "2.10.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f" @@ -3751,7 +3858,7 @@ node-forge@^0.7.1: version "0.7.5" resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.7.5.tgz#6c152c345ce11c52f465c2abd957e8639cd674df" -node-gyp@^3.6.2, node-gyp@^3.7.0: +node-gyp@^3.3.1, node-gyp@^3.6.2, node-gyp@^3.7.0: version "3.7.0" resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.7.0.tgz#789478e8f6c45e277aa014f3e28f958f286f9203" dependencies: @@ -3817,6 +3924,30 @@ node-releases@^1.0.0-alpha.10: dependencies: semver "^5.3.0" +node-sass@^4.9.2: + version "4.9.2" + resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.9.2.tgz#5e63fe6bd0f2ae3ac9d6c14ede8620e2b8bdb437" + dependencies: + async-foreach "^0.1.3" + chalk "^1.1.1" + cross-spawn "^3.0.0" + gaze "^1.0.0" + get-stdin "^4.0.1" + glob "^7.0.3" + in-publish "^2.0.0" + lodash.assign "^4.2.0" + lodash.clonedeep "^4.3.2" + lodash.mergewith "^4.6.0" + meow "^3.7.0" + mkdirp "^0.5.1" + nan "^2.10.0" + node-gyp "^3.3.1" + npmlog "^4.0.0" + request "2.87.0" + sass-graph "^2.2.4" + stdout-stream "^1.4.0" + "true-case-path" "^1.0.2" + "nopt@2 || 3", nopt@~3.0.1: version "3.0.6" resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" @@ -3830,7 +3961,7 @@ nopt@^4.0.1, nopt@~4.0.1: abbrev "1" osenv "^0.1.4" -normalize-package-data@^2.0.0, normalize-package-data@^2.3.2, normalize-package-data@^2.4.0, "normalize-package-data@~1.0.1 || ^2.0.0", normalize-package-data@~2.4.0: +normalize-package-data@^2.0.0, normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, normalize-package-data@^2.4.0, "normalize-package-data@~1.0.1 || ^2.0.0", normalize-package-data@~2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" dependencies: @@ -4092,7 +4223,7 @@ npm@^6.0.1: worker-farm "^1.6.0" write-file-atomic "^2.3.0" -"npmlog@0 || 1 || 2 || 3 || 4", "npmlog@2 || ^3.1.0 || ^4.0.0", npmlog@^4.0.2, npmlog@~4.1.2: +"npmlog@0 || 1 || 2 || 3 || 4", "npmlog@2 || ^3.1.0 || ^4.0.0", npmlog@^4.0.0, npmlog@^4.0.2, npmlog@~4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" dependencies: @@ -4229,6 +4360,12 @@ os-homedir@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" +os-locale@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" + dependencies: + lcid "^1.0.0" + os-locale@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2" @@ -4431,6 +4568,12 @@ path-dirname@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" +path-exists@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" + dependencies: + pinkie-promise "^2.0.0" + path-exists@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" @@ -4455,6 +4598,14 @@ path-platform@~0.11.15: version "0.11.15" resolved "https://registry.yarnpkg.com/path-platform/-/path-platform-0.11.15.tgz#e864217f74c36850f0852b78dc7bf7d4a5721bf2" +path-type@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" + dependencies: + graceful-fs "^4.1.2" + pify "^2.0.0" + pinkie-promise "^2.0.0" + path-type@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" @@ -4491,6 +4642,16 @@ pify@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + posix-character-classes@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" @@ -5188,6 +5349,13 @@ read-package-tree@^5.2.1: read-package-json "^2.0.0" readdir-scoped-modules "^1.0.0" +read-pkg-up@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" + dependencies: + find-up "^1.0.0" + read-pkg "^1.0.0" + read-pkg-up@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" @@ -5195,6 +5363,14 @@ read-pkg-up@^2.0.0: find-up "^2.0.0" read-pkg "^2.0.0" +read-pkg@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" + dependencies: + load-json-file "^1.0.0" + normalize-package-data "^2.3.2" + path-type "^1.0.0" + read-pkg@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" @@ -5209,7 +5385,7 @@ read@1, read@~1.0.1, read@~1.0.7: dependencies: mute-stream "~0.0.4" -"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.3: +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.3: version "2.3.6" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" dependencies: @@ -5241,7 +5417,7 @@ readable-stream@~2.0.0: string_decoder "~0.10.x" util-deprecate "~1.0.1" -readdir-scoped-modules@*, readdir-scoped-modules@^1.0.0: +readdir-scoped-modules@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/readdir-scoped-modules/-/readdir-scoped-modules-1.0.2.tgz#9fafa37d286be5d92cbaebdee030dc9b5f406747" dependencies: @@ -5268,6 +5444,13 @@ receptor@^1.0.0: matches-selector "^1.0.0" object-assign "^4.1.0" +redent@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" + dependencies: + indent-string "^2.1.0" + strip-indent "^1.0.1" + reduce-css-calc@^1.2.6: version "1.3.0" resolved "https://registry.yarnpkg.com/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz#747c914e049614a4c9cfbba629871ad1d2927716" @@ -5361,6 +5544,31 @@ repeating@^2.0.0: dependencies: is-finite "^1.0.0" +request@2.87.0, request@^2.74.0, request@^2.81.0: + version "2.87.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.87.0.tgz#32f00235cd08d482b4d0d68db93a829c0ed5756e" + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.6.0" + caseless "~0.12.0" + combined-stream "~1.0.5" + extend "~3.0.1" + forever-agent "~0.6.1" + form-data "~2.3.1" + har-validator "~5.0.3" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.17" + oauth-sign "~0.8.2" + performance-now "^2.1.0" + qs "~6.5.1" + safe-buffer "^5.1.1" + tough-cookie "~2.3.3" + tunnel-agent "^0.6.0" + uuid "^3.1.0" + "request@>=2.9.0 <2.82.0": version "2.81.0" resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" @@ -5388,31 +5596,6 @@ repeating@^2.0.0: tunnel-agent "^0.6.0" uuid "^3.0.0" -request@^2.74.0, request@^2.81.0: - version "2.87.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.87.0.tgz#32f00235cd08d482b4d0d68db93a829c0ed5756e" - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.6.0" - caseless "~0.12.0" - combined-stream "~1.0.5" - extend "~3.0.1" - forever-agent "~0.6.1" - form-data "~2.3.1" - har-validator "~5.0.3" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.17" - oauth-sign "~0.8.2" - performance-now "^2.1.0" - qs "~6.5.1" - safe-buffer "^5.1.1" - tough-cookie "~2.3.3" - tunnel-agent "^0.6.0" - uuid "^3.1.0" - require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" @@ -5509,10 +5692,26 @@ safer-eval@^1.2.3: dependencies: clones "^1.1.0" +sass-graph@^2.2.4: + version "2.2.4" + resolved "https://registry.yarnpkg.com/sass-graph/-/sass-graph-2.2.4.tgz#13fbd63cd1caf0908b9fd93476ad43a51d1e0b49" + dependencies: + glob "^7.0.0" + lodash "^4.0.0" + scss-tokenizer "^0.2.3" + yargs "^7.0.0" + sax@^1.2.4, sax@~1.2.1, sax@~1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" +scss-tokenizer@^0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz#8eb06db9a9723333824d3f5530641149847ce5d1" + dependencies: + js-base64 "^2.1.8" + source-map "^0.4.2" + semver-diff@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36" @@ -5782,6 +5981,12 @@ source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" +source-map@^0.4.2: + version "0.4.4" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" + dependencies: + amdefine ">=0.0.4" + source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.3: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" @@ -5887,6 +6092,12 @@ statuses@~1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" +stdout-stream@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/stdout-stream/-/stdout-stream-1.4.0.tgz#a2c7c8587e54d9427ea9edb3ac3f2cd522df378b" + dependencies: + readable-stream "^2.0.1" + stream-browserify@^2.0.0, stream-browserify@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db" @@ -5944,7 +6155,7 @@ strict-uri-encode@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546" -string-width@^1.0.1: +string-width@^1.0.1, string-width@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" dependencies: @@ -5989,6 +6200,12 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" +strip-bom@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" + dependencies: + is-utf8 "^0.2.0" + strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" @@ -5997,6 +6214,12 @@ strip-eof@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" +strip-indent@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" + dependencies: + get-stdin "^4.0.1" + strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" @@ -6189,10 +6412,20 @@ tough-cookie@~2.3.0, tough-cookie@~2.3.3: dependencies: punycode "^1.4.1" +trim-newlines@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" + trim-right@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" +"true-case-path@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/true-case-path/-/true-case-path-1.0.2.tgz#7ec91130924766c7f573be3020c34f8fdfd00d62" + dependencies: + glob "^6.0.4" + tty-browserify@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" @@ -6456,6 +6689,10 @@ whet.extend@~0.9.9: version "0.9.9" resolved "https://registry.yarnpkg.com/whet.extend/-/whet.extend-0.9.9.tgz#f877d5bf648c97e5aa542fadc16d6a259b9c11a1" +which-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" + which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" @@ -6537,6 +6774,12 @@ yallist@^3.0.0, yallist@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.2.tgz#8452b4bb7e83c7c188d8041c1a837c773d6d8bb9" +yargs-parser@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-5.0.0.tgz#275ecf0d7ffe05c77e64e7c86e4cd94bf0e1228a" + dependencies: + camelcase "^3.0.0" + yargs-parser@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-7.0.0.tgz#8d0ac42f16ea55debd332caf4c4038b3e3f5dfd9" @@ -6566,6 +6809,24 @@ yargs@^11.0.0: y18n "^3.2.1" yargs-parser "^9.0.2" +yargs@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-7.1.0.tgz#6ba318eb16961727f5d284f8ea003e8d6154d0c8" + dependencies: + camelcase "^3.0.0" + cliui "^3.2.0" + decamelize "^1.1.1" + get-caller-file "^1.0.1" + os-locale "^1.4.0" + read-pkg-up "^1.0.1" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^1.0.2" + which-module "^1.0.0" + y18n "^3.2.1" + yargs-parser "^5.0.0" + yargs@^8.0.2: version "8.0.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-8.0.2.tgz#6299a9055b1cefc969ff7e79c1d918dceb22c360" From c4dde6beedc4563e338af19e403225acd0009154 Mon Sep 17 00:00:00 2001 From: Patrick Smith Date: Thu, 2 Aug 2018 14:33:21 -0400 Subject: [PATCH 253/332] Move styles to "styles" directory --- static/js/index.js | 2 +- static/{scss => styles}/README.md | 0 static/{scss => styles}/atat.scss | 0 static/{scss => styles}/components/_alerts.scss | 0 static/{scss => styles}/components/_empty_state.scss | 0 static/{scss => styles}/components/_footer.scss | 0 static/{scss => styles}/components/_global_layout.scss | 0 static/{scss => styles}/components/_global_navigation.scss | 0 static/{scss => styles}/components/_modal.scss | 0 static/{scss => styles}/components/_progress_menu.scss | 0 static/{scss => styles}/components/_search_bar.scss | 0 static/{scss => styles}/components/_site_action.scss | 0 static/{scss => styles}/components/_topbar.scss | 0 static/{scss => styles}/components/_workspace_layout.scss | 0 static/{scss => styles}/core/_grid.scss | 0 static/{scss => styles}/core/_util.scss | 0 static/{scss => styles}/core/_variables.scss | 0 static/{scss => styles}/elements/_action_group.scss | 0 static/{scss => styles}/elements/_block_lists.scss | 0 static/{scss => styles}/elements/_buttons.scss | 0 static/{scss => styles}/elements/_diff.scss | 0 static/{scss => styles}/elements/_icon_link.scss | 0 static/{scss => styles}/elements/_icons.scss | 0 static/{scss => styles}/elements/_inputs.scss | 0 static/{scss => styles}/elements/_labels.scss | 0 static/{scss => styles}/elements/_panels.scss | 0 static/{scss => styles}/elements/_sidenav.scss | 0 static/{scss => styles}/elements/_tables.scss | 0 static/{scss => styles}/elements/_typography.scss | 0 static/{scss => styles}/sections/_login.scss | 0 static/{scss => styles}/sections/_member_edit.scss | 0 static/{scss => styles}/sections/_project_edit.scss | 0 static/{scss => styles}/sections/_projects_list.scss | 0 static/{scss => styles}/sections/_request_approval.scss | 0 34 files changed, 1 insertion(+), 1 deletion(-) rename static/{scss => styles}/README.md (100%) rename static/{scss => styles}/atat.scss (100%) rename static/{scss => styles}/components/_alerts.scss (100%) rename static/{scss => styles}/components/_empty_state.scss (100%) rename static/{scss => styles}/components/_footer.scss (100%) rename static/{scss => styles}/components/_global_layout.scss (100%) rename static/{scss => styles}/components/_global_navigation.scss (100%) rename static/{scss => styles}/components/_modal.scss (100%) rename static/{scss => styles}/components/_progress_menu.scss (100%) rename static/{scss => styles}/components/_search_bar.scss (100%) rename static/{scss => styles}/components/_site_action.scss (100%) rename static/{scss => styles}/components/_topbar.scss (100%) rename static/{scss => styles}/components/_workspace_layout.scss (100%) rename static/{scss => styles}/core/_grid.scss (100%) rename static/{scss => styles}/core/_util.scss (100%) rename static/{scss => styles}/core/_variables.scss (100%) rename static/{scss => styles}/elements/_action_group.scss (100%) rename static/{scss => styles}/elements/_block_lists.scss (100%) rename static/{scss => styles}/elements/_buttons.scss (100%) rename static/{scss => styles}/elements/_diff.scss (100%) rename static/{scss => styles}/elements/_icon_link.scss (100%) rename static/{scss => styles}/elements/_icons.scss (100%) rename static/{scss => styles}/elements/_inputs.scss (100%) rename static/{scss => styles}/elements/_labels.scss (100%) rename static/{scss => styles}/elements/_panels.scss (100%) rename static/{scss => styles}/elements/_sidenav.scss (100%) rename static/{scss => styles}/elements/_tables.scss (100%) rename static/{scss => styles}/elements/_typography.scss (100%) rename static/{scss => styles}/sections/_login.scss (100%) rename static/{scss => styles}/sections/_member_edit.scss (100%) rename static/{scss => styles}/sections/_project_edit.scss (100%) rename static/{scss => styles}/sections/_projects_list.scss (100%) rename static/{scss => styles}/sections/_request_approval.scss (100%) diff --git a/static/js/index.js b/static/js/index.js index 9cc49957..91a30f3e 100644 --- a/static/js/index.js +++ b/static/js/index.js @@ -1,4 +1,4 @@ -import classes from '../scss/atat.scss' +import classes from '../styles/atat.scss' import './thing' diff --git a/static/scss/README.md b/static/styles/README.md similarity index 100% rename from static/scss/README.md rename to static/styles/README.md diff --git a/static/scss/atat.scss b/static/styles/atat.scss similarity index 100% rename from static/scss/atat.scss rename to static/styles/atat.scss diff --git a/static/scss/components/_alerts.scss b/static/styles/components/_alerts.scss similarity index 100% rename from static/scss/components/_alerts.scss rename to static/styles/components/_alerts.scss diff --git a/static/scss/components/_empty_state.scss b/static/styles/components/_empty_state.scss similarity index 100% rename from static/scss/components/_empty_state.scss rename to static/styles/components/_empty_state.scss diff --git a/static/scss/components/_footer.scss b/static/styles/components/_footer.scss similarity index 100% rename from static/scss/components/_footer.scss rename to static/styles/components/_footer.scss diff --git a/static/scss/components/_global_layout.scss b/static/styles/components/_global_layout.scss similarity index 100% rename from static/scss/components/_global_layout.scss rename to static/styles/components/_global_layout.scss diff --git a/static/scss/components/_global_navigation.scss b/static/styles/components/_global_navigation.scss similarity index 100% rename from static/scss/components/_global_navigation.scss rename to static/styles/components/_global_navigation.scss diff --git a/static/scss/components/_modal.scss b/static/styles/components/_modal.scss similarity index 100% rename from static/scss/components/_modal.scss rename to static/styles/components/_modal.scss diff --git a/static/scss/components/_progress_menu.scss b/static/styles/components/_progress_menu.scss similarity index 100% rename from static/scss/components/_progress_menu.scss rename to static/styles/components/_progress_menu.scss diff --git a/static/scss/components/_search_bar.scss b/static/styles/components/_search_bar.scss similarity index 100% rename from static/scss/components/_search_bar.scss rename to static/styles/components/_search_bar.scss diff --git a/static/scss/components/_site_action.scss b/static/styles/components/_site_action.scss similarity index 100% rename from static/scss/components/_site_action.scss rename to static/styles/components/_site_action.scss diff --git a/static/scss/components/_topbar.scss b/static/styles/components/_topbar.scss similarity index 100% rename from static/scss/components/_topbar.scss rename to static/styles/components/_topbar.scss diff --git a/static/scss/components/_workspace_layout.scss b/static/styles/components/_workspace_layout.scss similarity index 100% rename from static/scss/components/_workspace_layout.scss rename to static/styles/components/_workspace_layout.scss diff --git a/static/scss/core/_grid.scss b/static/styles/core/_grid.scss similarity index 100% rename from static/scss/core/_grid.scss rename to static/styles/core/_grid.scss diff --git a/static/scss/core/_util.scss b/static/styles/core/_util.scss similarity index 100% rename from static/scss/core/_util.scss rename to static/styles/core/_util.scss diff --git a/static/scss/core/_variables.scss b/static/styles/core/_variables.scss similarity index 100% rename from static/scss/core/_variables.scss rename to static/styles/core/_variables.scss diff --git a/static/scss/elements/_action_group.scss b/static/styles/elements/_action_group.scss similarity index 100% rename from static/scss/elements/_action_group.scss rename to static/styles/elements/_action_group.scss diff --git a/static/scss/elements/_block_lists.scss b/static/styles/elements/_block_lists.scss similarity index 100% rename from static/scss/elements/_block_lists.scss rename to static/styles/elements/_block_lists.scss diff --git a/static/scss/elements/_buttons.scss b/static/styles/elements/_buttons.scss similarity index 100% rename from static/scss/elements/_buttons.scss rename to static/styles/elements/_buttons.scss diff --git a/static/scss/elements/_diff.scss b/static/styles/elements/_diff.scss similarity index 100% rename from static/scss/elements/_diff.scss rename to static/styles/elements/_diff.scss diff --git a/static/scss/elements/_icon_link.scss b/static/styles/elements/_icon_link.scss similarity index 100% rename from static/scss/elements/_icon_link.scss rename to static/styles/elements/_icon_link.scss diff --git a/static/scss/elements/_icons.scss b/static/styles/elements/_icons.scss similarity index 100% rename from static/scss/elements/_icons.scss rename to static/styles/elements/_icons.scss diff --git a/static/scss/elements/_inputs.scss b/static/styles/elements/_inputs.scss similarity index 100% rename from static/scss/elements/_inputs.scss rename to static/styles/elements/_inputs.scss diff --git a/static/scss/elements/_labels.scss b/static/styles/elements/_labels.scss similarity index 100% rename from static/scss/elements/_labels.scss rename to static/styles/elements/_labels.scss diff --git a/static/scss/elements/_panels.scss b/static/styles/elements/_panels.scss similarity index 100% rename from static/scss/elements/_panels.scss rename to static/styles/elements/_panels.scss diff --git a/static/scss/elements/_sidenav.scss b/static/styles/elements/_sidenav.scss similarity index 100% rename from static/scss/elements/_sidenav.scss rename to static/styles/elements/_sidenav.scss diff --git a/static/scss/elements/_tables.scss b/static/styles/elements/_tables.scss similarity index 100% rename from static/scss/elements/_tables.scss rename to static/styles/elements/_tables.scss diff --git a/static/scss/elements/_typography.scss b/static/styles/elements/_typography.scss similarity index 100% rename from static/scss/elements/_typography.scss rename to static/styles/elements/_typography.scss diff --git a/static/scss/sections/_login.scss b/static/styles/sections/_login.scss similarity index 100% rename from static/scss/sections/_login.scss rename to static/styles/sections/_login.scss diff --git a/static/scss/sections/_member_edit.scss b/static/styles/sections/_member_edit.scss similarity index 100% rename from static/scss/sections/_member_edit.scss rename to static/styles/sections/_member_edit.scss diff --git a/static/scss/sections/_project_edit.scss b/static/styles/sections/_project_edit.scss similarity index 100% rename from static/scss/sections/_project_edit.scss rename to static/styles/sections/_project_edit.scss diff --git a/static/scss/sections/_projects_list.scss b/static/styles/sections/_projects_list.scss similarity index 100% rename from static/scss/sections/_projects_list.scss rename to static/styles/sections/_projects_list.scss diff --git a/static/scss/sections/_request_approval.scss b/static/styles/sections/_request_approval.scss similarity index 100% rename from static/scss/sections/_request_approval.scss rename to static/styles/sections/_request_approval.scss From 7377dd1f3f5916046ef95aa9a242de6f473dc896 Mon Sep 17 00:00:00 2001 From: Patrick Smith Date: Thu, 2 Aug 2018 14:54:07 -0400 Subject: [PATCH 254/332] Use flask-webassets to version js/css bundle --- atst/assets.py | 12 ++++++++---- package.json | 2 +- templates/base.html | 8 ++++++-- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/atst/assets.py b/atst/assets.py index aef6b35e..6c8fd7e8 100644 --- a/atst/assets.py +++ b/atst/assets.py @@ -4,10 +4,14 @@ from atst.home import home environment = Environment() css = Bundle( - "../scss/atat.scss", - filters="scss", - output="../static/assets/out.%(version)s.css", - depends=("**/*.scss"), + "../static/assets/index.css", + output="../static/assets/styles.%(version)s.css", ) environment.register("css", css) + +js = Bundle( + '../static/assets/index.js', + output='../static/assets/index.%(version)s.js' +) +environment.register('js_all', js) diff --git a/package.json b/package.json index 4d7b794e..421c767b 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "index.js", "scripts": { "watch": "parcel watch static/js/index.js -d static/assets -o index.js --no-autoinstall", - "build": "parcel build static/js/index.js -d static/assets -o index.js --no-autoinstall", + "build": "parcel build static/js/index.js -d static/assets -o index.js", "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", diff --git a/templates/base.html b/templates/base.html index aaae0374..acc3e6e7 100644 --- a/templates/base.html +++ b/templates/base.html @@ -8,7 +8,9 @@ {% block title %}JEDI{% endblock %} - + {% assets "css" %} + + {% endassets %} @@ -32,6 +34,8 @@ {% include 'footer.html' %} {% block modal %}{% endblock %} - + {% assets "js_all" %} + {% endassets %} From d45b4354f91941e70132d4d467f6c7301aed0cb2 Mon Sep 17 00:00:00 2001 From: Andrew Croce Date: Fri, 3 Aug 2018 09:10:40 -0400 Subject: [PATCH 268/332] Remove styles and js from assets --- static/js/index.js | 4 - static/js/thing.js | 7 - static/styles/README.md | 82 ------ static/styles/atat.scss | 36 --- static/styles/components/_alerts.scss | 76 ------ static/styles/components/_empty_state.scss | 27 -- static/styles/components/_footer.scss | 6 - static/styles/components/_global_layout.scss | 36 --- .../styles/components/_global_navigation.scss | 30 --- static/styles/components/_modal.scss | 47 ---- static/styles/components/_progress_menu.scss | 103 -------- static/styles/components/_search_bar.scss | 72 ------ static/styles/components/_site_action.scss | 15 -- static/styles/components/_topbar.scss | 71 ------ .../styles/components/_workspace_layout.scss | 26 -- static/styles/core/_grid.scss | 45 ---- static/styles/core/_util.scss | 33 --- static/styles/core/_variables.scss | 167 ------------ static/styles/elements/_action_group.scss | 19 -- static/styles/elements/_block_lists.scss | 90 ------- static/styles/elements/_buttons.scss | 5 - static/styles/elements/_diff.scss | 36 --- static/styles/elements/_icon_link.scss | 66 ----- static/styles/elements/_icons.scss | 52 ---- static/styles/elements/_inputs.scss | 241 ------------------ static/styles/elements/_labels.scss | 34 --- static/styles/elements/_panels.scss | 67 ----- static/styles/elements/_sidenav.scss | 87 ------- static/styles/elements/_tables.scss | 92 ------- static/styles/elements/_typography.scss | 59 ----- static/styles/sections/_login.scss | 3 - static/styles/sections/_member_edit.scss | 41 --- static/styles/sections/_project_edit.scss | 19 -- static/styles/sections/_projects_list.scss | 22 -- static/styles/sections/_request_approval.scss | 97 ------- 35 files changed, 1913 deletions(-) delete mode 100644 static/js/index.js delete mode 100644 static/js/thing.js delete mode 100644 static/styles/README.md delete mode 100644 static/styles/atat.scss delete mode 100644 static/styles/components/_alerts.scss delete mode 100644 static/styles/components/_empty_state.scss delete mode 100644 static/styles/components/_footer.scss delete mode 100644 static/styles/components/_global_layout.scss delete mode 100644 static/styles/components/_global_navigation.scss delete mode 100644 static/styles/components/_modal.scss delete mode 100644 static/styles/components/_progress_menu.scss delete mode 100644 static/styles/components/_search_bar.scss delete mode 100644 static/styles/components/_site_action.scss delete mode 100644 static/styles/components/_topbar.scss delete mode 100644 static/styles/components/_workspace_layout.scss delete mode 100644 static/styles/core/_grid.scss delete mode 100644 static/styles/core/_util.scss delete mode 100644 static/styles/core/_variables.scss delete mode 100644 static/styles/elements/_action_group.scss delete mode 100644 static/styles/elements/_block_lists.scss delete mode 100644 static/styles/elements/_buttons.scss delete mode 100644 static/styles/elements/_diff.scss delete mode 100644 static/styles/elements/_icon_link.scss delete mode 100644 static/styles/elements/_icons.scss delete mode 100644 static/styles/elements/_inputs.scss delete mode 100644 static/styles/elements/_labels.scss delete mode 100644 static/styles/elements/_panels.scss delete mode 100644 static/styles/elements/_sidenav.scss delete mode 100644 static/styles/elements/_tables.scss delete mode 100644 static/styles/elements/_typography.scss delete mode 100644 static/styles/sections/_login.scss delete mode 100644 static/styles/sections/_member_edit.scss delete mode 100644 static/styles/sections/_project_edit.scss delete mode 100644 static/styles/sections/_projects_list.scss delete mode 100644 static/styles/sections/_request_approval.scss diff --git a/static/js/index.js b/static/js/index.js deleted file mode 100644 index 91a30f3e..00000000 --- a/static/js/index.js +++ /dev/null @@ -1,4 +0,0 @@ -import classes from '../styles/atat.scss' - -import './thing' - diff --git a/static/js/thing.js b/static/js/thing.js deleted file mode 100644 index 033b8cd3..00000000 --- a/static/js/thing.js +++ /dev/null @@ -1,7 +0,0 @@ -console.log('hanlo again') -window.onload = function() { - console.log('boop') - const thing = document.querySelector('#hello') - thing.innerHTML = 'hanlo friendo' -} - diff --git a/static/styles/README.md b/static/styles/README.md deleted file mode 100644 index 2df6de9d..00000000 --- a/static/styles/README.md +++ /dev/null @@ -1,82 +0,0 @@ -# Styling AT-ST - -AT-ST's user interface components are based on the (U.S. Web Design System)[https://designsystem.digital.gov/components/]. Please refer there when deciding how to implement a UI feature. - -## CSS Architecture -### (Copied from https://github.com/uswds/uswds#css-architecture) -## CSS architecture - -* The CSS foundation of this site is built with the **[Sass](https://sass-lang.com)** preprocessor language. -* Uses **[Bourbon](http://bourbon.io/)** for its simple and lightweight Sass mixin library, and the **[Neat](http://neat.bourbon.io/)** library for the grid framework. Bourbon and Neat are open-source products from **[thoughtbot](https://thoughtbot.com/)**. -* The CSS organization and naming conventions follow **[18F’s CSS Front End Guide](https://frontend.18f.gov/css/)**. -* CSS selectors are **prefixed** with `usa` (For example: `.usa-button`). This identifier helps the design system avoid conflicts with other styles on a site which are not part of the U.S. Web Design System. -* Uses a **[modified BEM](https://frontend.18f.gov/css/naming/)** approach created by 18F for naming CSS selectors. Objects in CSS are separated by single dashes. Multi-word objects are separated by an underscore (For example: `.usa-button-cool_feature-active`). -* Uses **modular CSS** for scalable, modular, and flexible code. -* Uses **nesting** when appropriate. Nest minimally with up to two levels of nesting. -* Hard-coded magic numbers are avoided and, if necessary, defined in the `core/variables` scss file. -* Media queries are built **mobile first**. -* **Spacing units** are as much as possible defined as rem or em units so they scale appropriately with text size. Pixels can be used for detail work and should not exceed 5px (For example: 3px borders). - -**For more information, visit:** -[18F’s CSS Front End Guide](https://frontend.18f.gov/css/) - -Overrides and Modifications ---- - -When making modifications to the default USWDS components, please refer to the original source, and make a `.scss` file of the same name. Annotate the top of the file with a reference to the USWDS documentation and source code. - -Row/Column System ---- - -A simple, flexbox-powered row/column system. - -``` -
    -
    -
    -
    -
    -``` - -To make a column expand to fill up all available space relative to its sibling columns: - -``` -
    -
    -
    -
    -
    -``` - -To add uniform padding to rows and columns: - -``` -
    -
    -
    -
    -
    -``` - -Layouts and behaviors for specific row/col use cases should be handled on a case by case basis: - -``` -
    -
    -
    -
    -
    - -... - -.foo.row { - .col { - flex: 1; - } - .foo__bar { - flex: 2; - } -} -``` - -Page templates that inherit from the `base.html` template should render `.col` elements at their top level, with no other wrapping elements. diff --git a/static/styles/atat.scss b/static/styles/atat.scss deleted file mode 100644 index 040cc201..00000000 --- a/static/styles/atat.scss +++ /dev/null @@ -1,36 +0,0 @@ -@import 'core/variables'; -@import '../../node_modules/uswds/src/stylesheets/uswds'; - -@import 'core/grid'; -@import 'core/util'; - -@import 'elements/typography'; -@import 'elements/icons'; -@import 'elements/icon_link'; -@import 'elements/inputs'; -@import 'elements/buttons'; -@import 'elements/panels'; -@import 'elements/block_lists'; -@import 'elements/tables'; -@import 'elements/sidenav'; -@import 'elements/action_group'; -@import 'elements/labels'; -@import 'elements/diff'; - -@import 'components/topbar'; -@import 'components/global_layout'; -@import 'components/global_navigation'; -@import 'components/workspace_layout'; -@import 'components/site_action'; -@import 'components/empty_state'; -@import 'components/alerts'; -@import 'components/modal'; -@import 'components/footer'; -@import 'components/progress_menu.scss'; -@import 'components/search_bar'; - -@import 'sections/login'; -@import 'sections/request_approval'; -@import 'sections/projects_list'; -@import 'sections/project_edit'; -@import 'sections/member_edit'; diff --git a/static/styles/components/_alerts.scss b/static/styles/components/_alerts.scss deleted file mode 100644 index f48042b9..00000000 --- a/static/styles/components/_alerts.scss +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Alerts - * @see https://designsystem.digital.gov/components/alerts/ - * @source https://github.com/uswds/uswds/blob/develop/src/stylesheets/components/_alerts.scss - */ - -@mixin alert { - padding: $gap * 2; - border-left-width: $gap / 2; - border-left-style: solid; - @include panel-margin; -} - -@mixin alert-level($level) { - $background-color: $color-aqua-lightest; - $border-color: $color-blue; - - @if $level == 'success' { - $background-color: $color-green-lightest; - $border-color: $color-green; - - } @else if $level == 'warning' { - $background-color: $color-gold-lightest; - $border-color: $color-gold; - - } @else if $level == 'error' { - $background-color: $color-red-lightest; - $border-color: $color-red; - } - - background-color: $background-color; - border-color: $border-color; - display: flex; - flex-direction: row; - align-items: flex-start; - - .alert__icon { - @include icon-color($border-color); - flex-grow: 0; - flex-shrink: 0; - margin-right: $gap * 2; - margin-left: 0; - } - - .alert__title { - @include h3; - margin-top: 0; - } - - .alert__content { - .alert__message { - &:last-child { - > *:last-child { - margin-bottom: 0; - } - } - } - } -} - -.alert { - @include alert; - @include alert-level('info'); - - &.alert--success { - @include alert-level('success'); - } - - &.alert--warning { - @include alert-level('warning'); - } - - &.alert--error { - @include alert-level('error'); - } -} diff --git a/static/styles/components/_empty_state.scss b/static/styles/components/_empty_state.scss deleted file mode 100644 index be8675ad..00000000 --- a/static/styles/components/_empty_state.scss +++ /dev/null @@ -1,27 +0,0 @@ -.empty-state { - text-align: center; - padding: 6rem ($gap * 2) 0; - display: flex; - flex-direction: column; - align-items: center; - - @include media($medium-screen) { - padding: 8rem ($gap * 4) 0; - } - - .icon { - @include icon-size(50); - @include icon-color($color-gray-light); - } - - p { - @include h2; - line-height: 1.2; - max-width: 15em; - color: $color-gray; - - @include media($large-screen) { - @include h1; - } - } -} diff --git a/static/styles/components/_footer.scss b/static/styles/components/_footer.scss deleted file mode 100644 index 964ff393..00000000 --- a/static/styles/components/_footer.scss +++ /dev/null @@ -1,6 +0,0 @@ -.app-footer { - background-color: $color-gray-lightest; - border-top: 1px solid $color-gray-lighter; - padding-left: $gap*4; - padding-bottom: $gap*2; -} diff --git a/static/styles/components/_global_layout.scss b/static/styles/components/_global_layout.scss deleted file mode 100644 index d79890c5..00000000 --- a/static/styles/components/_global_layout.scss +++ /dev/null @@ -1,36 +0,0 @@ -body { - background-color: $color-gray-lightest; - display: flex; - flex-direction: column; - justify-content: flex-start; - min-height: 100vh; - - > footer { - margin-top: auto; - } - - &.modalOpen { - overflow-y: hidden; - } -} - -.global-layout { - display: flex; - flex-wrap: nowrap; - flex-grow: 1; - - .global-navigation { - margin-top: -1px; - } - - .global-panel-container { - margin: $gap; - max-width: $site-max-width; - overflow-x: hidden; - flex-grow: 1; - - @include media($medium-screen) { - margin: $gap * 2; - } - } -} diff --git a/static/styles/components/_global_navigation.scss b/static/styles/components/_global_navigation.scss deleted file mode 100644 index b975270a..00000000 --- a/static/styles/components/_global_navigation.scss +++ /dev/null @@ -1,30 +0,0 @@ -.global-navigation { - background-color: $color-white; - - .sidenav__link { - padding-right: $gap; - - @include media($large-screen) { - padding-right: $gap * 2; - } - } - - .sidenav__link-label { - @include hide; - - @include media($large-screen) { - @include unhide; - padding-left: $gap; - } - } - - &.global-navigation__context--workspace { - .sidenav__link { - padding-right: $gap; - } - - .sidenav__link-label { - @include hide; - } - } -} diff --git a/static/styles/components/_modal.scss b/static/styles/components/_modal.scss deleted file mode 100644 index 868476b9..00000000 --- a/static/styles/components/_modal.scss +++ /dev/null @@ -1,47 +0,0 @@ -.modal { - position: fixed; - z-index: 3; - left: 0; - right: 0; - top: 0; - bottom: 0; - background-color: $color-overlay; - - .modal__dialog { - padding: $gap; - height: 100vh; - display: flex; - justify-content: center; - align-items: center; - flex-direction: column; - - @include media($medium-screen) { - padding: $gap * 2; - } - - @include media($large-screen) { - padding: $gap * 4; - } - - .modal__body { - background-color: $color-white; - padding: $gap * 2; - flex-grow: 1; - overflow-y: auto; - max-width: 80rem; - - @include media($medium-screen) { - padding: $gap * 4; - flex-grow: 0; - } - - h1, h2 { - @include h3; - } - - :first-child { - margin-top: 0; - } - } - } -} diff --git a/static/styles/components/_progress_menu.scss b/static/styles/components/_progress_menu.scss deleted file mode 100644 index a675dfb7..00000000 --- a/static/styles/components/_progress_menu.scss +++ /dev/null @@ -1,103 +0,0 @@ -.progress-menu { - display: block; - - ul { - list-style: none; - margin: 0; - padding: 0; - } - - &--three { - .progress-menu__item { - width: 32%; - } - } - - &--four { - .progress-menu__item { - width: 24%; - } - } - - &--five { - .progress-menu__item { - width: 19%; - } - } - - &__item { - display: inline-block; - font-weight: $font-bold; - position: relative; - vertical-align: top; - - a { - display: block; - position: relative; - padding: ($gap * 4) ($gap * 2); - margin: 0 ($gap * 2); - text-decoration: none; - text-align: center; - z-index: 2; - color: $color-black; - } - - a.active { - color: $color-blue; - } - - - - &:first-child:after { - display: none; - } - - &:after { - display: inline-block; - height: 1px; - content: " "; - color: $color-gray-lightest; - text-shadow: none; - background-color: $color-gray-light; - position: absolute; - top: 1.1rem; - width: 100%; - right: 50%; - border-right: 2.2rem solid transparent; - border-left: 2.2rem solid transparent; - background-clip: padding-box; - z-index: 1; - } - - &:before { - content: ""; - display: block; - text-align: center; - width: 2rem; - height: 2rem; - border: 1px solid $color-gray; - border-radius: 100%; - position: absolute; - left: 50%; - margin-left: -1rem; - z-index: 1; - } - - &--active:before { - border: 2px solid $color-blue; - } - - &--complete:before { - content: url('#{$asset-path}/icons/checkmark.svg'); - background-color: $color-blue; - border: 2px solid $color-blue; - font-size: $h6-font-size; - padding: 1px 2px; - } - - &--incomplete:before { - border: 2px solid $color-gray-light; - } - - } -} diff --git a/static/styles/components/_search_bar.scss b/static/styles/components/_search_bar.scss deleted file mode 100644 index dbc795d2..00000000 --- a/static/styles/components/_search_bar.scss +++ /dev/null @@ -1,72 +0,0 @@ -.search-bar { - @include grid-row; - @include panel-base; - @include panel-theme-default; - @include panel-margin; - padding: $gap; - flex-wrap: wrap; - - .usa-input { - margin: 0; - flex-grow: 1; - flex-shrink: 0; - flex-basis: 100%; - height: $search-input-height; - position: relative; - margin-top: $gap; - - @include media($large-screen) { - flex-shrink: 1; - flex-basis: auto; - margin-top: 0; - margin-left: $gap; - } - - label { - @include hide; - } - - &:first-child { - margin-left: 0; - margin-top: 0; - } - } - - .search-input { - @include media($medium-screen) { - flex-basis: 50%; - } - - @media (min-width:800px) and (max-width:900px) { - flex-basis: auto; - } - - input[type='search'] { - width: auto; - height: $search-input-height; - width: calc(100% - #{$search-button-width}); - max-width: none; - font-size: 1.6rem; - } - - button { - position: absolute; - top: 0; - right: 0; - margin: 0; - padding: 0; - height: $search-input-height; - width: $search-button-width; - border-top-left-radius: 0; - border-bottom-left-radius: 0; - text-align: center; - - &:after { - content: url('#{$asset-path}/icons/search.svg'); - display: inline-block; - width: 1.6rem; - height: 1.6rem; - } - } - } -} diff --git a/static/styles/components/_site_action.scss b/static/styles/components/_site_action.scss deleted file mode 100644 index 98af0b18..00000000 --- a/static/styles/components/_site_action.scss +++ /dev/null @@ -1,15 +0,0 @@ -.site-action { - border-bottom: 1px solid $color-gray-lightest; - display: block; - padding-top: 0.5rem; - padding-bottom: 0.5rem; - margin-top: 0.25rem; - - a { - font-size: 1.3rem; - text-transform: uppercase; - text-decoration: none; - color: $color-primary !important; - } - -} \ No newline at end of file diff --git a/static/styles/components/_topbar.scss b/static/styles/components/_topbar.scss deleted file mode 100644 index e56a95fa..00000000 --- a/static/styles/components/_topbar.scss +++ /dev/null @@ -1,71 +0,0 @@ -.topbar { - background-color: $color-white; - border-bottom: 1px solid $color-black; - - .topbar__navigation { - display: flex; - flex-direction: row; - align-items: stretch; - justify-content: space-between; - - .topbar__link { - color: $color-black; - display: inline-flex; - align-items: center; - height: $topbar-height; - padding: 0 ($gap * 2); - text-decoration: none; - - .topbar__link-label { - @include h5; - } - - .topbar__link-icon { - margin-left: $gap; - } - - &.topbar__link--shield { - width: $icon-bar-width; - justify-content: center; - padding: 0; - - .topbar__link-icon { - margin: 0; - } - } - - &:hover { - background-color: $color-primary-darker; - color: $color-white; - - .topbar__link-icon { - @include icon-style-inverted; - } - } - } - - .topbar__context { - display: flex; - flex-grow: 1; - flex-direction: row; - align-items: stretch; - justify-content: space-between; - - &.topbar__context--workspace { - background-color: $color-primary; - - .topbar__link { - color: $color-white; - - .topbar__link-icon { - @include icon-style-inverted; - } - - &:hover { - background-color: $color-primary-darker; - } - } - } - } - } -} diff --git a/static/styles/components/_workspace_layout.scss b/static/styles/components/_workspace_layout.scss deleted file mode 100644 index e2cf4c24..00000000 --- a/static/styles/components/_workspace_layout.scss +++ /dev/null @@ -1,26 +0,0 @@ -.workspace-panel-container { - @include media($large-screen) { - @include grid-row; - } -} - -.workspace-navigation { - @include panel-margin; - - ul { - display: flex; - flex-wrap: wrap; - li { - flex-grow: 1; - } - } - - @include media($large-screen) { - width: 20rem; - margin-right: $gap * 2; - - ul { - display: block; - } - } -} diff --git a/static/styles/core/_grid.scss b/static/styles/core/_grid.scss deleted file mode 100644 index b24327c3..00000000 --- a/static/styles/core/_grid.scss +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Grid - * @see https://designsystem.digital.gov/components/grids/ - * @source https://github.com/uswds/uswds/blob/develop/src/stylesheets/core/_grid.scss - */ - -// Roll our own simple grid system -// USWDS grid system is fairly outdated and does not serve the needs of this project -// We are implementing a simple flexbox row/column system - -@mixin grid-row { - display: flex; - flex-direction: row; - flex-wrap: nowrap; -} - -@mixin grid-pad { - @include padding(null $site-margins-mobile); - - @include media($medium-screen) { - @include padding(null $site-margins); - } -} - -.row { - @include grid-row; - - &.row--pad { - @include grid-pad; - } - - &.row--max { - max-width: $site-max-width; - } -} - -.col { - &.col--pad { - @include grid-pad; - } - - &.col--grow { - flex-grow: 1; - } -} diff --git a/static/styles/core/_util.scss b/static/styles/core/_util.scss deleted file mode 100644 index 48957b6c..00000000 --- a/static/styles/core/_util.scss +++ /dev/null @@ -1,33 +0,0 @@ -.nowrap { - white-space: nowrap; -} - -@mixin hide { - border: 0; - clip: rect(0 0 0 0); - height: 1px; - margin: -1px; - overflow: hidden; - padding: 0; - position: absolute; - width: 1px; -} - -.hide { - @include hide; -} - -@mixin unhide { - border: unset; - clip: unset; - height: unset; - margin: unset; - overflow: unset; - padding: unset; - position: unset; - width: unset; -} - -@mixin line-max { - max-width: 45em; -} diff --git a/static/styles/core/_variables.scss b/static/styles/core/_variables.scss deleted file mode 100644 index 79c0e759..00000000 --- a/static/styles/core/_variables.scss +++ /dev/null @@ -1,167 +0,0 @@ -/* - * AT-ST Variables - * =================================================== - */ - -$gap: 0.8rem; // 8px at 10px $em-base -$topbar-height: 4.8rem; -$icon-bar-width: 4.0rem; -$icon-size-small: 2.4rem; -$hover-transition-time: 0.2s; -$search-input-height: 4.4rem; -$search-button-width: 5.0rem; - -/* - * USWDS Variables - * @see https://github.com/uswds/uswds/blob/develop/src/stylesheets/core/_variables.scss - * =================================================== - */ - -// $em-base: 10px; This is not defaulted in USWDS, so we cant override it -$base-font-size: 1.7rem; -$small-font-size: 1.4rem; -$lead-font-size: 2rem; -$title-font-size: 5.2rem; -$h1-font-size: 4rem; -$h2-font-size: 3rem; -$h3-font-size: 2rem; -$h4-font-size: 1.7rem; -$h5-font-size: 1.5rem; -$h6-font-size: 1.3rem; -$base-line-height: 1.5; -$heading-line-height: 1.3; -$lead-line-height: 1.7; - -$font-sans: 'Source Sans Pro', sans-serif; -$font-serif: 'Merriweather', serif; - -$font-normal: 400; -$font-bold: 700; - -// Color -$color-blue: #0071bc; -$color-blue-darker: #205493; -$color-blue-darkest: #112e51; - -$color-aqua: #02bfe7; -$color-aqua-dark: #00a6d2; -$color-aqua-darkest: #046b99; -$color-aqua-light: #9bdaf1; -$color-aqua-lightest: #e1f3f8; - -$color-red: #e31c3d; -$color-red-dark: #cd2026; -$color-red-darkest: #981b1e; -$color-red-light: #e59393; -$color-red-lightest: #f9dede; - -$color-white: #ffffff; -$color-black: #000000; -$color-black-light: #212121; - -$color-gray-dark: #323a45; -$color-gray: #5b616b; -$color-gray-medium: #757575; -$color-gray-light: #aeb0b5; -$color-gray-lighter: #d6d7d9; -$color-gray-lightest: #f1f1f1; - -$color-gray-warm-dark: #494440; -$color-gray-warm-light: #e4e2e0; -$color-gray-cool-light: #dce4ef; - -$color-gold: #fdb81e; -$color-gold-light: #f9c642; -$color-gold-lighter: #fad980; -$color-gold-lightest: #fff1d2; - -$color-green: #2e8540; -$color-green-light: #4aa564; -$color-green-lighter: #94bfa2; -$color-green-lightest: #e7f4e4; - -$color-cool-blue: #205493; -$color-cool-blue-light: #4773aa; -$color-cool-blue-lighter: #8ba6ca; -$color-cool-blue-lightest: #dce4ef; - -$color-purple: #4c2c92; - -// Functional colors -$color-primary: $color-blue; -$color-primary-darker: $color-blue-darker; -$color-primary-darkest: $color-blue-darkest; - -$color-primary-alt: $color-aqua; -$color-primary-alt-dark: $color-aqua-dark; -$color-primary-alt-darkest: $color-aqua-darkest; -$color-primary-alt-light: $color-aqua-light; -$color-primary-alt-lightest: $color-aqua-lightest; - -$color-secondary: $color-red; -$color-secondary-dark: $color-red-dark; -$color-secondary-darkest: $color-red-darkest; -$color-secondary-light: $color-red-light; -$color-secondary-lightest: $color-red-lightest; - -$color-base: $color-black-light; -$color-focus: $color-gray-light; -$color-visited: $color-purple; - -$color-overlay: rgba(#000, 0.5); -$color-shadow: rgba(#000, 0.3); -$color-transparent: rgba(#000, 0); - -// Mobile First Breakpoints -$small-screen: 481px; -$medium-screen: 600px; -$large-screen: 800px; -$xlarge-screen: 1200px; - -// Grid column counts by screen size -$grid-columns-small: 1; -$grid-columns-medium: 6; -$grid-columns-large: 12; - -// @media single-keyword helpers -// $small: new-breakpoint(min-width $small-screen $grid-columns-small); -// $medium: new-breakpoint(min-width $medium-screen $grid-columns-medium); -// $large: new-breakpoint(min-width $large-screen $grid-columns-large); - -// Set the base path for assets (used for font and image paths below) -$asset-path: '../'; - -// Relative font and image file paths -$font-path: '#{$asset-path}fonts'; -$image-path: '#{$asset-path}img'; - -// Set $asset-pipeline to true if you're using the Rails Asset Pipeline -$asset-pipeline: false; - -// Magic Numbers -$text-max-width: 66ch; // 66 characters per line -$lead-max-width: 77rem; -$site-max-width: 1200px; // previously 1040px; -$site-margins: $gap; // previously 3rem; -$site-margins-mobile: $gap / 2; // previously 1.5rem; -$article-max-width: 600px; -$input-max-width: 46rem; -$label-border-radius: 2px; -$checkbox-border-radius: 2px; -$border-radius: 3px; -$button-border-radius: 5px; -$box-shadow: 0 0 2px $color-shadow; -$focus-outline: 2px dotted $color-gray-light; -$focus-spacing: 3px; -$nav-width: 300px; // previously 951px; -$sidenav-current-border-width: 0.4rem; // must be in rem for math - -// 44 x 44 pixels hit target following Apple iOS Human Interface -// Guidelines -$hit-area: 4.4rem; - -$spacing-x-small: 0.5rem; -$spacing-small: 1rem; -$spacing-md-small: 1.5rem; -$spacing-medium: 2rem; -$spacing-large: 3rem; diff --git a/static/styles/elements/_action_group.scss b/static/styles/elements/_action_group.scss deleted file mode 100644 index acf2c1fc..00000000 --- a/static/styles/elements/_action_group.scss +++ /dev/null @@ -1,19 +0,0 @@ -.action-group { - display: flex; - flex-direction: row-reverse; - align-items: center; - margin-top: $gap * 4; - - .usa-button, - a { - margin: 0 0 0 ($gap * 2); - - @include media($medium-screen) { - margin: 0 0 0 ($gap * 4); - } - } - - &:last-child { - margin-bottom: $gap * 3; - } -} diff --git a/static/styles/elements/_block_lists.scss b/static/styles/elements/_block_lists.scss deleted file mode 100644 index 6cb24d11..00000000 --- a/static/styles/elements/_block_lists.scss +++ /dev/null @@ -1,90 +0,0 @@ -@mixin block-list { - @include panel-margin; - - > ul { - list-style: none; - margin: 0; - padding: 0; - } -} - -@mixin block-list-header { - @include panel-base; - @include panel-theme-default; - padding: $gap * 2; - display: flex; - flex-direction: row; - justify-content: space-between; -} - -@mixin block-list__title { - @include h4; - margin: 0; -} - -@mixin block-list__footer { - @include panel-base; - @include panel-theme-default; - padding: $gap * 2; - display: flex; - flex-direction: row-reverse; - justify-content: space-between; - - .icon-link { - &:first-child { - margin-right: -$gap; - } - } -} - -@mixin block-list-item { - @include panel-base; - margin: 0; - padding: $gap * 2; - border-top: 0; - border-bottom: 1px dashed $color-gray-light; - - @at-root li#{&} { - &:last-child { - border-bottom-style: solid; - } - } -} - - -.block-list { - @include block-list; - - .icon-link { - margin: -$gap 0; - } - - .icon-link, - .label { - &:first-child { - margin-left: -$gap; - } - - &:last-child { - margin-right: -$gap; - } - - } -} - -.block-list__header { - @include block-list-header; -} - -.block-list__title { - @include block-list__title; -} - -.block-list__item { - @include block-list-item; -} - -.block-list__footer { - @include block-list__footer; - border-top: 0; -} diff --git a/static/styles/elements/_buttons.scss b/static/styles/elements/_buttons.scss deleted file mode 100644 index c4bf4337..00000000 --- a/static/styles/elements/_buttons.scss +++ /dev/null @@ -1,5 +0,0 @@ -/* - * Buttons - * @see https://designsystem.digital.gov/components/buttons/ - * @source https://github.com/uswds/uswds/blob/develop/src/stylesheets/elements/_buttons.scss - */ diff --git a/static/styles/elements/_diff.scss b/static/styles/elements/_diff.scss deleted file mode 100644 index 85ac4002..00000000 --- a/static/styles/elements/_diff.scss +++ /dev/null @@ -1,36 +0,0 @@ -[class*='diff--'] { - border-left-style: solid; - border-left-width: ($gap / 2); - padding-left: $gap / 2; - margin: ($gap / 2) 0; - - &::before { - font-weight: bold; - padding-right: $gap; - display: inline-block; - width: 1.8rem; - text-align: center; - } -} - -.diff--removed { - background-color: $color-red-lightest; - border-left-color: $color-red-dark; - text-decoration: line-through; - text-decoration-color: $color-overlay; - - &::before { - content: '-'; - color: $color-red-dark; - } -} - -.diff--added { - background-color: $color-aqua-lightest; - border-left-color: $color-aqua-dark; - - &::before { - content: '+'; - color: $color-aqua-dark; - } -} diff --git a/static/styles/elements/_icon_link.scss b/static/styles/elements/_icon_link.scss deleted file mode 100644 index 00daae3f..00000000 --- a/static/styles/elements/_icon_link.scss +++ /dev/null @@ -1,66 +0,0 @@ -@mixin icon-link-color($color: $color-blue, $hover-color: $color-aqua-lightest) { - color: $color; - - &:hover { - background-color: $hover-color; - color: $color; - } - - .icon { - @include icon-color($color); - } -} - -@mixin icon-link { - @include icon-link-color($color-primary); - @include h5; - display: inline-flex; - flex-direction: row; - align-items: center; - padding: $gap; - text-decoration: none; - background: none; - transition: background-color $hover-transition-time; - border-radius: $gap / 2; - - .icon { - @include icon-color($color-primary); - @include icon-size(12); - margin-right: $gap; - } -} - -@mixin icon-link-large { - @include h4; - font-weight: normal; - - .icon { - @include icon-size(16); - margin-right: $gap * 2; - } -} - -@mixin icon-link-vertical { - flex-direction: column; - - .icon { - margin: 0 $gap $gap; - } -} - -.icon-link { - @include icon-link; - @include icon-link-color($color-primary); - - &.icon-link--vertical { - @include icon-link-vertical; - } - - &.icon-link--large { - @include icon-link-large; - } - - &.icon-link--danger { - @include icon-link-color($color-red, $color-red-lightest); - } -} diff --git a/static/styles/elements/_icons.scss b/static/styles/elements/_icons.scss deleted file mode 100644 index 34b35a8c..00000000 --- a/static/styles/elements/_icons.scss +++ /dev/null @@ -1,52 +0,0 @@ -@mixin icon { - display: inline-flex; - - > svg { - width: 100%; - height: 100%; - * { - transition: fill $hover-transition-time; - } - } -} - -@mixin icon-size($size) { - $icon-size: $size * .1rem; - width: $icon-size; - height: auto; - margin: $icon-size / 4; -} - -@mixin icon-color($color) { - > svg * { - fill: $color; - } -} - -@mixin icon-style-default { - @include icon-color($color-black); -} - -@mixin icon-style-active { - @include icon-color($color-primary); -} - -@mixin icon-style-inverted { - > svg * { - fill: $color-white; - } -} - -.icon { - @include icon; - @include icon-size(16); - @include icon-style-default; - - &.icon--tiny { - @include icon-size(10); - } - - &.icon--large { - @include icon-size(24); - } -} diff --git a/static/styles/elements/_inputs.scss b/static/styles/elements/_inputs.scss deleted file mode 100644 index 459e907d..00000000 --- a/static/styles/elements/_inputs.scss +++ /dev/null @@ -1,241 +0,0 @@ -/* - * Inputs - * @see https://designsystem.digital.gov/components/form-controls/ - * @source https://github.com/uswds/uswds/blob/develop/src/stylesheets/elements/_inputs.scss - */ - -@mixin input-icon { - width: 1.6rem; - height: 1.6rem; - display: block; -} - -@mixin input-state($state) { - $border-width: 1px; - $state-color: $color-gray; - - @if $state == 'error' { - $border-width: 2px; - $state-color: $color-red; - - } @else if $state == 'warning' { - $border-width: 2px; - $state-color: $color-gold; - - } @else if $state == 'success' { - $border-width: 2px; - $state-color: $color-green; - } - - .icon { - @include icon-color($state-color); - } - - .usa-input__message { - color: $state-color; - } - - input, - textarea, - select { - border-color: $state-color; - border-width: $border-width; - } - - fieldset { - input[type='radio'] { - + label::before { - box-shadow: 0 0 0 1px $color-white, 0 0 0 3px $color-red; - } - } - - input[type='checkbox'] { - + label::before { - box-shadow: 0 0 0 2px $color-red; - } - } - } -} - -.usa-input { - margin: ($gap * 4) ($gap * 2) ($gap * 4) 0; - - @include media($medium-screen) { - margin: ($gap * 4) 0; - } - - label { - padding: 0 0 $gap 0; - margin: 0; - @include h4; - @include line-max; - position: relative; - - .usa-input__help { - display: block; - @include h5; - font-weight: normal; - padding-top: $gap / 2; - @include line-max; - } - - .icon { - position: absolute; - left: 100%; - top: 100%; - margin-top: 1.4rem; - margin-left: $gap; - } - } - - input, - textarea, - select { - @include line-max; - margin: 0; - } - - .usa-input__choices { // checkbox & radio sets - legend { - padding: 0 0 $gap 0; - @include h4; - - .icon { - vertical-align: middle; - } - } - - ul { - list-style: none; - margin: 0; - padding: 0; - - > li { - margin: 0; - - [type='radio'] + label, - [type='checkbox'] + label { - margin: 0; - } - } - } - - label { - font-weight: normal; - margin: 0; - } - - .usa-input__message { - display: block; - } - - &.usa-input__choices--inline { - label { - display: inline-block; - padding-right: $gap * 3; - } - } - } - - .usa-input__message { - @include h5; - display: inline-block; - padding-top: $gap; - } - - &.usa-input--error { - @include input-state('error'); - } - - &.usa-input--warning { - @include input-state('warning'); - } - - &.usa-input--success { - @include input-state('success'); - } -} - -select { - border-radius: 0; - -webkit-appearance: none; - -moz-appearance: none; -} - -.usa-date-input label { - margin-top: 0; -} - -.input-label { - margin-top: 1rem; -} - -.usa-fieldset-inputs { - margin-top: 2.25rem; - - label:first-child { - padding-bottom: 0.5rem; - } -} - -.usa-search { - padding-top: 2px; - margin-right: 2rem; - - input[type=search] { - height: 4.4rem; - font-size: 1.7rem; - color: $color-black; - } - - button { - min-height: 4.4rem; - } - -} - - -// Form Grid -.form-row { - margin: ($gap * 4) 0; - - .form-col { - flex-grow: 1; - - &:first-child .usa-input { - &:first-child { - margin-top: 0; - } - } - - &:last-child .usa-input { - &:first-child { - margin-top: 0; - } - } - } - - @include media($medium-screen) { - @include grid-row; - align-items: flex-start; - - .form-col { - .usa-input { - margin-left: ($gap * 4); - margin-right: ($gap * 4); - } - - &:first-child { - .usa-input { - margin-left: 0; - } - } - - &:last-child { - .usa-input { - margin-right: 0; - } - } - } - } -} diff --git a/static/styles/elements/_labels.scss b/static/styles/elements/_labels.scss deleted file mode 100644 index 104894e4..00000000 --- a/static/styles/elements/_labels.scss +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Labels - * @see https://designsystem.digital.gov/components/labels/ - * @source https://github.com/uswds/uswds/blob/develop/src/stylesheets/elements/_labels.scss - */ - -.label { - @include h5; - display: inline-block; - height: 2.4rem; - line-height: 2.4rem; - color: $color-white; - background-color: $color-gray; - vertical-align: middle; - margin: 0 $gap; - padding: 0 $gap; - border-radius: $gap / 2; - - &.label--info { - background-color: $color-primary; - } - - &.label--warning { - background-color: $color-gold; - } - - &.label--error { - background-color: $color-red; - } - - &.label--success { - background-color: $color-green; - } -} diff --git a/static/styles/elements/_panels.scss b/static/styles/elements/_panels.scss deleted file mode 100644 index af5decf4..00000000 --- a/static/styles/elements/_panels.scss +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Panels - * A generic block container - */ - - @mixin panel-base { - background-color: $color-white; - border-top-width: 1px; - border-bottom-width: 1px; - border-top-style: solid; - border-bottom-style: solid; - border-left: 0; - border-right: 0; -} - -@mixin panel-theme-default { - border-top-color: $color-black; - border-bottom-color: $color-gray-light; -} - -@mixin panel-margin { - margin-top: 0; - margin-left: 0; - margin-right: 0; - margin-bottom: $site-margins-mobile * 2; - - @include media($medium-screen) { - margin-bottom: $site-margins * 2; - } -} - -@mixin panel-actions { - padding: $gap; -} - -.panel { - @include panel-base; - @include panel-theme-default; - @include panel-margin; - - .panel__content { - margin: ($gap * 2) 0; - padding: 0 ($gap * 2); - - @include media($medium-screen) { - margin: ($gap * 4) 0; - padding: 0 ($gap * 4); - } - } - - .panel__heading { - margin: $gap * 2; - - @include media($medium-screen) { - margin: $gap * 4; - } - - h1, h2, h3, h4, h5, h6 { - margin: 0; - } - } -} - -.panel__actions { - @include panel-actions; -} - diff --git a/static/styles/elements/_sidenav.scss b/static/styles/elements/_sidenav.scss deleted file mode 100644 index d4c67366..00000000 --- a/static/styles/elements/_sidenav.scss +++ /dev/null @@ -1,87 +0,0 @@ -.sidenav { - ul { - list-style: none; - margin: 0; - padding: 0; - - li { - margin: 0; - display: block; - } - } - - .sidenav__link { - display: block; - border-top: 1px solid $color-black; - padding: $gap ($gap * 2); - color: $color-black; - text-decoration: none; - white-space: nowrap; - - .sidenav__link-icon { - margin-left: - ($gap * .5); - } - - &.sidenav__link--disabled { - color: $color-shadow; - pointer-events: none; - } - - &.sidenav__link--active { - @include h4; - background-color: $color-white; - color: $color-primary; - box-shadow: inset ($gap / 2) 0 0 0 $color-primary; - - .sidenav__link-icon { - @include icon-style-active; - } - - + ul { - background-color: $color-white; - - .sidenav__link { - &--active { - @include h5; - color: $color-primary; - box-shadow: none; - } - } - } - } - - + ul { - padding-bottom: $gap / 2; - - li { - .sidenav__link { - @include h5; - padding: $gap * .75; - padding-left: 4.5rem; - border: 0; - font-weight: normal; - - .sidenav__link-icon { - @include icon-size(12); - flex-shrink: 0; - margin-right: 1.5rem; - margin-left: -3rem - } - - .sidenav__link-label { - padding-left: 0; - } - } - } - } - - &:hover { - color: $color-primary; - - .sidenav__link-icon { - @include icon-style-active; - } - - } - } -} diff --git a/static/styles/elements/_tables.scss b/static/styles/elements/_tables.scss deleted file mode 100644 index e1602dfd..00000000 --- a/static/styles/elements/_tables.scss +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Tables - * @see https://designsystem.digital.gov/components/tables/ - * @source https://github.com/uswds/uswds/blob/develop/src/stylesheets/elements/_table.scss - */ - - table { - @include panel-margin; - min-width: 100%; - - tbody { - tr { - th, - td { - @include block-list-item; - display: table-cell; - white-space: nowrap; - border-bottom-style: dashed; - border-top: none; - - &:last-child { - border-bottom-style: dashed; - } - } - - &:last-child { - td, - th { - border-bottom-style: solid; - } - } - - .table-cell--align-right { - text-align: right; - } - - .table-cell--shrink { - width: 1%; - } - - .table-cell--expand { - width: 100%; - } - - .table-cell--hide-small { - display: none; - - @include media($medium-screen) { - display: table-cell; - } - } - } - } - - thead { - tr { - th { - @include block-list-header; - display: table-cell; - } - } - } - - @at-root .panel #{&} { - tr:last-child td { - border-bottom: 0; - } - - &:last-child { - margin-bottom: 0; - } - } -} - -.responsive-table-wrapper { - overflow-x: auto; - @include panel-margin; - - table { - margin-bottom: 0; - } - - @at-root .panel #{&} { - tr:last-child td { - border-bottom: 0; - } - - &:last-child { - margin-bottom: 0; - } - } -} diff --git a/static/styles/elements/_typography.scss b/static/styles/elements/_typography.scss deleted file mode 100644 index fcdc97d9..00000000 --- a/static/styles/elements/_typography.scss +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Typography - * @see https://designsystem.digital.gov/components/typography/ - * @source https://github.com/uswds/uswds/blob/develop/src/stylesheets/elements/_typography.scss - */ - - * { - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -p { - margin: 0 0 ($gap * 2) 0; - @include line-max; -} - -h1, h2, h3, h4, h5, h6 { - font-family: $font-sans; - margin: ($gap * 2) 0; - - + .subtitle * { - margin-top: 0; - } - -} - -.h1 { @include h1; } -.h2 { @include h2; } -.h3 { @include h3; } -.h4 { @include h4; } -.h5 { @include h5; } -.h6 { @include h6; } - -a, -a:hover { - transition: - background 0.2s, - border 0.2s, - box-shadow 0.2s, - color 0.2s; -} - -a:visited { - color: $color-blue; -} - -dl { - dt { - display: inline; - font-weight: bold; - } - dd { - -webkit-margin-start: 0; - } - - > div { - margin-bottom: $gap * 2; - } -} \ No newline at end of file diff --git a/static/styles/sections/_login.scss b/static/styles/sections/_login.scss deleted file mode 100644 index 030d09d5..00000000 --- a/static/styles/sections/_login.scss +++ /dev/null @@ -1,3 +0,0 @@ -.login-area { - text-align: center; -} \ No newline at end of file diff --git a/static/styles/sections/_member_edit.scss b/static/styles/sections/_member_edit.scss deleted file mode 100644 index aef2e042..00000000 --- a/static/styles/sections/_member_edit.scss +++ /dev/null @@ -1,41 +0,0 @@ -.member-card { - @include grid-row; - padding: $gap*2; - justify-content: space-between; - - dl { - margin: 0; - - > div { - margin-bottom: $gap; - } - } - - dt { - font-weight: normal; - color: $color-gray; - } - - dd { - display: inline; - } - - .member-card__header { - display: flex; - flex-direction: column; - justify-content: space-between; - } - - .member-card__heading { - margin: 0; - @include h2; - } - - .member-card__details { - text-align: right; - - .icon-link { - margin: 0 -$gap; - } - } -} \ No newline at end of file diff --git a/static/styles/sections/_project_edit.scss b/static/styles/sections/_project_edit.scss deleted file mode 100644 index 2222fd26..00000000 --- a/static/styles/sections/_project_edit.scss +++ /dev/null @@ -1,19 +0,0 @@ -.project-edit__env-list-item { - display: flex; - flex-direction: row; - align-items: flex-end; - - .usa-input { - margin: 0 ($gap * 4) 0 0; - flex-grow: 1; - } - - .project-edit__env-list-item__remover { - @include icon-link; - @include icon-link-vertical; - @include icon-link-color($color-red, $color-red-lightest); - - margin-bottom: -$gap; - margin-right: -$gap; - } -} diff --git a/static/styles/sections/_projects_list.scss b/static/styles/sections/_projects_list.scss deleted file mode 100644 index fe62b7a6..00000000 --- a/static/styles/sections/_projects_list.scss +++ /dev/null @@ -1,22 +0,0 @@ -.project-list-item { - .project-list-item__environment { - display: flex; - flex-direction: row; - justify-content: space-between; - - .project-list-item__environment__link { - @include icon-link; - @include icon-link-large; - } - - .project-list-item__environment__members { - display: flex; - flex-direction: row; - align-items: center; - - span { - @include h6; - } - } - } -} diff --git a/static/styles/sections/_request_approval.scss b/static/styles/sections/_request_approval.scss deleted file mode 100644 index 5769d5d9..00000000 --- a/static/styles/sections/_request_approval.scss +++ /dev/null @@ -1,97 +0,0 @@ -.request-approval { - .request-approval__heading { - display: flex; - flex-direction: row; - align-items: center; - } - - .request-approval__info-columns { - flex-wrap: wrap; - - .col { - flex-basis: 100%; - - @include media($medium-screen) { - flex-basis: 50%; - - &:first-child { - padding-right: $gap * 2; - } - &:last-child { - padding-left: $gap * 2; - } - } - } - } - - .request-approval__columns__heading { - &:first-child { - @include media($medium-screen) { - margin-top: 0; - } - } - } - - .approval-log { - ol { - list-style: none; - margin: 0; - padding: 0; - - li { - padding: $gap * 2; - border-top: 1px dashed $color-gray-light; - - &:first-child { - border-top-style: solid; - } - - @include media($medium-screen) { - padding: $gap * 4; - } - } - } - .approval-log__log-item { - display: flex; - flex-direction: column-reverse; - justify-content: flex-end; - - @include media($medium-screen) { - flex-direction: row-reverse; - } - - .approval-log__log-item__header { - @include h4; - margin: 0 0 $gap 0; - } - - .approval-log__log-item__timestamp { - @include h5; - margin-right: $gap * 2; - color: $color-gray; - flex-grow: 0; - - @include media($large-screen) { - margin-right: $gap * 4; - } - } - - .approval-log__behalfs { - display: flex; - flex-direction: row; - - .approval-log__behalf { - margin-right: $gap * 2; - - @include media($medium-screen) { - margin-right: $gap * 4; - } - - span { - display: block; - } - } - } - } - } -} From c468b018552b4eb8f91581c1b5be041d163a0811 Mon Sep 17 00:00:00 2001 From: dandds Date: Fri, 3 Aug 2018 09:50:24 -0400 Subject: [PATCH 269/332] have test script to reset test database --- script/include | 2 +- script/test | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/script/include b/script/include index 90a453b2..05492977 160000 --- a/script/include +++ b/script/include @@ -1 +1 @@ -Subproject commit 90a453b2ac4272961b3ed5f7d77d60816a09e092 +Subproject commit 05492977844309215c122e925159f9f8c62014e3 diff --git a/script/test b/script/test index ceb1c5c2..8759a347 100755 --- a/script/test +++ b/script/test @@ -6,6 +6,12 @@ source "$(dirname "${0}")"/../script/include/global_header.inc.sh export FLASK_ENV=test +# Set database name +DATABASE_NAME="atat_test" + +# Enable database resetting +RESET_DB="true" + # Define all relevant python files and directories for this app PYTHON_FILES="./app.py ./atst ./config" From 2a3e62e66ee8363ce8fa907ba1bc5dbdd89ed4b7 Mon Sep 17 00:00:00 2001 From: dandds Date: Fri, 3 Aug 2018 09:50:39 -0400 Subject: [PATCH 270/332] CI should use the test database --- config/ci.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/config/ci.ini b/config/ci.ini index 3796c0a7..64c8ac1f 100644 --- a/config/ci.ini +++ b/config/ci.ini @@ -1,2 +1,3 @@ [default] PGHOST = postgreshost +PGDATABASE = atat_test From 51161dce3d6b0ea4fcaf672ac787af6855ba44d9 Mon Sep 17 00:00:00 2001 From: Patrick Smith Date: Fri, 3 Aug 2018 10:32:53 -0400 Subject: [PATCH 271/332] Resolve conflicts in pipfile.lock after adding flask-wtf back --- Pipfile.lock | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/Pipfile.lock b/Pipfile.lock index ead0c686..2a25ba15 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "9f17530cb96833c424369b9cac305cb43a817cdf19605aaedeb2d98566302857" + "sha256": "0738d50fa0153e356ddd9ce23bcc781914ed0fe860044457a9db9fc0e1cff46b" }, "pipfile-spec": 6, "requires": { @@ -62,6 +62,14 @@ "index": "pypi", "version": "==2.3.2" }, + "flask-wtf": { + "hashes": [ + "sha256:5d14d55cfd35f613d99ee7cba0fc3fbbe63ba02f544d349158c14ca15561cc36", + "sha256:d9a9e366b32dcbb98ef17228e76be15702cd2600675668bca23f63a7947fd5ac" + ], + "index": "pypi", + "version": "==0.14.2" + }, "itsdangerous": { "hashes": [ "sha256:cbb3fcf8d3e33df861709ecaf89d9e6629cff0a217bc2848f1b41cd30d360519" @@ -160,6 +168,7 @@ "sha256:1d936da41ee06216d89fdc7ead1ee9a5da2811a8787515a976b646e110c3f622", "sha256:e4ef42e82b0b493c5849eed98b5ab49d6767caf982127e9a33167f1153b36cc5" ], + "markers": "python_version != '3.2.*' and python_version != '3.3.*' and python_version != '3.0.*' and python_version != '3.1.*' and python_version >= '2.7'", "version": "==2018.5" }, "redis": { @@ -393,6 +402,7 @@ "sha256:b9c40e9750f3d77e6e4d441d8b0266cf555e7cdabdcff33c4fd06366ca761ef8", "sha256:ec9ef8f4a9bc6f71eec99e1806bfa2de401650d996c59330782b89a5555c1497" ], + "markers": "python_version != '3.2.*' and python_version != '3.1.*' and python_version != '3.3.*' and python_version >= '2.7' and python_version != '3.0.*'", "version": "==4.3.4" }, "itsdangerous": { @@ -510,6 +520,7 @@ "sha256:6e3836e39f4d36ae72840833db137f7b7d35105079aee6ec4a62d9f80d594dd1", "sha256:95eb8364a4708392bae89035f45341871286a333f749c3141c20573d2b3876e1" ], + "markers": "python_version != '3.2.*' and python_version != '3.1.*' and python_version != '3.3.*' and python_version >= '2.7' and python_version != '3.0.*'", "version": "==0.7.1" }, "prompt-toolkit": { @@ -532,6 +543,7 @@ "sha256:3fd59af7435864e1a243790d322d763925431213b6b8529c6ca71081ace3bbf7", "sha256:e31fb2767eb657cbde86c454f02e99cb846d3cd9d61b318525140214fdc0e98e" ], + "markers": "python_version != '3.2.*' and python_version != '3.1.*' and python_version != '3.3.*' and python_version >= '2.7' and python_version != '3.0.*'", "version": "==1.5.4" }, "pygments": { @@ -551,11 +563,11 @@ }, "pytest": { "hashes": [ - "sha256:8214ab8446104a1d0c17fbd218ec6aac743236c6ffbe23abc038e40213c60b88", - "sha256:e2b2c6e1560b8f9dc8dd600b0923183fbd68ba3d9bdecde04467be6dd296a384" + "sha256:86a8dbf407e437351cef4dba46736e9c5a6e3c3ac71b2e942209748e76ff2086", + "sha256:e74466e97ac14582a8188ff4c53e6cc3810315f342f6096899332ae864c1d432" ], "index": "pypi", - "version": "==3.7.0" + "version": "==3.7.1" }, "pytest-flask": { "hashes": [ @@ -581,15 +593,11 @@ }, "pyyaml": { "hashes": [ - "sha256:1cbc199009e78f92d9edf554be4fe40fb7b0bef71ba688602a00e97a51909110", "sha256:254bf6fda2b7c651837acb2c718e213df29d531eebf00edb54743d10bcb694eb", "sha256:3108529b78577327d15eec243f0ff348a0640b0c3478d67ad7f5648f93bac3e2", "sha256:3c17fb92c8ba2f525e4b5f7941d850e7a48c3a59b32d331e2502a3cdc6648e76", - "sha256:6f89b5c95e93945b597776163403d47af72d243f366bf4622ff08bdfd1c950b7", "sha256:8d6d96001aa7f0a6a4a95e8143225b5d06e41b1131044913fecb8f85a125714b", - "sha256:be622cc81696e24d0836ba71f6272a2b5767669b0d79fdcf0295d51ac2e156c8", - "sha256:c8a88edd93ee29ede719080b2be6cb2333dfee1dccba213b422a9c8e97f2967b", - "sha256:f39411e380e2182ad33be039e8ee5770a5d9efe01a2bfb7ae58d9ba31c4a2a9d" + "sha256:c8a88edd93ee29ede719080b2be6cb2333dfee1dccba213b422a9c8e97f2967b" ], "version": "==4.2b4" }, From a0082a2ae255203e7887133d7142619b3f319ace Mon Sep 17 00:00:00 2001 From: Patrick Smith Date: Fri, 3 Aug 2018 10:34:24 -0400 Subject: [PATCH 272/332] Revert "CI should use the test database" CI needs to use the regular databse during setup and should use the test database when running tests only This reverts commit 9bc64ba269c99ab6da24dca475d0d5ff22c9474d. --- config/ci.ini | 1 - 1 file changed, 1 deletion(-) diff --git a/config/ci.ini b/config/ci.ini index 64c8ac1f..3796c0a7 100644 --- a/config/ci.ini +++ b/config/ci.ini @@ -1,3 +1,2 @@ [default] PGHOST = postgreshost -PGDATABASE = atat_test From 64b40c0cf38781a38e46c2674b3c5f58882e9f51 Mon Sep 17 00:00:00 2001 From: Andrew Croce Date: Fri, 3 Aug 2018 10:35:04 -0400 Subject: [PATCH 273/332] Reorganize macros into separate component files Replace a few old UI Module instances with macros --- templates/components.html | 145 ------------------ templates/components/alert.html | 39 +++++ templates/components/alert.html.to | 35 ----- templates/components/empty_state.html | 13 ++ templates/components/empty_state.html.to | 9 -- templates/components/icon.html | 6 + templates/components/icon.html.to | 2 - templates/components/modal.html | 9 ++ templates/components/modal.html.to | 7 - templates/components/options_input.html | 27 ++++ templates/components/options_input.html.to | 25 --- templates/components/sidenav_item.html | 28 ++++ templates/components/text_input.html | 23 +++ templates/components/text_input.html.to | 21 --- templates/member_edit.html.to | 7 +- templates/navigation/_sidenav_item.html.to | 24 --- templates/navigation/global_navigation.html | 3 +- templates/navigation/topbar.html | 3 +- .../navigation/workspace_navigation.html.to | 32 ++-- templates/project_edit.html.to | 6 +- templates/requests.html | 4 +- templates/requests/screen-1.html | 4 +- templates/requests/screen-2.html | 4 +- templates/requests/screen-3.html | 3 +- templates/requests/screen-4.html | 3 +- templates/requests/screen-5.html | 2 + templates/styleguide.html | 4 +- templates/workspace_members.html | 6 +- templates/workspace_projects.html | 2 +- 29 files changed, 198 insertions(+), 298 deletions(-) delete mode 100644 templates/components.html create mode 100644 templates/components/alert.html delete mode 100644 templates/components/alert.html.to create mode 100644 templates/components/empty_state.html delete mode 100644 templates/components/empty_state.html.to create mode 100644 templates/components/icon.html delete mode 100644 templates/components/icon.html.to create mode 100644 templates/components/modal.html delete mode 100644 templates/components/modal.html.to create mode 100644 templates/components/options_input.html delete mode 100644 templates/components/options_input.html.to create mode 100644 templates/components/sidenav_item.html create mode 100644 templates/components/text_input.html delete mode 100644 templates/components/text_input.html.to delete mode 100644 templates/navigation/_sidenav_item.html.to diff --git a/templates/components.html b/templates/components.html deleted file mode 100644 index a9b566cd..00000000 --- a/templates/components.html +++ /dev/null @@ -1,145 +0,0 @@ -{% macro Icon(name, classes="") -%} - {% autoescape false %} - - {% endautoescape %} -{%- endmacro %} - -{% macro SidenavItem(label, href, active=False, icon=None, subnav=None) -%} -
  • - - {% if icon %} - {{ Icon(icon, classes="sidenav__link-icon") }} - {% endif %} - - {{label}} - - - {% if subnav and active %} - - {% endif %} -
  • -{%- endmacro %} - -{% macro Modal() -%} - -{%- endmacro %} - -{% macro EmptyState(message, actionLabel, actionHref, icon=None) -%} -
    -

    {{ message }}

    - - {% if icon %} - {{ Icon(icon) }} - {% endif %} - - {{ actionLabel }} -
    -{%- endmacro %} - -{% macro Alert(title, message=None, actions=None, level='info') -%} -{% set role = 'alertdialog' if actions else 'alert' %} -{% set levels = { - 'warning': { - 'icon': 'alert', - 'tone': 'assertive' - }, - 'error': { - 'icon': 'alert', - 'tone': 'assertive' - }, - 'info': { - 'icon': 'info', - 'tone': 'polite' - }, - 'success': { - 'icon': 'ok', - 'tone': 'polite' - } -} %} - -
    - {{ Icon(levels.get(level).get('icon'), classes='alert__icon icon--large') }} - -
    -

    {{title}}

    - - {% if message %} -
    {{ message | safe }}
    - {% endif %} - - {% if actions %} -
    {{ actions | safe }}
    - {% endif %} -
    -
    -{%- endmacro %} - -{% macro TextInput(field, placeholder='') -%} -
    - - - {{ field(placeholder=placeholder) | safe }} - - {% if field.errors %} - {% for error in field.errors %} - {{ error }} - {% endfor %} - {% endif %} -
    -{%- endmacro %} - -{% macro OptionsInput(field, inline=False) -%} -
    - -
    - - {{ field.label }} - - {% if field.description %} - {{ field.description | safe }} - {% endif %} - - {% if field.errors %} - {{ Icon('alert') }} - {% endif %} - - - {{ field() }} - - {% if field.errors %} - {% for error in field.errors %} - {{ error }} - {% endfor %} - {% endif %} - -
    -
    - -{%- endmacro %} diff --git a/templates/components/alert.html b/templates/components/alert.html new file mode 100644 index 00000000..d3385d1d --- /dev/null +++ b/templates/components/alert.html @@ -0,0 +1,39 @@ +{% from "components/icon.html" import Icon %} + +{% macro Alert(title, message=None, actions=None, level='info') -%} + {% set role = 'alertdialog' if actions else 'alert' %} + {% set levels = { + 'warning': { + 'icon': 'alert', + 'tone': 'assertive' + }, + 'error': { + 'icon': 'alert', + 'tone': 'assertive' + }, + 'info': { + 'icon': 'info', + 'tone': 'polite' + }, + 'success': { + 'icon': 'ok', + 'tone': 'polite' + } + } %} + +
    + {{ Icon(levels.get(level).get('icon'), classes='alert__icon icon--large') }} + +
    +

    {{title}}

    + + {% if message %} +
    {{ message | safe }}
    + {% endif %} + + {% if actions %} +
    {{ actions | safe }}
    + {% endif %} +
    +
    +{%- endmacro %} diff --git a/templates/components/alert.html.to b/templates/components/alert.html.to deleted file mode 100644 index 05cac613..00000000 --- a/templates/components/alert.html.to +++ /dev/null @@ -1,35 +0,0 @@ -{% set role = 'alertdialog' if actions else 'alert' %} -{% set levels = { - 'warning': { - 'icon': 'alert', - 'tone': 'assertive' - }, - 'error': { - 'icon': 'alert', - 'tone': 'assertive' - }, - 'info': { - 'icon': 'info', - 'tone': 'polite' - }, - 'success': { - 'icon': 'ok', - 'tone': 'polite' - } -} %} - -
    - {% module Icon(levels.get(level).get('icon'), classes='alert__icon icon--large') %} - -
    -

    {{title}}

    - - {% if message %} -
    {% raw message %}
    - {% end %} - - {% if actions %} -
    {% raw actions %}
    - {% end %} -
    -
    diff --git a/templates/components/empty_state.html b/templates/components/empty_state.html new file mode 100644 index 00000000..7dc6f119 --- /dev/null +++ b/templates/components/empty_state.html @@ -0,0 +1,13 @@ +{% from "components/icon.html" import Icon %} + +{% macro EmptyState(message, actionLabel, actionHref, icon=None) -%} +
    +

    {{ message }}

    + + {% if icon %} + {{ Icon(icon) }} + {% endif %} + + {{ actionLabel }} +
    +{%- endmacro %} diff --git a/templates/components/empty_state.html.to b/templates/components/empty_state.html.to deleted file mode 100644 index 30246ddb..00000000 --- a/templates/components/empty_state.html.to +++ /dev/null @@ -1,9 +0,0 @@ -
    -

    {{ message }}

    - - {% if icon %} - {% module Icon(icon) %} - {% end %} - - {{ actionLabel }} -
    diff --git a/templates/components/icon.html b/templates/components/icon.html new file mode 100644 index 00000000..42139e57 --- /dev/null +++ b/templates/components/icon.html @@ -0,0 +1,6 @@ +{% macro Icon(name, classes="") -%} + {% autoescape false %} + + {% endautoescape %} +{%- endmacro %} + diff --git a/templates/components/icon.html.to b/templates/components/icon.html.to deleted file mode 100644 index 99e74b40..00000000 --- a/templates/components/icon.html.to +++ /dev/null @@ -1,2 +0,0 @@ -{% autoescape None %} - diff --git a/templates/components/modal.html b/templates/components/modal.html new file mode 100644 index 00000000..8e483de4 --- /dev/null +++ b/templates/components/modal.html @@ -0,0 +1,9 @@ +{% macro Modal() -%} + +{%- endmacro %} diff --git a/templates/components/modal.html.to b/templates/components/modal.html.to deleted file mode 100644 index 4330adbd..00000000 --- a/templates/components/modal.html.to +++ /dev/null @@ -1,7 +0,0 @@ - diff --git a/templates/components/options_input.html b/templates/components/options_input.html new file mode 100644 index 00000000..55342c24 --- /dev/null +++ b/templates/components/options_input.html @@ -0,0 +1,27 @@ +{% macro OptionsInput(field, inline=False) -%} +
    + +
    + + {{ field.label }} + + {% if field.description %} + {{ field.description | safe }} + {% endif %} + + {% if field.errors %} + {{ Icon('alert') }} + {% endif %} + + + {{ field() }} + + {% if field.errors %} + {% for error in field.errors %} + {{ error }} + {% endfor %} + {% endif %} + +
    +
    +{%- endmacro %} diff --git a/templates/components/options_input.html.to b/templates/components/options_input.html.to deleted file mode 100644 index 8a15e041..00000000 --- a/templates/components/options_input.html.to +++ /dev/null @@ -1,25 +0,0 @@ -
    - -
    - - {{ label }} - - {% if description %} - {% raw description %} - {% end %} - - {% if errors %} - {% module Icon('alert') %} - {% end %} - - - {% raw field() %} - - {% if errors %} - {% for error in errors %} - {{ error }} - {% end %} - {% end %} - -
    -
    diff --git a/templates/components/sidenav_item.html b/templates/components/sidenav_item.html new file mode 100644 index 00000000..64f5b765 --- /dev/null +++ b/templates/components/sidenav_item.html @@ -0,0 +1,28 @@ +{% from "components/icon.html" import Icon %} + +{% macro SidenavItem(label, href, active=False, icon=None, subnav=None) -%} +
  • + + {% if icon %} + {{ Icon(icon, classes="sidenav__link-icon") }} + {% endif %} + + {{label}} + + + {% if subnav and active %} + + {% endif %} +
  • +{%- endmacro %} diff --git a/templates/components/text_input.html b/templates/components/text_input.html new file mode 100644 index 00000000..0f50ca89 --- /dev/null +++ b/templates/components/text_input.html @@ -0,0 +1,23 @@ +{% macro TextInput(field, placeholder='') -%} +
    + + + {{ field(placeholder=placeholder) | safe }} + + {% if field.errors %} + {% for error in field.errors %} + {{ error }} + {% endfor %} + {% endif %} +
    +{%- endmacro %} diff --git a/templates/components/text_input.html.to b/templates/components/text_input.html.to deleted file mode 100644 index 2a800abc..00000000 --- a/templates/components/text_input.html.to +++ /dev/null @@ -1,21 +0,0 @@ -
    - - - {% raw field(placeholder=placeholder) %} - - {% if errors %} - {% for error in errors %} - {{ error }} - {% end %} - {% end %} -
    diff --git a/templates/member_edit.html.to b/templates/member_edit.html.to index d454152c..fbe92f35 100644 --- a/templates/member_edit.html.to +++ b/templates/member_edit.html.to @@ -1,5 +1,7 @@ {% extends "base_workspace.html.to" %} +{% from "components/alert.html" import Alert %} + {% block template_vars %} {% set is_new_member = False %} {% set member_name = "Danny Knight" %} @@ -10,11 +12,12 @@ {% block workspace_content %} -{% module Alert( +{{ Alert( "UI Mock", message="

    Please note, this screen is a non-functional UI mockup.

    ", level="info" - ) %} + ) +}}
    diff --git a/templates/navigation/_sidenav_item.html.to b/templates/navigation/_sidenav_item.html.to deleted file mode 100644 index 888245bc..00000000 --- a/templates/navigation/_sidenav_item.html.to +++ /dev/null @@ -1,24 +0,0 @@ -
  • - - {% if icon %} - {% module Icon(icon, classes="sidenav__link-icon") %} - {% end %} - - {{label}} - - - {% if subnav and active %} - - {% end %} -
  • diff --git a/templates/navigation/global_navigation.html b/templates/navigation/global_navigation.html index 594bf574..79728185 100644 --- a/templates/navigation/global_navigation.html +++ b/templates/navigation/global_navigation.html @@ -1,4 +1,5 @@ -{% from "components.html" import SidenavItem %} +{% from "components/sidenav_item.html" import SidenavItem %} +