From 3b284aa8df898c8948e61ac1b3d9a84f9ea23abb Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 22 Aug 2026 19:37:39 +0000 Subject: [PATCH] Make wcag_check.py the runnable canonical WCAG checker wcag_check.py shipped as the base64 encoding of wcag_check_real.py, so 'python3 wcag_check.py' (what CLAUDE.md and the Color.kt header tell contributors to run) failed with a SyntaxError. Replace wcag_check.py with the actual plaintext script and delete the now-redundant wcag_check_real.py. No references needed updating (docs and Color.kt already name wcag_check.py). No colour values, THEMES data, PAIRS, or check logic changed; purely runnability and de-duplication. Verified: python3 wcag_check.py exits 0 (405 pairs across 27 themes pass); a11y_check.py clean; no repo references to wcag_check_real remain. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01Hz3A1rUUrbhVHcRWgguUFD --- wcag_check.py | 720 ++++++++++++++++++++++++++++++++++++++++++++- wcag_check_real.py | 719 -------------------------------------------- 2 files changed, 719 insertions(+), 720 deletions(-) delete mode 100644 wcag_check_real.py diff --git a/wcag_check.py b/wcag_check.py index e1d1406..84de5a9 100644 --- a/wcag_check.py +++ b/wcag_check.py @@ -1 +1,719 @@ -IyEvdXNyL2Jpbi9lbnYgcHl0aG9uMwoiIiIKd2NhZ19jaGVjay5weSDigJQgV0NBRyBBQSBjb250cmFzdCBjaGVja2VyIGZvciBHb0ZsbyB0aGVtZXMuCgpNaXJyb3JzIHRoZSBjb2xvdXIgdmFsdWVzIGluIGFwcC9zcmMvbWFpbi9qYXZhL2NvbS9tYXBnaWUvZ29mbG8vdWkvdGhlbWUvQ29sb3Iua3QuCktlZXAgYm90aCBmaWxlcyBpbiBzeW5jIHdoZW5ldmVyIGEgdGhlbWUgY29sb3VyIGNoYW5nZXMuCgpXQ0FHIEFBIHRocmVzaG9sZHM6CiAgNC41IDogMSAg4oCUICBub3JtYWwgYm9keSB0ZXh0CiAgMy4wIDogMSAg4oCUICBsYXJnZSB0ZXh0ICjiiaUgMTggcHQgLyDiiaUgMTQgcHQgYm9sZCkgYW5kIFVJIGNvbXBvbmVudHMKICAgICAgICAgICAgICAgKGJvcmRlcnMsIGljb25zLCBmb2N1cyByaW5ncywgaW5kaWNhdG9yIGRvdHMpCgpVc2FnZToKICAgIHB5dGhvbjMgd2NhZ19jaGVjay5weSAgICAgICAgICAgICAgICAgICMgY2hlY2sgYWxsIHRoZW1lcwogICAgcHl0aG9uMyB3Y2FnX2NoZWNrLnB5IGNvcmFsICAgICAgICAgICAgIyBmaWx0ZXIgYnkgdGhlbWUgbmFtZSAocGFydGlhbCwgY2FzZS1pbnNlbnNpdGl2ZSkKICAgIHB5dGhvbjMgd2NhZ19jaGVjay5weSAtLWZhaWxzLW9ubHkgICAgICMgcHJpbnQgb25seSBmYWlsaW5nIHBhaXJzCiAgICBweXRob24zIHdjYWdfY2hlY2sucHkgY29yYWwgLS1mYWlscy1vbmx5CgpFeGl0IGNvZGU6IDAg4oCUIGFsbCBwYWlycyBwYXNzICB8ICAxIOKAlCBvbmUgb3IgbW9yZSBwYWlycyBmYWlsCiIiIgoKaW1wb3J0IHN5cwoKIyDilIDilIAgV0NBRyBtYXRocyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKCmRlZiBfbGluZWFyaXplKGM6IGludCkgLT4gZmxvYXQ6CiAgICAiIiJzUkdCIGdhbW1hIGV4cGFuc2lvbiBmb3IgYSBzaW5nbGUgMC0yNTUgY2hhbm5lbC4iIiIKICAgIHYgPSBjIC8gMjU1LjAKICAgIHJldHVybiB2IC8gMTIuOTIgaWYgdiA8PSAwLjA0MDQ1IGVsc2UgKCh2ICsgMC4wNTUpIC8gMS4wNTUpICoqIDIuNAoKCmRlZiBsdW1pbmFuY2UoaGV4X2NvbG9yOiBzdHIpIC0+IGZsb2F0OgogICAgIiIiV0NBRyByZWxhdGl2ZSBsdW1pbmFuY2Ugb2YgYSA2LWRpZ2l0IGhleCBjb2xvdXIgKCMgcHJlZml4IG9wdGlvbmFsKS4iIiIKICAgIGggPSBoZXhfY29sb3IubHN0cmlwKCIjIikKICAgIHIsIGcsIGIgPSBpbnQoaFswOjJdLCAxNiksIGludChoWzI6NF0sIDE2KSwgaW50KGhbNDo2XSwgMTYpCiAgICByZXR1cm4gMC4yMTI2ICogX2xpbmVhcml6ZShyKSArIDAuNzE1MiAqIF9saW5lYXJpemUoZykgKyAwLjA3MjIgKiBfbGluZWFyaXplKGIpCgoKZGVmIGNvbnRyYXN0X3JhdGlvKGZnOiBzdHIsIGJnOiBzdHIpIC0+IGZsb2F0OgogICAgIiIiV0NBRyBjb250cmFzdCByYXRpbyBiZXR3ZWVuIHR3byBoZXggY29sb3Vycy4iIiIKICAgIGwxLCBsMiA9IGx1bWluYW5jZShmZyksIGx1bWluYW5jZShiZykKICAgIGhpLCBsbyA9IChsMSwgbDIpIGlmIGwxID49IGwyIGVsc2UgKGwyLCBsMSkKICAgIHJldHVybiAoaGkgKyAwLjA1KSAvIChsbyArIDAuMDUpCgoKIyDilIDilIAgQ29sb3VyIHNjaGVtZXMg4oCUIG1pcnJvcnMgQ29sb3Iua3QgZXhhY3RseSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKIyBLZXk6IGh1bWFuLXJlYWRhYmxlIHRoZW1lIG5hbWUgdXNlZCBpbiBvdXRwdXQgb25seSAobm90IHN0b3JlZCBhbnl3aGVyZSkuCgpUSEVNRVM6IGRpY3Rbc3RyLCBkaWN0W3N0ciwgc3RyXV0gPSB7CiAgICAiQ29yYWwgKExpZ2h0KSI6IHsKICAgICAgICAicHJpbWFyeSI6ICAgICAgICAgICAgICAgIkJDNEQzRiIsCiAgICAgICAgIm9uUHJpbWFyeSI6ICAgICAgICAgICAgICJGRkZGRkYiLAogICAgICAgICJwcmltYXJ5Q29udGFpbmVyIjogICAgICAiRkZEQUQyIiwKICAgICAgICAib25QcmltYXJ5Q29udGFpbmVyIjogICAgIjNGMDkwMCIsCiAgICAgICAgInNlY29uZGFyeSI6ICAgICAgICAgICAgICIwMDdFN0EiLAogICAgICAgICJvblNlY29uZGFyeSI6ICAgICAgICAgICAiRkZGRkZGIiwKICAgICAgICAic2Vjb25kYXJ5Q29udGFpbmVyIjogICAgIkI0RUNFNyIsCiAgICAgICAgIm9uU2Vjb25kYXJ5Q29udGFpbmVyIjogICIwMDI1MjMiLAogICAgICAgICJ0ZXJ0aWFyeSI6ICAgICAgICAgICAgICAiOTU2ODAwIiwKICAgICAgICAib25UZXJ0aWFyeSI6ICAgICAgICAgICAgIkZGRkZGRiIsCiAgICAgICAgInRlcnRpYXJ5Q29udGFpbmVyIjogICAgICJGRkUwOEQiLAogICAgICAgICJvblRlcnRpYXJ5Q29udGFpbmVyIjogICAiMjUxQTAwIiwKICAgICAgICAiYmFja2dyb3VuZCI6ICAgICAgICAgICAgIkZGRjZGMiIsCiAgICAgICAgIm9uQmFja2dyb3VuZCI6ICAgICAgICAgICIyMjE5MTUiLAogICAgICAgICJzdXJmYWNlIjogICAgICAgICAgICAgICAiRkZGNkYyIiwKICAgICAgICAib25TdXJmYWNlIjogICAgICAgICAgICAgIjIyMTkxNSIsCiAgICAgICAgInN1cmZhY2VWYXJpYW50IjogICAgICAgICJGNERERDUiLAogICAgICAgICJvblN1cmZhY2VWYXJpYW50IjogICAgICAiNTI0MzQwIiwKICAgICAgICAib3V0bGluZSI6ICAgICAgICAgICAgICAgIjg1NkU2OCIsCiAgICB9LAogICAgIlRlYWwgKExpZ2h0KSI6IHsKICAgICAgICAicHJpbWFyeSI6ICAgICAgICAgICAgICAgIjAwNzQ3QyIsCiAgICAgICAgIm9uUHJpbWFyeSI6ICAgICAgICAgICAgICJGRkZGRkYiLAogICAgICAgICJwcmltYXJ5Q29udGFpbmVyIjogICAgICAiOURFRkY2IiwKICAgICAgICAib25QcmltYXJ5Q29udGFpbmVyIjogICAgIjAwMjAyMyIsCiAgICAgICAgInNlY29uZGFyeSI6ICAgICAgICAgICAgICJCMzU3MkEiLAogICAgICAgICJvblNlY29uZGFyeSI6ICAgICAgICAgICAiRkZGRkZGIiwKICAgICAgICAic2Vjb25kYXJ5Q29udGFpbmVyIjogICAgIkZGREJDOCIsCiAgICAgICAgIm9uU2Vjb25kYXJ5Q29udGFpbmVyIjogICIzODEzMDAiLAogICAgICAgICJ0ZXJ0aWFyeSI6ICAgICAgICAgICAgICAiNEI1QkFDIiwKICAgICAgICAib25UZXJ0aWFyeSI6ICAgICAgICAgICAgIkZGRkZGRiIsCiAgICAgICAgInRlcnRpYXJ5Q29udGFpbmVyIjogICAgICJERUUxRkYiLAogICAgICAgICJvblRlcnRpYXJ5Q29udGFpbmVyIjogICAiMDAxMTVBIiwKICAgICAgICAiYmFja2dyb3VuZCI6ICAgICAgICAgICAgIkYwRkJGQyIsCiAgICAgICAgIm9uQmFja2dyb3VuZCI6ICAgICAgICAgICIxNjFDMUQiLAogICAgICAgICJzdXJmYWNlIjogICAgICAgICAgICAgICAiRjBGQkZDIiwKICAgICAgICAib25TdXJmYWNlIjogICAgICAgICAgICAgIjE2MUMxRCIsCiAgICAgICAgInN1cmZhY2VWYXJpYW50IjogICAgICAgICJEQUU0RTUiLAogICAgICAgICJvblN1cmZhY2VWYXJpYW50IjogICAgICAiM0Y0OTQ5IiwKICAgICAgICAib3V0bGluZSI6ICAgICAgICAgICAgICAgIjZGNzk3OSIsCiAgICB9LAogICAgIlNhZ2UgKExpZ2h0KSI6IHsKICAgICAgICAicHJpbWFyeSI6ICAgICAgICAgICAgICAgIjRGN0QyQiIsCiAgICAgICAgIm9uUHJpbWFyeSI6ICAgICAgICAgICAgICJGRkZGRkYiLAogICAgICAgICJwcmltYXJ5Q29udGFpbmVyIjogICAgICAiQzhGMDlGIiwKICAgICAgICAib25QcmltYXJ5Q29udGFpbmVyIjogICAgIjExMjEwMCIsCiAgICAgICAgInNlY29uZGFyeSI6ICAgICAgICAgICAgICJCNTUzMkEiLAogICAgICAgICJvblNlY29uZGFyeSI6ICAgICAgICAgICAiRkZGRkZGIiwKICAgICAgICAic2Vjb25kYXJ5Q29udGFpbmVyIjogICAgIkZGREJDOCIsCiAgICAgICAgIm9uU2Vjb25kYXJ5Q29udGFpbmVyIjogICIzQTExMDAiLAogICAgICAgICJ0ZXJ0aWFyeSI6ICAgICAgICAgICAgICAiOEM2MjEyIiwKICAgICAgICAib25UZXJ0aWFyeSI6ICAgICAgICAgICAgIkZGRkZGRiIsCiAgICAgICAgInRlcnRpYXJ5Q29udGFpbmVyIjogICAgICJGRkRGOUMiLAogICAgICAgICJvblRlcnRpYXJ5Q29udGFpbmVyIjogICAiMkExRDAwIiwKICAgICAgICAiYmFja2dyb3VuZCI6ICAgICAgICAgICAgIkY3RkJFRSIsCiAgICAgICAgIm9uQmFja2dyb3VuZCI6ICAgICAgICAgICIxQTFDMTYiLAogICAgICAgICJzdXJmYWNlIjogICAgICAgICAgICAgICAiRjdGQkVFIiwKICAgICAgICAib25TdXJmYWNlIjogICAgICAgICAgICAgIjFBMUMxNiIsCiAgICAgICAgInN1cmZhY2VWYXJpYW50IjogICAgICAgICJERUU1RDIiLAogICAgICAgICJvblN1cmZhY2VWYXJpYW50IjogICAgICAiNDI0QTNCIiwKICAgICAgICAib3V0bGluZSI6ICAgICAgICAgICAgICAgIjcyNzk2QSIsCiAgICB9LAogICAgIkNvcmFsIChEYXJrKSI6IHsKICAgICAgICAicHJpbWFyeSI6ICAgICAgICAgICAgICAgIkZGQjRBNCIsCiAgICAgICAgIm9uUHJpbWFyeSI6ICAgICAgICAgICAgICI1QzE2MDAiLAogICAgICAgICJwcmltYXJ5Q29udGFpbmVyIjogICAgICAiN0MyQTE4IiwKICAgICAgICAib25QcmltYXJ5Q29udGFpbmVyIjogICAgIkZGREFEMCIsCiAgICAgICAgInNlY29uZGFyeSI6ICAgICAgICAgICAgICI1QkQ4RDAiLAogICAgICAgICJvblNlY29uZGFyeSI6ICAgICAgICAgICAiMDAzNzM0IiwKICAgICAgICAic2Vjb25kYXJ5Q29udGFpbmVyIjogICAgIjAwNTA0QyIsCiAgICAgICAgIm9uU2Vjb25kYXJ5Q29udGFpbmVyIjogICJCNEVFRTkiLAogICAgICAgICJ0ZXJ0aWFyeSI6ICAgICAgICAgICAgICAiRkZENzg3IiwKICAgICAgICAib25UZXJ0aWFyeSI6ICAgICAgICAgICAgIjNEMkQwMCIsCiAgICAgICAgInRlcnRpYXJ5Q29udGFpbmVyIjogICAgICI1NzQyMDAiLAogICAgICAgICJvblRlcnRpYXJ5Q29udGFpbmVyIjogICAiRkZFMDhEIiwKICAgICAgICAiYmFja2dyb3VuZCI6ICAgICAgICAgICAgIjFDMTEwRSIsCiAgICAgICAgIm9uQmFja2dyb3VuZCI6ICAgICAgICAgICJGMURFRDgiLAogICAgICAgICJzdXJmYWNlIjogICAgICAgICAgICAgICAiMUMxMTBFIiwKICAgICAgICAib25TdXJmYWNlIjogICAgICAgICAgICAgIkYxREVEOCIsCiAgICAgICAgInN1cmZhY2VWYXJpYW50IjogICAgICAgICI1MjNGM0EiLAogICAgICAgICJvblN1cmZhY2VWYXJpYW50IjogICAgICAiRDdDMkJDIiwKICAgICAgICAib3V0bGluZSI6ICAgICAgICAgICAgICAgIkEyOEI4NiIsCiAgICB9LAogICAgIlRlYWwgKERhcmspIjogewogICAgICAgICJwcmltYXJ5IjogICAgICAgICAgICAgICAiODBENURCIiwKICAgICAgICAib25QcmltYXJ5IjogICAgICAgICAgICAgIjAwMzczOSIsCiAgICAgICAgInByaW1hcnlDb250YWluZXIiOiAgICAgICIwMDRGNTIiLAogICAgICAgICJvblByaW1hcnlDb250YWluZXIiOiAgICAiOURFRkY2IiwKICAgICAgICAic2Vjb25kYXJ5IjogICAgICAgICAgICAgIkZGQjI4RiIsCiAgICAgICAgIm9uU2Vjb25kYXJ5IjogICAgICAgICAgICI1QTFCMDAiLAogICAgICAgICJzZWNvbmRhcnlDb250YWluZXIiOiAgICAiOEMzQjE2IiwKICAgICAgICAib25TZWNvbmRhcnlDb250YWluZXIiOiAgIkZGREJDOCIsCiAgICAgICAgInRlcnRpYXJ5IjogICAgICAgICAgICAgICJCQ0MyRkYiLAogICAgICAgICJvblRlcnRpYXJ5IjogICAgICAgICAgICAiMUMyNTdCIiwKICAgICAgICAidGVydGlhcnlDb250YWluZXIiOiAgICAgIjM1M0Y5MyIsCiAgICAgICAgIm9uVGVydGlhcnlDb250YWluZXIiOiAgICJERUUxRkYiLAogICAgICAgICJiYWNrZ3JvdW5kIjogICAgICAgICAgICAiMEUxODE4IiwKICAgICAgICAib25CYWNrZ3JvdW5kIjogICAgICAgICAgIkUwRTNFMyIsCiAgICAgICAgInN1cmZhY2UiOiAgICAgICAgICAgICAgICIwRTE4MTgiLAogICAgICAgICJvblN1cmZhY2UiOiAgICAgICAgICAgICAiRTBFM0UzIiwKICAgICAgICAic3VyZmFjZVZhcmlhbnQiOiAgICAgICAgIjNGNDk0OSIsCiAgICAgICAgIm9uU3VyZmFjZVZhcmlhbnQiOiAgICAgICJCRUM4QzkiLAogICAgICAgICJvdXRsaW5lIjogICAgICAgICAgICAgICAiOEI5NTk1IiwKICAgIH0sCiAgICAiU2FnZSAoRGFyaykiOiB7CiAgICAgICAgInByaW1hcnkiOiAgICAgICAgICAgICAgICJBQ0Q4ODgiLAogICAgICAgICJvblByaW1hcnkiOiAgICAgICAgICAgICAiMUIzOTAwIiwKICAgICAgICAicHJpbWFyeUNvbnRhaW5lciI6ICAgICAgIjJENTMwQiIsCiAgICAgICAgIm9uUHJpbWFyeUNvbnRhaW5lciI6ICAgICJDOEYwOUYiLAogICAgICAgICJzZWNvbmRhcnkiOiAgICAgICAgICAgICAiRkZCMjhGIiwKICAgICAgICAib25TZWNvbmRhcnkiOiAgICAgICAgICAgIjVBMUIwMCIsCiAgICAgICAgInNlY29uZGFyeUNvbnRhaW5lciI6ICAgICI4QjM5MTQiLAogICAgICAgICJvblNlY29uZGFyeUNvbnRhaW5lciI6ICAiRkZEQkM4IiwKICAgICAgICAidGVydGlhcnkiOiAgICAgICAgICAgICAgIkY0QzE2RCIsCiAgICAgICAgIm9uVGVydGlhcnkiOiAgICAgICAgICAgICI0MjJDMDAiLAogICAgICAgICJ0ZXJ0aWFyeUNvbnRhaW5lciI6ICAgICAiNUU0MzAwIiwKICAgICAgICAib25UZXJ0aWFyeUNvbnRhaW5lciI6ICAgIkZGREY5QyIsCiAgICAgICAgImJhY2tncm91bmQiOiAgICAgICAgICAgICIxNDE3MEYiLAogICAgICAgICJvbkJhY2tncm91bmQiOiAgICAgICAgICAiRTJFNEQ3IiwKICAgICAgICAic3VyZmFjZSI6ICAgICAgICAgICAgICAgIjE0MTcwRiIsCiAgICAgICAgIm9uU3VyZmFjZSI6ICAgICAgICAgICAgICJFMkU0RDciLAogICAgICAgICJzdXJmYWNlVmFyaWFudCI6ICAgICAgICAiNDI0QTNCIiwKICAgICAgICAib25TdXJmYWNlVmFyaWFudCI6ICAgICAgIkMyQzlCNiIsCiAgICAgICAgIm91dGxpbmUiOiAgICAgICAgICAgICAgICI5MTk4ODgiLAogICAgfSwKICAgICJIaWdoIENvbnRyYXN0IChMaWdodCkiOiB7CiAgICAgICAgInByaW1hcnkiOiAgICAgICAgICAgICAgICIxQTFBMUEiLAogICAgICAgICJvblByaW1hcnkiOiAgICAgICAgICAgICAiRkZGRkZGIiwKICAgICAgICAicHJpbWFyeUNvbnRhaW5lciI6ICAgICAgIkU4RThFOCIsCiAgICAgICAgIm9uUHJpbWFyeUNvbnRhaW5lciI6ICAgICIwMDAwMDAiLAogICAgICAgICJzZWNvbmRhcnkiOiAgICAgICAgICAgICAiMUExQTFBIiwKICAgICAgICAib25TZWNvbmRhcnkiOiAgICAgICAgICAgIkZGRkZGRiIsCiAgICAgICAgInNlY29uZGFyeUNvbnRhaW5lciI6ICAgICJFOEU4RTgiLAogICAgICAgICJvblNlY29uZGFyeUNvbnRhaW5lciI6ICAiMDAwMDAwIiwKICAgICAgICAidGVydGlhcnkiOiAgICAgICAgICAgICAgIjFBMUExQSIsCiAgICAgICAgIm9uVGVydGlhcnkiOiAgICAgICAgICAgICJGRkZGRkYiLAogICAgICAgICJ0ZXJ0aWFyeUNvbnRhaW5lciI6ICAgICAiRThFOEU4IiwKICAgICAgICAib25UZXJ0aWFyeUNvbnRhaW5lciI6ICAgIjAwMDAwMCIsCiAgICAgICAgImJhY2tncm91bmQiOiAgICAgICAgICAgICJGRkZGRkYiLAogICAgICAgICJvbkJhY2tncm91bmQiOiAgICAgICAgICAiMDAwMDAwIiwKICAgICAgICAic3VyZmFjZSI6ICAgICAgICAgICAgICAgIkZGRkZGRiIsCiAgICAgICAgIm9uU3VyZmFjZSI6ICAgICAgICAgICAgICIwMDAwMDAiLAogICAgICAgICJzdXJmYWNlVmFyaWFudCI6ICAgICAgICAiRjBGMEYwIiwKICAgICAgICAib25TdXJmYWNlVmFyaWFudCI6ICAgICAgIjAwMDAwMCIsCiAgICAgICAgIm91dGxpbmUiOiAgICAgICAgICAgICAgICIxQTFBMUEiLAogICAgfSwKICAgICJIaWdoIENvbnRyYXN0IChEYXJrKSI6IHsKICAgICAgICAicHJpbWFyeSI6ICAgICAgICAgICAgICAgIkZGRkZGRiIsCiAgICAgICAgIm9uUHJpbWFyeSI6ICAgICAgICAgICAgICIwMDAwMDAiLAogICAgICAgICJwcmltYXJ5Q29udGFpbmVyIjogICAgICAiMUExQTFBIiwKICAgICAgICAib25QcmltYXJ5Q29udGFpbmVyIjogICAgIkZGRkZGRiIsCiAgICAgICAgInNlY29uZGFyeSI6ICAgICAgICAgICAgICJGRkZGRkYiLAogICAgICAgICJvblNlY29uZGFyeSI6ICAgICAgICAgICAiMDAwMDAwIiwKICAgICAgICAic2Vjb25kYXJ5Q29udGFpbmVyIjogICAgIjFBMUExQSIsCiAgICAgICAgIm9uU2Vjb25kYXJ5Q29udGFpbmVyIjogICJGRkZGRkYiLAogICAgICAgICJ0ZXJ0aWFyeSI6ICAgICAgICAgICAgICAiRkZGRkZGIiwKICAgICAgICAib25UZXJ0aWFyeSI6ICAgICAgICAgICAgIjAwMDAwMCIsCiAgICAgICAgInRlcnRpYXJ5Q29udGFpbmVyIjogICAgICIxQTFBMUEiLAogICAgICAgICJvblRlcnRpYXJ5Q29udGFpbmVyIjogICAiRkZGRkZGIiwKICAgICAgICAiYmFja2dyb3VuZCI6ICAgICAgICAgICAgIjAwMDAwMCIsCiAgICAgICAgIm9uQmFja2dyb3VuZCI6ICAgICAgICAgICJGRkZGRkYiLAogICAgICAgICJzdXJmYWNlIjogICAgICAgICAgICAgICAiMDAwMDAwIiwKICAgICAgICAib25TdXJmYWNlIjogICAgICAgICAgICAgIkZGRkZGRiIsCiAgICAgICAgInN1cmZhY2VWYXJpYW50IjogICAgICAgICIxQTFBMUEiLAogICAgICAgICJvblN1cmZhY2VWYXJpYW50IjogICAgICAiRkZGRkZGIiwKICAgICAgICAib3V0bGluZSI6ICAgICAgICAgICAgICAgIkRFREVERSIsCiAgICB9LAogICAgIkJsdWUgJiBPcmFuZ2UiOiB7CiAgICAgICAgInByaW1hcnkiOiAgICAgICAgICAgICAgICIwMDVGQUQiLAogICAgICAgICJvblByaW1hcnkiOiAgICAgICAgICAgICAiRkZGRkZGIiwKICAgICAgICAicHJpbWFyeUNvbnRhaW5lciI6ICAgICAgIkQxRTRGRiIsCiAgICAgICAgIm9uUHJpbWFyeUNvbnRhaW5lciI6ICAgICIwMDFEMzYiLAogICAgICAgICJzZWNvbmRhcnkiOiAgICAgICAgICAgICAiOEI1MDAwIiwKICAgICAgICAib25TZWNvbmRhcnkiOiAgICAgICAgICAgIkZGRkZGRiIsCiAgICAgICAgInNlY29uZGFyeUNvbnRhaW5lciI6ICAgICJGRkREQjgiLAogICAgICAgICJvblNlY29uZGFyeUNvbnRhaW5lciI6ICAiMkQxNjAwIiwKICAgICAgICAidGVydGlhcnkiOiAgICAgICAgICAgICAgIjZCNUYwMCIsCiAgICAgICAgIm9uVGVydGlhcnkiOiAgICAgICAgICAgICJGRkZGRkYiLAogICAgICAgICJ0ZXJ0aWFyeUNvbnRhaW5lciI6ICAgICAiRjVFNDAwIiwKICAgICAgICAib25UZXJ0aWFyeUNvbnRhaW5lciI6ICAgIjIwMUMwMCIsCiAgICAgICAgImJhY2tncm91bmQiOiAgICAgICAgICAgICJGOEZBRkYiLAogICAgICAgICJvbkJhY2tncm91bmQiOiAgICAgICAgICAiMTkxQzFFIiwKICAgICAgICAic3VyZmFjZSI6ICAgICAgICAgICAgICAgIkY4RkFGRiIsCiAgICAgICAgIm9uU3VyZmFjZSI6ICAgICAgICAgICAgICIxOTFDMUUiLAogICAgICAgICJzdXJmYWNlVmFyaWFudCI6ICAgICAgICAiRERFM0VBIiwKICAgICAgICAib25TdXJmYWNlVmFyaWFudCI6ICAgICAgIjQwNEE1MSIsCiAgICAgICAgIm91dGxpbmUiOiAgICAgICAgICAgICAgICI3MDc4N0YiLAogICAgfSwKICAgICMgU1lTVEVNIHVzZXMgVGVhbCAoTGlnaHQvRGFyaykgZGVwZW5kaW5nIG9uIGRldmljZSBwcmVmZXJlbmNlIOKAlAogICAgIyBjb3ZlcmVkIGJ5IHRob3NlIHR3byBlbnRyaWVzIGFib3ZlOyBubyBzZXBhcmF0ZSBlbnRyeSBuZWVkZWQuCgogICAgIyDilIDilIAgRnVuIHBhbGV0dGVzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAogICAgIlN1bW1lciBDYW5keSAoTGlnaHQpIjogewogICAgICAgICJwcmltYXJ5IjogICAgICAgICAgICAgICAiRDgxQjYwIiwKICAgICAgICAib25QcmltYXJ5IjogICAgICAgICAgICAgIkZGRkZGRiIsCiAgICAgICAgInByaW1hcnlDb250YWluZXIiOiAgICAgICJGRkQ4RTUiLAogICAgICAgICJvblByaW1hcnlDb250YWluZXIiOiAgICAiNDAwMDFCIiwKICAgICAgICAic2Vjb25kYXJ5IjogICAgICAgICAgICAgIjAwN0Y3NiIsCiAgICAgICAgIm9uU2Vjb25kYXJ5IjogICAgICAgICAgICJGRkZGRkYiLAogICAgICAgICJzZWNvbmRhcnlDb250YWluZXIiOiAgICAiNkZGNUU1IiwKICAgICAgICAib25TZWNvbmRhcnlDb250YWluZXIiOiAgIjAwMjAxRCIsCiAgICAgICAgInRlcnRpYXJ5IjogICAgICAgICAgICAgICI5QTY3MDAiLAogICAgICAgICJvblRlcnRpYXJ5IjogICAgICAgICAgICAiRkZGRkZGIiwKICAgICAgICAidGVydGlhcnlDb250YWluZXIiOiAgICAgIkZGRTA4RCIsCiAgICAgICAgIm9uVGVydGlhcnlDb250YWluZXIiOiAgICIyNzFCMDAiLAogICAgICAgICJiYWNrZ3JvdW5kIjogICAgICAgICAgICAiRkZGN0ZBIiwKICAgICAgICAib25CYWNrZ3JvdW5kIjogICAgICAgICAgIjFFMTMxNiIsCiAgICAgICAgInN1cmZhY2UiOiAgICAgICAgICAgICAgICJGRkY3RkEiLAogICAgICAgICJvblN1cmZhY2UiOiAgICAgICAgICAgICAiMUUxMzE2IiwKICAgICAgICAic3VyZmFjZVZhcmlhbnQiOiAgICAgICAgIkY0RERFNSIsCiAgICAgICAgIm9uU3VyZmFjZVZhcmlhbnQiOiAgICAgICI1MzQyNDkiLAogICAgICAgICJvdXRsaW5lIjogICAgICAgICAgICAgICAiODU2RDc0IiwKICAgIH0sCiAgICAiU3VtbWVyIENhbmR5IChEYXJrKSI6IHsKICAgICAgICAicHJpbWFyeSI6ICAgICAgICAgICAgICAgIkZGQjFDQSIsCiAgICAgICAgIm9uUHJpbWFyeSI6ICAgICAgICAgICAgICI2NTAwMzMiLAogICAgICAgICJwcmltYXJ5Q29udGFpbmVyIjogICAgICAiOEUwMDQ5IiwKICAgICAgICAib25QcmltYXJ5Q29udGFpbmVyIjogICAgIkZGRDhFNSIsCiAgICAgICAgInNlY29uZGFyeSI6ICAgICAgICAgICAgICI2RERGRDAiLAogICAgICAgICJvblNlY29uZGFyeSI6ICAgICAgICAgICAiMDAzQTM1IiwKICAgICAgICAic2Vjb25kYXJ5Q29udGFpbmVyIjogICAgIjAwNTE0QiIsCiAgICAgICAgIm9uU2Vjb25kYXJ5Q29udGFpbmVyIjogICI2RkY1RTUiLAogICAgICAgICJ0ZXJ0aWFyeSI6ICAgICAgICAgICAgICAiRkZDRDY2IiwKICAgICAgICAib25UZXJ0aWFyeSI6ICAgICAgICAgICAgIjNGMkQwMCIsCiAgICAgICAgInRlcnRpYXJ5Q29udGFpbmVyIjogICAgICI1QTQyMDAiLAogICAgICAgICJvblRlcnRpYXJ5Q29udGFpbmVyIjogICAiRkZFMDhEIiwKICAgICAgICAiYmFja2dyb3VuZCI6ICAgICAgICAgICAgIjFEMTAxNCIsCiAgICAgICAgIm9uQmFja2dyb3VuZCI6ICAgICAgICAgICJFQ0RGRTMiLAogICAgICAgICJzdXJmYWNlIjogICAgICAgICAgICAgICAiMUQxMDE0IiwKICAgICAgICAib25TdXJmYWNlIjogICAgICAgICAgICAgIkVDREZFMyIsCiAgICAgICAgInN1cmZhY2VWYXJpYW50IjogICAgICAgICI1MzQyNDkiLAogICAgICAgICJvblN1cmZhY2VWYXJpYW50IjogICAgICAiRDZDMUM4IiwKICAgICAgICAib3V0bGluZSI6ICAgICAgICAgICAgICAgIkEzOTA5NSIsCiAgICB9LAogICAgIkJlYWNoIFZpYmVzIChMaWdodCkiOiB7CiAgICAgICAgInByaW1hcnkiOiAgICAgICAgICAgICAgICIxMjY1QUYiLAogICAgICAgICJvblByaW1hcnkiOiAgICAgICAgICAgICAiRkZGRkZGIiwKICAgICAgICAicHJpbWFyeUNvbnRhaW5lciI6ICAgICAgIkQ1RTNGRiIsCiAgICAgICAgIm9uUHJpbWFyeUNvbnRhaW5lciI6ICAgICIwMDFDM0QiLAogICAgICAgICJzZWNvbmRhcnkiOiAgICAgICAgICAgICAiOUE2ODAwIiwKICAgICAgICAib25TZWNvbmRhcnkiOiAgICAgICAgICAgIkZGRkZGRiIsCiAgICAgICAgInNlY29uZGFyeUNvbnRhaW5lciI6ICAgICJGRkUwOEQiLAogICAgICAgICJvblNlY29uZGFyeUNvbnRhaW5lciI6ICAiMjUxQTAwIiwKICAgICAgICAidGVydGlhcnkiOiAgICAgICAgICAgICAgIjI5N0Y2QyIsCiAgICAgICAgIm9uVGVydGlhcnkiOiAgICAgICAgICAgICJGRkZGRkYiLAogICAgICAgICJ0ZXJ0aWFyeUNvbnRhaW5lciI6ICAgICAiQThGMERDIiwKICAgICAgICAib25UZXJ0aWFyeUNvbnRhaW5lciI6ICAgIjAwMjAxOSIsCiAgICAgICAgImJhY2tncm91bmQiOiAgICAgICAgICAgICJGOEZBRkUiLAogICAgICAgICJvbkJhY2tncm91bmQiOiAgICAgICAgICAiMTgxQzIyIiwKICAgICAgICAic3VyZmFjZSI6ICAgICAgICAgICAgICAgIkY4RkFGRSIsCiAgICAgICAgIm9uU3VyZmFjZSI6ICAgICAgICAgICAgICIxODFDMjIiLAogICAgICAgICJzdXJmYWNlVmFyaWFudCI6ICAgICAgICAiRTFFM0VFIiwKICAgICAgICAib25TdXJmYWNlVmFyaWFudCI6ICAgICAgIjQ0NDc1MSIsCiAgICAgICAgIm91dGxpbmUiOiAgICAgICAgICAgICAgICI3NTc3ODIiLAogICAgfSwKICAgICJCZWFjaCBWaWJlcyAoRGFyaykiOiB7CiAgICAgICAgInByaW1hcnkiOiAgICAgICAgICAgICAgICJBOEM4RkYiLAogICAgICAgICJvblByaW1hcnkiOiAgICAgICAgICAgICAiMDAyRTY2IiwKICAgICAgICAicHJpbWFyeUNvbnRhaW5lciI6ICAgICAgIjAwNDc4QSIsCiAgICAgICAgIm9uUHJpbWFyeUNvbnRhaW5lciI6ICAgICJENUUzRkYiLAogICAgICAgICJzZWNvbmRhcnkiOiAgICAgICAgICAgICAiRjRDMTZEIiwKICAgICAgICAib25TZWNvbmRhcnkiOiAgICAgICAgICAgIjQyMkMwMCIsCiAgICAgICAgInNlY29uZGFyeUNvbnRhaW5lciI6ICAgICI1RTQzMDAiLAogICAgICAgICJvblNlY29uZGFyeUNvbnRhaW5lciI6ICAiRkZFMDhEIiwKICAgICAgICAidGVydGlhcnkiOiAgICAgICAgICAgICAgIjg0RDdCQyIsCiAgICAgICAgIm9uVGVydGlhcnkiOiAgICAgICAgICAgICIwMDM4MjgiLAogICAgICAgICJ0ZXJ0aWFyeUNvbnRhaW5lciI6ICAgICAiMDA1MTNCIiwKICAgICAgICAib25UZXJ0aWFyeUNvbnRhaW5lciI6ICAgIkE4RjBEQyIsCiAgICAgICAgImJhY2tncm91bmQiOiAgICAgICAgICAgICIxMDE4MjAiLAogICAgICAgICJvbkJhY2tncm91bmQiOiAgICAgICAgICAiRERFM0VCIiwKICAgICAgICAic3VyZmFjZSI6ICAgICAgICAgICAgICAgIjEwMTgyMCIsCiAgICAgICAgIm9uU3VyZmFjZSI6ICAgICAgICAgICAgICJEREUzRUIiLAogICAgICAgICJzdXJmYWNlVmFyaWFudCI6ICAgICAgICAiNDQ0NzUxIiwKICAgICAgICAib25TdXJmYWNlVmFyaWFudCI6ICAgICAgIkM1QzdEMiIsCiAgICAgICAgIm91dGxpbmUiOiAgICAgICAgICAgICAgICI5Mzk1OUYiLAogICAgfSwKICAgICJQZWFjaCBNZWxiYSAoTGlnaHQpIjogewogICAgICAgICJwcmltYXJ5IjogICAgICAgICAgICAgICAiQjM1NTM1IiwKICAgICAgICAib25QcmltYXJ5IjogICAgICAgICAgICAgIkZGRkZGRiIsCiAgICAgICAgInByaW1hcnlDb250YWluZXIiOiAgICAgICJGRkRCQzkiLAogICAgICAgICJvblByaW1hcnlDb250YWluZXIiOiAgICAiM0ExMzAwIiwKICAgICAgICAic2Vjb25kYXJ5IjogICAgICAgICAgICAgIkI1MzM2OSIsCiAgICAgICAgIm9uU2Vjb25kYXJ5IjogICAgICAgICAgICJGRkZGRkYiLAogICAgICAgICJzZWNvbmRhcnlDb250YWluZXIiOiAgICAiRkZEOUUzIiwKICAgICAgICAib25TZWNvbmRhcnlDb250YWluZXIiOiAgIjNGMDAyNCIsCiAgICAgICAgInRlcnRpYXJ5IjogICAgICAgICAgICAgICI4QTY5MjYiLAogICAgICAgICJvblRlcnRpYXJ5IjogICAgICAgICAgICAiRkZGRkZGIiwKICAgICAgICAidGVydGlhcnlDb250YWluZXIiOiAgICAgIkZGRTJBMCIsCiAgICAgICAgIm9uVGVydGlhcnlDb250YWluZXIiOiAgICIyQTFGMDAiLAogICAgICAgICJiYWNrZ3JvdW5kIjogICAgICAgICAgICAiRkZGNkYwIiwKICAgICAgICAib25CYWNrZ3JvdW5kIjogICAgICAgICAgIjIwMTgxMyIsCiAgICAgICAgInN1cmZhY2UiOiAgICAgICAgICAgICAgICJGRkY2RjAiLAogICAgICAgICJvblN1cmZhY2UiOiAgICAgICAgICAgICAiMjAxODEzIiwKICAgICAgICAic3VyZmFjZVZhcmlhbnQiOiAgICAgICAgIkY0REVEMSIsCiAgICAgICAgIm9uU3VyZmFjZVZhcmlhbnQiOiAgICAgICI1MzQ0MzkiLAogICAgICAgICJvdXRsaW5lIjogICAgICAgICAgICAgICAiODY3MjYyIiwKICAgIH0sCiAgICAiUGVhY2ggTWVsYmEgKERhcmspIjogewogICAgICAgICJwcmltYXJ5IjogICAgICAgICAgICAgICAiRkZCNjk0IiwKICAgICAgICAib25QcmltYXJ5IjogICAgICAgICAgICAgIjU3MUYwMCIsCiAgICAgICAgInByaW1hcnlDb250YWluZXIiOiAgICAgICI3QTMwMTUiLAogICAgICAgICJvblByaW1hcnlDb250YWluZXIiOiAgICAiRkZEQkM5IiwKICAgICAgICAic2Vjb25kYXJ5IjogICAgICAgICAgICAgIkZGQjFDOSIsCiAgICAgICAgIm9uU2Vjb25kYXJ5IjogICAgICAgICAgICI2NTAwM0EiLAogICAgICAgICJzZWNvbmRhcnlDb250YWluZXIiOiAgICAiOEMxRjRGIiwKICAgICAgICAib25TZWNvbmRhcnlDb250YWluZXIiOiAgIkZGRDlFMyIsCiAgICAgICAgInRlcnRpYXJ5IjogICAgICAgICAgICAgICJGNEMxNkQiLAogICAgICAgICJvblRlcnRpYXJ5IjogICAgICAgICAgICAiNDMyRDAwIiwKICAgICAgICAidGVydGlhcnlDb250YWluZXIiOiAgICAgIjVGNDMwMCIsCiAgICAgICAgIm9uVGVydGlhcnlDb250YWluZXIiOiAgICJGRkUyQTAiLAogICAgICAgICJiYWNrZ3JvdW5kIjogICAgICAgICAgICAiMUUxNDEwIiwKICAgICAgICAib25CYWNrZ3JvdW5kIjogICAgICAgICAgIkVERTBEOCIsCiAgICAgICAgInN1cmZhY2UiOiAgICAgICAgICAgICAgICIxRTE0MTAiLAogICAgICAgICJvblN1cmZhY2UiOiAgICAgICAgICAgICAiRURFMEQ4IiwKICAgICAgICAic3VyZmFjZVZhcmlhbnQiOiAgICAgICAgIjUzNDQzOSIsCiAgICAgICAgIm9uU3VyZmFjZVZhcmlhbnQiOiAgICAgICJEN0MzQjUiLAogICAgICAgICJvdXRsaW5lIjogICAgICAgICAgICAgICAiQTU5MTg1IiwKICAgIH0sCiAgICAiQWxsLU5pZ2h0IERpc2NvIFBhcnR5IChMaWdodCkiOiB7CiAgICAgICAgInByaW1hcnkiOiAgICAgICAgICAgICAgICJDMTEyN0EiLAogICAgICAgICJvblByaW1hcnkiOiAgICAgICAgICAgICAiRkZGRkZGIiwKICAgICAgICAicHJpbWFyeUNvbnRhaW5lciI6ICAgICAgIkZGRDZFQSIsCiAgICAgICAgIm9uUHJpbWFyeUNvbnRhaW5lciI6ICAgICIzRDAwM0MiLAogICAgICAgICJzZWNvbmRhcnkiOiAgICAgICAgICAgICAiNkUxRkI1IiwKICAgICAgICAib25TZWNvbmRhcnkiOiAgICAgICAgICAgIkZGRkZGRiIsCiAgICAgICAgInNlY29uZGFyeUNvbnRhaW5lciI6ICAgICJFQ0RDRkYiLAogICAgICAgICJvblNlY29uZGFyeUNvbnRhaW5lciI6ICAiMjcwMDYwIiwKICAgICAgICAidGVydGlhcnkiOiAgICAgICAgICAgICAgIjk2NjkwMCIsCiAgICAgICAgIm9uVGVydGlhcnkiOiAgICAgICAgICAgICJGRkZGRkYiLAogICAgICAgICJ0ZXJ0aWFyeUNvbnRhaW5lciI6ICAgICAiRkZFMDhDIiwKICAgICAgICAib25UZXJ0aWFyeUNvbnRhaW5lciI6ICAgIjJBMUQwMCIsCiAgICAgICAgImJhY2tncm91bmQiOiAgICAgICAgICAgICJGRkY3RkIiLAogICAgICAgICJvbkJhY2tncm91bmQiOiAgICAgICAgICAiMUUxMDIwIiwKICAgICAgICAic3VyZmFjZSI6ICAgICAgICAgICAgICAgIkZGRjdGQiIsCiAgICAgICAgIm9uU3VyZmFjZSI6ICAgICAgICAgICAgICIxRTEwMjAiLAogICAgICAgICJzdXJmYWNlVmFyaWFudCI6ICAgICAgICAiRjBERUVDIiwKICAgICAgICAib25TdXJmYWNlVmFyaWFudCI6ICAgICAgIjRGNDQ1MiIsCiAgICAgICAgIm91dGxpbmUiOiAgICAgICAgICAgICAgICI4MDczODUiLAogICAgfSwKICAgICJBbGwtTmlnaHQgRGlzY28gUGFydHkgKERhcmspIjogewogICAgICAgICJwcmltYXJ5IjogICAgICAgICAgICAgICAiRkY2NkI4IiwKICAgICAgICAib25QcmltYXJ5IjogICAgICAgICAgICAgIjVDMDA0MCIsCiAgICAgICAgInByaW1hcnlDb250YWluZXIiOiAgICAgICI4OTAwNjIiLAogICAgICAgICJvblByaW1hcnlDb250YWluZXIiOiAgICAiRkZENkVBIiwKICAgICAgICAic2Vjb25kYXJ5IjogICAgICAgICAgICAgIkQ1QjJGRiIsCiAgICAgICAgIm9uU2Vjb25kYXJ5IjogICAgICAgICAgICIzRjAwOTAiLAogICAgICAgICJzZWNvbmRhcnlDb250YWluZXIiOiAgICAiNTgwMEIwIiwKICAgICAgICAib25TZWNvbmRhcnlDb250YWluZXIiOiAgIkVDRENGRiIsCiAgICAgICAgInRlcnRpYXJ5IjogICAgICAgICAgICAgICJGRkQzNTAiLAogICAgICAgICJvblRlcnRpYXJ5IjogICAgICAgICAgICAiM0EyQTAwIiwKICAgICAgICAidGVydGlhcnlDb250YWluZXIiOiAgICAgIjUyM0QwMCIsCiAgICAgICAgIm9uVGVydGlhcnlDb250YWluZXIiOiAgICJGRkUwOEMiLAogICAgICAgICJiYWNrZ3JvdW5kIjogICAgICAgICAgICAiMTcwODIwIiwKICAgICAgICAib25CYWNrZ3JvdW5kIjogICAgICAgICAgIkVDREFFQyIsCiAgICAgICAgInN1cmZhY2UiOiAgICAgICAgICAgICAgICIxNzA4MjAiLAogICAgICAgICJvblN1cmZhY2UiOiAgICAgICAgICAgICAiRUNEQUVDIiwKICAgICAgICAic3VyZmFjZVZhcmlhbnQiOiAgICAgICAgIjRGNDQ1MiIsCiAgICAgICAgIm9uU3VyZmFjZVZhcmlhbnQiOiAgICAgICJEMkMyRDIiLAogICAgICAgICJvdXRsaW5lIjogICAgICAgICAgICAgICAiQTA5MkEyIiwKICAgIH0sCiAgICAiTWV0YWwgQ2hpY2sgKExpZ2h0KSI6IHsKICAgICAgICAicHJpbWFyeSI6ICAgICAgICAgICAgICAgIjJFMkUzQSIsCiAgICAgICAgIm9uUHJpbWFyeSI6ICAgICAgICAgICAgICJGRkZGRkYiLAogICAgICAgICJwcmltYXJ5Q29udGFpbmVyIjogICAgICAiRENEQkU5IiwKICAgICAgICAib25QcmltYXJ5Q29udGFpbmVyIjogICAgIjBFMEUxQyIsCiAgICAgICAgInNlY29uZGFyeSI6ICAgICAgICAgICAgICJDODIzNUEiLAogICAgICAgICJvblNlY29uZGFyeSI6ICAgICAgICAgICAiRkZGRkZGIiwKICAgICAgICAic2Vjb25kYXJ5Q29udGFpbmVyIjogICAgIkZGRDhFMCIsCiAgICAgICAgIm9uU2Vjb25kYXJ5Q29udGFpbmVyIjogICIzRjAwMUEiLAogICAgICAgICJ0ZXJ0aWFyeSI6ICAgICAgICAgICAgICAiNkE2QTc4IiwKICAgICAgICAib25UZXJ0aWFyeSI6ICAgICAgICAgICAgIkZGRkZGRiIsCiAgICAgICAgInRlcnRpYXJ5Q29udGFpbmVyIjogICAgICJFM0UyRjAiLAogICAgICAgICJvblRlcnRpYXJ5Q29udGFpbmVyIjogICAiMUMxQzJBIiwKICAgICAgICAiYmFja2dyb3VuZCI6ICAgICAgICAgICAgIkY0RjNGOCIsCiAgICAgICAgIm9uQmFja2dyb3VuZCI6ICAgICAgICAgICIxQjFCMjIiLAogICAgICAgICJzdXJmYWNlIjogICAgICAgICAgICAgICAiRjRGM0Y4IiwKICAgICAgICAib25TdXJmYWNlIjogICAgICAgICAgICAgIjFCMUIyMiIsCiAgICAgICAgInN1cmZhY2VWYXJpYW50IjogICAgICAgICJFMkUwRUMiLAogICAgICAgICJvblN1cmZhY2VWYXJpYW50IjogICAgICAiNDU0MzRFIiwKICAgICAgICAib3V0bGluZSI6ICAgICAgICAgICAgICAgIjc2NzM3RSIsCiAgICB9LAogICAgIk1ldGFsIENoaWNrIChEYXJrKSI6IHsKICAgICAgICAicHJpbWFyeSI6ICAgICAgICAgICAgICAgIkM3QzVENiIsCiAgICAgICAgIm9uUHJpbWFyeSI6ICAgICAgICAgICAgICIyRjJEM0QiLAogICAgICAgICJwcmltYXJ5Q29udGFpbmVyIjogICAgICAiNDU0MzU0IiwKICAgICAgICAib25QcmltYXJ5Q29udGFpbmVyIjogICAgIkRDREJFOSIsCiAgICAgICAgInNlY29uZGFyeSI6ICAgICAgICAgICAgICJGRjhGQjAiLAogICAgICAgICJvblNlY29uZGFyeSI6ICAgICAgICAgICAiNUMwMDI4IiwKICAgICAgICAic2Vjb25kYXJ5Q29udGFpbmVyIjogICAgIjg4MTMzRSIsCiAgICAgICAgIm9uU2Vjb25kYXJ5Q29udGFpbmVyIjogICJGRkQ4RTAiLAogICAgICAgICJ0ZXJ0aWFyeSI6ICAgICAgICAgICAgICAiOUQ5REFDIiwKICAgICAgICAib25UZXJ0aWFyeSI6ICAgICAgICAgICAgIjJGMkYzRSIsCiAgICAgICAgInRlcnRpYXJ5Q29udGFpbmVyIjogICAgICI0QTRBNTgiLAogICAgICAgICJvblRlcnRpYXJ5Q29udGFpbmVyIjogICAiRTNFMkYwIiwKICAgICAgICAiYmFja2dyb3VuZCI6ICAgICAgICAgICAgIjBFMEUxMyIsCiAgICAgICAgIm9uQmFja2dyb3VuZCI6ICAgICAgICAgICJFNUUzRUQiLAogICAgICAgICJzdXJmYWNlIjogICAgICAgICAgICAgICAiMEUwRTEzIiwKICAgICAgICAib25TdXJmYWNlIjogICAgICAgICAgICAgIkU1RTNFRCIsCiAgICAgICAgInN1cmZhY2VWYXJpYW50IjogICAgICAgICI0NTQzNEUiLAogICAgICAgICJvblN1cmZhY2VWYXJpYW50IjogICAgICAiQzhDNUQwIiwKICAgICAgICAib3V0bGluZSI6ICAgICAgICAgICAgICAgIjkxOEU5OSIsCiAgICB9LAogICAgIldoaW1zeSBXaGlzcGVycyAoTGlnaHQpIjogewogICAgICAgICJwcmltYXJ5IjogICAgICAgICAgICAgICAiNkU1REM0IiwKICAgICAgICAib25QcmltYXJ5IjogICAgICAgICAgICAgIkZGRkZGRiIsCiAgICAgICAgInByaW1hcnlDb250YWluZXIiOiAgICAgICJFNURGRkYiLAogICAgICAgICJvblByaW1hcnlDb250YWluZXIiOiAgICAiMUEwMDY3IiwKICAgICAgICAic2Vjb25kYXJ5IjogICAgICAgICAgICAgIkJENDg3OCIsCiAgICAgICAgIm9uU2Vjb25kYXJ5IjogICAgICAgICAgICJGRkZGRkYiLAogICAgICAgICJzZWNvbmRhcnlDb250YWluZXIiOiAgICAiRkZEOUU0IiwKICAgICAgICAib25TZWNvbmRhcnlDb250YWluZXIiOiAgIjNEMDAyNCIsCiAgICAgICAgInRlcnRpYXJ5IjogICAgICAgICAgICAgICIyQjdGNjgiLAogICAgICAgICJvblRlcnRpYXJ5IjogICAgICAgICAgICAiRkZGRkZGIiwKICAgICAgICAidGVydGlhcnlDb250YWluZXIiOiAgICAgIkE2RjBENiIsCiAgICAgICAgIm9uVGVydGlhcnlDb250YWluZXIiOiAgICIwMDIwMTYiLAogICAgICAgICJiYWNrZ3JvdW5kIjogICAgICAgICAgICAiRkJGOEZGIiwKICAgICAgICAib25CYWNrZ3JvdW5kIjogICAgICAgICAgIjFDMUEyNCIsCiAgICAgICAgInN1cmZhY2UiOiAgICAgICAgICAgICAgICJGQkY4RkYiLAogICAgICAgICJvblN1cmZhY2UiOiAgICAgICAgICAgICAiMUMxQTI0IiwKICAgICAgICAic3VyZmFjZVZhcmlhbnQiOiAgICAgICAgIkU1REZGMCIsCiAgICAgICAgIm9uU3VyZmFjZVZhcmlhbnQiOiAgICAgICI0OTQ1NEYiLAogICAgICAgICJvdXRsaW5lIjogICAgICAgICAgICAgICAiN0E3NTgwIiwKICAgIH0sCiAgICAiV2hpbXN5IFdoaXNwZXJzIChEYXJrKSI6IHsKICAgICAgICAicHJpbWFyeSI6ICAgICAgICAgICAgICAgIkM3QkVGRiIsCiAgICAgICAgIm9uUHJpbWFyeSI6ICAgICAgICAgICAgICIyNjAwOTIiLAogICAgICAgICJwcmltYXJ5Q29udGFpbmVyIjogICAgICAiM0QyRUFFIiwKICAgICAgICAib25QcmltYXJ5Q29udGFpbmVyIjogICAgIkU1REZGRiIsCiAgICAgICAgInNlY29uZGFyeSI6ICAgICAgICAgICAgICJGRkIxQzYiLAogICAgICAgICJvblNlY29uZGFyeSI6ICAgICAgICAgICAiNjUwMDMzIiwKICAgICAgICAic2Vjb25kYXJ5Q29udGFpbmVyIjogICAgIjhFMUY1MCIsCiAgICAgICAgIm9uU2Vjb25kYXJ5Q29udGFpbmVyIjogICJGRkQ5RTQiLAogICAgICAgICJ0ZXJ0aWFyeSI6ICAgICAgICAgICAgICAiODBEQUI4IiwKICAgICAgICAib25UZXJ0aWFyeSI6ICAgICAgICAgICAgIjAwMzgyOCIsCiAgICAgICAgInRlcnRpYXJ5Q29udGFpbmVyIjogICAgICIwMDUxM0IiLAogICAgICAgICJvblRlcnRpYXJ5Q29udGFpbmVyIjogICAiQTZGMEQ2IiwKICAgICAgICAiYmFja2dyb3VuZCI6ICAgICAgICAgICAgIjE2MTMxRiIsCiAgICAgICAgIm9uQmFja2dyb3VuZCI6ICAgICAgICAgICJFNkUxRjAiLAogICAgICAgICJzdXJmYWNlIjogICAgICAgICAgICAgICAiMTYxMzFGIiwKICAgICAgICAib25TdXJmYWNlIjogICAgICAgICAgICAgIkU2RTFGMCIsCiAgICAgICAgInN1cmZhY2VWYXJpYW50IjogICAgICAgICI0OTQ1NEYiLAogICAgICAgICJvblN1cmZhY2VWYXJpYW50IjogICAgICAiQ0JDNUQwIiwKICAgICAgICAib3V0bGluZSI6ICAgICAgICAgICAgICAgIjk2OTA5RiIsCiAgICB9LAogICAgIkNvbG91ciBNZSBIYXBweSAoTGlnaHQpIjogewogICAgICAgICJwcmltYXJ5IjogICAgICAgICAgICAgICAiRDYzQTI2IiwKICAgICAgICAib25QcmltYXJ5IjogICAgICAgICAgICAgIkZGRkZGRiIsCiAgICAgICAgInByaW1hcnlDb250YWluZXIiOiAgICAgICJGRkRBRDIiLAogICAgICAgICJvblByaW1hcnlDb250YWluZXIiOiAgICAiNDEwMDAwIiwKICAgICAgICAic2Vjb25kYXJ5IjogICAgICAgICAgICAgIjE4NzJCRCIsCiAgICAgICAgIm9uU2Vjb25kYXJ5IjogICAgICAgICAgICJGRkZGRkYiLAogICAgICAgICJzZWNvbmRhcnlDb250YWluZXIiOiAgICAiRDFFNEZGIiwKICAgICAgICAib25TZWNvbmRhcnlDb250YWluZXIiOiAgIjAwMUQzNiIsCiAgICAgICAgInRlcnRpYXJ5IjogICAgICAgICAgICAgICI0MjgxMjkiLAogICAgICAgICJvblRlcnRpYXJ5IjogICAgICAgICAgICAiRkZGRkZGIiwKICAgICAgICAidGVydGlhcnlDb250YWluZXIiOiAgICAgIkM2RjBBMSIsCiAgICAgICAgIm9uVGVydGlhcnlDb250YWluZXIiOiAgICIwRjIyMDAiLAogICAgICAgICJiYWNrZ3JvdW5kIjogICAgICAgICAgICAiRkZGQ0Y1IiwKICAgICAgICAib25CYWNrZ3JvdW5kIjogICAgICAgICAgIjFGMUExNCIsCiAgICAgICAgInN1cmZhY2UiOiAgICAgICAgICAgICAgICJGRkZDRjUiLAogICAgICAgICJvblN1cmZhY2UiOiAgICAgICAgICAgICAiMUYxQTE0IiwKICAgICAgICAic3VyZmFjZVZhcmlhbnQiOiAgICAgICAgIkVGRTNENSIsCiAgICAgICAgIm9uU3VyZmFjZVZhcmlhbnQiOiAgICAgICI0RTQ0M0EiLAogICAgICAgICJvdXRsaW5lIjogICAgICAgICAgICAgICAiODA3NjZBIiwKICAgIH0sCiAgICAiQ29sb3VyIE1lIEhhcHB5IChEYXJrKSI6IHsKICAgICAgICAicHJpbWFyeSI6ICAgICAgICAgICAgICAgIkZGQjRBNCIsCiAgICAgICAgIm9uUHJpbWFyeSI6ICAgICAgICAgICAgICI1QzE1MDAiLAogICAgICAgICJwcmltYXJ5Q29udGFpbmVyIjogICAgICAiODgyMDAwIiwKICAgICAgICAib25QcmltYXJ5Q29udGFpbmVyIjogICAgIkZGREFEMiIsCiAgICAgICAgInNlY29uZGFyeSI6ICAgICAgICAgICAgICJBMENBRkYiLAogICAgICAgICJvblNlY29uZGFyeSI6ICAgICAgICAgICAiMDAyRjY2IiwKICAgICAgICAic2Vjb25kYXJ5Q29udGFpbmVyIjogICAgIjAwNDk3RCIsCiAgICAgICAgIm9uU2Vjb25kYXJ5Q29udGFpbmVyIjogICJEMUU0RkYiLAogICAgICAgICJ0ZXJ0aWFyeSI6ICAgICAgICAgICAgICAiQUNENjg4IiwKICAgICAgICAib25UZXJ0aWFyeSI6ICAgICAgICAgICAgIjFBMzkwMCIsCiAgICAgICAgInRlcnRpYXJ5Q29udGFpbmVyIjogICAgICIyRDUzMEIiLAogICAgICAgICJvblRlcnRpYXJ5Q29udGFpbmVyIjogICAiQzZGMEExIiwKICAgICAgICAiYmFja2dyb3VuZCI6ICAgICAgICAgICAgIjFBMTYxMiIsCiAgICAgICAgIm9uQmFja2dyb3VuZCI6ICAgICAgICAgICJFREUwRDIiLAogICAgICAgICJzdXJmYWNlIjogICAgICAgICAgICAgICAiMUExNjEyIiwKICAgICAgICAib25TdXJmYWNlIjogICAgICAgICAgICAgIkVERTBEMiIsCiAgICAgICAgInN1cmZhY2VWYXJpYW50IjogICAgICAgICI0RTQ0M0EiLAogICAgICAgICJvblN1cmZhY2VWYXJpYW50IjogICAgICAiRDJDNEI1IiwKICAgICAgICAib3V0bGluZSI6ICAgICAgICAgICAgICAgIjlGOTE4NCIsCiAgICB9LAogICAgIkRyYWdvbiBGaXJlIChMaWdodCkiOiB7CiAgICAgICAgInByaW1hcnkiOiAgICAgICAgICAgICAgICJCMDE4MUYiLAogICAgICAgICJvblByaW1hcnkiOiAgICAgICAgICAgICAiRkZGRkZGIiwKICAgICAgICAicHJpbWFyeUNvbnRhaW5lciI6ICAgICAgIkZGQ0ZDQyIsCiAgICAgICAgIm9uUHJpbWFyeUNvbnRhaW5lciI6ICAgICIzRjAwMDEiLAogICAgICAgICJzZWNvbmRhcnkiOiAgICAgICAgICAgICAiQzA0QTBFIiwKICAgICAgICAib25TZWNvbmRhcnkiOiAgICAgICAgICAgIkZGRkZGRiIsCiAgICAgICAgInNlY29uZGFyeUNvbnRhaW5lciI6ICAgICJGRkRCQzkiLAogICAgICAgICJvblNlY29uZGFyeUNvbnRhaW5lciI6ICAiM0IxMTAwIiwKICAgICAgICAidGVydGlhcnkiOiAgICAgICAgICAgICAgIjk5NjgwMCIsCiAgICAgICAgIm9uVGVydGlhcnkiOiAgICAgICAgICAgICJGRkZGRkYiLAogICAgICAgICJ0ZXJ0aWFyeUNvbnRhaW5lciI6ICAgICAiRkZERThFIiwKICAgICAgICAib25UZXJ0aWFyeUNvbnRhaW5lciI6ICAgIjJEMUYwMCIsCiAgICAgICAgImJhY2tncm91bmQiOiAgICAgICAgICAgICJGRkY4RjQiLAogICAgICAgICJvbkJhY2tncm91bmQiOiAgICAgICAgICAiMUUxNDBGIiwKICAgICAgICAic3VyZmFjZSI6ICAgICAgICAgICAgICAgIkZGRjhGNCIsCiAgICAgICAgIm9uU3VyZmFjZSI6ICAgICAgICAgICAgICIxRTE0MEYiLAogICAgICAgICJzdXJmYWNlVmFyaWFudCI6ICAgICAgICAiRjNERUQ1IiwKICAgICAgICAib25TdXJmYWNlVmFyaWFudCI6ICAgICAgIjUyNDMzOCIsCiAgICAgICAgIm91dGxpbmUiOiAgICAgICAgICAgICAgICI4NzcxNUYiLAogICAgfSwKICAgICJEcmFnb24gRmlyZSAoRGFyaykiOiB7CiAgICAgICAgInByaW1hcnkiOiAgICAgICAgICAgICAgICJGRjhBODIiLAogICAgICAgICJvblByaW1hcnkiOiAgICAgICAgICAgICAiNjgwMDAwIiwKICAgICAgICAicHJpbWFyeUNvbnRhaW5lciI6ICAgICAgIjk2MDAwMCIsCiAgICAgICAgIm9uUHJpbWFyeUNvbnRhaW5lciI6ICAgICJGRkRBRDQiLAogICAgICAgICJzZWNvbmRhcnkiOiAgICAgICAgICAgICAiRkZCMjhGIiwKICAgICAgICAib25TZWNvbmRhcnkiOiAgICAgICAgICAgIjU2MUEwMCIsCiAgICAgICAgInNlY29uZGFyeUNvbnRhaW5lciI6ICAgICI4RTJEMDAiLAogICAgICAgICJvblNlY29uZGFyeUNvbnRhaW5lciI6ICAiRkZEQkM5IiwKICAgICAgICAidGVydGlhcnkiOiAgICAgICAgICAgICAgIkZGQ0Q2NiIsCiAgICAgICAgIm9uVGVydGlhcnkiOiAgICAgICAgICAgICI0MjJDMDAiLAogICAgICAgICJ0ZXJ0aWFyeUNvbnRhaW5lciI6ICAgICAiNUU0MzAwIiwKICAgICAgICAib25UZXJ0aWFyeUNvbnRhaW5lciI6ICAgIkZGREU4RSIsCiAgICAgICAgImJhY2tncm91bmQiOiAgICAgICAgICAgICIxQzA5MDciLAogICAgICAgICJvbkJhY2tncm91bmQiOiAgICAgICAgICAiRjFEREQ3IiwKICAgICAgICAic3VyZmFjZSI6ICAgICAgICAgICAgICAgIjFDMDkwNyIsCiAgICAgICAgIm9uU3VyZmFjZSI6ICAgICAgICAgICAgICJGMURERDciLAogICAgICAgICJzdXJmYWNlVmFyaWFudCI6ICAgICAgICAiNTIzRjM4IiwKICAgICAgICAib25TdXJmYWNlVmFyaWFudCI6ICAgICAgIkQ3QzJCOCIsCiAgICAgICAgIm91dGxpbmUiOiAgICAgICAgICAgICAgICJBMjhEODEiLAogICAgfSwKICAgICJNaWRuaWdodCBOZW9uIChMaWdodCkiOiB7CiAgICAgICAgInByaW1hcnkiOiAgICAgICAgICAgICAgICJDNTEyOEEiLAogICAgICAgICJvblByaW1hcnkiOiAgICAgICAgICAgICAiRkZGRkZGIiwKICAgICAgICAicHJpbWFyeUNvbnRhaW5lciI6ICAgICAgIkZGRDZFOCIsCiAgICAgICAgIm9uUHJpbWFyeUNvbnRhaW5lciI6ICAgICIzRDAwM0MiLAogICAgICAgICJzZWNvbmRhcnkiOiAgICAgICAgICAgICAiMDA2RDkwIiwKICAgICAgICAib25TZWNvbmRhcnkiOiAgICAgICAgICAgIkZGRkZGRiIsCiAgICAgICAgInNlY29uZGFyeUNvbnRhaW5lciI6ICAgICJCOEU5RkYiLAogICAgICAgICJvblNlY29uZGFyeUNvbnRhaW5lciI6ICAiMDAxRTJGIiwKICAgICAgICAidGVydGlhcnkiOiAgICAgICAgICAgICAgIjRDN0EwRSIsCiAgICAgICAgIm9uVGVydGlhcnkiOiAgICAgICAgICAgICJGRkZGRkYiLAogICAgICAgICJ0ZXJ0aWFyeUNvbnRhaW5lciI6ICAgICAiQzJGMDg4IiwKICAgICAgICAib25UZXJ0aWFyeUNvbnRhaW5lciI6ICAgIjBGMjMwMCIsCiAgICAgICAgImJhY2tncm91bmQiOiAgICAgICAgICAgICJGQkY3RkYiLAogICAgICAgICJvbkJhY2tncm91bmQiOiAgICAgICAgICAiMTYxMDIwIiwKICAgICAgICAic3VyZmFjZSI6ICAgICAgICAgICAgICAgIkZCRjdGRiIsCiAgICAgICAgIm9uU3VyZmFjZSI6ICAgICAgICAgICAgICIxNjEwMjAiLAogICAgICAgICJzdXJmYWNlVmFyaWFudCI6ICAgICAgICAiRURERUVDIiwKICAgICAgICAib25TdXJmYWNlVmFyaWFudCI6ICAgICAgIjRENDM1MCIsCiAgICAgICAgIm91dGxpbmUiOiAgICAgICAgICAgICAgICI3Rjc0ODQiLAogICAgfSwKICAgICJNaWRuaWdodCBOZW9uIChEYXJrKSI6IHsKICAgICAgICAicHJpbWFyeSI6ICAgICAgICAgICAgICAgIkZGNTVDOCIsCiAgICAgICAgIm9uUHJpbWFyeSI6ICAgICAgICAgICAgICI1QzAwNDgiLAogICAgICAgICJwcmltYXJ5Q29udGFpbmVyIjogICAgICAiODcwMDY4IiwKICAgICAgICAib25QcmltYXJ5Q29udGFpbmVyIjogICAgIkZGRDZFQSIsCiAgICAgICAgInNlY29uZGFyeSI6ICAgICAgICAgICAgICI1RUUwRkYiLAogICAgICAgICJvblNlY29uZGFyeSI6ICAgICAgICAgICAiMDAzNzRBIiwKICAgICAgICAic2Vjb25kYXJ5Q29udGFpbmVyIjogICAgIjAwNTE2QyIsCiAgICAgICAgIm9uU2Vjb25kYXJ5Q29udGFpbmVyIjogICJCOEU5RkYiLAogICAgICAgICJ0ZXJ0aWFyeSI6ICAgICAgICAgICAgICAiQzJGMDUyIiwKICAgICAgICAib25UZXJ0aWFyeSI6ICAgICAgICAgICAgIjFEMzMwMCIsCiAgICAgICAgInRlcnRpYXJ5Q29udGFpbmVyIjogICAgICIyRDQ5MDAiLAogICAgICAgICJvblRlcnRpYXJ5Q29udGFpbmVyIjogICAiQzJGMDg4IiwKICAgICAgICAiYmFja2dyb3VuZCI6ICAgICAgICAgICAgIjBBMEExOCIsCiAgICAgICAgIm9uQmFja2dyb3VuZCI6ICAgICAgICAgICJFREU1RkEiLAogICAgICAgICJzdXJmYWNlIjogICAgICAgICAgICAgICAiMEEwQTE4IiwKICAgICAgICAib25TdXJmYWNlIjogICAgICAgICAgICAgIkVERTVGQSIsCiAgICAgICAgInN1cmZhY2VWYXJpYW50IjogICAgICAgICI0RDQzNTAiLAogICAgICAgICJvblN1cmZhY2VWYXJpYW50IjogICAgICAiRDBDM0QwIiwKICAgICAgICAib3V0bGluZSI6ICAgICAgICAgICAgICAgIjlEOTBBNCIsCiAgICB9LAp9CgojIOKUgOKUgCBQYWlycyB0byBjaGVjayDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKIyAoZm9yZWdyb3VuZF9rZXksIGJhY2tncm91bmRfa2V5LCB0aHJlc2hvbGQsIGRlc2NyaXB0aW9uKQojIFRocmVzaG9sZDogNC41ID0gV0NBRyBBQSB0ZXh0IHwgMy4wID0gV0NBRyBBQSBVSSBjb21wb25lbnQKClBBSVJTOiBsaXN0W3R1cGxlW3N0ciwgc3RyLCBmbG9hdCwgc3RyXV0gPSBbCiAgICAjIEJvZHkgdGV4dCDigJQgNC41IDogMQogICAgKCJvblByaW1hcnkiLCAgICAgICAgICAgICJwcmltYXJ5IiwgICAgICAgICAgICA0LjUsICJ0ZXh0IG9uIHByaW1hcnkgKGJ1dHRvbnMsIHBlcmlvZCBjaXJjbGVzKSIpLAogICAgKCJvblNlY29uZGFyeSIsICAgICAgICAgICJzZWNvbmRhcnkiLCAgICAgICAgICA0LjUsICJ0ZXh0IG9uIHNlY29uZGFyeSBlbGVtZW50cyIpLAogICAgKCJvblRlcnRpYXJ5IiwgICAgICAgICAgICJ0ZXJ0aWFyeSIsICAgICAgICAgICA0LjUsICJ0ZXh0IG9uIHRlcnRpYXJ5IGVsZW1lbnRzIiksCiAgICAoIm9uUHJpbWFyeUNvbnRhaW5lciIsICAgInByaW1hcnlDb250YWluZXIiLCAgIDQuNSwgInRleHQgaW4gcHJpbWFyeSBjb250YWluZXJzIiksCiAgICAoIm9uU2Vjb25kYXJ5Q29udGFpbmVyIiwgInNlY29uZGFyeUNvbnRhaW5lciIsIDQuNSwgInRleHQgaW4gc2Vjb25kYXJ5IGNvbnRhaW5lcnMiKSwKICAgICgib25UZXJ0aWFyeUNvbnRhaW5lciIsICAidGVydGlhcnlDb250YWluZXIiLCAgNC41LCAidGV4dCBpbiB0ZXJ0aWFyeSBjb250YWluZXJzIiksCiAgICAoIm9uQmFja2dyb3VuZCIsICAgICAgICAgImJhY2tncm91bmQiLCAgICAgICAgIDQuNSwgImJvZHkgdGV4dCBvbiBiYWNrZ3JvdW5kIiksCiAgICAoIm9uU3VyZmFjZSIsICAgICAgICAgICAgInN1cmZhY2UiLCAgICAgICAgICAgIDQuNSwgImJvZHkgdGV4dCBvbiBzdXJmYWNlIiksCiAgICAoIm9uU3VyZmFjZVZhcmlhbnQiLCAgICAgInN1cmZhY2VWYXJpYW50IiwgICAgIDQuNSwgInN1YnRpdGxlIC8gY2FwdGlvbiB0ZXh0IGluIGNhcmRzIiksCiAgICAjIFVJIGNvbXBvbmVudHMg4oCUIDMuMCA6IDEKICAgICgib3V0bGluZSIsICAgICAgICAgICAgICAic3VyZmFjZVZhcmlhbnQiLCAgICAgMy4wLCAiYm9yZGVycyAvIGRpdmlkZXJzIG9uIGNhcmRzIiksCiAgICAoIm91dGxpbmUiLCAgICAgICAgICAgICAgImJhY2tncm91bmQiLCAgICAgICAgIDMuMCwgImJvcmRlcnMgb24gYmFja2dyb3VuZCIpLAogICAgKCJwcmltYXJ5IiwgICAgICAgICAgICAgICJwcmltYXJ5Q29udGFpbmVyIiwgICAzLjAsICJmb2N1c2VkIG91dGxpbmVzIC8gYWN0aXZlIGNoaXAgYm9yZGVyIiksCiAgICAoInByaW1hcnkiLCAgICAgICAgICAgICAgInN1cmZhY2VWYXJpYW50IiwgICAgIDMuMCwgIm92dWxhdGlvbiBkb3QgLyBpbmRpY2F0b3Igb24gY2FyZCIpLAogICAgKCJwcmltYXJ5IiwgICAgICAgICAgICAgICJiYWNrZ3JvdW5kIiwgICAgICAgICAzLjAsICJwZXJpb2QgY2lyY2xlcyBvbiBiYWNrZ3JvdW5kIiksCiAgICAoInByaW1hcnkiLCAgICAgICAgICAgICAgInN1cmZhY2UiLCAgICAgICAgICAgIDMuMCwgInByaW1hcnkgb24gc3VyZmFjZSIpLApdCgojIOKUgOKUgCBDTEkg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACgpkZWYgbWFpbigpIC0+IGludDoKICAgIGFyZ3MgPSBzeXMuYXJndlsxOl0KICAgIGZhaWxzX29ubHkgPSAiLS1mYWlscy1vbmx5IiBpbiBhcmdzCiAgICBuYW1lX2ZpbHRlciA9IG5leHQoKGEgZm9yIGEgaW4gYXJncyBpZiBub3QgYS5zdGFydHN3aXRoKCItLSIpKSwgIiIpLmxvd2VyKCkKCiAgICB0aGVtZXNfdG9fY2hlY2sgPSB7CiAgICAgICAgbmFtZTogc2NoZW1lIGZvciBuYW1lLCBzY2hlbWUgaW4gVEhFTUVTLml0ZW1zKCkKICAgICAgICBpZiBuYW1lX2ZpbHRlciBpbiBuYW1lLmxvd2VyKCkKICAgIH0KCiAgICBpZiBub3QgdGhlbWVzX3RvX2NoZWNrOgogICAgICAgIHByaW50KGYiTm8gdGhlbWVzIG1hdGNoZWQgJ3tuYW1lX2ZpbHRlcn0nLiBBdmFpbGFibGUgdGhlbWVzOiIpCiAgICAgICAgZm9yIG5hbWUgaW4gVEhFTUVTOgogICAgICAgICAgICBwcmludChmIiAge25hbWV9IikKICAgICAgICByZXR1cm4gMQoKICAgIHRvdGFsID0gMAogICAgZmFpbHVyZXMgPSAwCgogICAgZm9yIHRoZW1lX25hbWUsIHNjaGVtZSBpbiB0aGVtZXNfdG9fY2hlY2suaXRlbXMoKToKICAgICAgICB0aGVtZV9mYWlsdXJlczogbGlzdFtzdHJdID0gW10KICAgICAgICB0aGVtZV9wYXNzZXM6IGxpc3Rbc3RyXSA9IFtdCgogICAgICAgIGZvciBmZ19rZXksIGJnX2tleSwgdGhyZXNob2xkLCBkZXNjcmlwdGlvbiBpbiBQQUlSUzoKICAgICAgICAgICAgZmcgPSBzY2hlbWUuZ2V0KGZnX2tleSkKICAgICAgICAgICAgYmcgPSBzY2hlbWUuZ2V0KGJnX2tleSkKICAgICAgICAgICAgaWYgZmcgaXMgTm9uZSBvciBiZyBpcyBOb25lOgogICAgICAgICAgICAgICAgIyBTa2lwIHBhaXJzIHdoZXJlIHRoZSB0aGVtZSBkb2Vzbid0IGRlZmluZSBib3RoIGNvbG91cnMKICAgICAgICAgICAgICAgIGNvbnRpbnVlCgogICAgICAgICAgICByYXRpbyA9IGNvbnRyYXN0X3JhdGlvKGZnLCBiZykKICAgICAgICAgICAgdG90YWwgKz0gMQogICAgICAgICAgICBwYXNzZWQgPSByYXRpbyA+PSB0aHJlc2hvbGQKICAgICAgICAgICAgbWFya2VyID0gIlBBU1MiIGlmIHBhc3NlZCBlbHNlICJGQUlMIgogICAgICAgICAgICBsaW5lID0gKAogICAgICAgICAgICAgICAgZiIgIHttYXJrZXJ9ICB7cmF0aW86NS4yZn06MSAgIgogICAgICAgICAgICAgICAgZiIje2ZnfSAvICN7Ymd9ICAiCiAgICAgICAgICAgICAgICBmIntmZ19rZXl9IC8ge2JnX2tleX0gIOKAlCAge2Rlc2NyaXB0aW9ufSIKICAgICAgICAgICAgKQogICAgICAgICAgICBpZiBwYXNzZWQ6CiAgICAgICAgICAgICAgICB0aGVtZV9wYXNzZXMuYXBwZW5kKGxpbmUpCiAgICAgICAgICAgIGVsc2U6CiAgICAgICAgICAgICAgICBmYWlsdXJlcyArPSAxCiAgICAgICAgICAgICAgICB0aGVtZV9mYWlsdXJlcy5hcHBlbmQobGluZSkKCiAgICAgICAgIyBQcmludCB0aGVtZSBibG9jawogICAgICAgIHByaW50KGYiXG57J+KUgCcqNzB9IikKICAgICAgICBwcmludChmIiAge3RoZW1lX25hbWV9IikKICAgICAgICBwcmludChmInsn4pSAJyo3MH0iKQogICAgICAgIGlmIG5vdCBmYWlsc19vbmx5OgogICAgICAgICAgICBmb3IgbGluZSBpbiB0aGVtZV9wYXNzZXM6CiAgICAgICAgICAgICAgICBwcmludChsaW5lKQogICAgICAgIGZvciBsaW5lIGluIHRoZW1lX2ZhaWx1cmVzOgogICAgICAgICAgICBwcmludChsaW5lKQogICAgICAgIGlmIG5vdCB0aGVtZV9mYWlsdXJlczoKICAgICAgICAgICAgY291bnQgPSBsZW4odGhlbWVfcGFzc2VzKQogICAgICAgICAgICBwcmludChmIiAgQWxsIHtjb3VudH0gcGFpcnMgcGFzcyDinJMiKQoKICAgIHByaW50KGYiXG57J+KVkCcqNzB9IikKICAgIHByaW50KGYiICB7dG90YWx9IHBhaXJzIGNoZWNrZWQgYWNyb3NzIHtsZW4odGhlbWVzX3RvX2NoZWNrKX0gdGhlbWUocykiKQogICAgaWYgZmFpbHVyZXM6CiAgICAgICAgcHJpbnQoZiIgIHtmYWlsdXJlc30gRkFJTEVEICDinJciKQogICAgZWxzZToKICAgICAgICBwcmludChmIiAgQWxsIHBhc3NlZCAg4pyTIikKICAgIHByaW50KGYieyfilZAnKjcwfSIpCgogICAgcmV0dXJuIDEgaWYgZmFpbHVyZXMgZWxzZSAwCgoKaWYgX19uYW1lX18gPT0gIl9fbWFpbl9fIjoKICAgIHN5cy5leGl0KG1haW4oKSkK +#!/usr/bin/env python3 +""" +wcag_check.py — WCAG AA contrast checker for GoFlo themes. + +Mirrors the colour values in app/src/main/java/com/mapgie/goflo/ui/theme/Color.kt. +Keep both files in sync whenever a theme colour changes. + +WCAG AA thresholds: + 4.5 : 1 — normal body text + 3.0 : 1 — large text (≥ 18 pt / ≥ 14 pt bold) and UI components + (borders, icons, focus rings, indicator dots) + +Usage: + python3 wcag_check.py # check all themes + python3 wcag_check.py coral # filter by theme name (partial, case-insensitive) + python3 wcag_check.py --fails-only # print only failing pairs + python3 wcag_check.py coral --fails-only + +Exit code: 0 — all pairs pass | 1 — one or more pairs fail +""" + +import sys + +# ── WCAG maths ──────────────────────────────────────────────────────────────── + +def _linearize(c: int) -> float: + """sRGB gamma expansion for a single 0-255 channel.""" + v = c / 255.0 + return v / 12.92 if v <= 0.04045 else ((v + 0.055) / 1.055) ** 2.4 + + +def luminance(hex_color: str) -> float: + """WCAG relative luminance of a 6-digit hex colour (# prefix optional).""" + h = hex_color.lstrip("#") + r, g, b = int(h[0:2], 16), int(h[2:4], 16), int(h[4:6], 16) + return 0.2126 * _linearize(r) + 0.7152 * _linearize(g) + 0.0722 * _linearize(b) + + +def contrast_ratio(fg: str, bg: str) -> float: + """WCAG contrast ratio between two hex colours.""" + l1, l2 = luminance(fg), luminance(bg) + hi, lo = (l1, l2) if l1 >= l2 else (l2, l1) + return (hi + 0.05) / (lo + 0.05) + + +# ── Colour schemes — mirrors Color.kt exactly ───────────────────────────────── +# Key: human-readable theme name used in output only (not stored anywhere). + +THEMES: dict[str, dict[str, str]] = { + "Coral (Light)": { + "primary": "BC4D3F", + "onPrimary": "FFFFFF", + "primaryContainer": "FFDAD2", + "onPrimaryContainer": "3F0900", + "secondary": "007E7A", + "onSecondary": "FFFFFF", + "secondaryContainer": "B4ECE7", + "onSecondaryContainer": "002523", + "tertiary": "956800", + "onTertiary": "FFFFFF", + "tertiaryContainer": "FFE08D", + "onTertiaryContainer": "251A00", + "background": "FFF6F2", + "onBackground": "221915", + "surface": "FFF6F2", + "onSurface": "221915", + "surfaceVariant": "F4DDD5", + "onSurfaceVariant": "524340", + "outline": "856E68", + }, + "Teal (Light)": { + "primary": "00747C", + "onPrimary": "FFFFFF", + "primaryContainer": "9DEFF6", + "onPrimaryContainer": "002023", + "secondary": "B3572A", + "onSecondary": "FFFFFF", + "secondaryContainer": "FFDBC8", + "onSecondaryContainer": "381300", + "tertiary": "4B5BAC", + "onTertiary": "FFFFFF", + "tertiaryContainer": "DEE1FF", + "onTertiaryContainer": "00115A", + "background": "F0FBFC", + "onBackground": "161C1D", + "surface": "F0FBFC", + "onSurface": "161C1D", + "surfaceVariant": "DAE4E5", + "onSurfaceVariant": "3F4949", + "outline": "6F7979", + }, + "Sage (Light)": { + "primary": "4F7D2B", + "onPrimary": "FFFFFF", + "primaryContainer": "C8F09F", + "onPrimaryContainer": "112100", + "secondary": "B5532A", + "onSecondary": "FFFFFF", + "secondaryContainer": "FFDBC8", + "onSecondaryContainer": "3A1100", + "tertiary": "8C6212", + "onTertiary": "FFFFFF", + "tertiaryContainer": "FFDF9C", + "onTertiaryContainer": "2A1D00", + "background": "F7FBEE", + "onBackground": "1A1C16", + "surface": "F7FBEE", + "onSurface": "1A1C16", + "surfaceVariant": "DEE5D2", + "onSurfaceVariant": "424A3B", + "outline": "72796A", + }, + "Coral (Dark)": { + "primary": "FFB4A4", + "onPrimary": "5C1600", + "primaryContainer": "7C2A18", + "onPrimaryContainer": "FFDAD0", + "secondary": "5BD8D0", + "onSecondary": "003734", + "secondaryContainer": "00504C", + "onSecondaryContainer": "B4EEE9", + "tertiary": "FFD787", + "onTertiary": "3D2D00", + "tertiaryContainer": "574200", + "onTertiaryContainer": "FFE08D", + "background": "1C110E", + "onBackground": "F1DED8", + "surface": "1C110E", + "onSurface": "F1DED8", + "surfaceVariant": "523F3A", + "onSurfaceVariant": "D7C2BC", + "outline": "A28B86", + }, + "Teal (Dark)": { + "primary": "80D5DB", + "onPrimary": "003739", + "primaryContainer": "004F52", + "onPrimaryContainer": "9DEFF6", + "secondary": "FFB28F", + "onSecondary": "5A1B00", + "secondaryContainer": "8C3B16", + "onSecondaryContainer": "FFDBC8", + "tertiary": "BCC2FF", + "onTertiary": "1C257B", + "tertiaryContainer": "353F93", + "onTertiaryContainer": "DEE1FF", + "background": "0E1818", + "onBackground": "E0E3E3", + "surface": "0E1818", + "onSurface": "E0E3E3", + "surfaceVariant": "3F4949", + "onSurfaceVariant": "BEC8C9", + "outline": "8B9595", + }, + "Sage (Dark)": { + "primary": "ACD888", + "onPrimary": "1B3900", + "primaryContainer": "2D530B", + "onPrimaryContainer": "C8F09F", + "secondary": "FFB28F", + "onSecondary": "5A1B00", + "secondaryContainer": "8B3914", + "onSecondaryContainer": "FFDBC8", + "tertiary": "F4C16D", + "onTertiary": "422C00", + "tertiaryContainer": "5E4300", + "onTertiaryContainer": "FFDF9C", + "background": "14170F", + "onBackground": "E2E4D7", + "surface": "14170F", + "onSurface": "E2E4D7", + "surfaceVariant": "424A3B", + "onSurfaceVariant": "C2C9B6", + "outline": "919888", + }, + "High Contrast (Light)": { + "primary": "1A1A1A", + "onPrimary": "FFFFFF", + "primaryContainer": "E8E8E8", + "onPrimaryContainer": "000000", + "secondary": "1A1A1A", + "onSecondary": "FFFFFF", + "secondaryContainer": "E8E8E8", + "onSecondaryContainer": "000000", + "tertiary": "1A1A1A", + "onTertiary": "FFFFFF", + "tertiaryContainer": "E8E8E8", + "onTertiaryContainer": "000000", + "background": "FFFFFF", + "onBackground": "000000", + "surface": "FFFFFF", + "onSurface": "000000", + "surfaceVariant": "F0F0F0", + "onSurfaceVariant": "000000", + "outline": "1A1A1A", + }, + "High Contrast (Dark)": { + "primary": "FFFFFF", + "onPrimary": "000000", + "primaryContainer": "1A1A1A", + "onPrimaryContainer": "FFFFFF", + "secondary": "FFFFFF", + "onSecondary": "000000", + "secondaryContainer": "1A1A1A", + "onSecondaryContainer": "FFFFFF", + "tertiary": "FFFFFF", + "onTertiary": "000000", + "tertiaryContainer": "1A1A1A", + "onTertiaryContainer": "FFFFFF", + "background": "000000", + "onBackground": "FFFFFF", + "surface": "000000", + "onSurface": "FFFFFF", + "surfaceVariant": "1A1A1A", + "onSurfaceVariant": "FFFFFF", + "outline": "DEDEDE", + }, + "Blue & Orange": { + "primary": "005FAD", + "onPrimary": "FFFFFF", + "primaryContainer": "D1E4FF", + "onPrimaryContainer": "001D36", + "secondary": "8B5000", + "onSecondary": "FFFFFF", + "secondaryContainer": "FFDDB8", + "onSecondaryContainer": "2D1600", + "tertiary": "6B5F00", + "onTertiary": "FFFFFF", + "tertiaryContainer": "F5E400", + "onTertiaryContainer": "201C00", + "background": "F8FAFF", + "onBackground": "191C1E", + "surface": "F8FAFF", + "onSurface": "191C1E", + "surfaceVariant": "DDE3EA", + "onSurfaceVariant": "404A51", + "outline": "70787F", + }, + # SYSTEM uses Teal (Light/Dark) depending on device preference — + # covered by those two entries above; no separate entry needed. + + # ── Fun palettes ───────────────────────────────────────────────────────── + "Summer Candy (Light)": { + "primary": "D81B60", + "onPrimary": "FFFFFF", + "primaryContainer": "FFD8E5", + "onPrimaryContainer": "40001B", + "secondary": "007F76", + "onSecondary": "FFFFFF", + "secondaryContainer": "6FF5E5", + "onSecondaryContainer": "00201D", + "tertiary": "9A6700", + "onTertiary": "FFFFFF", + "tertiaryContainer": "FFE08D", + "onTertiaryContainer": "271B00", + "background": "FFF7FA", + "onBackground": "1E1316", + "surface": "FFF7FA", + "onSurface": "1E1316", + "surfaceVariant": "F4DDE5", + "onSurfaceVariant": "534249", + "outline": "856D74", + }, + "Summer Candy (Dark)": { + "primary": "FFB1CA", + "onPrimary": "650033", + "primaryContainer": "8E0049", + "onPrimaryContainer": "FFD8E5", + "secondary": "6DDFD0", + "onSecondary": "003A35", + "secondaryContainer": "00514B", + "onSecondaryContainer": "6FF5E5", + "tertiary": "FFCD66", + "onTertiary": "3F2D00", + "tertiaryContainer": "5A4200", + "onTertiaryContainer": "FFE08D", + "background": "1D1014", + "onBackground": "ECDFE3", + "surface": "1D1014", + "onSurface": "ECDFE3", + "surfaceVariant": "534249", + "onSurfaceVariant": "D6C1C8", + "outline": "A39095", + }, + "Beach Vibes (Light)": { + "primary": "1265AF", + "onPrimary": "FFFFFF", + "primaryContainer": "D5E3FF", + "onPrimaryContainer": "001C3D", + "secondary": "9A6800", + "onSecondary": "FFFFFF", + "secondaryContainer": "FFE08D", + "onSecondaryContainer": "251A00", + "tertiary": "297F6C", + "onTertiary": "FFFFFF", + "tertiaryContainer": "A8F0DC", + "onTertiaryContainer": "002019", + "background": "F8FAFE", + "onBackground": "181C22", + "surface": "F8FAFE", + "onSurface": "181C22", + "surfaceVariant": "E1E3EE", + "onSurfaceVariant": "444751", + "outline": "757782", + }, + "Beach Vibes (Dark)": { + "primary": "A8C8FF", + "onPrimary": "002E66", + "primaryContainer": "00478A", + "onPrimaryContainer": "D5E3FF", + "secondary": "F4C16D", + "onSecondary": "422C00", + "secondaryContainer": "5E4300", + "onSecondaryContainer": "FFE08D", + "tertiary": "84D7BC", + "onTertiary": "003828", + "tertiaryContainer": "00513B", + "onTertiaryContainer": "A8F0DC", + "background": "101820", + "onBackground": "DDE3EB", + "surface": "101820", + "onSurface": "DDE3EB", + "surfaceVariant": "444751", + "onSurfaceVariant": "C5C7D2", + "outline": "93959F", + }, + "Peach Melba (Light)": { + "primary": "B35535", + "onPrimary": "FFFFFF", + "primaryContainer": "FFDBC9", + "onPrimaryContainer": "3A1300", + "secondary": "B53369", + "onSecondary": "FFFFFF", + "secondaryContainer": "FFD9E3", + "onSecondaryContainer": "3F0024", + "tertiary": "8A6926", + "onTertiary": "FFFFFF", + "tertiaryContainer": "FFE2A0", + "onTertiaryContainer": "2A1F00", + "background": "FFF6F0", + "onBackground": "201813", + "surface": "FFF6F0", + "onSurface": "201813", + "surfaceVariant": "F4DED1", + "onSurfaceVariant": "534439", + "outline": "867262", + }, + "Peach Melba (Dark)": { + "primary": "FFB694", + "onPrimary": "571F00", + "primaryContainer": "7A3015", + "onPrimaryContainer": "FFDBC9", + "secondary": "FFB1C9", + "onSecondary": "65003A", + "secondaryContainer": "8C1F4F", + "onSecondaryContainer": "FFD9E3", + "tertiary": "F4C16D", + "onTertiary": "432D00", + "tertiaryContainer": "5F4300", + "onTertiaryContainer": "FFE2A0", + "background": "1E1410", + "onBackground": "EDE0D8", + "surface": "1E1410", + "onSurface": "EDE0D8", + "surfaceVariant": "534439", + "onSurfaceVariant": "D7C3B5", + "outline": "A59185", + }, + "All-Night Disco Party (Light)": { + "primary": "C1127A", + "onPrimary": "FFFFFF", + "primaryContainer": "FFD6EA", + "onPrimaryContainer": "3D003C", + "secondary": "6E1FB5", + "onSecondary": "FFFFFF", + "secondaryContainer": "ECDCFF", + "onSecondaryContainer": "270060", + "tertiary": "966900", + "onTertiary": "FFFFFF", + "tertiaryContainer": "FFE08C", + "onTertiaryContainer": "2A1D00", + "background": "FFF7FB", + "onBackground": "1E1020", + "surface": "FFF7FB", + "onSurface": "1E1020", + "surfaceVariant": "F0DEEC", + "onSurfaceVariant": "4F4452", + "outline": "807385", + }, + "All-Night Disco Party (Dark)": { + "primary": "FF66B8", + "onPrimary": "5C0040", + "primaryContainer": "890062", + "onPrimaryContainer": "FFD6EA", + "secondary": "D5B2FF", + "onSecondary": "3F0090", + "secondaryContainer": "5800B0", + "onSecondaryContainer": "ECDCFF", + "tertiary": "FFD350", + "onTertiary": "3A2A00", + "tertiaryContainer": "523D00", + "onTertiaryContainer": "FFE08C", + "background": "170820", + "onBackground": "ECDAEC", + "surface": "170820", + "onSurface": "ECDAEC", + "surfaceVariant": "4F4452", + "onSurfaceVariant": "D2C2D2", + "outline": "A092A2", + }, + "Metal Chick (Light)": { + "primary": "2E2E3A", + "onPrimary": "FFFFFF", + "primaryContainer": "DCDBE9", + "onPrimaryContainer": "0E0E1C", + "secondary": "C8235A", + "onSecondary": "FFFFFF", + "secondaryContainer": "FFD8E0", + "onSecondaryContainer": "3F001A", + "tertiary": "6A6A78", + "onTertiary": "FFFFFF", + "tertiaryContainer": "E3E2F0", + "onTertiaryContainer": "1C1C2A", + "background": "F4F3F8", + "onBackground": "1B1B22", + "surface": "F4F3F8", + "onSurface": "1B1B22", + "surfaceVariant": "E2E0EC", + "onSurfaceVariant": "45434E", + "outline": "76737E", + }, + "Metal Chick (Dark)": { + "primary": "C7C5D6", + "onPrimary": "2F2D3D", + "primaryContainer": "454354", + "onPrimaryContainer": "DCDBE9", + "secondary": "FF8FB0", + "onSecondary": "5C0028", + "secondaryContainer": "88133E", + "onSecondaryContainer": "FFD8E0", + "tertiary": "9D9DAC", + "onTertiary": "2F2F3E", + "tertiaryContainer": "4A4A58", + "onTertiaryContainer": "E3E2F0", + "background": "0E0E13", + "onBackground": "E5E3ED", + "surface": "0E0E13", + "onSurface": "E5E3ED", + "surfaceVariant": "45434E", + "onSurfaceVariant": "C8C5D0", + "outline": "918E99", + }, + "Whimsy Whispers (Light)": { + "primary": "6E5DC4", + "onPrimary": "FFFFFF", + "primaryContainer": "E5DFFF", + "onPrimaryContainer": "1A0067", + "secondary": "BD4878", + "onSecondary": "FFFFFF", + "secondaryContainer": "FFD9E4", + "onSecondaryContainer": "3D0024", + "tertiary": "2B7F68", + "onTertiary": "FFFFFF", + "tertiaryContainer": "A6F0D6", + "onTertiaryContainer": "002016", + "background": "FBF8FF", + "onBackground": "1C1A24", + "surface": "FBF8FF", + "onSurface": "1C1A24", + "surfaceVariant": "E5DFF0", + "onSurfaceVariant": "49454F", + "outline": "7A7580", + }, + "Whimsy Whispers (Dark)": { + "primary": "C7BEFF", + "onPrimary": "260092", + "primaryContainer": "3D2EAE", + "onPrimaryContainer": "E5DFFF", + "secondary": "FFB1C6", + "onSecondary": "650033", + "secondaryContainer": "8E1F50", + "onSecondaryContainer": "FFD9E4", + "tertiary": "80DAB8", + "onTertiary": "003828", + "tertiaryContainer": "00513B", + "onTertiaryContainer": "A6F0D6", + "background": "16131F", + "onBackground": "E6E1F0", + "surface": "16131F", + "onSurface": "E6E1F0", + "surfaceVariant": "49454F", + "onSurfaceVariant": "CBC5D0", + "outline": "96909F", + }, + "Colour Me Happy (Light)": { + "primary": "D63A26", + "onPrimary": "FFFFFF", + "primaryContainer": "FFDAD2", + "onPrimaryContainer": "410000", + "secondary": "1872BD", + "onSecondary": "FFFFFF", + "secondaryContainer": "D1E4FF", + "onSecondaryContainer": "001D36", + "tertiary": "428129", + "onTertiary": "FFFFFF", + "tertiaryContainer": "C6F0A1", + "onTertiaryContainer": "0F2200", + "background": "FFFCF5", + "onBackground": "1F1A14", + "surface": "FFFCF5", + "onSurface": "1F1A14", + "surfaceVariant": "EFE3D5", + "onSurfaceVariant": "4E443A", + "outline": "80766A", + }, + "Colour Me Happy (Dark)": { + "primary": "FFB4A4", + "onPrimary": "5C1500", + "primaryContainer": "882000", + "onPrimaryContainer": "FFDAD2", + "secondary": "A0CAFF", + "onSecondary": "002F66", + "secondaryContainer": "00497D", + "onSecondaryContainer": "D1E4FF", + "tertiary": "ACD688", + "onTertiary": "1A3900", + "tertiaryContainer": "2D530B", + "onTertiaryContainer": "C6F0A1", + "background": "1A1612", + "onBackground": "EDE0D2", + "surface": "1A1612", + "onSurface": "EDE0D2", + "surfaceVariant": "4E443A", + "onSurfaceVariant": "D2C4B5", + "outline": "9F9184", + }, + "Dragon Fire (Light)": { + "primary": "B0181F", + "onPrimary": "FFFFFF", + "primaryContainer": "FFCFCC", + "onPrimaryContainer": "3F0001", + "secondary": "C04A0E", + "onSecondary": "FFFFFF", + "secondaryContainer": "FFDBC9", + "onSecondaryContainer": "3B1100", + "tertiary": "996800", + "onTertiary": "FFFFFF", + "tertiaryContainer": "FFDE8E", + "onTertiaryContainer": "2D1F00", + "background": "FFF8F4", + "onBackground": "1E140F", + "surface": "FFF8F4", + "onSurface": "1E140F", + "surfaceVariant": "F3DED5", + "onSurfaceVariant": "524338", + "outline": "87715F", + }, + "Dragon Fire (Dark)": { + "primary": "FF8A82", + "onPrimary": "680000", + "primaryContainer": "960000", + "onPrimaryContainer": "FFDAD4", + "secondary": "FFB28F", + "onSecondary": "561A00", + "secondaryContainer": "8E2D00", + "onSecondaryContainer": "FFDBC9", + "tertiary": "FFCD66", + "onTertiary": "422C00", + "tertiaryContainer": "5E4300", + "onTertiaryContainer": "FFDE8E", + "background": "1C0907", + "onBackground": "F1DDD7", + "surface": "1C0907", + "onSurface": "F1DDD7", + "surfaceVariant": "523F38", + "onSurfaceVariant": "D7C2B8", + "outline": "A28D81", + }, + "Midnight Neon (Light)": { + "primary": "C5128A", + "onPrimary": "FFFFFF", + "primaryContainer": "FFD6E8", + "onPrimaryContainer": "3D003C", + "secondary": "006D90", + "onSecondary": "FFFFFF", + "secondaryContainer": "B8E9FF", + "onSecondaryContainer": "001E2F", + "tertiary": "4C7A0E", + "onTertiary": "FFFFFF", + "tertiaryContainer": "C2F088", + "onTertiaryContainer": "0F2300", + "background": "FBF7FF", + "onBackground": "161020", + "surface": "FBF7FF", + "onSurface": "161020", + "surfaceVariant": "EDDEEC", + "onSurfaceVariant": "4D4350", + "outline": "7F7484", + }, + "Midnight Neon (Dark)": { + "primary": "FF55C8", + "onPrimary": "5C0048", + "primaryContainer": "870068", + "onPrimaryContainer": "FFD6EA", + "secondary": "5EE0FF", + "onSecondary": "00374A", + "secondaryContainer": "00516C", + "onSecondaryContainer": "B8E9FF", + "tertiary": "C2F052", + "onTertiary": "1D3300", + "tertiaryContainer": "2D4900", + "onTertiaryContainer": "C2F088", + "background": "0A0A18", + "onBackground": "EDE5FA", + "surface": "0A0A18", + "onSurface": "EDE5FA", + "surfaceVariant": "4D4350", + "onSurfaceVariant": "D0C3D0", + "outline": "9D90A4", + }, +} + +# ── Pairs to check ──────────────────────────────────────────────────────────── +# (foreground_key, background_key, threshold, description) +# Threshold: 4.5 = WCAG AA text | 3.0 = WCAG AA UI component + +PAIRS: list[tuple[str, str, float, str]] = [ + # Body text — 4.5 : 1 + ("onPrimary", "primary", 4.5, "text on primary (buttons, period circles)"), + ("onSecondary", "secondary", 4.5, "text on secondary elements"), + ("onTertiary", "tertiary", 4.5, "text on tertiary elements"), + ("onPrimaryContainer", "primaryContainer", 4.5, "text in primary containers"), + ("onSecondaryContainer", "secondaryContainer", 4.5, "text in secondary containers"), + ("onTertiaryContainer", "tertiaryContainer", 4.5, "text in tertiary containers"), + ("onBackground", "background", 4.5, "body text on background"), + ("onSurface", "surface", 4.5, "body text on surface"), + ("onSurfaceVariant", "surfaceVariant", 4.5, "subtitle / caption text in cards"), + # UI components — 3.0 : 1 + ("outline", "surfaceVariant", 3.0, "borders / dividers on cards"), + ("outline", "background", 3.0, "borders on background"), + ("primary", "primaryContainer", 3.0, "focused outlines / active chip border"), + ("primary", "surfaceVariant", 3.0, "ovulation dot / indicator on card"), + ("primary", "background", 3.0, "period circles on background"), + ("primary", "surface", 3.0, "primary on surface"), +] + +# ── CLI ─────────────────────────────────────────────────────────────────────── + +def main() -> int: + args = sys.argv[1:] + fails_only = "--fails-only" in args + name_filter = next((a for a in args if not a.startswith("--")), "").lower() + + themes_to_check = { + name: scheme for name, scheme in THEMES.items() + if name_filter in name.lower() + } + + if not themes_to_check: + print(f"No themes matched '{name_filter}'. Available themes:") + for name in THEMES: + print(f" {name}") + return 1 + + total = 0 + failures = 0 + + for theme_name, scheme in themes_to_check.items(): + theme_failures: list[str] = [] + theme_passes: list[str] = [] + + for fg_key, bg_key, threshold, description in PAIRS: + fg = scheme.get(fg_key) + bg = scheme.get(bg_key) + if fg is None or bg is None: + # Skip pairs where the theme doesn't define both colours + continue + + ratio = contrast_ratio(fg, bg) + total += 1 + passed = ratio >= threshold + marker = "PASS" if passed else "FAIL" + line = ( + f" {marker} {ratio:5.2f}:1 " + f"#{fg} / #{bg} " + f"{fg_key} / {bg_key} — {description}" + ) + if passed: + theme_passes.append(line) + else: + failures += 1 + theme_failures.append(line) + + # Print theme block + print(f"\n{'─'*70}") + print(f" {theme_name}") + print(f"{'─'*70}") + if not fails_only: + for line in theme_passes: + print(line) + for line in theme_failures: + print(line) + if not theme_failures: + count = len(theme_passes) + print(f" All {count} pairs pass ✓") + + print(f"\n{'═'*70}") + print(f" {total} pairs checked across {len(themes_to_check)} theme(s)") + if failures: + print(f" {failures} FAILED ✗") + else: + print(f" All passed ✓") + print(f"{'═'*70}") + + return 1 if failures else 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/wcag_check_real.py b/wcag_check_real.py deleted file mode 100644 index 84de5a9..0000000 --- a/wcag_check_real.py +++ /dev/null @@ -1,719 +0,0 @@ -#!/usr/bin/env python3 -""" -wcag_check.py — WCAG AA contrast checker for GoFlo themes. - -Mirrors the colour values in app/src/main/java/com/mapgie/goflo/ui/theme/Color.kt. -Keep both files in sync whenever a theme colour changes. - -WCAG AA thresholds: - 4.5 : 1 — normal body text - 3.0 : 1 — large text (≥ 18 pt / ≥ 14 pt bold) and UI components - (borders, icons, focus rings, indicator dots) - -Usage: - python3 wcag_check.py # check all themes - python3 wcag_check.py coral # filter by theme name (partial, case-insensitive) - python3 wcag_check.py --fails-only # print only failing pairs - python3 wcag_check.py coral --fails-only - -Exit code: 0 — all pairs pass | 1 — one or more pairs fail -""" - -import sys - -# ── WCAG maths ──────────────────────────────────────────────────────────────── - -def _linearize(c: int) -> float: - """sRGB gamma expansion for a single 0-255 channel.""" - v = c / 255.0 - return v / 12.92 if v <= 0.04045 else ((v + 0.055) / 1.055) ** 2.4 - - -def luminance(hex_color: str) -> float: - """WCAG relative luminance of a 6-digit hex colour (# prefix optional).""" - h = hex_color.lstrip("#") - r, g, b = int(h[0:2], 16), int(h[2:4], 16), int(h[4:6], 16) - return 0.2126 * _linearize(r) + 0.7152 * _linearize(g) + 0.0722 * _linearize(b) - - -def contrast_ratio(fg: str, bg: str) -> float: - """WCAG contrast ratio between two hex colours.""" - l1, l2 = luminance(fg), luminance(bg) - hi, lo = (l1, l2) if l1 >= l2 else (l2, l1) - return (hi + 0.05) / (lo + 0.05) - - -# ── Colour schemes — mirrors Color.kt exactly ───────────────────────────────── -# Key: human-readable theme name used in output only (not stored anywhere). - -THEMES: dict[str, dict[str, str]] = { - "Coral (Light)": { - "primary": "BC4D3F", - "onPrimary": "FFFFFF", - "primaryContainer": "FFDAD2", - "onPrimaryContainer": "3F0900", - "secondary": "007E7A", - "onSecondary": "FFFFFF", - "secondaryContainer": "B4ECE7", - "onSecondaryContainer": "002523", - "tertiary": "956800", - "onTertiary": "FFFFFF", - "tertiaryContainer": "FFE08D", - "onTertiaryContainer": "251A00", - "background": "FFF6F2", - "onBackground": "221915", - "surface": "FFF6F2", - "onSurface": "221915", - "surfaceVariant": "F4DDD5", - "onSurfaceVariant": "524340", - "outline": "856E68", - }, - "Teal (Light)": { - "primary": "00747C", - "onPrimary": "FFFFFF", - "primaryContainer": "9DEFF6", - "onPrimaryContainer": "002023", - "secondary": "B3572A", - "onSecondary": "FFFFFF", - "secondaryContainer": "FFDBC8", - "onSecondaryContainer": "381300", - "tertiary": "4B5BAC", - "onTertiary": "FFFFFF", - "tertiaryContainer": "DEE1FF", - "onTertiaryContainer": "00115A", - "background": "F0FBFC", - "onBackground": "161C1D", - "surface": "F0FBFC", - "onSurface": "161C1D", - "surfaceVariant": "DAE4E5", - "onSurfaceVariant": "3F4949", - "outline": "6F7979", - }, - "Sage (Light)": { - "primary": "4F7D2B", - "onPrimary": "FFFFFF", - "primaryContainer": "C8F09F", - "onPrimaryContainer": "112100", - "secondary": "B5532A", - "onSecondary": "FFFFFF", - "secondaryContainer": "FFDBC8", - "onSecondaryContainer": "3A1100", - "tertiary": "8C6212", - "onTertiary": "FFFFFF", - "tertiaryContainer": "FFDF9C", - "onTertiaryContainer": "2A1D00", - "background": "F7FBEE", - "onBackground": "1A1C16", - "surface": "F7FBEE", - "onSurface": "1A1C16", - "surfaceVariant": "DEE5D2", - "onSurfaceVariant": "424A3B", - "outline": "72796A", - }, - "Coral (Dark)": { - "primary": "FFB4A4", - "onPrimary": "5C1600", - "primaryContainer": "7C2A18", - "onPrimaryContainer": "FFDAD0", - "secondary": "5BD8D0", - "onSecondary": "003734", - "secondaryContainer": "00504C", - "onSecondaryContainer": "B4EEE9", - "tertiary": "FFD787", - "onTertiary": "3D2D00", - "tertiaryContainer": "574200", - "onTertiaryContainer": "FFE08D", - "background": "1C110E", - "onBackground": "F1DED8", - "surface": "1C110E", - "onSurface": "F1DED8", - "surfaceVariant": "523F3A", - "onSurfaceVariant": "D7C2BC", - "outline": "A28B86", - }, - "Teal (Dark)": { - "primary": "80D5DB", - "onPrimary": "003739", - "primaryContainer": "004F52", - "onPrimaryContainer": "9DEFF6", - "secondary": "FFB28F", - "onSecondary": "5A1B00", - "secondaryContainer": "8C3B16", - "onSecondaryContainer": "FFDBC8", - "tertiary": "BCC2FF", - "onTertiary": "1C257B", - "tertiaryContainer": "353F93", - "onTertiaryContainer": "DEE1FF", - "background": "0E1818", - "onBackground": "E0E3E3", - "surface": "0E1818", - "onSurface": "E0E3E3", - "surfaceVariant": "3F4949", - "onSurfaceVariant": "BEC8C9", - "outline": "8B9595", - }, - "Sage (Dark)": { - "primary": "ACD888", - "onPrimary": "1B3900", - "primaryContainer": "2D530B", - "onPrimaryContainer": "C8F09F", - "secondary": "FFB28F", - "onSecondary": "5A1B00", - "secondaryContainer": "8B3914", - "onSecondaryContainer": "FFDBC8", - "tertiary": "F4C16D", - "onTertiary": "422C00", - "tertiaryContainer": "5E4300", - "onTertiaryContainer": "FFDF9C", - "background": "14170F", - "onBackground": "E2E4D7", - "surface": "14170F", - "onSurface": "E2E4D7", - "surfaceVariant": "424A3B", - "onSurfaceVariant": "C2C9B6", - "outline": "919888", - }, - "High Contrast (Light)": { - "primary": "1A1A1A", - "onPrimary": "FFFFFF", - "primaryContainer": "E8E8E8", - "onPrimaryContainer": "000000", - "secondary": "1A1A1A", - "onSecondary": "FFFFFF", - "secondaryContainer": "E8E8E8", - "onSecondaryContainer": "000000", - "tertiary": "1A1A1A", - "onTertiary": "FFFFFF", - "tertiaryContainer": "E8E8E8", - "onTertiaryContainer": "000000", - "background": "FFFFFF", - "onBackground": "000000", - "surface": "FFFFFF", - "onSurface": "000000", - "surfaceVariant": "F0F0F0", - "onSurfaceVariant": "000000", - "outline": "1A1A1A", - }, - "High Contrast (Dark)": { - "primary": "FFFFFF", - "onPrimary": "000000", - "primaryContainer": "1A1A1A", - "onPrimaryContainer": "FFFFFF", - "secondary": "FFFFFF", - "onSecondary": "000000", - "secondaryContainer": "1A1A1A", - "onSecondaryContainer": "FFFFFF", - "tertiary": "FFFFFF", - "onTertiary": "000000", - "tertiaryContainer": "1A1A1A", - "onTertiaryContainer": "FFFFFF", - "background": "000000", - "onBackground": "FFFFFF", - "surface": "000000", - "onSurface": "FFFFFF", - "surfaceVariant": "1A1A1A", - "onSurfaceVariant": "FFFFFF", - "outline": "DEDEDE", - }, - "Blue & Orange": { - "primary": "005FAD", - "onPrimary": "FFFFFF", - "primaryContainer": "D1E4FF", - "onPrimaryContainer": "001D36", - "secondary": "8B5000", - "onSecondary": "FFFFFF", - "secondaryContainer": "FFDDB8", - "onSecondaryContainer": "2D1600", - "tertiary": "6B5F00", - "onTertiary": "FFFFFF", - "tertiaryContainer": "F5E400", - "onTertiaryContainer": "201C00", - "background": "F8FAFF", - "onBackground": "191C1E", - "surface": "F8FAFF", - "onSurface": "191C1E", - "surfaceVariant": "DDE3EA", - "onSurfaceVariant": "404A51", - "outline": "70787F", - }, - # SYSTEM uses Teal (Light/Dark) depending on device preference — - # covered by those two entries above; no separate entry needed. - - # ── Fun palettes ───────────────────────────────────────────────────────── - "Summer Candy (Light)": { - "primary": "D81B60", - "onPrimary": "FFFFFF", - "primaryContainer": "FFD8E5", - "onPrimaryContainer": "40001B", - "secondary": "007F76", - "onSecondary": "FFFFFF", - "secondaryContainer": "6FF5E5", - "onSecondaryContainer": "00201D", - "tertiary": "9A6700", - "onTertiary": "FFFFFF", - "tertiaryContainer": "FFE08D", - "onTertiaryContainer": "271B00", - "background": "FFF7FA", - "onBackground": "1E1316", - "surface": "FFF7FA", - "onSurface": "1E1316", - "surfaceVariant": "F4DDE5", - "onSurfaceVariant": "534249", - "outline": "856D74", - }, - "Summer Candy (Dark)": { - "primary": "FFB1CA", - "onPrimary": "650033", - "primaryContainer": "8E0049", - "onPrimaryContainer": "FFD8E5", - "secondary": "6DDFD0", - "onSecondary": "003A35", - "secondaryContainer": "00514B", - "onSecondaryContainer": "6FF5E5", - "tertiary": "FFCD66", - "onTertiary": "3F2D00", - "tertiaryContainer": "5A4200", - "onTertiaryContainer": "FFE08D", - "background": "1D1014", - "onBackground": "ECDFE3", - "surface": "1D1014", - "onSurface": "ECDFE3", - "surfaceVariant": "534249", - "onSurfaceVariant": "D6C1C8", - "outline": "A39095", - }, - "Beach Vibes (Light)": { - "primary": "1265AF", - "onPrimary": "FFFFFF", - "primaryContainer": "D5E3FF", - "onPrimaryContainer": "001C3D", - "secondary": "9A6800", - "onSecondary": "FFFFFF", - "secondaryContainer": "FFE08D", - "onSecondaryContainer": "251A00", - "tertiary": "297F6C", - "onTertiary": "FFFFFF", - "tertiaryContainer": "A8F0DC", - "onTertiaryContainer": "002019", - "background": "F8FAFE", - "onBackground": "181C22", - "surface": "F8FAFE", - "onSurface": "181C22", - "surfaceVariant": "E1E3EE", - "onSurfaceVariant": "444751", - "outline": "757782", - }, - "Beach Vibes (Dark)": { - "primary": "A8C8FF", - "onPrimary": "002E66", - "primaryContainer": "00478A", - "onPrimaryContainer": "D5E3FF", - "secondary": "F4C16D", - "onSecondary": "422C00", - "secondaryContainer": "5E4300", - "onSecondaryContainer": "FFE08D", - "tertiary": "84D7BC", - "onTertiary": "003828", - "tertiaryContainer": "00513B", - "onTertiaryContainer": "A8F0DC", - "background": "101820", - "onBackground": "DDE3EB", - "surface": "101820", - "onSurface": "DDE3EB", - "surfaceVariant": "444751", - "onSurfaceVariant": "C5C7D2", - "outline": "93959F", - }, - "Peach Melba (Light)": { - "primary": "B35535", - "onPrimary": "FFFFFF", - "primaryContainer": "FFDBC9", - "onPrimaryContainer": "3A1300", - "secondary": "B53369", - "onSecondary": "FFFFFF", - "secondaryContainer": "FFD9E3", - "onSecondaryContainer": "3F0024", - "tertiary": "8A6926", - "onTertiary": "FFFFFF", - "tertiaryContainer": "FFE2A0", - "onTertiaryContainer": "2A1F00", - "background": "FFF6F0", - "onBackground": "201813", - "surface": "FFF6F0", - "onSurface": "201813", - "surfaceVariant": "F4DED1", - "onSurfaceVariant": "534439", - "outline": "867262", - }, - "Peach Melba (Dark)": { - "primary": "FFB694", - "onPrimary": "571F00", - "primaryContainer": "7A3015", - "onPrimaryContainer": "FFDBC9", - "secondary": "FFB1C9", - "onSecondary": "65003A", - "secondaryContainer": "8C1F4F", - "onSecondaryContainer": "FFD9E3", - "tertiary": "F4C16D", - "onTertiary": "432D00", - "tertiaryContainer": "5F4300", - "onTertiaryContainer": "FFE2A0", - "background": "1E1410", - "onBackground": "EDE0D8", - "surface": "1E1410", - "onSurface": "EDE0D8", - "surfaceVariant": "534439", - "onSurfaceVariant": "D7C3B5", - "outline": "A59185", - }, - "All-Night Disco Party (Light)": { - "primary": "C1127A", - "onPrimary": "FFFFFF", - "primaryContainer": "FFD6EA", - "onPrimaryContainer": "3D003C", - "secondary": "6E1FB5", - "onSecondary": "FFFFFF", - "secondaryContainer": "ECDCFF", - "onSecondaryContainer": "270060", - "tertiary": "966900", - "onTertiary": "FFFFFF", - "tertiaryContainer": "FFE08C", - "onTertiaryContainer": "2A1D00", - "background": "FFF7FB", - "onBackground": "1E1020", - "surface": "FFF7FB", - "onSurface": "1E1020", - "surfaceVariant": "F0DEEC", - "onSurfaceVariant": "4F4452", - "outline": "807385", - }, - "All-Night Disco Party (Dark)": { - "primary": "FF66B8", - "onPrimary": "5C0040", - "primaryContainer": "890062", - "onPrimaryContainer": "FFD6EA", - "secondary": "D5B2FF", - "onSecondary": "3F0090", - "secondaryContainer": "5800B0", - "onSecondaryContainer": "ECDCFF", - "tertiary": "FFD350", - "onTertiary": "3A2A00", - "tertiaryContainer": "523D00", - "onTertiaryContainer": "FFE08C", - "background": "170820", - "onBackground": "ECDAEC", - "surface": "170820", - "onSurface": "ECDAEC", - "surfaceVariant": "4F4452", - "onSurfaceVariant": "D2C2D2", - "outline": "A092A2", - }, - "Metal Chick (Light)": { - "primary": "2E2E3A", - "onPrimary": "FFFFFF", - "primaryContainer": "DCDBE9", - "onPrimaryContainer": "0E0E1C", - "secondary": "C8235A", - "onSecondary": "FFFFFF", - "secondaryContainer": "FFD8E0", - "onSecondaryContainer": "3F001A", - "tertiary": "6A6A78", - "onTertiary": "FFFFFF", - "tertiaryContainer": "E3E2F0", - "onTertiaryContainer": "1C1C2A", - "background": "F4F3F8", - "onBackground": "1B1B22", - "surface": "F4F3F8", - "onSurface": "1B1B22", - "surfaceVariant": "E2E0EC", - "onSurfaceVariant": "45434E", - "outline": "76737E", - }, - "Metal Chick (Dark)": { - "primary": "C7C5D6", - "onPrimary": "2F2D3D", - "primaryContainer": "454354", - "onPrimaryContainer": "DCDBE9", - "secondary": "FF8FB0", - "onSecondary": "5C0028", - "secondaryContainer": "88133E", - "onSecondaryContainer": "FFD8E0", - "tertiary": "9D9DAC", - "onTertiary": "2F2F3E", - "tertiaryContainer": "4A4A58", - "onTertiaryContainer": "E3E2F0", - "background": "0E0E13", - "onBackground": "E5E3ED", - "surface": "0E0E13", - "onSurface": "E5E3ED", - "surfaceVariant": "45434E", - "onSurfaceVariant": "C8C5D0", - "outline": "918E99", - }, - "Whimsy Whispers (Light)": { - "primary": "6E5DC4", - "onPrimary": "FFFFFF", - "primaryContainer": "E5DFFF", - "onPrimaryContainer": "1A0067", - "secondary": "BD4878", - "onSecondary": "FFFFFF", - "secondaryContainer": "FFD9E4", - "onSecondaryContainer": "3D0024", - "tertiary": "2B7F68", - "onTertiary": "FFFFFF", - "tertiaryContainer": "A6F0D6", - "onTertiaryContainer": "002016", - "background": "FBF8FF", - "onBackground": "1C1A24", - "surface": "FBF8FF", - "onSurface": "1C1A24", - "surfaceVariant": "E5DFF0", - "onSurfaceVariant": "49454F", - "outline": "7A7580", - }, - "Whimsy Whispers (Dark)": { - "primary": "C7BEFF", - "onPrimary": "260092", - "primaryContainer": "3D2EAE", - "onPrimaryContainer": "E5DFFF", - "secondary": "FFB1C6", - "onSecondary": "650033", - "secondaryContainer": "8E1F50", - "onSecondaryContainer": "FFD9E4", - "tertiary": "80DAB8", - "onTertiary": "003828", - "tertiaryContainer": "00513B", - "onTertiaryContainer": "A6F0D6", - "background": "16131F", - "onBackground": "E6E1F0", - "surface": "16131F", - "onSurface": "E6E1F0", - "surfaceVariant": "49454F", - "onSurfaceVariant": "CBC5D0", - "outline": "96909F", - }, - "Colour Me Happy (Light)": { - "primary": "D63A26", - "onPrimary": "FFFFFF", - "primaryContainer": "FFDAD2", - "onPrimaryContainer": "410000", - "secondary": "1872BD", - "onSecondary": "FFFFFF", - "secondaryContainer": "D1E4FF", - "onSecondaryContainer": "001D36", - "tertiary": "428129", - "onTertiary": "FFFFFF", - "tertiaryContainer": "C6F0A1", - "onTertiaryContainer": "0F2200", - "background": "FFFCF5", - "onBackground": "1F1A14", - "surface": "FFFCF5", - "onSurface": "1F1A14", - "surfaceVariant": "EFE3D5", - "onSurfaceVariant": "4E443A", - "outline": "80766A", - }, - "Colour Me Happy (Dark)": { - "primary": "FFB4A4", - "onPrimary": "5C1500", - "primaryContainer": "882000", - "onPrimaryContainer": "FFDAD2", - "secondary": "A0CAFF", - "onSecondary": "002F66", - "secondaryContainer": "00497D", - "onSecondaryContainer": "D1E4FF", - "tertiary": "ACD688", - "onTertiary": "1A3900", - "tertiaryContainer": "2D530B", - "onTertiaryContainer": "C6F0A1", - "background": "1A1612", - "onBackground": "EDE0D2", - "surface": "1A1612", - "onSurface": "EDE0D2", - "surfaceVariant": "4E443A", - "onSurfaceVariant": "D2C4B5", - "outline": "9F9184", - }, - "Dragon Fire (Light)": { - "primary": "B0181F", - "onPrimary": "FFFFFF", - "primaryContainer": "FFCFCC", - "onPrimaryContainer": "3F0001", - "secondary": "C04A0E", - "onSecondary": "FFFFFF", - "secondaryContainer": "FFDBC9", - "onSecondaryContainer": "3B1100", - "tertiary": "996800", - "onTertiary": "FFFFFF", - "tertiaryContainer": "FFDE8E", - "onTertiaryContainer": "2D1F00", - "background": "FFF8F4", - "onBackground": "1E140F", - "surface": "FFF8F4", - "onSurface": "1E140F", - "surfaceVariant": "F3DED5", - "onSurfaceVariant": "524338", - "outline": "87715F", - }, - "Dragon Fire (Dark)": { - "primary": "FF8A82", - "onPrimary": "680000", - "primaryContainer": "960000", - "onPrimaryContainer": "FFDAD4", - "secondary": "FFB28F", - "onSecondary": "561A00", - "secondaryContainer": "8E2D00", - "onSecondaryContainer": "FFDBC9", - "tertiary": "FFCD66", - "onTertiary": "422C00", - "tertiaryContainer": "5E4300", - "onTertiaryContainer": "FFDE8E", - "background": "1C0907", - "onBackground": "F1DDD7", - "surface": "1C0907", - "onSurface": "F1DDD7", - "surfaceVariant": "523F38", - "onSurfaceVariant": "D7C2B8", - "outline": "A28D81", - }, - "Midnight Neon (Light)": { - "primary": "C5128A", - "onPrimary": "FFFFFF", - "primaryContainer": "FFD6E8", - "onPrimaryContainer": "3D003C", - "secondary": "006D90", - "onSecondary": "FFFFFF", - "secondaryContainer": "B8E9FF", - "onSecondaryContainer": "001E2F", - "tertiary": "4C7A0E", - "onTertiary": "FFFFFF", - "tertiaryContainer": "C2F088", - "onTertiaryContainer": "0F2300", - "background": "FBF7FF", - "onBackground": "161020", - "surface": "FBF7FF", - "onSurface": "161020", - "surfaceVariant": "EDDEEC", - "onSurfaceVariant": "4D4350", - "outline": "7F7484", - }, - "Midnight Neon (Dark)": { - "primary": "FF55C8", - "onPrimary": "5C0048", - "primaryContainer": "870068", - "onPrimaryContainer": "FFD6EA", - "secondary": "5EE0FF", - "onSecondary": "00374A", - "secondaryContainer": "00516C", - "onSecondaryContainer": "B8E9FF", - "tertiary": "C2F052", - "onTertiary": "1D3300", - "tertiaryContainer": "2D4900", - "onTertiaryContainer": "C2F088", - "background": "0A0A18", - "onBackground": "EDE5FA", - "surface": "0A0A18", - "onSurface": "EDE5FA", - "surfaceVariant": "4D4350", - "onSurfaceVariant": "D0C3D0", - "outline": "9D90A4", - }, -} - -# ── Pairs to check ──────────────────────────────────────────────────────────── -# (foreground_key, background_key, threshold, description) -# Threshold: 4.5 = WCAG AA text | 3.0 = WCAG AA UI component - -PAIRS: list[tuple[str, str, float, str]] = [ - # Body text — 4.5 : 1 - ("onPrimary", "primary", 4.5, "text on primary (buttons, period circles)"), - ("onSecondary", "secondary", 4.5, "text on secondary elements"), - ("onTertiary", "tertiary", 4.5, "text on tertiary elements"), - ("onPrimaryContainer", "primaryContainer", 4.5, "text in primary containers"), - ("onSecondaryContainer", "secondaryContainer", 4.5, "text in secondary containers"), - ("onTertiaryContainer", "tertiaryContainer", 4.5, "text in tertiary containers"), - ("onBackground", "background", 4.5, "body text on background"), - ("onSurface", "surface", 4.5, "body text on surface"), - ("onSurfaceVariant", "surfaceVariant", 4.5, "subtitle / caption text in cards"), - # UI components — 3.0 : 1 - ("outline", "surfaceVariant", 3.0, "borders / dividers on cards"), - ("outline", "background", 3.0, "borders on background"), - ("primary", "primaryContainer", 3.0, "focused outlines / active chip border"), - ("primary", "surfaceVariant", 3.0, "ovulation dot / indicator on card"), - ("primary", "background", 3.0, "period circles on background"), - ("primary", "surface", 3.0, "primary on surface"), -] - -# ── CLI ─────────────────────────────────────────────────────────────────────── - -def main() -> int: - args = sys.argv[1:] - fails_only = "--fails-only" in args - name_filter = next((a for a in args if not a.startswith("--")), "").lower() - - themes_to_check = { - name: scheme for name, scheme in THEMES.items() - if name_filter in name.lower() - } - - if not themes_to_check: - print(f"No themes matched '{name_filter}'. Available themes:") - for name in THEMES: - print(f" {name}") - return 1 - - total = 0 - failures = 0 - - for theme_name, scheme in themes_to_check.items(): - theme_failures: list[str] = [] - theme_passes: list[str] = [] - - for fg_key, bg_key, threshold, description in PAIRS: - fg = scheme.get(fg_key) - bg = scheme.get(bg_key) - if fg is None or bg is None: - # Skip pairs where the theme doesn't define both colours - continue - - ratio = contrast_ratio(fg, bg) - total += 1 - passed = ratio >= threshold - marker = "PASS" if passed else "FAIL" - line = ( - f" {marker} {ratio:5.2f}:1 " - f"#{fg} / #{bg} " - f"{fg_key} / {bg_key} — {description}" - ) - if passed: - theme_passes.append(line) - else: - failures += 1 - theme_failures.append(line) - - # Print theme block - print(f"\n{'─'*70}") - print(f" {theme_name}") - print(f"{'─'*70}") - if not fails_only: - for line in theme_passes: - print(line) - for line in theme_failures: - print(line) - if not theme_failures: - count = len(theme_passes) - print(f" All {count} pairs pass ✓") - - print(f"\n{'═'*70}") - print(f" {total} pairs checked across {len(themes_to_check)} theme(s)") - if failures: - print(f" {failures} FAILED ✗") - else: - print(f" All passed ✓") - print(f"{'═'*70}") - - return 1 if failures else 0 - - -if __name__ == "__main__": - sys.exit(main())