changeset 0:3c1bc3bc5a6c

pull out of homeauto/ project, and add skaffold/pipenv
author drewp@bigasterisk.com
date Thu, 31 Mar 2022 22:03:43 -0700
parents
children 0f532eb91364
files .flake8 .style.yapf .vscode/settings.json Dockerfile Pipfile Pipfile.lock deploy.yaml docs.n3 environment.py index.html patch_cyclone.py rdfdoc.py skaffold.yaml tasks.py twilight.py
diffstat 15 files changed, 882 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.flake8	Thu Mar 31 22:03:43 2022 -0700
@@ -0,0 +1,3 @@
+[flake8]
+max-line-length=160
+ignore=E722,W503,E741,E201,E202,E241,E231
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.style.yapf	Thu Mar 31 22:03:43 2022 -0700
@@ -0,0 +1,3 @@
+[style]
+based_on_style = google
+column_limit = 160
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.vscode/settings.json	Thu Mar 31 22:03:43 2022 -0700
@@ -0,0 +1,10 @@
+{
+  "python.linting.pylintEnabled": false,
+  "python.linting.flake8Enabled": true,
+  "python.linting.enabled": true,
+  "python.pythonPath": "/home/drewp/.local/share/virtualenvs/environment-l9Nv7hqc/bin/python",
+  "python.formatting.provider": "yapf",
+  "files.watcherExclude": {
+    "_darcs_old/**": true
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Dockerfile	Thu Mar 31 22:03:43 2022 -0700
@@ -0,0 +1,12 @@
+FROM bang5:5000/base_basic
+
+WORKDIR /opt
+ENV XDG_CACHE_HOME=/tmp/cache
+COPY Pipfile* ./
+RUN pipenv install
+
+COPY *.py req* *.n3 *.html ./
+
+EXPOSE 9075
+
+#0 jones
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pipfile	Thu Mar 31 22:03:43 2022 -0700
@@ -0,0 +1,39 @@
+[[source]]
+url = "https://pypi.python.org/simple"
+verify_ssl = true
+name = "pypi"
+
+[[source]]
+url = "https://projects.bigasterisk.com/"
+verify_ssl = true
+name = "home"
+
+[packages]
+docopt = "*"
+cyclone = "*"
+python-dateutil = "*"
+
+[dev-packages]
+flake8 = "*"
+yapf = "*"
+
+[requires]
+python_version = "3.9"
+
+
+
+[packages.standardservice]
+version = "*"
+index = "home"
+
+[packages.cycloneerr]
+version = "*"
+index = "home"
+
+[packages.rdfdb]
+version = "*"
+index = "home"
+
+[packages.patchablegraph]
+version = "*"
+index = "home"
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pipfile.lock	Thu Mar 31 22:03:43 2022 -0700
@@ -0,0 +1,510 @@
+{
+    "_meta": {
+        "hash": {
+            "sha256": "3cc44e0936e38900650f2eb474e5f50bbebb48da2b5ed09821cac0b003c75e81"
+        },
+        "pipfile-spec": 6,
+        "requires": {
+            "python_version": "3.9"
+        },
+        "sources": [
+            {
+                "name": "pypi",
+                "url": "https://pypi.python.org/simple",
+                "verify_ssl": true
+            },
+            {
+                "name": "home",
+                "url": "https://projects.bigasterisk.com/",
+                "verify_ssl": true
+            }
+        ]
+    },
+    "default": {
+        "attrs": {
+            "hashes": [
+                "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4",
+                "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"
+            ],
+            "version": "==21.4.0"
+        },
+        "autobahn": {
+            "hashes": [
+                "sha256:58a887c7a196bb08d8b6624cb3695f493a9e5c9f00fd350d8d6f829b47ff9036"
+            ],
+            "version": "==22.3.2"
+        },
+        "automat": {
+            "hashes": [
+                "sha256:7979803c74610e11ef0c0d68a2942b152df52da55336e0c9d58daf1831cbdf33",
+                "sha256:b6feb6455337df834f6c9962d6ccf771515b7d939bca142b29c20c2376bc6111"
+            ],
+            "version": "==20.2.0"
+        },
+        "certifi": {
+            "hashes": [
+                "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872",
+                "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"
+            ],
+            "version": "==2021.10.8"
+        },
+        "cffi": {
+            "hashes": [
+                "sha256:00c878c90cb53ccfaae6b8bc18ad05d2036553e6d9d1d9dbcf323bbe83854ca3",
+                "sha256:0104fb5ae2391d46a4cb082abdd5c69ea4eab79d8d44eaaf79f1b1fd806ee4c2",
+                "sha256:06c48159c1abed75c2e721b1715c379fa3200c7784271b3c46df01383b593636",
+                "sha256:0808014eb713677ec1292301ea4c81ad277b6cdf2fdd90fd540af98c0b101d20",
+                "sha256:10dffb601ccfb65262a27233ac273d552ddc4d8ae1bf93b21c94b8511bffe728",
+                "sha256:14cd121ea63ecdae71efa69c15c5543a4b5fbcd0bbe2aad864baca0063cecf27",
+                "sha256:17771976e82e9f94976180f76468546834d22a7cc404b17c22df2a2c81db0c66",
+                "sha256:181dee03b1170ff1969489acf1c26533710231c58f95534e3edac87fff06c443",
+                "sha256:23cfe892bd5dd8941608f93348c0737e369e51c100d03718f108bf1add7bd6d0",
+                "sha256:263cc3d821c4ab2213cbe8cd8b355a7f72a8324577dc865ef98487c1aeee2bc7",
+                "sha256:2756c88cbb94231c7a147402476be2c4df2f6078099a6f4a480d239a8817ae39",
+                "sha256:27c219baf94952ae9d50ec19651a687b826792055353d07648a5695413e0c605",
+                "sha256:2a23af14f408d53d5e6cd4e3d9a24ff9e05906ad574822a10563efcef137979a",
+                "sha256:31fb708d9d7c3f49a60f04cf5b119aeefe5644daba1cd2a0fe389b674fd1de37",
+                "sha256:3415c89f9204ee60cd09b235810be700e993e343a408693e80ce7f6a40108029",
+                "sha256:3773c4d81e6e818df2efbc7dd77325ca0dcb688116050fb2b3011218eda36139",
+                "sha256:3b96a311ac60a3f6be21d2572e46ce67f09abcf4d09344c49274eb9e0bf345fc",
+                "sha256:3f7d084648d77af029acb79a0ff49a0ad7e9d09057a9bf46596dac9514dc07df",
+                "sha256:41d45de54cd277a7878919867c0f08b0cf817605e4eb94093e7516505d3c8d14",
+                "sha256:4238e6dab5d6a8ba812de994bbb0a79bddbdf80994e4ce802b6f6f3142fcc880",
+                "sha256:45db3a33139e9c8f7c09234b5784a5e33d31fd6907800b316decad50af323ff2",
+                "sha256:45e8636704eacc432a206ac7345a5d3d2c62d95a507ec70d62f23cd91770482a",
+                "sha256:4958391dbd6249d7ad855b9ca88fae690783a6be9e86df65865058ed81fc860e",
+                "sha256:4a306fa632e8f0928956a41fa8e1d6243c71e7eb59ffbd165fc0b41e316b2474",
+                "sha256:57e9ac9ccc3101fac9d6014fba037473e4358ef4e89f8e181f8951a2c0162024",
+                "sha256:59888172256cac5629e60e72e86598027aca6bf01fa2465bdb676d37636573e8",
+                "sha256:5e069f72d497312b24fcc02073d70cb989045d1c91cbd53979366077959933e0",
+                "sha256:64d4ec9f448dfe041705426000cc13e34e6e5bb13736e9fd62e34a0b0c41566e",
+                "sha256:6dc2737a3674b3e344847c8686cf29e500584ccad76204efea14f451d4cc669a",
+                "sha256:74fdfdbfdc48d3f47148976f49fab3251e550a8720bebc99bf1483f5bfb5db3e",
+                "sha256:75e4024375654472cc27e91cbe9eaa08567f7fbdf822638be2814ce059f58032",
+                "sha256:786902fb9ba7433aae840e0ed609f45c7bcd4e225ebb9c753aa39725bb3e6ad6",
+                "sha256:8b6c2ea03845c9f501ed1313e78de148cd3f6cad741a75d43a29b43da27f2e1e",
+                "sha256:91d77d2a782be4274da750752bb1650a97bfd8f291022b379bb8e01c66b4e96b",
+                "sha256:91ec59c33514b7c7559a6acda53bbfe1b283949c34fe7440bcf917f96ac0723e",
+                "sha256:920f0d66a896c2d99f0adbb391f990a84091179542c205fa53ce5787aff87954",
+                "sha256:a5263e363c27b653a90078143adb3d076c1a748ec9ecc78ea2fb916f9b861962",
+                "sha256:abb9a20a72ac4e0fdb50dae135ba5e77880518e742077ced47eb1499e29a443c",
+                "sha256:c2051981a968d7de9dd2d7b87bcb9c939c74a34626a6e2f8181455dd49ed69e4",
+                "sha256:c21c9e3896c23007803a875460fb786118f0cdd4434359577ea25eb556e34c55",
+                "sha256:c2502a1a03b6312837279c8c1bd3ebedf6c12c4228ddbad40912d671ccc8a962",
+                "sha256:d4d692a89c5cf08a8557fdeb329b82e7bf609aadfaed6c0d79f5a449a3c7c023",
+                "sha256:da5db4e883f1ce37f55c667e5c0de439df76ac4cb55964655906306918e7363c",
+                "sha256:e7022a66d9b55e93e1a845d8c9eba2a1bebd4966cd8bfc25d9cd07d515b33fa6",
+                "sha256:ef1f279350da2c586a69d32fc8733092fd32cc8ac95139a00377841f59a3f8d8",
+                "sha256:f54a64f8b0c8ff0b64d18aa76675262e1700f3995182267998c31ae974fbc382",
+                "sha256:f5c7150ad32ba43a07c4479f40241756145a1f03b43480e058cfd862bf5041c7",
+                "sha256:f6f824dc3bce0edab5f427efcfb1d63ee75b6fcb7282900ccaf925be84efb0fc",
+                "sha256:fd8a250edc26254fe5b33be00402e6d287f562b6a5b2152dec302fa15bb3e997",
+                "sha256:ffaa5c925128e29efbde7301d8ecaf35c8c60ffbcd6a1ffd3a552177c8e5e796"
+            ],
+            "version": "==1.15.0"
+        },
+        "charset-normalizer": {
+            "hashes": [
+                "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597",
+                "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df"
+            ],
+            "markers": "python_version >= '3'",
+            "version": "==2.0.12"
+        },
+        "constantly": {
+            "hashes": [
+                "sha256:586372eb92059873e29eba4f9dec8381541b4d3834660707faf8ba59146dfc35",
+                "sha256:dd2fa9d6b1a51a83f0d7dd76293d734046aa176e384bf6e33b7e44880eb37c5d"
+            ],
+            "version": "==15.1.0"
+        },
+        "cryptography": {
+            "hashes": [
+                "sha256:0a3bf09bb0b7a2c93ce7b98cb107e9170a90c51a0162a20af1c61c765b90e60b",
+                "sha256:1f64a62b3b75e4005df19d3b5235abd43fa6358d5516cfc43d87aeba8d08dd51",
+                "sha256:32db5cc49c73f39aac27574522cecd0a4bb7384e71198bc65a0d23f901e89bb7",
+                "sha256:4881d09298cd0b669bb15b9cfe6166f16fc1277b4ed0d04a22f3d6430cb30f1d",
+                "sha256:4e2dddd38a5ba733be6a025a1475a9f45e4e41139d1321f412c6b360b19070b6",
+                "sha256:53e0285b49fd0ab6e604f4c5d9c5ddd98de77018542e88366923f152dbeb3c29",
+                "sha256:70f8f4f7bb2ac9f340655cbac89d68c527af5bb4387522a8413e841e3e6628c9",
+                "sha256:7b2d54e787a884ffc6e187262823b6feb06c338084bbe80d45166a1cb1c6c5bf",
+                "sha256:7be666cc4599b415f320839e36367b273db8501127b38316f3b9f22f17a0b815",
+                "sha256:8241cac0aae90b82d6b5c443b853723bcc66963970c67e56e71a2609dc4b5eaf",
+                "sha256:82740818f2f240a5da8dfb8943b360e4f24022b093207160c77cadade47d7c85",
+                "sha256:8897b7b7ec077c819187a123174b645eb680c13df68354ed99f9b40a50898f77",
+                "sha256:c2c5250ff0d36fd58550252f54915776940e4e866f38f3a7866d92b32a654b86",
+                "sha256:ca9f686517ec2c4a4ce930207f75c00bf03d94e5063cbc00a1dc42531511b7eb",
+                "sha256:d2b3d199647468d410994dbeb8cec5816fb74feb9368aedf300af709ef507e3e",
+                "sha256:da73d095f8590ad437cd5e9faf6628a218aa7c387e1fdf67b888b47ba56a17f0",
+                "sha256:e167b6b710c7f7bc54e67ef593f8731e1f45aa35f8a8a7b72d6e42ec76afd4b3",
+                "sha256:ea634401ca02367c1567f012317502ef3437522e2fc44a3ea1844de028fa4b84",
+                "sha256:ec6597aa85ce03f3e507566b8bcdf9da2227ec86c4266bd5e6ab4d9e0cc8dab2",
+                "sha256:f64b232348ee82f13aac22856515ce0195837f6968aeaa94a3d0353ea2ec06a6"
+            ],
+            "version": "==36.0.2"
+        },
+        "cyclone": {
+            "hashes": [
+                "sha256:6e5ec576c719240180d56e6e8f83bb474ab52ca3e56ed6417a90f60fd0bf562b",
+                "sha256:adc1c8736bafc668f1f55236d1919cfb96c1f377831361deb73d633f0c1db779"
+            ],
+            "index": "pypi",
+            "version": "==1.3"
+        },
+        "cycloneerr": {
+            "hashes": [
+                "sha256:2860b88c3d81c4e1fac19f7e7f7cdd663232012d5aa05b597b55de129fa071f5"
+            ],
+            "index": "home",
+            "version": "==0.4.0"
+        },
+        "docopt": {
+            "hashes": [
+                "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491"
+            ],
+            "index": "pypi",
+            "version": "==0.6.2"
+        },
+        "hyperlink": {
+            "hashes": [
+                "sha256:427af957daa58bc909471c6c40f74c5450fa123dd093fc53efd2e91d2705a56b",
+                "sha256:e6b14c37ecb73e89c77d78cdb4c2cc8f3fb59a885c5b3f819ff4ed80f25af1b4"
+            ],
+            "version": "==21.0.0"
+        },
+        "idna": {
+            "hashes": [
+                "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff",
+                "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"
+            ],
+            "version": "==3.3"
+        },
+        "incremental": {
+            "hashes": [
+                "sha256:02f5de5aff48f6b9f665d99d48bfc7ec03b6e3943210de7cfc88856d755d6f57",
+                "sha256:92014aebc6a20b78a8084cdd5645eeaa7f74b8933f70fa3ada2cfbd1e3b54321"
+            ],
+            "version": "==21.3.0"
+        },
+        "isodate": {
+            "hashes": [
+                "sha256:0751eece944162659049d35f4f549ed815792b38793f07cf73381c1c87cbed96",
+                "sha256:48c5881de7e8b0a0d648cb024c8062dc84e7b840ed81e864c7614fd3c127bde9"
+            ],
+            "version": "==0.6.1"
+        },
+        "mock": {
+            "hashes": [
+                "sha256:122fcb64ee37cfad5b3f48d7a7d51875d7031aaf3d8be7c42e2bee25044eee62",
+                "sha256:7d3fbbde18228f4ff2f1f119a45cdffa458b4c0dee32eb4d2bb2f82554bac7bc"
+            ],
+            "version": "==4.0.3"
+        },
+        "patchablegraph": {
+            "hashes": [
+                "sha256:77bb2b9513584139e8ba28956846eec49a096bc4c2834daff86a6880cb4b9200"
+            ],
+            "index": "home",
+            "version": "==0.19.0"
+        },
+        "prometheus-client": {
+            "hashes": [
+                "sha256:357a447fd2359b0a1d2e9b311a0c5778c330cfbe186d880ad5a6b39884652316",
+                "sha256:ada41b891b79fca5638bd5cfe149efa86512eaa55987893becd2c6d8d0a5dfc5"
+            ],
+            "version": "==0.13.1"
+        },
+        "psutil": {
+            "hashes": [
+                "sha256:072664401ae6e7c1bfb878c65d7282d4b4391f1bc9a56d5e03b5a490403271b5",
+                "sha256:1070a9b287846a21a5d572d6dddd369517510b68710fca56b0e9e02fd24bed9a",
+                "sha256:1d7b433519b9a38192dfda962dd8f44446668c009833e1429a52424624f408b4",
+                "sha256:3151a58f0fbd8942ba94f7c31c7e6b310d2989f4da74fcbf28b934374e9bf841",
+                "sha256:32acf55cb9a8cbfb29167cd005951df81b567099295291bcfd1027365b36591d",
+                "sha256:3611e87eea393f779a35b192b46a164b1d01167c9d323dda9b1e527ea69d697d",
+                "sha256:3d00a664e31921009a84367266b35ba0aac04a2a6cad09c550a89041034d19a0",
+                "sha256:4e2fb92e3aeae3ec3b7b66c528981fd327fb93fd906a77215200404444ec1845",
+                "sha256:539e429da49c5d27d5a58e3563886057f8fc3868a5547b4f1876d9c0f007bccf",
+                "sha256:55ce319452e3d139e25d6c3f85a1acf12d1607ddedea5e35fb47a552c051161b",
+                "sha256:58c7d923dc209225600aec73aa2c4ae8ea33b1ab31bc11ef8a5933b027476f07",
+                "sha256:7336292a13a80eb93c21f36bde4328aa748a04b68c13d01dfddd67fc13fd0618",
+                "sha256:742c34fff804f34f62659279ed5c5b723bb0195e9d7bd9907591de9f8f6558e2",
+                "sha256:7641300de73e4909e5d148e90cc3142fb890079e1525a840cf0dfd39195239fd",
+                "sha256:76cebf84aac1d6da5b63df11fe0d377b46b7b500d892284068bacccf12f20666",
+                "sha256:7779be4025c540d1d65a2de3f30caeacc49ae7a2152108adeaf42c7534a115ce",
+                "sha256:7d190ee2eaef7831163f254dc58f6d2e2a22e27382b936aab51c835fc080c3d3",
+                "sha256:8293942e4ce0c5689821f65ce6522ce4786d02af57f13c0195b40e1edb1db61d",
+                "sha256:869842dbd66bb80c3217158e629d6fceaecc3a3166d3d1faee515b05dd26ca25",
+                "sha256:90a58b9fcae2dbfe4ba852b57bd4a1dded6b990a33d6428c7614b7d48eccb492",
+                "sha256:9b51917c1af3fa35a3f2dabd7ba96a2a4f19df3dec911da73875e1edaf22a40b",
+                "sha256:b2237f35c4bbae932ee98902a08050a27821f8f6dfa880a47195e5993af4702d",
+                "sha256:c3400cae15bdb449d518545cbd5b649117de54e3596ded84aacabfbb3297ead2",
+                "sha256:c51f1af02334e4b516ec221ee26b8fdf105032418ca5a5ab9737e8c87dafe203",
+                "sha256:cb8d10461c1ceee0c25a64f2dd54872b70b89c26419e147a05a10b753ad36ec2",
+                "sha256:d62a2796e08dd024b8179bd441cb714e0f81226c352c802fca0fd3f89eeacd94",
+                "sha256:df2c8bd48fb83a8408c8390b143c6a6fa10cb1a674ca664954de193fdcab36a9",
+                "sha256:e5c783d0b1ad6ca8a5d3e7b680468c9c926b804be83a3a8e95141b05c39c9f64",
+                "sha256:e9805fed4f2a81de98ae5fe38b75a74c6e6ad2df8a5c479594c7629a1fe35f56",
+                "sha256:ea42d747c5f71b5ccaa6897b216a7dadb9f52c72a0fe2b872ef7d3e1eacf3ba3",
+                "sha256:ef216cc9feb60634bda2f341a9559ac594e2eeaadd0ba187a4c2eb5b5d40b91c",
+                "sha256:ff0d41f8b3e9ebb6b6110057e40019a432e96aae2008951121ba4e56040b84f3"
+            ],
+            "version": "==5.9.0"
+        },
+        "pyasn1": {
+            "hashes": [
+                "sha256:014c0e9976956a08139dc0712ae195324a75e142284d5f87f1a87ee1b068a359",
+                "sha256:03840c999ba71680a131cfaee6fab142e1ed9bbd9c693e285cc6aca0d555e576",
+                "sha256:0458773cfe65b153891ac249bcf1b5f8f320b7c2ce462151f8fa74de8934becf",
+                "sha256:08c3c53b75eaa48d71cf8c710312316392ed40899cb34710d092e96745a358b7",
+                "sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d",
+                "sha256:5c9414dcfede6e441f7e8f81b43b34e834731003427e5b09e4e00e3172a10f00",
+                "sha256:6e7545f1a61025a4e58bb336952c5061697da694db1cae97b116e9c46abcf7c8",
+                "sha256:78fa6da68ed2727915c4767bb386ab32cdba863caa7dbe473eaae45f9959da86",
+                "sha256:7ab8a544af125fb704feadb008c99a88805126fb525280b2270bb25cc1d78a12",
+                "sha256:99fcc3c8d804d1bc6d9a099921e39d827026409a58f2a720dcdb89374ea0c776",
+                "sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba",
+                "sha256:e89bf84b5437b532b0803ba5c9a5e054d21fec423a89952a74f87fa2c9b7bce2",
+                "sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3"
+            ],
+            "version": "==0.4.8"
+        },
+        "pyasn1-modules": {
+            "hashes": [
+                "sha256:0845a5582f6a02bb3e1bde9ecfc4bfcae6ec3210dd270522fee602365430c3f8",
+                "sha256:0fe1b68d1e486a1ed5473f1302bd991c1611d319bba158e98b106ff86e1d7199",
+                "sha256:15b7c67fabc7fc240d87fb9aabf999cf82311a6d6fb2c70d00d3d0604878c811",
+                "sha256:426edb7a5e8879f1ec54a1864f16b882c2837bfd06eee62f2c982315ee2473ed",
+                "sha256:65cebbaffc913f4fe9e4808735c95ea22d7a7775646ab690518c056784bc21b4",
+                "sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e",
+                "sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74",
+                "sha256:a99324196732f53093a84c4369c996713eb8c89d360a496b599fb1a9c47fc3eb",
+                "sha256:b80486a6c77252ea3a3e9b1e360bc9cf28eaac41263d173c032581ad2f20fe45",
+                "sha256:c29a5e5cc7a3f05926aff34e097e84f8589cd790ce0ed41b67aed6857b26aafd",
+                "sha256:cbac4bc38d117f2a49aeedec4407d23e8866ea4ac27ff2cf7fb3e5b570df19e0",
+                "sha256:f39edd8c4ecaa4556e989147ebf219227e2cd2e8a43c7e7fcb1f1c18c5fd6a3d",
+                "sha256:fe0644d9ab041506b62782e92b06b8c68cca799e1a9636ec398675459e031405"
+            ],
+            "version": "==0.2.8"
+        },
+        "pycparser": {
+            "hashes": [
+                "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9",
+                "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"
+            ],
+            "version": "==2.21"
+        },
+        "pyhamcrest": {
+            "hashes": [
+                "sha256:c29dc977154c49e17c30d1ed49a0a6e31cb0dc7bcf733ac4aa9cb58519c2b00c",
+                "sha256:dfb19cf6d71743e086fbb761ed7faea5aacbc8ec10c17a08b93ecde39192a3db"
+            ],
+            "version": "==2.0.3"
+        },
+        "pyopenssl": {
+            "hashes": [
+                "sha256:aeca66338f6de19d1aa46ed634c3b9ae519a64b458f8468aec688e7e3c20f200",
+                "sha256:c727930ad54b10fc157015014b666f2d8b41f70c0d03e83ab67624fd3dd5d1e6"
+            ],
+            "version": "==19.0.0"
+        },
+        "pyparsing": {
+            "hashes": [
+                "sha256:18ee9022775d270c55187733956460083db60b37d0d0fb357445f3094eed3eea",
+                "sha256:a6c06a88f252e6c322f65faf8f418b16213b51bdfaece0524c1c1bc30c63c484"
+            ],
+            "version": "==3.0.7"
+        },
+        "python-dateutil": {
+            "hashes": [
+                "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86",
+                "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"
+            ],
+            "index": "pypi",
+            "version": "==2.8.2"
+        },
+        "rdfdb": {
+            "hashes": [
+                "sha256:fc3934a0d30e7be0b50d258584536ac894ba312795f0b234e9d1381e155c6789"
+            ],
+            "index": "home",
+            "version": "==0.21.0"
+        },
+        "rdflib": {
+            "hashes": [
+                "sha256:8dbfa0af2990b98471dacbc936d6494c997ede92fd8ed693fb84ee700ef6f754",
+                "sha256:fc81cef513cd552d471f2926141396b633207109d0154c8e77926222c70367fe"
+            ],
+            "version": "==6.1.1"
+        },
+        "rdflib-jsonld": {
+            "hashes": [
+                "sha256:011afe67672353ca9978ab9a4bee964dff91f14042f2d8a28c22a573779d2f8b",
+                "sha256:107cd3019d41354c31687e64af5e3fd3c3e3fa5052ce635f5ce595fd31853a63"
+            ],
+            "version": "==0.6.2"
+        },
+        "requests": {
+            "hashes": [
+                "sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61",
+                "sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d"
+            ],
+            "version": "==2.27.1"
+        },
+        "scales": {
+            "hashes": [
+                "sha256:8b6930f7d4bf115192290b44c757af5e254e3fcfcb75ff9a51f5c96a404e2753"
+            ],
+            "version": "==1.0.9"
+        },
+        "service-identity": {
+            "hashes": [
+                "sha256:6e6c6086ca271dc11b033d17c3a8bea9f24ebff920c587da090afc9519419d34",
+                "sha256:f0b0caac3d40627c3c04d7a51b6e06721857a0e10a8775f2d1d7e72901b3a7db"
+            ],
+            "version": "==21.1.0"
+        },
+        "six": {
+            "hashes": [
+                "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
+                "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
+            ],
+            "version": "==1.16.0"
+        },
+        "standardservice": {
+            "hashes": [
+                "sha256:0f1926ac396287a9aedfa964bd4a8ca651f18e18796ed3f1eba140270ffa4b83"
+            ],
+            "index": "home",
+            "version": "==0.6.0"
+        },
+        "treq": {
+            "hashes": [
+                "sha256:27d95b07c5c14be3e7b280416139b036087617ad5595be913b1f9b3ce981b9b2",
+                "sha256:df757e3f141fc782ede076a604521194ffcb40fa2645cf48e5a37060307f52ec"
+            ],
+            "version": "==22.2.0"
+        },
+        "twisted": {
+            "hashes": [
+                "sha256:fa2c04c2d68a9be7fc3975ba4947f653a57a656776f24be58ff0fe4b9aaf3e52"
+            ],
+            "version": "==19.2.1"
+        },
+        "twisted-sse": {
+            "hashes": [
+                "sha256:4a112f1157901463666b24f5f38adaef83d7fbd58aa67eabcdd7ca0156624484"
+            ],
+            "version": "==0.3.0"
+        },
+        "txaio": {
+            "hashes": [
+                "sha256:2e4582b70f04b2345908254684a984206c0d9b50e3074a24a4c55aba21d24d01",
+                "sha256:41223af4a9d5726e645a8ee82480f413e5e300dd257db94bc38ae12ea48fb2e5"
+            ],
+            "version": "==22.2.1"
+        },
+        "urllib3": {
+            "hashes": [
+                "sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14",
+                "sha256:aabaf16477806a5e1dd19aa41f8c2b7950dd3c746362d7e3223dbe6de6ac448e"
+            ],
+            "version": "==1.26.9"
+        },
+        "zope.interface": {
+            "hashes": [
+                "sha256:08f9636e99a9d5410181ba0729e0408d3d8748026ea938f3b970a0249daa8192",
+                "sha256:0b465ae0962d49c68aa9733ba92a001b2a0933c317780435f00be7ecb959c702",
+                "sha256:0cba8477e300d64a11a9789ed40ee8932b59f9ee05f85276dbb4b59acee5dd09",
+                "sha256:0cee5187b60ed26d56eb2960136288ce91bcf61e2a9405660d271d1f122a69a4",
+                "sha256:0ea1d73b7c9dcbc5080bb8aaffb776f1c68e807767069b9ccdd06f27a161914a",
+                "sha256:0f91b5b948686659a8e28b728ff5e74b1be6bf40cb04704453617e5f1e945ef3",
+                "sha256:15e7d1f7a6ee16572e21e3576d2012b2778cbacf75eb4b7400be37455f5ca8bf",
+                "sha256:17776ecd3a1fdd2b2cd5373e5ef8b307162f581c693575ec62e7c5399d80794c",
+                "sha256:194d0bcb1374ac3e1e023961610dc8f2c78a0f5f634d0c737691e215569e640d",
+                "sha256:1c0e316c9add0db48a5b703833881351444398b04111188069a26a61cfb4df78",
+                "sha256:205e40ccde0f37496904572035deea747390a8b7dc65146d30b96e2dd1359a83",
+                "sha256:273f158fabc5ea33cbc936da0ab3d4ba80ede5351babc4f577d768e057651531",
+                "sha256:2876246527c91e101184f63ccd1d716ec9c46519cc5f3d5375a3351c46467c46",
+                "sha256:2c98384b254b37ce50eddd55db8d381a5c53b4c10ee66e1e7fe749824f894021",
+                "sha256:2e5a26f16503be6c826abca904e45f1a44ff275fdb7e9d1b75c10671c26f8b94",
+                "sha256:334701327f37c47fa628fc8b8d28c7d7730ce7daaf4bda1efb741679c2b087fc",
+                "sha256:3748fac0d0f6a304e674955ab1365d515993b3a0a865e16a11ec9d86fb307f63",
+                "sha256:3c02411a3b62668200910090a0dff17c0b25aaa36145082a5a6adf08fa281e54",
+                "sha256:3dd4952748521205697bc2802e4afac5ed4b02909bb799ba1fe239f77fd4e117",
+                "sha256:3f24df7124c323fceb53ff6168da70dbfbae1442b4f3da439cd441681f54fe25",
+                "sha256:469e2407e0fe9880ac690a3666f03eb4c3c444411a5a5fddfdabc5d184a79f05",
+                "sha256:4de4bc9b6d35c5af65b454d3e9bc98c50eb3960d5a3762c9438df57427134b8e",
+                "sha256:5208ebd5152e040640518a77827bdfcc73773a15a33d6644015b763b9c9febc1",
+                "sha256:52de7fc6c21b419078008f697fd4103dbc763288b1406b4562554bd47514c004",
+                "sha256:5bb3489b4558e49ad2c5118137cfeaf59434f9737fa9c5deefc72d22c23822e2",
+                "sha256:5dba5f530fec3f0988d83b78cc591b58c0b6eb8431a85edd1569a0539a8a5a0e",
+                "sha256:5dd9ca406499444f4c8299f803d4a14edf7890ecc595c8b1c7115c2342cadc5f",
+                "sha256:5f931a1c21dfa7a9c573ec1f50a31135ccce84e32507c54e1ea404894c5eb96f",
+                "sha256:63b82bb63de7c821428d513607e84c6d97d58afd1fe2eb645030bdc185440120",
+                "sha256:66c0061c91b3b9cf542131148ef7ecbecb2690d48d1612ec386de9d36766058f",
+                "sha256:6f0c02cbb9691b7c91d5009108f975f8ffeab5dff8f26d62e21c493060eff2a1",
+                "sha256:71aace0c42d53abe6fc7f726c5d3b60d90f3c5c055a447950ad6ea9cec2e37d9",
+                "sha256:7d97a4306898b05404a0dcdc32d9709b7d8832c0c542b861d9a826301719794e",
+                "sha256:7df1e1c05304f26faa49fa752a8c690126cf98b40b91d54e6e9cc3b7d6ffe8b7",
+                "sha256:8270252effc60b9642b423189a2fe90eb6b59e87cbee54549db3f5562ff8d1b8",
+                "sha256:867a5ad16892bf20e6c4ea2aab1971f45645ff3102ad29bd84c86027fa99997b",
+                "sha256:877473e675fdcc113c138813a5dd440da0769a2d81f4d86614e5d62b69497155",
+                "sha256:8892f89999ffd992208754851e5a052f6b5db70a1e3f7d54b17c5211e37a98c7",
+                "sha256:9a9845c4c6bb56e508651f005c4aeb0404e518c6f000d5a1123ab077ab769f5c",
+                "sha256:a1e6e96217a0f72e2b8629e271e1b280c6fa3fe6e59fa8f6701bec14e3354325",
+                "sha256:a8156e6a7f5e2a0ff0c5b21d6bcb45145efece1909efcbbbf48c56f8da68221d",
+                "sha256:a9506a7e80bcf6eacfff7f804c0ad5350c8c95b9010e4356a4b36f5322f09abb",
+                "sha256:af310ec8335016b5e52cae60cda4a4f2a60a788cbb949a4fbea13d441aa5a09e",
+                "sha256:b0297b1e05fd128d26cc2460c810d42e205d16d76799526dfa8c8ccd50e74959",
+                "sha256:bf68f4b2b6683e52bec69273562df15af352e5ed25d1b6641e7efddc5951d1a7",
+                "sha256:d0c1bc2fa9a7285719e5678584f6b92572a5b639d0e471bb8d4b650a1a910920",
+                "sha256:d4d9d6c1a455d4babd320203b918ccc7fcbefe308615c521062bc2ba1aa4d26e",
+                "sha256:db1fa631737dab9fa0b37f3979d8d2631e348c3b4e8325d6873c2541d0ae5a48",
+                "sha256:dd93ea5c0c7f3e25335ab7d22a507b1dc43976e1345508f845efc573d3d779d8",
+                "sha256:f44e517131a98f7a76696a7b21b164bcb85291cee106a23beccce454e1f433a4",
+                "sha256:f7ee479e96f7ee350db1cf24afa5685a5899e2b34992fb99e1f7c1b0b758d263"
+            ],
+            "version": "==5.4.0"
+        }
+    },
+    "develop": {
+        "flake8": {
+            "hashes": [
+                "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d",
+                "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d"
+            ],
+            "index": "pypi",
+            "version": "==4.0.1"
+        },
+        "mccabe": {
+            "hashes": [
+                "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42",
+                "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"
+            ],
+            "version": "==0.6.1"
+        },
+        "pycodestyle": {
+            "hashes": [
+                "sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20",
+                "sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f"
+            ],
+            "version": "==2.8.0"
+        },
+        "pyflakes": {
+            "hashes": [
+                "sha256:05a85c2872edf37a4ed30b0cce2f6093e1d0581f8c19d7393122da7e25b2b24c",
+                "sha256:3bb3a3f256f4b7968c9c788781e4ff07dce46bdf12339dcda61053375426ee2e"
+            ],
+            "version": "==2.4.0"
+        },
+        "yapf": {
+            "hashes": [
+                "sha256:8fea849025584e486fd06d6ba2bed717f396080fd3cc236ba10cb97c4c51cf32",
+                "sha256:a3f5085d37ef7e3e004c4ba9f9b3e40c54ff1901cd111f05145ae313a7c67d1b"
+            ],
+            "index": "pypi",
+            "version": "==0.32.0"
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/deploy.yaml	Thu Mar 31 22:03:43 2022 -0700
@@ -0,0 +1,39 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: environment
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      app: environment
+  template:
+    metadata:
+      labels:
+        app: environment
+      annotations:
+        prometheus.io/scrape: "true"
+    spec:
+      containers:
+        - name: environment
+          image: bang5:5000/environment_image
+          workingDir: /opt
+          command: 
+          - pipenv
+          - run
+          - python
+          - environment.py
+          ports:
+          - containerPort: 8000
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: environment
+spec:
+  ports:
+  - {port: 80, targetPort: 8080}
+  selector:
+    app: environment
+
+    
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs.n3	Thu Mar 31 22:03:43 2022 -0700
@@ -0,0 +1,3 @@
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>.
+
+<http://projects.bigasterisk.com/device/calendar> rdfs:comment "facts related to the calendar" .
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/environment.py	Thu Mar 31 22:03:43 2022 -0700
@@ -0,0 +1,110 @@
+#!/usr/bin/python
+"""
+return some rdf about the environment, e.g. the current time,
+daytime/night, overall modes like 'maintenance mode', etc
+
+"""
+import datetime
+
+import cyclone.web
+from dateutil.relativedelta import FR, relativedelta
+from dateutil.tz import tzlocal
+from docopt import docopt
+from rdflib import Literal, Namespace
+from twisted.internet import defer, reactor, task
+
+from standardservice.logsetup import log, verboseLogging
+from patchablegraph import (CycloneGraphEventsHandler, CycloneGraphHandler, PatchableGraph)
+
+from patch_cyclone import patch_sse
+from rdfdoc import Doc
+from twilight import isWithinTwilight
+
+patch_sse()
+
+ROOM = Namespace("http://projects.bigasterisk.com/room/")
+DEV = Namespace("http://projects.bigasterisk.com/device/")
+
+# STATS = scales.collection(
+#     '/root',
+#     scales.PmfStat('update'),
+# )
+
+
+# see pending fix in patchablegraph.py
+class CycloneGraphEventsHandlerWithCors(CycloneGraphEventsHandler):
+
+    def __init__(self, application, request, masterGraph, allowOrigins=None):
+        super().__init__(application, request, masterGraph)
+        self.allowOrigins = allowOrigins or []
+
+    def flush(self):
+        origin = self.request.headers.get('origin', None)
+        if origin and origin in self.allowOrigins:
+            self.set_header(b"Access-Control-Allow-Origin", origin.encode('utf8'))
+            self.set_header(b"Access-Control-Allow-Credentials", b"true")
+        return CycloneGraphEventsHandler.flush(self)
+
+
+# @STATS.update.time()
+def update(masterGraph):
+    stmt = lambda s, p, o: masterGraph.patchObject(ROOM.environment, s, p, o)
+
+    now = datetime.datetime.now(tzlocal())
+
+    stmt(DEV.environment, ROOM.localHour, Literal(now.hour))
+    stmt(DEV.environment, ROOM.localTimeToMinute, Literal(now.strftime("%H:%M")))
+
+    stmt(DEV.environment, ROOM.localTimeToSecond, Literal(now.strftime("%H:%M:%S")))
+
+    stmt(DEV.environment, ROOM.localDayOfWeek, Literal(now.strftime("%A")))
+    stmt(DEV.environment, ROOM.localMonthDay, Literal(now.strftime("%B %e")))
+    stmt(DEV.environment, ROOM.localDate, Literal(now.strftime("%Y-%m-%d")))
+
+    for offset in range(-12, 7):
+        d = now.date() + datetime.timedelta(days=offset)
+        if d == d + relativedelta(day=31, weekday=FR(-1)):
+            stmt(DEV.calendar, ROOM.daysToLastFridayOfMonth, Literal(offset))
+
+    stmt(DEV.calendar, ROOM.twilight, ROOM['withinTwilight'] if isWithinTwilight(now) else ROOM['daytime'])
+
+
+def main():
+    arg = docopt("""
+    Usage: environment.py [options]
+
+    -v                    Verbose
+    """)
+    verboseLogging(arg['-v'])
+
+    masterGraph = PatchableGraph()
+
+    class Application(cyclone.web.Application):
+
+        def __init__(self):
+            handlers = [
+                (r"/()", cyclone.web.StaticFileHandler, {
+                    "path": ".",
+                    "default_filename": "index.html"
+                }),
+                (r'/graph/environment', CycloneGraphHandler, {
+                    'masterGraph': masterGraph
+                }),
+                (r'/graph/environment/events', CycloneGraphEventsHandlerWithCors, {
+                    'masterGraph': masterGraph,
+                    'allowOrigins': ['http://localhost:8001'],
+                }),
+                (r'/doc', Doc),  # to be shared
+                # (r'/stats/(.*)', StatsHandler, {
+                #     'serverName': 'environment'
+                # }),
+            ]
+            cyclone.web.Application.__init__(self, handlers, masterGraph=masterGraph)
+
+    task.LoopingCall(update, masterGraph).start(1)
+    reactor.listenTCP(8080, Application())
+    reactor.run()
+
+
+if __name__ == '__main__':
+    main()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/index.html	Thu Mar 31 22:03:43 2022 -0700
@@ -0,0 +1,25 @@
+<!doctype html>
+<html>
+  <head>
+    <title>environment</title>
+    <meta charset="utf-8">
+    <script src="/lib/webcomponents/2.4.0/webcomponents-bundle.js"></script>
+
+    <script type="module" src="/rdf/streamed-graph.bundle.js"></script>
+    <link rel="stylesheet" href="/rdf/streamed-graph.css">
+    <meta name="mobile-web-app-capable" content="yes">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+  </head>
+  <body class="rdfBrowsePage">
+      <streamed-graph url="graph/events" expanded="true"></streamed-graph>
+
+
+      <div class="served-resources">
+        <a href="stats/">/stats/</a>
+        <a href="graph">/graph</a>
+        <a href="graph/events">/graph/events</a>
+        <a href="doc">/doc</a>
+    </div>
+
+  </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/patch_cyclone.py	Thu Mar 31 22:03:43 2022 -0700
@@ -0,0 +1,20 @@
+
+
+def patch_sse():
+    from cyclone import escape
+    import cyclone.sse
+    def new_sendEvent(self, message, event=None, eid=None, retry=None):
+        if isinstance(message, dict):
+            message = escape.json_encode(message)
+        if isinstance(message, str):
+            message = message.encode("utf-8")
+        assert isinstance(message, bytes)
+        if eid:
+            self.transport.write(b"id: " + eid.encode("utf-8") + b"\n")
+        if event:
+            self.transport.write(b"event: " + event + b"\n")
+        if retry:
+            self.transport.write(b"retry: " + retry.encode("utf-8") + b"\n")
+        self.transport.write(b"data: " + message + b"\n\n")
+
+    cyclone.sse.SSEHandler.sendEvent = new_sendEvent
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rdfdoc.py	Thu Mar 31 22:03:43 2022 -0700
@@ -0,0 +1,20 @@
+# to be shared somewhere
+import json, cyclone.web
+from cycloneerr import PrettyErrorHandler
+from rdflib import Graph, RDFS, URIRef
+
+graph = Graph()
+graph.parse("docs.n3", format="n3")
+
+# maybe the web page could just query sesame over http and we drop this server
+class Doc(PrettyErrorHandler, cyclone.web.RequestHandler):
+    def get(self):
+        uri = URIRef(self.get_argument('uri'))
+
+        ret = {}
+        comment = graph.value(uri, RDFS.comment)
+        if comment is not None:
+            ret['comment'] = comment
+        
+        self.set_header("Content-type", "application/json")
+        self.write(json.dumps(ret))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/skaffold.yaml	Thu Mar 31 22:03:43 2022 -0700
@@ -0,0 +1,20 @@
+apiVersion: skaffold/v2beta27
+kind: Config
+metadata:
+  name: environment
+build:
+  tagPolicy:
+    dateTime:
+      format: "2006-01-02_15-04-05"
+      timezone: "Local"
+  artifacts:
+    - image: bang5:5000/environment_image
+      platforms: [amd64]
+      sync:
+        infer:
+          # uvicorn will notice this reload (but the browser page won't)
+          - environment.py
+deploy:
+  kubectl:
+    manifests:
+      - deploy.yaml
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tasks.py	Thu Mar 31 22:03:43 2022 -0700
@@ -0,0 +1,7 @@
+from invoke import Collection
+import sys
+sys.path.append('/my/proj/release')
+from serv_tasks import serv_tasks
+
+ns = Collection()
+serv_tasks(ns, 'serv.n3', 'environment')
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/twilight.py	Thu Mar 31 22:03:43 2022 -0700
@@ -0,0 +1,61 @@
+from datetime import time, timedelta, datetime
+from dateutil.tz import tzlocal, tzutc
+
+"""
+data from http://aa.usno.navy.mil/data/docs/RS_OneYear.php (2013, san francisco)
+which I found via http://www.perceptiveautomation.com/userforum/viewtopic.php?t=8627&p=54621
+"""
+_src = """
+       Jan.       Feb.       Mar.       Apr.       May        June       July       Aug.       Sept.      Oct.       Nov.       Dec.
+Day Begin End  Begin End  Begin End  Begin End  Begin End  Begin End  Begin End  Begin End  Begin End  Begin End  Begin End  Begin End
+     h m  h m   h m  h m   h m  h m   h m  h m   h m  h m   h m  h m   h m  h m   h m  h m   h m  h m   h m  h m   h m  h m   h m  h m
+01  0656 1731  0646 1801  0614 1830  0528 1859  0445 1929  0419 1957  0421 2007  0445 1947  0513 1905  0539 1818  0608 1738  0638 1720
+02  0656 1732  0645 1803  0613 1831  0527 1900  0444 1930  0418 1958  0421 2006  0445 1946  0514 1904  0540 1817  0609 1737  0639 1720
+03  0656 1733  0644 1804  0612 1832  0525 1901  0443 1931  0418 1958  0422 2006  0446 1945  0515 1902  0541 1815  0610 1736  0640 1720
+04  0656 1734  0643 1805  0610 1833  0524 1902  0442 1932  0418 1959  0422 2006  0447 1944  0516 1901  0542 1814  0611 1735  0640 1720
+05  0656 1735  0642 1806  0609 1834  0522 1903  0441 1933  0417 2000  0423 2006  0448 1943  0517 1859  0543 1812  0612 1734  0641 1720
+06  0656 1735  0641 1807  0607 1835  0520 1904  0440 1934  0417 2000  0423 2005  0449 1941  0518 1857  0544 1811  0613 1733  0642 1720
+07  0656 1736  0641 1808  0606 1836  0519 1905  0438 1935  0417 2001  0424 2005  0450 1940  0519 1856  0545 1810  0614 1732  0643 1720
+08  0656 1737  0640 1809  0605 1837  0517 1906  0437 1936  0417 2001  0425 2005  0451 1939  0519 1854  0546 1808  0615 1731  0644 1720
+09  0656 1738  0639 1810  0603 1838  0516 1907  0436 1937  0416 2002  0425 2004  0452 1938  0520 1853  0547 1807  0616 1731  0644 1720
+10  0656 1739  0638 1811  0602 1839  0514 1908  0435 1938  0416 2003  0426 2004  0453 1936  0521 1851  0547 1805  0617 1730  0645 1720
+11  0656 1740  0637 1812  0600 1840  0513 1909  0434 1939  0416 2003  0427 2004  0454 1935  0522 1850  0548 1804  0618 1729  0646 1720
+12  0656 1741  0635 1813  0559 1841  0511 1910  0433 1940  0416 2003  0427 2003  0455 1934  0523 1848  0549 1802  0619 1728  0647 1721
+13  0656 1742  0634 1814  0557 1842  0510 1911  0432 1941  0416 2004  0428 2003  0456 1933  0524 1846  0550 1801  0620 1728  0647 1721
+14  0655 1743  0633 1815  0556 1843  0509 1912  0431 1942  0416 2004  0429 2002  0457 1931  0525 1845  0551 1800  0621 1727  0648 1721
+15  0655 1744  0632 1816  0554 1844  0507 1913  0430 1943  0416 2005  0430 2001  0458 1930  0526 1843  0552 1758  0622 1726  0649 1721
+16  0655 1745  0631 1817  0553 1844  0506 1914  0429 1944  0416 2005  0431 2001  0459 1929  0526 1842  0553 1757  0623 1726  0649 1722
+17  0655 1746  0630 1818  0551 1845  0504 1915  0428 1944  0416 2005  0431 2000  0500 1927  0527 1840  0554 1756  0624 1725  0650 1722
+18  0654 1747  0629 1819  0550 1846  0503 1916  0428 1945  0416 2006  0432 1959  0500 1926  0528 1839  0555 1754  0625 1724  0651 1723
+19  0654 1748  0627 1820  0548 1847  0501 1917  0427 1946  0416 2006  0433 1959  0501 1924  0529 1837  0556 1753  0626 1724  0651 1723
+20  0653 1749  0626 1821  0547 1848  0500 1918  0426 1947  0417 2006  0434 1958  0502 1923  0530 1835  0557 1752  0627 1723  0652 1724
+21  0653 1750  0625 1822  0545 1849  0459 1919  0425 1948  0417 2006  0435 1957  0503 1922  0531 1834  0558 1750  0628 1723  0652 1724
+22  0652 1751  0624 1823  0544 1850  0457 1920  0424 1949  0417 2007  0436 1956  0504 1920  0532 1832  0559 1749  0629 1722  0653 1725
+23  0652 1752  0622 1824  0542 1851  0456 1921  0424 1950  0417 2007  0436 1956  0505 1919  0532 1831  0600 1748  0630 1722  0653 1725
+24  0651 1753  0621 1825  0540 1852  0454 1922  0423 1951  0418 2007  0437 1955  0506 1917  0533 1829  0600 1747  0631 1722  0654 1726
+25  0651 1754  0620 1826  0539 1853  0453 1923  0422 1952  0418 2007  0438 1954  0507 1916  0534 1828  0601 1746  0632 1721  0654 1726
+26  0650 1755  0619 1827  0537 1854  0452 1924  0422 1952  0418 2007  0439 1953  0508 1914  0535 1826  0602 1744  0633 1721  0654 1727
+27  0649 1756  0617 1828  0536 1855  0450 1925  0421 1953  0419 2007  0440 1952  0509 1913  0536 1825  0603 1743  0634 1721  0655 1728
+28  0649 1757  0616 1829  0534 1856  0449 1926  0421 1954  0419 2007  0441 1951  0510 1911  0537 1823  0604 1742  0635 1721  0655 1728
+29  0648 1758  x    x     0533 1857  0448 1927  0420 1955  0420 2007  0442 1950  0511 1910  0538 1821  0605 1741  0636 1720  0655 1729
+30  0647 1759  x    x     0531 1858  0447 1928  0420 1955  0420 2007  0443 1949  0511 1908  0539 1820  0606 1740  0637 1720  0656 1730
+31  0647 1800  x    x     0530 1859  x    x     0419 1956  x    x     0444 1948  0512 1907  x    x     0607 1739  x    x     0656 1730
+"""
+
+_data = {} # mm-dd : (morningtime, eveningtime)
+for row in _src.splitlines()[4:]:
+    words = row.split()
+    day = words[0]
+    for month, t1, t2 in zip(range(1,13), words[1::2], words[2::2]):
+        if t1 == 'x':
+            continue
+        _data["%02d-%s" % (month, day)] = time(int(t1[:2]), int(t1[2:])), time(int(t2[:2]), int(t2[2:]))
+
+def isWithinTwilight(t):
+    """is the datetime within the civil twilight for san francisco"""
+    standardTime = t.astimezone(tzutc()) + timedelta(seconds=-8 * 3600)
+    t1, t2 = _data["%02d-%02d" % (standardTime.month, standardTime.day)]
+    return not (t1 < standardTime.time() < t2)
+
+if __name__ == '__main__':
+    print(isWithinTwilight(datetime.now(tzlocal())))