@brandlab-digital/conformance 3.14.0 → 3.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +60 -3
- package/dist/current-release.js +5 -5
- package/dist/current-release.js.map +1 -1
- package/dist/engineering.d.ts.map +1 -1
- package/dist/engineering.js +18 -2
- package/dist/engineering.js.map +1 -1
- package/dist/estate-snapshot.d.ts +54 -0
- package/dist/estate-snapshot.d.ts.map +1 -0
- package/dist/estate-snapshot.js +164 -0
- package/dist/estate-snapshot.js.map +1 -0
- package/dist/estate.d.ts +10 -0
- package/dist/estate.d.ts.map +1 -1
- package/dist/estate.js +36 -16
- package/dist/estate.js.map +1 -1
- package/dist/media-snapshot.d.ts +53 -0
- package/dist/media-snapshot.d.ts.map +1 -0
- package/dist/media-snapshot.js +66 -0
- package/dist/media-snapshot.js.map +1 -0
- package/dist/site-system/checks.d.ts +2 -2
- package/dist/site-system/checks.js +2 -2
- package/dist/site-system/checks.js.map +1 -1
- package/dist/site-system/config.d.ts +13 -0
- package/dist/site-system/config.d.ts.map +1 -1
- package/dist/site-system/config.js +30 -1
- package/dist/site-system/config.js.map +1 -1
- package/dist/site-system/index.d.ts +1 -1
- package/dist/site-system/index.d.ts.map +1 -1
- package/dist/site-system/index.js +1 -1
- package/dist/site-system/index.js.map +1 -1
- package/dist/site-system/journeys/conversion.d.ts.map +1 -1
- package/dist/site-system/journeys/conversion.js +15 -2
- package/dist/site-system/journeys/conversion.js.map +1 -1
- package/dist/site-system/journeys/menu.d.ts.map +1 -1
- package/dist/site-system/journeys/menu.js +24 -1
- package/dist/site-system/journeys/menu.js.map +1 -1
- package/dist/site-system/journeys/page-helpers.d.ts.map +1 -1
- package/dist/site-system/journeys/page-helpers.js +1 -1
- package/dist/site-system/journeys/page-helpers.js.map +1 -1
- package/dist/site-system/journeys/plan.d.ts +13 -3
- package/dist/site-system/journeys/plan.d.ts.map +1 -1
- package/dist/site-system/journeys/plan.js +12 -2
- package/dist/site-system/journeys/plan.js.map +1 -1
- package/dist/site-system/journeys/shell.d.ts +1 -1
- package/dist/site-system/journeys/shell.js +2 -2
- package/dist/site-system/journeys/shell.js.map +1 -1
- package/dist/site-system/report.d.ts.map +1 -1
- package/dist/site-system/report.js +24 -4
- package/dist/site-system/report.js.map +1 -1
- package/dist/site-system/rules/form/c7-thank-you.d.ts +7 -1
- package/dist/site-system/rules/form/c7-thank-you.d.ts.map +1 -1
- package/dist/site-system/rules/form/c7-thank-you.js +26 -3
- package/dist/site-system/rules/form/c7-thank-you.js.map +1 -1
- package/dist/site-system/rules/form/index.d.ts.map +1 -1
- package/dist/site-system/rules/form/index.js +11 -1
- package/dist/site-system/rules/form/index.js.map +1 -1
- package/dist/site-system/rules/full/common.d.ts +2 -0
- package/dist/site-system/rules/full/common.d.ts.map +1 -1
- package/dist/site-system/rules/full/common.js.map +1 -1
- package/dist/site-system/rules/full/estate.d.ts +10 -2
- package/dist/site-system/rules/full/estate.d.ts.map +1 -1
- package/dist/site-system/rules/full/estate.js +35 -5
- package/dist/site-system/rules/full/estate.js.map +1 -1
- package/dist/site-system/rules/full/geography.d.ts +7 -0
- package/dist/site-system/rules/full/geography.d.ts.map +1 -1
- package/dist/site-system/rules/full/geography.js +9 -0
- package/dist/site-system/rules/full/geography.js.map +1 -1
- package/dist/site-system/rules/full/index.d.ts +2 -1
- package/dist/site-system/rules/full/index.d.ts.map +1 -1
- package/dist/site-system/rules/full/index.js +5 -1
- package/dist/site-system/rules/full/index.js.map +1 -1
- package/dist/site-system/rules/full/l10-location-copy.d.ts +1 -1
- package/dist/site-system/rules/full/l10-location-copy.d.ts.map +1 -1
- package/dist/site-system/rules/full/l10-location-copy.js +5 -2
- package/dist/site-system/rules/full/l10-location-copy.js.map +1 -1
- package/dist/site-system/rules/full/l3-neighbours.d.ts +3 -2
- package/dist/site-system/rules/full/l3-neighbours.d.ts.map +1 -1
- package/dist/site-system/rules/full/l3-neighbours.js +4 -1
- package/dist/site-system/rules/full/l3-neighbours.js.map +1 -1
- package/dist/site-system/rules/full/l4-local-copy.d.ts +2 -1
- package/dist/site-system/rules/full/l4-local-copy.d.ts.map +1 -1
- package/dist/site-system/rules/full/l4-local-copy.js +8 -3
- package/dist/site-system/rules/full/l4-local-copy.js.map +1 -1
- package/dist/site-system/rules/full/l9-data-contract.js +2 -2
- package/dist/site-system/rules/full/l9-data-contract.js.map +1 -1
- package/dist/site-system/rules/full/links.d.ts +3 -1
- package/dist/site-system/rules/full/links.d.ts.map +1 -1
- package/dist/site-system/rules/full/links.js +15 -5
- package/dist/site-system/rules/full/links.js.map +1 -1
- package/dist/site-system/rules/full/route-kinds.d.ts +15 -0
- package/dist/site-system/rules/full/route-kinds.d.ts.map +1 -0
- package/dist/site-system/rules/full/route-kinds.js +52 -0
- package/dist/site-system/rules/full/route-kinds.js.map +1 -0
- package/dist/site-system/rules/full/strategy.d.ts +2 -0
- package/dist/site-system/rules/full/strategy.d.ts.map +1 -1
- package/dist/site-system/rules/full/strategy.js +86 -14
- package/dist/site-system/rules/full/strategy.js.map +1 -1
- package/dist/site-system/rules/sections/k2-skin-coverage.d.ts +2 -2
- package/dist/site-system/rules/sections/k2-skin-coverage.d.ts.map +1 -1
- package/dist/site-system/rules/sections/k2-skin-coverage.js +9 -2
- package/dist/site-system/rules/sections/k2-skin-coverage.js.map +1 -1
- package/dist/site-system/rules/sections/t6-media-entries.d.ts.map +1 -1
- package/dist/site-system/rules/sections/t6-media-entries.js +69 -5
- package/dist/site-system/rules/sections/t6-media-entries.js.map +1 -1
- package/dist/site-system-e2e.d.ts +1 -1
- package/dist/site-system-e2e.d.ts.map +1 -1
- package/dist/site-system-e2e.js +17 -4
- package/dist/site-system-e2e.js.map +1 -1
- package/package.json +10 -2
package/dist/estate.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"estate.js","sourceRoot":"","sources":["../src/estate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,IAAI,EAA0B,MAAM,kBAAkB,CAAC;AACxE,OAAO,EACL,eAAe,EACf,uBAAuB,EACvB,qBAAqB,EACrB,qBAAqB,EACrB,wBAAwB,EACxB,cAAc,EACd,YAAY,EACZ,qBAAqB,EACrB,sBAAsB,EACtB,mBAAmB,EACnB,iBAAiB,EACjB,eAAe,EACf,qBAAqB,EACrB,sBAAsB,EACtB,sBAAsB,EACtB,UAAU,EACV,mBAAmB,EACnB,oBAAoB,GAKrB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,sCAAsC,EAAE,MAAM,2BAA2B,CAAC;AACnF,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,YAAY,EAAE,kBAAkB,EAAoC,MAAM,oBAAoB,CAAC;AAEjJ,OAAO,EACL,mBAAmB,EACnB,eAAe,EACf,oBAAoB,EACpB,kBAAkB,EAClB,YAAY,EACZ,kBAAkB,GAKnB,MAAM,oBAAoB,CAAC;AA8H5B,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,CAAC,UAAU,EAAE,kBAAkB,CAAC,CAAC,CAAC;AAYjE;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CACjC,MAAsC,EACtC,MAAsC;IAEtC,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;IACvH,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,IAAI,EAAE,CAAC,CAAC,CAAC;IACzE,MAAM,aAAa,GAAG,MAAM,EAAE,KAAK,EAAE,OAAO,IAAI,EAAE,CAAC;IACnD,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;IACtH,OAAO,CAAC,KAAK,EAAE,EAAE;QACf,IAAI,CAAC,KAAK,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC;YAAE,OAAO,SAAS,CAAC;QACtE,MAAM,UAAU,GAAG,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/E,IAAI,CAAC,UAAU;YAAE,OAAO,SAAS,CAAC;QAClC,MAAM,MAAM,GAAG,cAAc,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAC9C,MAAM,MAAM,GACV,CAAC,KAAK,CAAC,EAAE,KAAK,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YACjD,WAAW,CAAC,GAAG,CAAC,UAAU,CAAC;YAC3B,CAAC,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,MAAM,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC,CAAC;QACrE,OAAO,EAAE,IAAI,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,EAAE,CAAC;IAChD,CAAC,CAAC;AACJ,CAAC;AAGD,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC;IAC7B,eAAe,EAAE,6BAA6B,EAAE,mBAAmB,EAAE,SAAS,EAAE,aAAa;IAC7F,mBAAmB,EAAE,cAAc,EAAE,WAAW,EAAE,eAAe,EAAE,cAAc,EAAE,qBAAqB;CACzG,CAAC,CAAC;AACH,MAAM,YAAY,GAAG,8BAA8B,CAAC;AACpD,MAAM,eAAe,GAAG,MAAM,CAAC;AAC/B,MAAM,cAAc,GAAG,wBAAwB,CAAC;AAChD,MAAM,UAAU,GAAG,mBAAmB,CAAC;AAEvC,MAAM,UAAU,yBAAyB,CAAC,OAAkC;IAC1E,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC;IACjE,MAAM,SAAS,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,IAAI,EAAE,GAAG,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC;IACrE,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAC9B,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC7E,MAAM,SAAS,GAAG,CAAC,OAAO,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzE,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAC9B,SAAS,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,CAC9G,CAAC;IACF,MAAM,gBAAgB,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;QAClD,MAAM,OAAO,GAAG,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,qBAAqB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAChG,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5C,CAAC,CAAC,CAAC;IACH,MAAM,YAAY,GAAG,CAAC,IAAY,EAAE,EAAE,CACpC,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,gBAAgB,CAAC,IAAI,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC;IACjG,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC;IAC3C,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC;IACxC,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;IAC3F,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IACvF,MAAM,YAAY,GAAG,mBAAmB,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IACjE,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,CAAC,EAAE,IAAI,IAAI,GAAG,CAAC,CAAC;IAC3F,4GAA4G;IAC5G,MAAM,KAAK,GAAG,kBAAkB,EAAE,CAAC;IACnC,MAAM,MAAM,GAAG,kBAAkB,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,YAAY,EAAE,mBAAmB,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC1H,MAAM,SAAS,GAAG,CAAC,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1E,MAAM,gBAAgB,GAAG,KAAK,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAE/H,IAAI,CAAC,QAAQ,CAAC,2BAA2B,EAAE,GAAG,EAAE;QAC9C,IAAI,CAAC,0DAA0D,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;YACrF,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;YACzB,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,OAAO,EAAE,cAAc,EAAE,MAAM,CAAC,CAAC;YAClE,MAAM,QAAQ,GAAG,MAAM;iBACpB,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,KAAK,OAAO,CAAC;iBAC7C,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,aAAa,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;YAChE,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,2BAA2B,CAAC,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC;YAC9E,MAAM,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QACpE,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,8EAA8E,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,EAAE;YACnH,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;YACzB,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,MAAM,gBAAgB,CAAC,OAAO,EAAE,cAAc,EAAE,MAAM,CAAC,CAAC;YACjF,MAAM,QAAQ,GAAG;gBACf,GAAG,qBAAqB,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;gBAC1D,GAAG,sBAAsB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC;aACjF,CAAC;YACF,MAAM,QAAQ,CAAC,MAAM,CAAC,oBAAoB,EAAE;gBAC1C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;gBACpG,WAAW,EAAE,kBAAkB;aAChC,CAAC,CAAC;YACH,MAAM,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC/B,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,kDAAkD,EAAE,KAAK,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE;YAC9E,MAAM,MAAM,GAAG,qBAAqB,CAAC,MAAM,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAC;YACvE,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,mBAAmB,EAAE,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;YACzH,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACpD,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,kFAAkF,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,EAAE;YACvH,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;YACzB,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,CAAC,MAAM,qBAAqB,EAAE,CAAC,CAAC,QAAQ,CAAC;YAC9E,MAAM,QAAQ,GAAa,EAAE,CAAC;YAC9B,MAAM,aAAa,GAAG,IAAI,GAAG,EAAkB,CAAC;YAChD,MAAM,OAAO,GAAiE,EAAE,CAAC;YACjF,MAAM,aAAa,GAAG,IAAI,GAAG,EAA8C,CAAC;YAC5E,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,WAAW,EAAE,SAAS,EAAE,CAAC,CAAC;YAC5E,MAAM,mBAAmB,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,WAAW,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;gBACjF,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;oBACpC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,YAAY,EAAE,CAAC,EAAE,CAAC;oBAC5C,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,YAAY,EAAE,CAAC,EAAE,CAAC;iBAC9C,CAAC,CAAC;gBACH,4DAA4D;gBAC5D,MAAM,QAAQ,GAAG,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,eAAe,CAAC;gBAC/D,MAAM,cAAc,GAAG,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;gBAC5C,IAAI,GAAG,CAAC,MAAM,EAAE,KAAK,cAAc,IAAI,IAAI,CAAC,MAAM,EAAE,KAAK,cAAc,EAAE,CAAC;oBACxE,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,IAAI,SAAS,GAAG,CAAC,MAAM,EAAE,UAAU,IAAI,CAAC,MAAM,EAAE,cAAc,cAAc,GAAG,CAAC,CAAC;oBACxG,OAAO;gBACT,CAAC;gBACD,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;gBAC9B,MAAM,QAAQ,GAAG,sCAAsC,CAAC,IAAI,CAAC,CAAC;gBAC9D,MAAM,MAAM,GAAG,GAAG,QAAQ,CAAC,MAAM,IAAI,EAAE,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC,cAAc,CAAC,IAAI,EAAE,EAAE,CAAC;gBACjF,IAAI,QAAQ,EAAE,CAAC;oBACb,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC;wBAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,IAAI,mCAAmC,CAAC,CAAC;oBAC9F,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;oBAClG,OAAO;gBACT,CAAC;gBACD,MAAM,iBAAiB,GAAG,SAAS,CAAC,KAAK,CAAC,aAAa,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC;gBACvE,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,6CAA6C,CAAC,IAAI,EAAE,CAAC;gBACtF,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC;oBAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,IAAI,KAAK,aAAa,CAAC,MAAM,kBAAkB,CAAC,CAAC;gBACxG,IAAI,CAAC,QAAQ,CAAC,SAAS,IAAI,IAAI,GAAG,CAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,IAAI,KAAK,iBAAiB,EAAE,CAAC;oBAC1F,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,IAAI,eAAe,QAAQ,CAAC,SAAS,IAAI,SAAS,cAAc,iBAAiB,GAAG,CAAC,CAAC;gBAC/G,CAAC;gBACD,IAAI,KAAK,CAAC,QAAQ,KAAK,OAAO,IAAI,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC;oBAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,IAAI,8BAA8B,CAAC,CAAC;gBACtH,IAAI,KAAK,CAAC,QAAQ,KAAK,OAAO,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC;oBAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,QAAQ,qBAAqB,CAAC,CAAC;gBACjI,KAAK,MAAM,OAAO,IAAI,sBAAsB,CAAC,QAAQ,CAAC,MAAM,CAAC;oBAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC,CAAC;gBAC1G,IAAI,KAAK,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;oBAC/B,IAAI,CAAC,QAAQ,CAAC,KAAK;wBAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,IAAI,iCAAiC,CAAC,CAAC;oBACnF,IAAI,CAAC,QAAQ,CAAC,WAAW;wBAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,IAAI,0CAA0C,CAAC,CAAC;oBAClG,IAAI,QAAQ,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC;wBAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,IAAI,iCAAiC,CAAC,CAAC;gBAClG,CAAC;gBACD,IAAI,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAE,OAAoC,CAAC,UAAU,CAAC;oBAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,IAAI,mBAAmB,CAAC,CAAC;gBACzI,KAAK,MAAM,OAAO,IAAI,sBAAsB,CAAC,QAAQ,CAAC,MAAM,EAAE;oBAC5D,MAAM;oBACN,IAAI,EAAE,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,QAAQ;oBAC5C,UAAU,EAAE,OAAO,CAAC,UAAU;oBAC9B,QAAQ,EAAE,OAAO,CAAC,QAAQ;iBAC3B,CAAC;oBAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC,CAAC;gBAC/C,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;gBAClC,IAAI,KAAK,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;oBACnD,KAAK,MAAM,OAAO,IAAI,sBAAsB,CAAC;wBAC3C,IAAI;wBACJ,MAAM,EAAE,KAAK,CAAC,IAAI;wBAClB,OAAO,EAAE,iBAAiB;wBAC1B,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;4BAChB,MAAM,MAAM,GAAG,YAAY,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;4BACnD,OAAO,MAAM,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;wBAC5D,CAAC;wBACD,QAAQ;qBACT,CAAC;wBAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC,CAAC;gBACjD,CAAC;gBACD,MAAM,IAAI,GAAG,eAAe,CAAC;oBAC3B,IAAI;oBACJ,OAAO,EAAE,iBAAiB;oBAC1B,WAAW,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,QAAQ,KAAK,OAAO;oBAClE,QAAQ,EAAE,OAAO,CAAC,eAAe;iBAClC,CAAC,CAAC;gBACH,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,QAAQ;oBAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC,CAAC;gBAChF,KAAK,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;oBAC1C,MAAM,KAAK,GAAG,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,GAAG,EAAU,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC;oBACtF,KAAK,MAAM,EAAE,IAAI,GAAG;wBAAE,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;oBACxC,aAAa,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;gBACjC,CAAC;gBACD,KAAK,MAAM,IAAI,IAAI,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;oBACtC,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,EAAE,iBAAiB,EAAE,MAAM,CAAC,CAAC;oBAC3D,IAAI,IAAI,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC;wBAAE,aAAa,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;gBAC5E,CAAC;gBACD,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;YACpG,CAAC,CAAC,CAAC;YACH,6FAA6F;YAC7F,KAAK,MAAM,CAAC,IAAI,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,aAAa,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC9F,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,YAAY,EAAE,CAAC,EAAE,CAAC,CAAC;gBAC9D,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,EAAE,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC;gBACtD,IAAI,QAAQ,CAAC,MAAM,EAAE,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC;oBACjE,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,0BAA0B,IAAI,YAAY,QAAQ,CAAC,MAAM,EAAE,IAAI,IAAI,IAAI,wBAAwB,EAAE,CAAC,CAAC;oBACxH,SAAS;gBACX,CAAC;gBACD,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;gBAClC,KAAK,MAAM,EAAE,IAAI,GAAG;oBAAE,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC;wBAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,0BAA0B,IAAI,kBAAkB,EAAE,EAAE,CAAC,CAAC;YACpI,CAAC;YACD,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,aAAa,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;gBACrD,IAAI,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC;oBAAE,SAAS;gBAC5D,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;gBACpC,IAAI,QAAQ,IAAI,qBAAqB,CAAC,QAAQ,CAAC,WAAW,CAAC;oBAAE,SAAS;gBACtE,QAAQ,CAAC,IAAI,CAAC,QAAQ;oBACpB,CAAC,CAAC,GAAG,IAAI,cAAc,IAAI,8BAA8B,QAAQ,CAAC,WAAW,WAAW;oBACxF,CAAC,CAAC,GAAG,IAAI,cAAc,IAAI,kCAAkC,CAAC,CAAC;YACnE,CAAC;YACD,MAAM,QAAQ,CAAC,MAAM,CAAC,uBAAuB,EAAE;gBAC7C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,aAAa,EAAE,CAAC,GAAG,aAAa,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;gBAChJ,WAAW,EAAE,kBAAkB;aAChC,CAAC,CAAC;YACH,MAAM,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC/B,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,+DAA+D,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,EAAE;YACpG,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;YACzB,MAAM,QAAQ,GAAa,EAAE,CAAC;YAC9B,MAAM,OAAO,GAAa,EAAE,CAAC;YAC7B,IAAI,KAAK,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;gBAC7B,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,WAAW,EAAE,WAAW,gBAAgB,CAAC,MAAM,OAAO,SAAS,CAAC,MAAM,8FAA8F,EAAE,CAAC,CAAC;YAC5N,CAAC;YACD,KAAK,MAAM,IAAI,IAAI,gBAAgB,EAAE,CAAC;gBACpC,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;gBAClC,IAAI,CAAC,KAAK,EAAE,CAAC;oBACX,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;oBACrD,SAAS;gBACX,CAAC;gBACD,MAAM,OAAO,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,CAAC,OAAO,CAAC,sBAAsB,KAAK,KAAK,IAAI,KAAK,CAAC,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;gBAChK,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;oBAC7B,KAAK,MAAM,MAAM,IAAI,CAAC,KAAK,EAAE,MAAM,CAAU,EAAE,CAAC;wBAC9C,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,GAAG,MAAM,oBAAoB,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,EAAE,CAAC,CAAC;wBACjG,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC;wBAC7C,MAAM,cAAc,GAAa,MAAM,KAAK,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;wBACtF,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;4BAC7D,QAAQ,CAAC,IAAI,CAAC,GAAG,MAAM,IAAI,MAAM,KAAK,QAAQ,CAAC,MAAM,EAAE,cAAc,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,KAAK,CAAC,WAAW,GAAG,CAAC,CAAC;4BAC7H,SAAS;wBACX,CAAC;wBACD,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;wBACzC,IAAI,qBAAqB,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC;4BAC7C,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;gCAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,MAAM,IAAI,MAAM,cAAc,QAAQ,cAAc,KAAK,CAAC,WAAW,GAAG,CAAC,CAAC;4BACpL,SAAS;wBACX,CAAC;wBACD,IAAI,MAAM,CAAC,QAAQ,KAAK,IAAI,GAAG,CAAC,KAAK,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,QAAQ;4BAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,MAAM,IAAI,MAAM,cAAc,QAAQ,cAAc,KAAK,CAAC,WAAW,GAAG,CAAC,CAAC;wBAChK,IAAI,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,iBAAiB,CAAC,KAAK,GAAG;4BAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,MAAM,IAAI,MAAM,gCAAgC,CAAC,CAAC;oBAC7H,CAAC;gBACH,CAAC;gBACD,uGAAuG;gBACvG,IAAI,CAAC,qBAAqB,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;oBAChE,MAAM,WAAW,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,EAAE,EAAE,YAAY,EAAE,CAAC,EAAE,CAAC,CAAC;oBAC9E,IAAI,WAAW,CAAC,MAAM,EAAE,KAAK,GAAG;wBAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM,iBAAiB,KAAK,CAAC,WAAW,YAAY,WAAW,CAAC,MAAM,EAAE,8BAA8B,CAAC,CAAC;gBAClK,CAAC;YACH,CAAC;YACD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACvB,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,mBAAmB,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,MAAM,iEAAiE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;YAChL,CAAC;YACD,MAAM,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC/B,CAAC,CAAC,CAAC;QAEH,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxB,IAAI,CAAC,0FAA0F,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;gBACrH,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;gBACzB,MAAM,QAAQ,GAAa,EAAE,CAAC;gBAC9B,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,IAAI,YAAY,EAAE,EAAE,EAAE,YAAY,EAAE,CAAC,EAAE,CAAC,CAAC;gBAC7E,MAAM,YAAY,GAAG,SAAS,CAAC,MAAM,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBACxF,IAAI,CAAC,YAAY;oBAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,YAAY,KAAK,SAAS,CAAC,MAAM,EAAE,yDAAyD,CAAC,CAAC;gBACnI,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;oBAC9B,MAAM,MAAM,GAAG,gBAAgB,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;oBACpD,IAAI,CAAC,MAAM,EAAE,CAAC;wBACZ,QAAQ,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,OAAO,4BAA4B,CAAC,CAAC;wBAC7D,SAAS;oBACX,CAAC;oBACD,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE,YAAY,EAAE,CAAC,EAAE,CAAC,CAAC;oBAChE,IAAI,QAAQ,CAAC,MAAM,EAAE,KAAK,GAAG,EAAE,CAAC;wBAC9B,QAAQ,CAAC,IAAI,CAAC,GAAG,MAAM,KAAK,QAAQ,CAAC,MAAM,EAAE,gCAAgC,MAAM,CAAC,OAAO,GAAG,CAAC,CAAC;oBAClG,CAAC;yBAAM,CAAC;wBACN,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;wBACnC,MAAM,QAAQ,GAAG,sCAAsC,CAAC,IAAI,CAAC,CAAC;wBAC9D,MAAM,MAAM,GAAG,GAAG,QAAQ,CAAC,MAAM,IAAI,EAAE,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC,cAAc,CAAC,IAAI,EAAE,EAAE,CAAC;wBACtF,MAAM,iBAAiB,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;wBAC5C,IAAI,CAAC,QAAQ,CAAC,SAAS,IAAI,IAAI,GAAG,CAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,IAAI,KAAK,iBAAiB,EAAE,CAAC;4BAC1F,QAAQ,CAAC,IAAI,CAAC,GAAG,MAAM,eAAe,QAAQ,CAAC,SAAS,IAAI,SAAS,cAAc,iBAAiB,GAAG,CAAC,CAAC;wBAC3G,CAAC;wBACD,IAAI,MAAM,CAAC,QAAQ,KAAK,OAAO,IAAI,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC;4BAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,MAAM,yDAAyD,CAAC,CAAC;wBAC9I,IAAI,MAAM,CAAC,QAAQ,KAAK,OAAO,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC;4BAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,MAAM,4BAA4B,MAAM,CAAC,QAAQ,yBAAyB,CAAC,CAAC;oBAC5J,CAAC;oBACD,KAAK,MAAM,OAAO,IAAI,mBAAmB,CAAC,MAAM,CAAC,EAAE,CAAC;wBAClD,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,YAAY,EAAE,CAAC,EAAE,CAAC,CAAC;wBAC7D,IAAI,IAAI,CAAC,MAAM,EAAE,KAAK,GAAG,EAAE,CAAC;4BAC1B,QAAQ,CAAC,IAAI,CAAC,GAAG,OAAO,KAAK,IAAI,CAAC,MAAM,EAAE,0BAA0B,MAAM,CAAC,OAAO,WAAW,CAAC,CAAC;4BAC/F,SAAS;wBACX,CAAC;wBACD,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;wBACzC,IAAI,YAAY,IAAI,IAAI,KAAK,YAAY,EAAE,CAAC;4BAC1C,QAAQ,CAAC,IAAI,CAAC,GAAG,OAAO,sEAAsE,IAAI,CAAC,CAAC,CAAC,aAAa,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,gDAAgD,GAAG,CAAC,CAAC;wBAChM,CAAC;oBACH,CAAC;gBACH,CAAC;gBACD,MAAM,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YAC/B,CAAC,CAAC,CAAC;QACL,CAAC;QAED,IAAI,CAAC,qDAAqD,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,EAAE;YAC1F,2GAA2G;YAC3G,6EAA6E;YAC7E,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,aAAa;gBACzD,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,aAAa,EAAE,UAAU,EAAE,EAAE,EAAE;gBACnD,CAAC,CAAC,iBAAiB,CAAC,oBAAoB,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC3F,KAAK,MAAM,IAAI,IAAI,UAAU;gBAAE,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,GAAG,IAAI,8BAA8B,EAAE,CAAC,CAAC;YAClI,MAAM,QAAQ,GAAa,EAAE,CAAC;YAC9B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;oBACpC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,YAAY,EAAE,CAAC,EAAE,CAAC;oBACtC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,YAAY,EAAE,CAAC,EAAE,CAAC;iBACxC,CAAC,CAAC;gBACH,IAAI,GAAG,CAAC,MAAM,EAAE,KAAK,GAAG;oBAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,SAAS,GAAG,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;gBACvF,IAAI,IAAI,CAAC,MAAM,EAAE,KAAK,GAAG;oBAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,UAAU,IAAI,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;YAC5F,CAAC;YACD,MAAM,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC/B,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,kDAAkD,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;YAC7E,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;YAClD,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACpC,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACnC,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,gBAAgB,YAAY,CAAC,GAAG,MAAM,cAAc,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;YACrG,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,uBAAuB,CAAC,CAAC;QACpD,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,oFAAoF,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;YAC/G,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,KAAK,YAAY,EAAE,oGAAoG,CAAC,CAAC;YACzJ,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,OAAO,IAAI,wBAAwB,CAAC,CAAC;YAC5D,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC;YAC/C,yFAAyF;YACzF,MAAM,KAAK,GAAG,GAAG,aAAa,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,0BAA0B,CAAC;YACvE,MAAM,CAAC,MAAM,cAAc,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,cAAc,CAAC,EAAE,GAAG,KAAK,gBAAgB,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAC3G,MAAM,CAAC,MAAM,cAAc,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,cAAc,CAAC,EAAE,GAAG,aAAa,gBAAgB,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QACpI,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CAAC,MAA0B;IAC/D,MAAM,KAAK,GAA8B,EAAE,CAAC;IAC5C,MAAM,OAAO,GAAG,CAAC,KAAc,EAAE,EAAE;QACjC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YACvB,OAAO;QACT,CAAC;QACD,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,OAAO;QAChD,MAAM,IAAI,GAAG,KAAgC,CAAC;QAC9C,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC;QAC3B,IAAI,IAAI,KAAK,gBAAgB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5G,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAAE,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC7D,CAAC,CAAC;IACF,OAAO,CAAC,MAAM,CAAC,CAAC;IAChB,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9E,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;YAC1C,MAAM,IAAI,GAAG,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAE,KAAiC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;YACtG,MAAM,KAAK,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAE,IAAgC,CAAC,KAAK,CAAC,IAAK,IAAgC,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACtM,IAAI,KAAK;gBAAE,OAAO;YAClB,MAAM,IAAI,GAAG,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAE,KAAiC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;YACtG,QAAQ,CAAC,IAAI,CAAC,uBAAuB,KAAK,GAAG,CAAC,GAAG,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,sFAAsF,CAAC,CAAC;QAC/M,CAAC,CAAC,CAAC;IACL,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,4HAA4H;AAC5H,MAAM,UAAU,cAAc,CAAC,MAAW,EAAE,IAAY,EAAE,IAAY,EAAE,IAAY;IAClF,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,OAAO,GAAG,WAAW,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,QAAQ,EAAE,EAAE;YACrK,QAAQ,CAAC,MAAM,EAAE,CAAC;YAClB,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;YACnD,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QAC3D,CAAC,CAAC,CAAC;QACH,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC5B,OAAO,CAAC,GAAG,EAAE,CAAC;IAChB,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,OAA0B,EAAE,IAAY,EAAE,MAAe;IACzF,MAAM,IAAI,GAAG,KAAK,EAAE,MAAc,EAAE,EAAE;QACpC,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE,YAAY,EAAE,CAAC,EAAE,CAAC,CAAC;QAChE,IAAI,QAAQ,CAAC,MAAM,EAAE,KAAK,GAAG;YAAE,MAAM,IAAI,KAAK,CAAC,GAAG,MAAM,YAAY,QAAQ,CAAC,MAAM,EAAE,kDAAkD,CAAC,CAAC;QACzI,OAAO,QAAQ,CAAC,IAAI,EAAE,CAAC;IACzB,CAAC,CAAC;IACF,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7B,MAAM,SAAS,GAAG,uBAAuB,CAAC,GAAG,CAAC,CAAC;IAC/C,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC;IACpD,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC9B,IAAI,MAAM,IAAI,GAAG,CAAC,MAAM,KAAK,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,CAAC;YACpD,MAAM,IAAI,KAAK,CAAC,2BAA2B,QAAQ,qBAAqB,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;QACrG,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,GAAG,uBAAuB,CAAC,MAAM,IAAI,CAAC,GAAG,GAAG,CAAC,QAAQ,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC;IACtF,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,OAA0B,EAC1B,IAAY,EACZ,MAAc;IAEd,MAAM,IAAI,GAAG,KAAK,EAAE,MAAc,EAAE,EAAE;QACpC,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE,YAAY,EAAE,CAAC,EAAE,CAAC,CAAC;QAChE,IAAI,QAAQ,CAAC,MAAM,EAAE,KAAK,GAAG;YAAE,MAAM,IAAI,KAAK,CAAC,GAAG,MAAM,YAAY,QAAQ,CAAC,MAAM,EAAE,kDAAkD,CAAC,CAAC;QACzI,OAAO,QAAQ,CAAC,IAAI,EAAE,CAAC;IACzB,CAAC,CAAC;IACF,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7B,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,mBAAmB,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;IACjH,MAAM,KAAK,GAAkB,EAAE,CAAC;IAChC,KAAK,MAAM,QAAQ,IAAI,uBAAuB,CAAC,GAAG,CAAC,EAAE,CAAC;QACpD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC9B,IAAI,GAAG,CAAC,MAAM,KAAK,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,QAAQ,qBAAqB,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;QAC9I,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,QAAQ,EAAE,OAAO,EAAE,mBAAmB,CAAC,MAAM,IAAI,CAAC,GAAG,GAAG,CAAC,QAAQ,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;IAC/G,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,GAAW;IACjD,OAAO,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC,+BAA+B,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CACtE,IAAI,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,MAAsC;IACzE,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC9B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,QAAQ,GAAG,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACtE,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,CAAC,GAAG,CAAC,IAAI,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC5E,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,CAAC,GAAG,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAC5D,CAAC;IACD,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,MAAM,IAAI,YAAY,EAAE,CAAC,CAAC;AAC1E,CAAC;AAED,oFAAoF;AACpF,MAAM,UAAU,iBAAiB,CAAC,KAAwB,EAAE,SAAoC;IAC9F,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,KAAK,MAAM,IAAI,IAAI,KAAK;QAAE,CAAC,SAAS,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5F,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;AAChC,CAAC;AAED,6GAA6G;AAC7G,MAAM,UAAU,gBAAgB,CAAC,MAA2C,EAAE,SAA8B;IAC1G,OAAO,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC7F,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAuD;IACzF,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC9B,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,CAAC;IACtB,MAAM,KAAK,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC9C,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC3C,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC,QAAQ,KAAK,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC7K,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC;IACvD,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;AAChE,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAY;IACnC,MAAM,IAAI,GAAG,wCAAwC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAC7G,OAAO,SAAS,CAAC,IAAI;SAClB,OAAO,CAAC,qDAAqD,EAAE,GAAG,CAAC;SACnE,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;SACzB,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC;SACvB,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;SACpB,IAAI,EAAE,CAAC;AACZ,CAAC;AAED,iHAAiH;AACjH,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,OAAO,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,0BAA0B,EAAE,EAAE,CAAC,CAAC,CAAC;AAC/E,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,IAA4D;IACxF,MAAM,MAAM,GAAG,CAAC,IAAY,EAAE,EAAE;QAC9B,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;QAC1C,+EAA+E;QAC/E,MAAM,MAAM,GAAG,+BAA+B,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACrE,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACvC,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;YAAE,OAAO,SAAS,CAAC;QACzC,OAAO,GAAG,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,sBAAsB,EAAE,cAAc,CAAC,EAAE,CAAC;IAC5E,CAAC,CAAC;IACF,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACnC,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAC7C,IAAI,MAAM,KAAK,SAAS,IAAI,WAAW,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IACxE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,iBAAiB,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;AAC/E,CAAC;AAED,gFAAgF;AAChF,SAAS,qBAAqB,CAAC,MAAc;IAC3C,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC;IAC3C,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QAChF,MAAM,SAAS,GAAG,yBAAyB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACvD,IAAI,CAAC,SAAS;YAAE,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC;QAC1C,OAAO,SAAS,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI,SAAS,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;IACxG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACZ,OAAO,IAAI,MAAM,CAAC,IAAI,OAAO,GAAG,CAAC,CAAC;AACpC,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,8BAA8B,CAAC,OAAuC;IACpF,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC;IACjE,MAAM,SAAS,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,IAAI,EAAE,GAAG,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC;IACrE,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,GAAG,MAAM,YAAY,CAAC;IAC/D,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC;IAC3C,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,eAAe,CAAC,CAAC;IAC/F,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IACvF,MAAM,YAAY,GAAG,mBAAmB,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IACjE,MAAM,GAAG,GAAG,qBAAqB,EAAE,CAAC;IAEpC,IAAI,CAAC,QAAQ,CAAC,kCAAkC,EAAE,GAAG,EAAE;QACrD,IAAI,CAAC,0DAA0D,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,EAAE;YAC/F,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;YAChC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;YACzB,MAAM,QAAQ,GAAiC,EAAE,CAAC;YAClD,MAAM,SAAS,GAAG,MAAM,qBAAqB,EAAE,CAAC;YAChD,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,SAAS,CAAC,QAAQ,CAAC;YACxD,MAAM,MAAM,GAAG,IAAI,GAAG,EAAoB,CAAC;YAC3C,MAAM,YAAY,GAAG,IAAI,GAAG,EAAoB,CAAC;YACjD,MAAM,eAAe,GAAqB,EAAE,CAAC;YAC7C,MAAM,SAAS,GAAG,IAAI,GAAG,EAAuB,CAAC;YACjD,MAAM,mBAAmB,CAAC,MAAM,EAAE,OAAO,CAAC,WAAW,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;gBAC1E,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,YAAY,EAAE,CAAC,EAAE,CAAC,CAAC;gBACpE,kFAAkF;gBAClF,IAAI,QAAQ,CAAC,MAAM,EAAE,KAAK,GAAG;oBAAE,OAAO;gBACtC,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;gBACnC,MAAM,QAAQ,GAAG,sCAAsC,CAAC,IAAI,CAAC,CAAC;gBAC9D,MAAM,GAAG,GAAG,CAAC,IAAwC,EAAE,MAAc,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;gBAC5H,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;gBAC/B,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;oBAAE,GAAG,CAAC,UAAU,EAAE,GAAG,GAAG,CAAC,MAAM,cAAc,CAAC,CAAC;gBACnE,IAAI,CAAC,QAAQ,CAAC,KAAK;oBAAE,GAAG,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;gBAC9C,IAAI,CAAC,QAAQ,CAAC,WAAW;oBAAE,GAAG,CAAC,aAAa,EAAE,qBAAqB,CAAC,CAAC;gBACrE,MAAM,SAAS,GAAG,KAAK,CAAC,QAAQ,KAAK,OAAO,CAAC;gBAC7C,IAAI,SAAS,IAAI,QAAQ,CAAC,KAAK,EAAE,CAAC;oBAChC,MAAM,cAAc,GAAG,mBAAmB,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;oBAC3D,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC;wBAAE,GAAG,CAAC,cAAc,EAAE,IAAI,QAAQ,CAAC,KAAK,MAAM,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;oBACxG,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;oBAChF,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;oBAClC,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;wBACrB,MAAM,QAAQ,GAAG,oBAAoB,CAAC,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAE,EAAE,KAAK,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;wBAC1I,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;4BAAE,GAAG,CAAC,UAAU,EAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;oBAChE,CAAC;gBACH,CAAC;gBACD,IAAI,SAAS,IAAI,QAAQ,CAAC,WAAW,EAAE,CAAC;oBACtC,MAAM,OAAO,GAAG,wBAAwB,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;oBAC/D,IAAI,OAAO;wBAAE,GAAG,CAAC,oBAAoB,EAAE,OAAO,CAAC,CAAC;oBAChD,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;gBAC1G,CAAC;gBACD,MAAM,KAAK,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;gBACtC,IAAI,KAAK,GAAG,cAAc;oBAAE,GAAG,CAAC,WAAW,EAAE,GAAG,CAAC,KAAK,GAAG,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,8CAA8C,CAAC,CAAC;gBAC9H,MAAM,iBAAiB,GAAG,SAAS,CAAC,KAAK,CAAC,aAAa,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC;gBACvE,MAAM,KAAK,GAAG,QAAQ,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;gBAC3C,IAAI,KAAK,IAAI,IAAI,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,IAAI,KAAK,iBAAiB;oBAAE,GAAG,CAAC,QAAQ,EAAE,UAAU,KAAK,2BAA2B,CAAC,CAAC;gBAC1H,IAAI,QAAQ,CAAC,yBAAyB,CAAC,MAAM,GAAG,CAAC;oBAAE,GAAG,CAAC,wBAAwB,EAAE,QAAQ,CAAC,yBAAyB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;gBAChI,KAAK,MAAM,OAAO,IAAI,qBAAqB,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC,EAAE,CAAC;oBAChF,GAAG,CAAC,iBAAiB,EAAE,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;gBAC/D,CAAC;gBACD,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC;gBACxC,IAAI,SAAS,IAAI,KAAK;oBAAE,eAAe,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;gBAC9H,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;gBAClC,KAAK,MAAM,IAAI,IAAI,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;oBACtC,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,EAAE,iBAAiB,EAAE,MAAM,CAAC,CAAC;oBAC3D,IAAI,IAAI,IAAI,IAAI,KAAK,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC;wBAAE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBACpE,CAAC;gBACD,SAAS,CAAC,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC;YACpD,CAAC,CAAC,CAAC;YACH,0HAA0H;YAC1H,MAAM,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAC;YAC1C,KAAK,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,SAAS,EAAE,CAAC;gBACxC,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBACrC,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;oBAC7B,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;oBACpD,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;oBACvC,IAAI,MAAM,EAAE,QAAQ,KAAK,OAAO,IAAI,MAAM,IAAI,MAAM,CAAC,QAAQ,KAAK,OAAO,IAAI,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC,EAAE,CAAC;wBACnH,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,YAAY,MAAM,iEAAiE,EAAE,CAAC,CAAC;oBACnJ,CAAC;gBACH,CAAC;YACH,CAAC;YACD,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;gBAC3B,MAAM,IAAI,GAAG,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBACvC,IAAI,KAAK,CAAC,QAAQ,KAAK,OAAO,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,GAAG,IAAI,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;oBACrH,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,qCAAqC,EAAE,CAAC,CAAC;gBACrG,CAAC;YACH,CAAC;YACD,KAAK,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,MAAM,EAAE,CAAC;gBACpC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;oBAAE,KAAK,MAAM,IAAI,IAAI,KAAK;wBAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,iBAAiB,EAAE,MAAM,EAAE,IAAI,KAAK,0BAA0B,KAAK,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;YACxP,CAAC;YACD,KAAK,MAAM,CAAC,WAAW,EAAE,KAAK,CAAC,IAAI,YAAY,EAAE,CAAC;gBAChD,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;oBAAE,KAAK,MAAM,IAAI,IAAI,KAAK;wBAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,uBAAuB,EAAE,MAAM,EAAE,uCAAuC,KAAK,CAAC,MAAM,GAAG,CAAC,oBAAoB,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC;YAC3N,CAAC;YACD,+EAA+E;YAC/E,MAAM,UAAU,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;iBAC5G,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,qBAAqB,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,KAAK,IAAI,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC;YAClJ,KAAK,MAAM,KAAK,IAAI,UAAU,EAAE,CAAC;gBAC/B,IAAI,KAAK,CAAC,KAAK,GAAG,eAAe;oBAAE,SAAS;gBAC5C,QAAQ,CAAC,IAAI,CAAC;oBACZ,IAAI,EAAE,KAAK,CAAC,IAAI;oBAChB,IAAI,EAAE,YAAY;oBAClB,MAAM,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,gDAAgD,KAAK,CAAC,OAAO,IAAI,gBAAgB,GAAG,KAAK,CAAC,KAAK,IAAI,iBAAiB,CAAC,CAAC,CAAC,gEAAgE,CAAC,CAAC,CAAC,gDAAgD,EAAE;iBAC9Q,CAAC,CAAC;YACL,CAAC;YACD,MAAM,UAAU,GAAG,uBAAuB,CAAC,MAAM,CAAC,CAAC;YACnD,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,IAAI,iBAAiB,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;YACnH,MAAM,MAAM,GAAG;gBACb,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,wCAAwC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;gBACrJ,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,EAAE,gBAAgB,EAAE,QAAQ,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC,wCAAwC,CAAC,EAAE,CAAC,CAAC;aAClP,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;YAC/C,KAAK,MAAM,IAAI,IAAI,MAAM;gBAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,iBAAiB,EAAE,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACxH,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;YACtF,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,CAC/B,CAAC,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAC/I,CAAC;YACF,MAAM,OAAO,GAAG;gBACd,mBAAmB,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC5H,sBAAsB,EAAE,IAAI,CAAC,SAAS,CAAC;oBACrC,QAAQ,EAAE,MAAM,CAAC,MAAM;oBACvB,IAAI,EAAE,sLAAsL;oBAC5L,UAAU,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC;oBACxD,MAAM;iBACP,EAAE,IAAI,EAAE,CAAC,CAAC;aACZ,CAAC;YACF,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC;gBAAE,MAAM,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,kBAAkB,EAAE,CAAC,CAAC;YAC3H,0GAA0G;YAC1G,IAAI,GAAG,CAAC,SAAS,EAAE,CAAC;gBAClB,SAAS,CAAC,GAAG,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC9C,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC;oBAAE,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,EAAE,GAAG,IAAI,IAAI,CAAC,CAAC;YAC5G,CAAC;YACD,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC;gBACxB,IAAI,EAAE,UAAU;gBAChB,WAAW,EAAE,GAAG,QAAQ,CAAC,MAAM,mCAAmC,MAAM,CAAC,MAAM,WAAW,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,IAAI,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,0BAA0B;aAC/N,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CAAC,MAAyB,OAAO,CAAC,GAAG;IACxE,MAAM,SAAS,GAAG,GAAG,CAAC,yBAAyB,EAAE,IAAI,EAAE,IAAI,SAAS,CAAC;IACrE,IAAI,CAAC,GAAG,CAAC,qBAAqB,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,MAAM,EAAE,CAAC;QACxD,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,kJAAkJ,EAAE,CAAC;IACpL,CAAC;IACD,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;AACxE,CAAC;AAED,SAAS,qBAAqB,CAAC,KAA0B,EAAE,QAA4B,EAAE,UAA0B;IACjH,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAE,OAAoC,CAAC,UAAU,CAAC;QAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,IAAI,mBAAmB,CAAC,CAAC;IAClI,IAAI,KAAK,CAAC,QAAQ,KAAK,OAAO,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,IAAI,cAAc,CAAC,CAAC;IACpG,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,IAAI,kBAAkB,GAAG,KAAK,CAAC;IAC/B,MAAM,KAAK,GAAG,CAAC,KAAc,EAAE,EAAE;QAC/B,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,OAAO;QAChD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YAAC,OAAO;QAAC,CAAC;QAC3D,MAAM,IAAI,GAAG,KAAgC,CAAC;QAC9C,MAAM,KAAK,GAAI,EAAgB,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACxE,IAAI,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,QAAQ,EAAE,CAAC;YACpC,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,UAAU;gBAAE,kBAAkB,GAAG,IAAI,CAAC;YAC1D,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;gBAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;QAC9C,CAAC;QACD,IAAI,UAAU,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,UAAU,EAAE,CAAC;YAC/F,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,IAAI,uBAAuB,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,SAAS,CAAC,cAAc,UAAU,GAAG,CAAC,CAAC;QACjH,CAAC;QACD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACrC,CAAC,CAAC;IACF,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACxB,MAAM,SAAS,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,KAAK,CAAC,CAAC;IACrE,IAAI,SAAS;QAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,IAAI,0BAA0B,SAAS,EAAE,CAAC,CAAC;IACjF,IAAI,UAAU,IAAI,KAAK,CAAC,QAAQ,KAAK,OAAO,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,kBAAkB;QAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,IAAI,gCAAgC,UAAU,EAAE,CAAC,CAAC;IACrK,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,YAAY,CAAC,IAAY;IAChC,OAAO,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,oCAAoC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC;AACvG,CAAC;AAED,SAAS,YAAY,CAAC,IAAY,EAAE,IAAY,EAAE,MAAc;IAC9D,IAAI,kCAAkC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IACvF,IAAI,GAAQ,CAAC;IACb,IAAI,CAAC;QAAC,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC;QAAC,OAAO,IAAI,CAAC;IAAC,CAAC;IACzD,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,IAAI,CAAC,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC;QAAE,OAAO,IAAI,CAAC;IAC7F,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC;QAAE,OAAO,IAAI,CAAC;IACzH,OAAO,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AACrC,CAAC;AAED,SAAS,aAAa,CAAC,IAAY;IACjC,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC;IAC9C,OAAO,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;AAClE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAC,WAAmB;IACvD,OAAO,mCAAmC,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC;AACtE,CAAC;AAED,SAAS,SAAS,CAAC,KAAa;IAC9B,OAAO,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;AACjI,CAAC;AAED,SAAS,YAAY,CAAC,KAAa;IACjC,OAAO,KAAK,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;AACtD,CAAC;AAED,KAAK,UAAU,mBAAmB,CAAI,KAAmB,EAAE,KAAa,EAAE,IAAgC;IACxG,MAAM,KAAK,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC;IACzB,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,KAAK,IAAI,EAAE;QAC9F,KAAK,IAAI,IAAI,GAAG,KAAK,CAAC,KAAK,EAAE,EAAE,IAAI,KAAK,SAAS,EAAE,IAAI,GAAG,KAAK,CAAC,KAAK,EAAE;YAAE,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5F,CAAC,CAAC,CAAC,CAAC;AACN,CAAC","sourcesContent":["/**\n * The shared technical-estate journey for a Brandlab production build:\n *\n * // tests/e2e/estate.spec.ts\n * import { defineBrandlabEstateTests } from '@brandlab-digital/conformance/estate'\n * import { site } from '../../src/config/site'\n * import { routes } from '../../src/data/routes'\n * import { redirects } from '../../src/data/redirects'\n *\n * defineBrandlabEstateTests({ site, routes, redirects })\n *\n * It asserts the estate and its routes: the sitemap, each route's status,\n * canonical, indexing and breadcrumb JSON-LD (every item but the last names its\n * page, from 3.3.3), internal links, redirects, unknown slugs, the page families\n * rendered on request and robots.txt. Page and structured-data\n * quality is reported, never enforced,\n * by defineBrandlabPageQualityTests: a backend release keeps production's pages\n * as they are, which the comparison harness proves. Counts are always derived\n * from the current catalogue, never a historic constant.\n *\n * From 3.4.0 (the Brandlab on-page and location standard) the estate journey\n * also fails on: a sitemap that is not split by page family once the catalogue\n * spans families, or whose lastmod is not the route's content date; an\n * indexable page without a title, meta description or JSON-LD in its server HTML; FAQPage or\n * HowTo markup, or a rating on the business itself; a homepage without a\n * WebSite node (name and url); an unknown slug that does not answer 404 to GET\n * and HEAD; a nearby list on a location page that is not ranked by distance\n * between suburb centres; and a catalogue that adds indexable location pages\n * beyond the recorded capacity (`locationCapacity`). From 3.6.0 it also fails\n * on a service-area map (`<figure data-area-map>`) without a caption carrying\n * the CC BY boundary credit, with a link that is a tab stop or does not go to an\n * indexable catalogue page, with more than `areaMapMaxBytes` inline, or whose\n * base-layer file does not answer as SVG with the groups it uses. The page-quality journey\n * reports title, heading, description and HTML-size warnings, orphan pages,\n * links from indexable pages to noindex location pages, centerpiece\n * similarity (warn at 0.5, review list at 0.7) and the location review list\n * (location-review.json); pages on that list stay indexed.\n *\n * From 3.13.0 (client CI v2) a draft pull request sets BRANDLAB_ESTATE_SCOPE=sample:\n * the catalogue and redirect journeys check the hubs, the first and last route of\n * each kind, the routes changed files feed and a fixed-seed sample (estate-sample.ts),\n * and say so in an `estate-scope` annotation. Every other run crawls the full estate.\n * BRANDLAB_PAGE_QUALITY=skip skips the advisory crawl, which CI v2 runs on its own.\n */\nimport { mkdirSync, writeFileSync } from 'node:fs';\nimport { request as httpRequest } from 'node:http';\nimport { join } from 'node:path';\nimport { expect, test, type APIRequestContext } from '@playwright/test';\nimport {\n areaMapProblems,\n buildLocationReviewList,\n centerpieceSimilarity,\n checkLocationCapacity,\n descriptionLengthProblem,\n HTML_MAX_BYTES,\n headingTexts,\n loadBrandlabGeography,\n neighbourOrderProblems,\n parseSitemapEntries,\n SIMILARITY_REVIEW,\n SIMILARITY_WARN,\n sitemapFamilyProblems,\n sitemapLastmodProblems,\n structuredDataProblems,\n textBlocks,\n titleFormatProblems,\n titleHeadingProblems,\n type LocationCapacityRecord,\n type SimilarityPage,\n type SitemapFile,\n type SuburbCentreLookup,\n} from './page-standard.js';\nimport { extractSearchCertificationHtmlSnapshot } from './search-certification.js';\nimport { changedFilesFromEnv, estateScopeFromEnv, sampleBySeed, sampleEstateRoutes, type BrandlabEstateSampleOptions } from './estate-sample.js';\n\nexport {\n changedFilesFromEnv,\n changedFileStem,\n defaultRoutesForFile,\n estateScopeFromEnv,\n sampleBySeed,\n sampleEstateRoutes,\n type BrandlabEstateSample,\n type BrandlabEstateSampleOptions,\n type BrandlabEstateSampleRoute,\n type BrandlabEstateScope,\n} from './estate-sample.js';\n\nexport interface BrandlabEstateRoute {\n path: string;\n canonicalPath?: string;\n indexing: 'index' | 'noindex-follow' | 'noindex-nofollow';\n /** The route kind (a catalogue route has it): sitemap families and location checks read it. */\n kind?: string;\n id?: string;\n /** The catalogue parent: a location page other location pages sit under is a region page. */\n parentId?: string;\n /** The content date the sitemap's lastmod must carry. */\n lastSignificantChange?: string;\n locationDecision?: { indexing?: string; evidence?: readonly string[]; review?: string };\n}\n\nexport interface BrandlabEstateRedirect {\n source: string;\n destination: string;\n status: 301 | 302 | 303 | 307 | 308;\n /** Host-scoped alias rules are proved by the comparison harness host probes. */\n host?: string;\n}\n\n/**\n * A page family the site renders on request outside the catalogue: a dynamic\n * route that prerenders nothing and renders every page of its space (every\n * combination of its values) when it is first requested.\n */\nexport interface BrandlabEstateFamily {\n /** The app route, e.g. `/services/[service]/[location]`. */\n pattern: string;\n /** Every page of the family's space; catalogued pages of the route may be among them. */\n paths: readonly string[];\n /** The indexing its pages outside the catalogue render. */\n indexing: BrandlabEstateRoute['indexing'];\n}\n\nexport interface BrandlabEstateTestOptions {\n site: { canonicalUrl: string | URL };\n /** The route catalogue. A `/404` route is Next's not-found page and must answer 404. */\n routes: readonly BrandlabEstateRoute[];\n /**\n * The redirect table. A source with parameters (`/old/:slug`, `:path*`) is\n * requested with one sample segment per parameter and checked against its\n * destination filled in the same way; a parameter with its own regular\n * expression cannot be sampled and is listed as skipped.\n */\n redirects?: readonly BrandlabEstateRedirect[];\n /** Paths that must answer 404; defaults to one unknown slug under every catalogue parent. */\n notFoundPaths?: readonly string[];\n /** Also prove `<source>/` redirects straight to the destination (the shared helper emits these). */\n trailingSlashRedirects?: boolean;\n /**\n * Page families rendered on request outside the catalogue. Links into a\n * family's space count as live pages; one page of each family (outside the\n * catalogue where it has one) is checked for its status, canonical and\n * indexing; and a path of its pattern outside the space, one unknown value\n * per dynamic segment, must answer 404 with the site's not-found page rendered\n * on the server: the text an unknown top-level path's 404 page shows.\n */\n families?: readonly BrandlabEstateFamily[];\n /**\n * The site's recorded location capacity (site-core/location-policy). The\n * journey fails only when the catalogue holds more indexable location pages\n * than the capacity and the pages at record allow; without one it notes that\n * none is recorded.\n */\n locationCapacity?: LocationCapacityRecord | null;\n /** The business node's @id (default `<origin>/#business`); `false` when the site has none. */\n businessId?: string | false;\n /** The business facts record: the business node's name and telephone must match it. */\n business?: { name?: string; telephone?: string };\n /** A place's centre for neighbour order (default: the registry's suburb centres). */\n centreOf?: SuburbCentreLookup;\n /**\n * The site's estate plan (site-core `siteStrategy.estate`, 3.14.0): its public slugs map a location page to the\n * registry suburb it names (`ryde-suburb` → `ryde`) and mark region pages (`ryde`), which are not ranked by distance.\n */\n estate?: BrandlabEstateSlugPlan | null;\n /** The most inline markup one service-area map may carry (default 60 000 bytes, 3.6.0). */\n areaMapMaxBytes?: number;\n /**\n * The sampled crawl a draft pull request runs (`BRANDLAB_ESTATE_SCOPE=sample`, 3.13.0): how many routes and\n * redirects the fixed seed adds, the seed, and which routes a changed file feeds.\n */\n sample?: BrandlabEstateSampleOptions;\n concurrency?: number;\n timeout?: number;\n}\n\nexport interface BrandlabPageQualityTestOptions {\n site: { canonicalUrl: string | URL };\n routes: readonly BrandlabEstateRoute[];\n /** The @id every indexable page's graph references; defaults to `<origin>/#business`, `false` skips it. */\n businessId?: string | false;\n /** A place's centre for similarity siblings (default: the registry's suburb centres). */\n centreOf?: SuburbCentreLookup;\n /** The site's estate plan, as for the estate journey: public slugs resolve to the places they name. */\n estate?: BrandlabEstateSlugPlan | null;\n concurrency?: number;\n timeout?: number;\n}\n\nexport interface BrandlabPageQualityFinding {\n path: string;\n kind:\n | 'headings'\n | 'title'\n | 'title-format'\n | 'title-duplicate'\n | 'title-h1'\n | 'description'\n | 'description-length'\n | 'description-duplicate'\n | 'html-size'\n | 'similarity'\n | 'location-review'\n | 'orphan'\n | 'noindex-link'\n | 'og-url'\n | 'implementation-wording'\n | 'structured-data';\n detail: string;\n}\n\nconst LOCATION_KINDS = new Set(['location', 'service-location']);\n\n/** The public-slug part of site-core's SiteEstatePlan (mirrored: conformance compiles without site-core). */\nexport interface BrandlabEstateSlugPlan {\n slugs?: {\n /** Registry region slug → public slug, for example `{ 'ryde-area': 'ryde' }`. */\n regions?: Readonly<Record<string, string>>;\n /** Registry suburb slug → public slug, for example `{ ryde: 'ryde-suburb' }`. */\n suburbs?: Readonly<Record<string, string>>;\n };\n}\n\n/**\n * A location route's place: the registry suburb slug its last path segment names (through the estate plan's public\n * slugs, as site-core's `estatePublicSlug`), and whether it is a region page. A region page has no centre, so its\n * nearby lists are not ranked by distance: it is a region when other location pages sit under it, when its slug is a\n * region's public slug, or when its slug is a suburb's registry slug that the plan moved elsewhere (AA: `ryde`).\n */\nexport function estatePlaceResolver(\n routes: readonly BrandlabEstateRoute[],\n estate?: BrandlabEstateSlugPlan | null,\n): (route: BrandlabEstateRoute | undefined) => { slug: string; region: boolean } | undefined {\n const parents = new Set(routes.filter((route) => LOCATION_KINDS.has(route.kind ?? '')).map((route) => route.parentId));\n const regionSlugs = new Set(Object.values(estate?.slugs?.regions ?? {}));\n const suburbRenames = estate?.slugs?.suburbs ?? {};\n const suburbByPublic = new Map(Object.entries(suburbRenames).map(([registry, publicSlug]) => [publicSlug, registry]));\n return (route) => {\n if (!route || !LOCATION_KINDS.has(route.kind ?? '')) return undefined;\n const publicSlug = normalisePath(route.path).split('/').filter(Boolean).at(-1);\n if (!publicSlug) return undefined;\n const suburb = suburbByPublic.get(publicSlug);\n const region =\n (route.id !== undefined && parents.has(route.id)) ||\n regionSlugs.has(publicSlug) ||\n (suburb === undefined && Object.hasOwn(suburbRenames, publicSlug));\n return { slug: suburb ?? publicSlug, region };\n };\n}\n\n\nconst BUSINESS_TYPES = new Set([\n 'LocalBusiness', 'HomeAndConstructionBusiness', 'GeneralContractor', 'Plumber', 'Electrician',\n 'RoofingContractor', 'HousePainter', 'Locksmith', 'MovingCompany', 'HVACBusiness', 'ProfessionalService',\n]);\nconst UNKNOWN_SLUG = 'brandlab-estate-unknown-page';\nconst NOT_FOUND_ROUTE = '/404';\nconst PATTERN_SAMPLE = 'brandlab-estate-sample';\nconst ASSET_PATH = /\\.[a-z0-9]{2,5}$/i;\n\nexport function defineBrandlabEstateTests(options: BrandlabEstateTestOptions) {\n const origin = new URL(String(options.site.canonicalUrl)).origin;\n const canonical = (path: string) => new URL(path, `${origin}/`).href;\n const routes = options.routes;\n const knownPaths = new Set(routes.map((route) => normalisePath(route.path)));\n const redirects = (options.redirects ?? []).filter((rule) => !rule.host);\n const redirectBySource = new Map(\n redirects.filter((rule) => !isRedirectPattern(rule.source)).map((rule) => [normalisePath(rule.source), rule]),\n );\n const patternRedirects = redirects.flatMap((rule) => {\n const matcher = isRedirectPattern(rule.source) ? redirectSourceMatcher(rule.source) : undefined;\n return matcher ? [{ rule, matcher }] : [];\n });\n const findRedirect = (path: string) =>\n redirectBySource.get(path) ?? patternRedirects.find(({ matcher }) => matcher.test(path))?.rule;\n const timeout = options.timeout ?? 240_000;\n const families = options.families ?? [];\n const familyPaths = new Set(families.flatMap((family) => family.paths.map(normalisePath)));\n const routeByPath = new Map(routes.map((route) => [normalisePath(route.path), route]));\n const placeOfRoute = estatePlaceResolver(routes, options.estate);\n const homePath = normalisePath(routes.find((route) => route.kind === 'home')?.path ?? '/');\n // A draft pull request crawls a sample (BRANDLAB_ESTATE_SCOPE=sample); ready for review crawls every route.\n const scope = estateScopeFromEnv();\n const sample = sampleEstateRoutes(routes, { scope: scope.scope, changedFiles: changedFilesFromEnv(), ...options.sample });\n const scopeNote = [sample.summary, scope.note].filter(Boolean).join('; ');\n const crawledRedirects = scope.scope === 'sample' ? sampleBySeed(redirects, (rule) => rule.source, options.sample) : redirects;\n\n test.describe('Brandlab technical estate', () => {\n test('the sitemap lists exactly the indexable catalogue routes', async ({ request }) => {\n test.setTimeout(timeout);\n const listed = await readSitemap(request, '/sitemap.xml', origin);\n const expected = routes\n .filter((route) => route.indexing === 'index')\n .map((route) => canonical(route.canonicalPath ?? route.path));\n expect(listed.length, 'the sitemap repeats a URL').toBe(new Set(listed).size);\n expect([...listed].sort()).toEqual([...new Set(expected)].sort());\n });\n\n test('the sitemap is split by page family and dated by content, never by the build', async ({ request }, testInfo) => {\n test.setTimeout(timeout);\n const { index, files } = await readSitemapFiles(request, '/sitemap.xml', origin);\n const problems = [\n ...sitemapFamilyProblems({ index, files, routes, origin }),\n ...sitemapLastmodProblems(files.flatMap((file) => file.entries), routes, origin),\n ];\n await testInfo.attach('sitemap-files.json', {\n body: JSON.stringify(files.map((file) => ({ path: file.path, urls: file.entries.length })), null, 2),\n contentType: 'application/json',\n });\n expect(problems).toEqual([]);\n });\n\n test('location pages stay within the recorded capacity', async ({}, testInfo) => {\n const result = checkLocationCapacity(routes, options.locationCapacity);\n testInfo.annotations.push({ type: result.limit === null ? 'warning' : 'location-capacity', description: result.detail });\n expect(result.blocked, result.detail).toBe(false);\n });\n\n test('every catalogue route serves its canonical identity and links only to live pages', async ({ request }, testInfo) => {\n test.setTimeout(timeout);\n const centreOf = options.centreOf ?? (await loadBrandlabGeography()).centreOf;\n const failures: string[] = [];\n const internalLinks = new Map<string, string>();\n const checked: { path: string; canonical: string | null; jsonLd: number }[] = [];\n const areaMapLayers = new Map<string, { ids: Set<string>; from: string }>();\n testInfo.annotations.push({ type: 'estate-scope', description: scopeNote });\n await eachWithConcurrency(sample.routes, options.concurrency ?? 8, async (route) => {\n const [get, head] = await Promise.all([\n request.get(route.path, { maxRedirects: 0 }),\n request.head(route.path, { maxRedirects: 0 }),\n ]);\n // Next serves its not-found page at /404 with a 404 status.\n const notFound = normalisePath(route.path) === NOT_FOUND_ROUTE;\n const expectedStatus = notFound ? 404 : 200;\n if (get.status() !== expectedStatus || head.status() !== expectedStatus) {\n failures.push(`${route.path}: GET ${get.status()}, HEAD ${head.status()} (expected ${expectedStatus})`);\n return;\n }\n const html = await get.text();\n const snapshot = extractSearchCertificationHtmlSnapshot(html);\n const robots = `${snapshot.robots ?? ''} ${get.headers()['x-robots-tag'] ?? ''}`;\n if (notFound) {\n if (!/noindex/i.test(robots)) failures.push(`${route.path}: the not-found page is indexable`);\n checked.push({ path: route.path, canonical: snapshot.canonical, jsonLd: snapshot.jsonLd.length });\n return;\n }\n const expectedCanonical = canonical(route.canonicalPath ?? route.path);\n const canonicalTags = html.match(/<link\\b[^>]*\\brel=[\"']canonical[\"'][^>]*>/gi) ?? [];\n if (canonicalTags.length !== 1) failures.push(`${route.path}: ${canonicalTags.length} canonical links`);\n if (!snapshot.canonical || new URL(snapshot.canonical, origin).href !== expectedCanonical) {\n failures.push(`${route.path}: canonical ${snapshot.canonical ?? 'missing'} (expected ${expectedCanonical})`);\n }\n if (route.indexing === 'index' && /noindex/i.test(robots)) failures.push(`${route.path}: indexable route is noindex`);\n if (route.indexing !== 'index' && !/noindex/i.test(robots)) failures.push(`${route.path}: ${route.indexing} route is indexable`);\n for (const problem of breadcrumbListProblems(snapshot.jsonLd)) failures.push(`${route.path}: ${problem}`);\n if (route.indexing === 'index') {\n if (!snapshot.title) failures.push(`${route.path}: no <title> in the server HTML`);\n if (!snapshot.description) failures.push(`${route.path}: no meta description in the server HTML`);\n if (snapshot.jsonLd.length === 0) failures.push(`${route.path}: no JSON-LD in the server HTML`);\n }\n if (snapshot.jsonLd.some((payload) => (payload as { parseError?: boolean }).parseError)) failures.push(`${route.path}: invalid JSON-LD`);\n for (const problem of structuredDataProblems(snapshot.jsonLd, {\n origin,\n home: normalisePath(route.path) === homePath,\n businessId: options.businessId,\n business: options.business,\n })) failures.push(`${route.path}: ${problem}`);\n const place = placeOfRoute(route);\n if (place && !place.region && centreOf(place.slug)) {\n for (const problem of neighbourOrderProblems({\n html,\n origin: place.slug,\n pageUrl: expectedCanonical,\n placeOf: (path) => {\n const linked = placeOfRoute(routeByPath.get(path));\n return linked && !linked.region ? linked.slug : undefined;\n },\n centreOf,\n })) failures.push(`${route.path}: ${problem}`);\n }\n const maps = areaMapProblems({\n html,\n pageUrl: expectedCanonical,\n isIndexable: (path) => routeByPath.get(path)?.indexing === 'index',\n maxBytes: options.areaMapMaxBytes,\n });\n for (const problem of maps.problems) failures.push(`${route.path}: ${problem}`);\n for (const [path, ids] of maps.baseLayers) {\n const entry = areaMapLayers.get(path) ?? { ids: new Set<string>(), from: route.path };\n for (const id of ids) entry.ids.add(id);\n areaMapLayers.set(path, entry);\n }\n for (const href of extractLinks(html)) {\n const path = internalPath(href, expectedCanonical, origin);\n if (path && !internalLinks.has(path)) internalLinks.set(path, route.path);\n }\n checked.push({ path: route.path, canonical: snapshot.canonical, jsonLd: snapshot.jsonLd.length });\n });\n // Each service-area map's base layer is a cached SVG file holding the groups the page draws.\n for (const [path, { ids, from }] of [...areaMapLayers].sort(([a], [b]) => a.localeCompare(b))) {\n const response = await request.get(path, { maxRedirects: 0 });\n const type = response.headers()['content-type'] ?? '';\n if (response.status() !== 200 || !type.includes('image/svg+xml')) {\n failures.push(`${from}: the map's base layer ${path} answers ${response.status()} ${type || 'without a content type'}`);\n continue;\n }\n const svg = await response.text();\n for (const id of ids) if (!svg.includes(`id=\"${id}\"`)) failures.push(`${from}: the map's base layer ${path} has no group #${id}`);\n }\n for (const [path, from] of [...internalLinks].sort()) {\n if (knownPaths.has(path) || familyPaths.has(path)) continue;\n const redirect = findRedirect(path);\n if (redirect && isExternalDestination(redirect.destination)) continue;\n failures.push(redirect\n ? `${from}: links to ${path}, which redirects; link to ${redirect.destination} directly`\n : `${from}: links to ${path}, which is not a catalogue route`);\n }\n await testInfo.attach('technical-estate.json', {\n body: JSON.stringify({ routes: checked.sort((a, b) => a.path.localeCompare(b.path)), internalLinks: [...internalLinks.keys()].sort() }, null, 2),\n contentType: 'application/json',\n });\n expect(failures).toEqual([]);\n });\n\n test('every redirect resolves in one hop and keeps the query string', async ({ request }, testInfo) => {\n test.setTimeout(timeout);\n const failures: string[] = [];\n const skipped: string[] = [];\n if (scope.scope === 'sample') {\n testInfo.annotations.push({ type: 'estate-scope', description: `sample: ${crawledRedirects.length} of ${redirects.length} redirects (fixed seed); every redirect is checked when the pull request is ready for review` });\n }\n for (const rule of crawledRedirects) {\n const probe = redirectProbe(rule);\n if (!probe) {\n skipped.push(`${rule.source} → ${rule.destination}`);\n continue;\n }\n const sources = [probe.source, ...(options.trailingSlashRedirects === false || probe.source === '/' || probe.source.endsWith('/') ? [] : [`${probe.source}/`])];\n for (const source of sources) {\n for (const method of ['GET', 'HEAD'] as const) {\n const response = await request.fetch(`${source}?brandlab_estate=1`, { method, maxRedirects: 0 });\n const location = response.headers().location;\n const expectedStatus: number[] = source === probe.source ? [rule.status] : [301, 308];\n if (!expectedStatus.includes(response.status()) || !location) {\n failures.push(`${method} ${source}: ${response.status()} (expected ${expectedStatus.join(' or ')} to ${probe.destination})`);\n continue;\n }\n const target = new URL(location, origin);\n if (isExternalDestination(probe.destination)) {\n if (!target.href.startsWith(new URL(probe.destination, origin).href.replace(/\\/$/, ''))) failures.push(`${method} ${source}: Location ${location} (expected ${probe.destination})`);\n continue;\n }\n if (target.pathname !== new URL(probe.destination, origin).pathname) failures.push(`${method} ${source}: Location ${location} (expected ${probe.destination})`);\n if (target.searchParams.get('brandlab_estate') !== '1') failures.push(`${method} ${source}: the query string was dropped`);\n }\n }\n // A destination with parameters names many pages; the sample fills it with a page that does not exist.\n if (!isExternalDestination(probe.destination) && !probe.sampled) {\n const destination = await request.get(probe.destination, { maxRedirects: 0 });\n if (destination.status() !== 200) failures.push(`${rule.source}: destination ${probe.destination} answers ${destination.status()} (a chain or a missing page)`);\n }\n }\n if (skipped.length > 0) {\n testInfo.annotations.push({ type: 'skipped-redirects', description: `${skipped.length} redirect(s) with a parameter pattern that cannot be sampled: ${skipped.join('; ')}` });\n }\n expect(failures).toEqual([]);\n });\n\n if (families.length > 0) {\n test('every page family rendered on request serves its pages and answers 404 outside its space', async ({ request }) => {\n test.setTimeout(timeout);\n const failures: string[] = [];\n const reference = await request.get(`/${UNKNOWN_SLUG}`, { maxRedirects: 0 });\n const notFoundText = reference.status() === 404 ? bodyText(await reference.text()) : '';\n if (!notFoundText) failures.push(`/${UNKNOWN_SLUG}: ${reference.status()} with no server-rendered not-found page to compare with`);\n for (const family of families) {\n const sample = familySamplePath(family, knownPaths);\n if (!sample) {\n failures.push(`${family.pattern}: the family lists no page`);\n continue;\n }\n const response = await request.get(sample, { maxRedirects: 0 });\n if (response.status() !== 200) {\n failures.push(`${sample}: ${response.status()} (expected 200 for a page of ${family.pattern})`);\n } else {\n const html = await response.text();\n const snapshot = extractSearchCertificationHtmlSnapshot(html);\n const robots = `${snapshot.robots ?? ''} ${response.headers()['x-robots-tag'] ?? ''}`;\n const expectedCanonical = canonical(sample);\n if (!snapshot.canonical || new URL(snapshot.canonical, origin).href !== expectedCanonical) {\n failures.push(`${sample}: canonical ${snapshot.canonical ?? 'missing'} (expected ${expectedCanonical})`);\n }\n if (family.indexing === 'index' && /noindex/i.test(robots)) failures.push(`${sample}: the family's pages are indexable, this one is noindex`);\n if (family.indexing !== 'index' && !/noindex/i.test(robots)) failures.push(`${sample}: the family's pages are ${family.indexing}, this one is indexable`);\n }\n for (const outside of familyNotFoundPaths(family)) {\n const miss = await request.get(outside, { maxRedirects: 0 });\n if (miss.status() !== 404) {\n failures.push(`${outside}: ${miss.status()} (expected 404 outside ${family.pattern}'s space)`);\n continue;\n }\n const text = bodyText(await miss.text());\n if (notFoundText && text !== notFoundText) {\n failures.push(`${outside}: the 404 is not the site's not-found page rendered on the server (${text ? `it shows \"${text.slice(0, 80)}\"` : 'its body is empty until the browser renders it'})`);\n }\n }\n }\n expect(failures).toEqual([]);\n });\n }\n\n test('unknown slugs answer 404 instead of inventing pages', async ({ request }, testInfo) => {\n // A default probe a redirect rule covers (a wildcard such as /blog/:slug) is the redirect's to answer; the\n // redirect journey proves it. Paths the site lists itself are always probed.\n const { probes: paths, redirected } = options.notFoundPaths\n ? { probes: options.notFoundPaths, redirected: [] }\n : unknownSlugProbes(defaultNotFoundPaths(routes), (path) => Boolean(findRedirect(path)));\n for (const path of redirected) testInfo.annotations.push({ type: 'skipped', description: `${path}: a redirect rule answers it` });\n const failures: string[] = [];\n for (const path of paths) {\n const [get, head] = await Promise.all([\n request.get(path, { maxRedirects: 0 }),\n request.head(path, { maxRedirects: 0 }),\n ]);\n if (get.status() !== 404) failures.push(`${path}: GET ${get.status()} (expected 404)`);\n if (head.status() !== 404) failures.push(`${path}: HEAD ${head.status()} (expected 404)`);\n }\n expect(failures).toEqual([]);\n });\n\n test('robots.txt allows crawling and names the sitemap', async ({ request }) => {\n const response = await request.get('/robots.txt');\n expect(response.status()).toBe(200);\n const body = await response.text();\n expect(body).toMatch(new RegExp(`^sitemap:\\\\s*${escapeRegExp(`${origin}/sitemap.xml`)}\\\\s*$`, 'im'));\n expect(body).not.toMatch(/^disallow:\\s*\\/\\s*$/im);\n });\n\n test('a production deployment tells crawlers not to index any host but its canonical one', async ({ baseURL }) => {\n test.skip(process.env.VERCEL_ENV !== 'production', 'Only a production build (VERCEL_ENV=production, as CI builds it) answers other hosts with noindex.');\n const server = new URL(baseURL ?? 'http://127.0.0.1:3100/');\n const canonicalHost = new URL(origin).hostname;\n // The production *.vercel.app alias serves the full site; its pages must not be indexed.\n const alias = `${canonicalHost.split('.')[0]}-brandlab-e2e.vercel.app`;\n expect(await responseHeader(server, alias, '/', 'x-robots-tag'), `${alias}: X-Robots-Tag`).toBe('noindex');\n expect(await responseHeader(server, canonicalHost, '/', 'x-robots-tag'), `${canonicalHost}: X-Robots-Tag`).not.toMatch(/noindex/);\n });\n });\n}\n\n/**\n * Why a page's BreadcrumbList JSON-LD would fail Google's breadcrumb rich result (3.3.3): every\n * ListItem but the last needs its `item` (the page it names), as the shared builder requires;\n * Google reports \"Missing field item\" otherwise. Lists inside an `@graph` count; an empty list\n * has nothing to judge.\n */\nexport function breadcrumbListProblems(jsonLd: readonly unknown[]): string[] {\n const lists: Record<string, unknown>[] = [];\n const collect = (value: unknown) => {\n if (Array.isArray(value)) {\n value.forEach(collect);\n return;\n }\n if (!value || typeof value !== 'object') return;\n const node = value as Record<string, unknown>;\n const type = node['@type'];\n if (type === 'BreadcrumbList' || (Array.isArray(type) && type.includes('BreadcrumbList'))) lists.push(node);\n if (Array.isArray(node['@graph'])) collect(node['@graph']);\n };\n collect(jsonLd);\n const problems: string[] = [];\n for (const list of lists) {\n const items = Array.isArray(list.itemListElement) ? list.itemListElement : [];\n items.slice(0, -1).forEach((entry, index) => {\n const item = entry && typeof entry === 'object' ? (entry as Record<string, unknown>).item : undefined;\n const named = typeof item === 'string' ? item.trim() : item && typeof item === 'object' ? String((item as Record<string, unknown>)['@id'] ?? (item as Record<string, unknown>).url ?? '').trim() : '';\n if (named) return;\n const name = entry && typeof entry === 'object' ? (entry as Record<string, unknown>).name : undefined;\n problems.push(`BreadcrumbList item ${index + 1}${typeof name === 'string' && name.trim() ? ` (\"${name.trim()}\")` : ''} has no URL (item); only the last breadcrumb may omit it, or Google rejects the list`);\n });\n }\n return problems;\n}\n\n/** One response header for a request that names its own Host (the Playwright request context always sends the server's). */\nexport function responseHeader(server: URL, host: string, path: string, name: string): Promise<string | undefined> {\n return new Promise((resolve, reject) => {\n const request = httpRequest({ hostname: server.hostname, port: server.port || 80, path, method: 'GET', headers: { host, 'x-forwarded-proto': 'https' } }, (response) => {\n response.resume();\n const value = response.headers[name.toLowerCase()];\n resolve(Array.isArray(value) ? value.join(', ') : value);\n });\n request.on('error', reject);\n request.end();\n });\n}\n\n/**\n * Every `<loc>` in a sitemap, following one level of sitemap index. Nothing is\n * followed through a redirect, and with `origin` every nested sitemap must be\n * on that origin (it is then fetched from the build under test).\n */\nexport async function readSitemap(request: APIRequestContext, path: string, origin?: string): Promise<string[]> {\n const read = async (target: string) => {\n const response = await request.get(target, { maxRedirects: 0 });\n if (response.status() !== 200) throw new Error(`${target} answers ${response.status()}; a sitemap must answer 200 without redirecting.`);\n return response.text();\n };\n const xml = await read(path);\n const locations = extractSitemapLocations(xml);\n if (!/<sitemapindex\\b/i.test(xml)) return locations;\n const nested: string[] = [];\n for (const location of locations) {\n const url = new URL(location);\n if (origin && url.origin !== new URL(origin).origin) {\n throw new Error(`The sitemap index lists ${location}, which is not on ${new URL(origin).origin}.`);\n }\n nested.push(...extractSitemapLocations(await read(`${url.pathname}${url.search}`)));\n }\n return nested;\n}\n\n/**\n * The sitemap's URL files with their entries: the sitemap itself, or every\n * file a sitemap index lists (one level, same origin, no redirects).\n */\nexport async function readSitemapFiles(\n request: APIRequestContext,\n path: string,\n origin: string,\n): Promise<{ index: boolean; files: SitemapFile[] }> {\n const read = async (target: string) => {\n const response = await request.get(target, { maxRedirects: 0 });\n if (response.status() !== 200) throw new Error(`${target} answers ${response.status()}; a sitemap must answer 200 without redirecting.`);\n return response.text();\n };\n const xml = await read(path);\n if (!/<sitemapindex\\b/i.test(xml)) return { index: false, files: [{ path, entries: parseSitemapEntries(xml) }] };\n const files: SitemapFile[] = [];\n for (const location of extractSitemapLocations(xml)) {\n const url = new URL(location);\n if (url.origin !== new URL(origin).origin) throw new Error(`The sitemap index lists ${location}, which is not on ${new URL(origin).origin}.`);\n files.push({ path: url.pathname, entries: parseSitemapEntries(await read(`${url.pathname}${url.search}`)) });\n }\n return { index: true, files };\n}\n\nexport function extractSitemapLocations(xml: string): string[] {\n return [...xml.matchAll(/<loc>\\s*([^<\\s]+)\\s*<\\/loc>/gi)].map((match) =>\n new URL(decodeXml(match[1]!)).href);\n}\n\nexport function defaultNotFoundPaths(routes: readonly BrandlabEstateRoute[]): string[] {\n const parents = new Set(['']);\n for (const route of routes) {\n const segments = normalisePath(route.path).split('/').filter(Boolean);\n if (segments.length > 1) parents.add(`/${segments.slice(0, -1).join('/')}`);\n if (segments.length === 1) parents.add(`/${segments[0]}`);\n }\n return [...parents].sort().map((parent) => `${parent}/${UNKNOWN_SLUG}`);\n}\n\n/** The unknown-slug probes to request, apart from those a redirect rule answers. */\nexport function unknownSlugProbes(paths: readonly string[], redirects: (path: string) => boolean): { probes: string[]; redirected: string[] } {\n const probes: string[] = [];\n const redirected: string[] = [];\n for (const path of paths) (redirects(normalisePath(path)) ? redirected : probes).push(path);\n return { probes, redirected };\n}\n\n/** The page of a family its estate check opens: the first one outside the catalogue, else its first page. */\nexport function familySamplePath(family: Pick<BrandlabEstateFamily, 'paths'>, catalogue: ReadonlySet<string>): string | undefined {\n return family.paths.find((path) => !catalogue.has(normalisePath(path))) ?? family.paths[0];\n}\n\n/**\n * Paths of a family's pattern outside its space: a page of the family with one\n * dynamic segment at a time replaced by an unknown slug.\n */\nexport function familyNotFoundPaths(family: Pick<BrandlabEstateFamily, 'pattern' | 'paths'>): string[] {\n const first = family.paths[0];\n if (!first) return [];\n const parts = normalisePath(first).split('/');\n const segments = family.pattern.split('/');\n const paths = segments.flatMap((segment, index) => (/^\\[[^.\\]]/.test(segment) ? [parts.map((part, position) => (position === index ? UNKNOWN_SLUG : part)).join('/')] : []));\n const space = new Set(family.paths.map(normalisePath));\n return [...new Set(paths)].filter((path) => !space.has(path));\n}\n\n/**\n * The text a page shows before any script runs: its body without scripts,\n * styles and templates, tags removed and whitespace collapsed. Empty for the\n * document Next sends when it leaves a page to the browser to render.\n */\nexport function bodyText(html: string): string {\n const body = /<body\\b[^>]*>([\\s\\S]*?)(?:<\\/body>|$)/i.exec(html)?.[1] ?? (/<html\\b/i.test(html) ? '' : html);\n return decodeXml(body\n .replace(/<(script|style|template|noscript)\\b[\\s\\S]*?<\\/\\1>/gi, ' ')\n .replace(/<[^>]+>/g, ' '))\n .replace(/ /g, ' ')\n .replace(/\\s+/g, ' ')\n .trim();\n}\n\n/** A Next redirect path with parameters: `:name`, `:name*`, `:name+`, `:name?` or a regular-expression group. */\nexport function isRedirectPattern(path: string): boolean {\n return /:[A-Za-z_]\\w*|\\(/.test(path.replace(/^[a-z][a-z0-9+.-]*:\\/\\//i, ''));\n}\n\n/**\n * The request that proves a redirect rule: a pattern gets one sample segment\n * per parameter, in its source and destination alike. Undefined when a\n * parameter carries its own regular expression, which no sample can satisfy\n * with certainty.\n */\nexport function redirectProbe(rule: Pick<BrandlabEstateRedirect, 'source' | 'destination'>): { source: string; destination: string; sampled: boolean } | undefined {\n const sample = (path: string) => {\n if (!isRedirectPattern(path)) return path;\n // Keep an external destination's scheme and host; parameters live in the path.\n const origin = /^[a-z][a-z0-9+.-]*:\\/\\/[^/]*/i.exec(path)?.[0] ?? '';\n const rest = path.slice(origin.length);\n if (rest.includes('(')) return undefined;\n return `${origin}${rest.replace(/:[A-Za-z_]\\w*[*+?]?/g, PATTERN_SAMPLE)}`;\n };\n const source = sample(rule.source);\n const destination = sample(rule.destination);\n if (source === undefined || destination === undefined) return undefined;\n return { source, destination, sampled: isRedirectPattern(rule.destination) };\n}\n\n/** A matcher for paths a pattern source redirects, for internal-link checks. */\nfunction redirectSourceMatcher(source: string): RegExp | undefined {\n if (source.includes('(')) return undefined;\n const pattern = normalisePath(source).split(/(:[A-Za-z_]\\w*[*+?]?)/).map((part) => {\n const parameter = /^:[A-Za-z_]\\w*([*+?]?)$/.exec(part);\n if (!parameter) return escapeRegExp(part);\n return parameter[1] === '*' || parameter[1] === '+' ? '.+' : parameter[1] === '?' ? '[^/]*' : '[^/]+';\n }).join('');\n return new RegExp(`^${pattern}$`);\n}\n\n/**\n * The advisory page-quality journey: headings, title, description, og:url,\n * implementation wording and structured-data identity for every catalogue\n * page. It reports what it finds (page-quality.json and an annotation) and\n * never fails, because a backend release keeps production's pages as they\n * are; the comparison harness proves them unchanged.\n *\n * // tests/e2e/page-quality.spec.ts\n * defineBrandlabPageQualityTests({ site, routes })\n */\nexport function defineBrandlabPageQualityTests(options: BrandlabPageQualityTestOptions) {\n const origin = new URL(String(options.site.canonicalUrl)).origin;\n const canonical = (path: string) => new URL(path, `${origin}/`).href;\n const businessId = options.businessId ?? `${origin}/#business`;\n const timeout = options.timeout ?? 240_000;\n const routes = options.routes.filter((route) => normalisePath(route.path) !== NOT_FOUND_ROUTE);\n const routeByPath = new Map(routes.map((route) => [normalisePath(route.path), route]));\n const placeOfRoute = estatePlaceResolver(routes, options.estate);\n const run = pageQualityRunFromEnv();\n\n test.describe('Brandlab page quality (advisory)', () => {\n test('reports page and structured-data quality without failing', async ({ request }, testInfo) => {\n test.skip(!run.run, run.reason);\n test.setTimeout(timeout);\n const findings: BrandlabPageQualityFinding[] = [];\n const geography = await loadBrandlabGeography();\n const centreOf = options.centreOf ?? geography.centreOf;\n const titles = new Map<string, string[]>();\n const descriptions = new Map<string, string[]>();\n const similarityPages: SimilarityPage[] = [];\n const linksFrom = new Map<string, Set<string>>();\n await eachWithConcurrency(routes, options.concurrency ?? 8, async (route) => {\n const response = await request.get(route.path, { maxRedirects: 0 });\n // The estate journey owns status codes; quality is read from the pages that load.\n if (response.status() !== 200) return;\n const html = await response.text();\n const snapshot = extractSearchCertificationHtmlSnapshot(html);\n const add = (kind: BrandlabPageQualityFinding['kind'], detail: string) => findings.push({ path: route.path, kind, detail });\n const h1s = headingTexts(html);\n if (h1s.length !== 1) add('headings', `${h1s.length} h1 headings`);\n if (!snapshot.title) add('title', 'no title');\n if (!snapshot.description) add('description', 'no meta description');\n const indexable = route.indexing === 'index';\n if (indexable && snapshot.title) {\n const formatProblems = titleFormatProblems(snapshot.title);\n if (formatProblems.length > 0) add('title-format', `\"${snapshot.title}\": ${formatProblems.join('; ')}`);\n titles.set(snapshot.title, [...(titles.get(snapshot.title) ?? []), route.path]);\n const place = placeOfRoute(route);\n if (h1s.length === 1) {\n const problems = titleHeadingProblems(snapshot.title, h1s[0]!, place && !place.region ? geography.placeNames.get(place.slug) : undefined);\n if (problems.length > 0) add('title-h1', problems.join('; '));\n }\n }\n if (indexable && snapshot.description) {\n const problem = descriptionLengthProblem(snapshot.description);\n if (problem) add('description-length', problem);\n descriptions.set(snapshot.description, [...(descriptions.get(snapshot.description) ?? []), route.path]);\n }\n const bytes = Buffer.byteLength(html);\n if (bytes > HTML_MAX_BYTES) add('html-size', `${(bytes / 1_048_576).toFixed(2)} MB of HTML (investigate anything over 1 MB)`);\n const expectedCanonical = canonical(route.canonicalPath ?? route.path);\n const ogUrl = snapshot.openGraph['og:url'];\n if (ogUrl && new URL(ogUrl, origin).href !== expectedCanonical) add('og-url', `og:url ${ogUrl} is not the canonical URL`);\n if (snapshot.implementationCopyMatches.length > 0) add('implementation-wording', snapshot.implementationCopyMatches.join(', '));\n for (const failure of inspectStructuredData(route, snapshot.jsonLd, businessId)) {\n add('structured-data', failure.slice(route.path.length + 2));\n }\n const place = placeOfRoute(route)?.slug;\n if (indexable && place) similarityPages.push({ path: route.path, place, blocks: textBlocks(html).map(geography.maskPlaces) });\n const targets = new Set<string>();\n for (const href of extractLinks(html)) {\n const path = internalPath(href, expectedCanonical, origin);\n if (path && path !== normalisePath(route.path)) targets.add(path);\n }\n linksFrom.set(normalisePath(route.path), targets);\n });\n // Internal links: every indexable page needs a link from another page, and indexable pages link no noindex location page.\n const inbound = new Map<string, number>();\n for (const [from, targets] of linksFrom) {\n const source = routeByPath.get(from);\n for (const target of targets) {\n inbound.set(target, (inbound.get(target) ?? 0) + 1);\n const linked = routeByPath.get(target);\n if (source?.indexing === 'index' && linked && linked.indexing !== 'index' && LOCATION_KINDS.has(linked.kind ?? '')) {\n findings.push({ path: from, kind: 'noindex-link', detail: `links to ${target}, a noindex location page (list unindexed places as plain text)` });\n }\n }\n }\n for (const route of routes) {\n const path = normalisePath(route.path);\n if (route.indexing === 'index' && route.kind !== 'home' && path !== '/' && linksFrom.has(path) && !inbound.get(path)) {\n findings.push({ path: route.path, kind: 'orphan', detail: 'no other catalogue page links to it' });\n }\n }\n for (const [title, paths] of titles) {\n if (paths.length > 1) for (const path of paths) findings.push({ path, kind: 'title-duplicate', detail: `\"${title}\" is also the title of ${paths.filter((other) => other !== path).slice(0, 3).join(', ')}${paths.length > 4 ? ' and others' : ''}` });\n }\n for (const [description, paths] of descriptions) {\n if (paths.length > 1) for (const path of paths) findings.push({ path, kind: 'description-duplicate', detail: `the meta description is shared with ${paths.length - 1} other page(s) (\"${description.slice(0, 60)}…\")` });\n }\n // Location pages: centerpiece similarity against near siblings, by route kind.\n const similarity = [...new Set(similarityPages.map((page) => routeByPath.get(normalisePath(page.path))?.kind))]\n .flatMap((kind) => centerpieceSimilarity(similarityPages.filter((page) => routeByPath.get(normalisePath(page.path))?.kind === kind), centreOf));\n for (const score of similarity) {\n if (score.score < SIMILARITY_WARN) continue;\n findings.push({\n path: score.path,\n kind: 'similarity',\n detail: `${score.score.toFixed(2)} of its page-specific phrases also appear on ${score.sibling ?? 'a near sibling'}${score.score >= SIMILARITY_REVIEW ? ' (at or above 0.7: on the review list; the page stays indexed)' : ' (at or above 0.5: add page-specific evidence)'}`,\n });\n }\n const reviewList = buildLocationReviewList(routes);\n const flagged = new Set(similarity.filter((score) => score.score >= SIMILARITY_REVIEW).map((score) => score.path));\n const review = [\n ...reviewList.map((item) => ({ ...item, reasons: [...item.reasons, ...(flagged.has(item.path) ? ['centerpiece similarity at or above 0.7'] : [])] })),\n ...[...flagged].filter((path) => !reviewList.some((item) => item.path === path)).map((path) => ({ path, evidence: routeByPath.get(normalisePath(path))?.locationDecision?.evidence ?? [], reasons: ['centerpiece similarity at or above 0.7'] })),\n ].sort((a, b) => a.path.localeCompare(b.path));\n for (const item of review) findings.push({ path: item.path, kind: 'location-review', detail: item.reasons.join('; ') });\n findings.sort((a, b) => a.path.localeCompare(b.path) || a.kind.localeCompare(b.kind));\n const byKind = Object.fromEntries(\n [...new Set(findings.map((finding) => finding.kind))].sort().map((kind) => [kind, findings.filter((finding) => finding.kind === kind).length]),\n );\n const reports = {\n 'page-quality.json': JSON.stringify({ pages: routes.length, findings: findings.length, byKind, details: findings }, null, 2),\n 'location-review.json': JSON.stringify({\n reviewed: review.length,\n note: 'Pages on the review list stay indexed. Each review ends in adding evidence, merging into the nearest owner or hiding with noindex, follow; merging and hiding are Romie\\'s decision.',\n similarity: similarity.sort((a, b) => b.score - a.score),\n review,\n }, null, 2),\n };\n for (const [name, body] of Object.entries(reports)) await testInfo.attach(name, { body, contentType: 'application/json' });\n // CI's page-quality run keeps the reports beside the ready report (BRANDLAB_PAGE_QUALITY_DIR=docs/ready).\n if (run.directory) {\n mkdirSync(run.directory, { recursive: true });\n for (const [name, body] of Object.entries(reports)) writeFileSync(join(run.directory, name), `${body}\\n`);\n }\n testInfo.annotations.push({\n type: 'advisory',\n description: `${findings.length} page-quality finding(s) across ${routes.length} page(s)${findings.length ? `: ${Object.entries(byKind).map(([kind, count]) => `${kind} ${count}`).join(', ')}` : ''}; see page-quality.json.`,\n });\n });\n });\n}\n\n/**\n * Whether the advisory page-quality crawl runs (3.13.0, client CI v2). CI v2 runs it on its own when a pull request\n * is ready for review, on a manual run and monthly for large estates, and sets `BRANDLAB_PAGE_QUALITY=skip` for the required journeys so\n * drafts and merges do not crawl every page twice. `BRANDLAB_PAGE_QUALITY_DIR` also writes its reports there.\n */\nexport function pageQualityRunFromEnv(env: NodeJS.ProcessEnv = process.env): { run: boolean; reason: string; directory?: string } {\n const directory = env.BRANDLAB_PAGE_QUALITY_DIR?.trim() || undefined;\n if ((env.BRANDLAB_PAGE_QUALITY ?? '').trim() === 'skip') {\n return { run: false, reason: 'The advisory page-quality crawl runs on its own in CI (ready for review, manual runs and monthly for large estates); BRANDLAB_PAGE_QUALITY=skip.' };\n }\n return { run: true, reason: '', ...(directory ? { directory } : {}) };\n}\n\nfunction inspectStructuredData(route: BrandlabEstateRoute, payloads: readonly unknown[], businessId: string | false): string[] {\n const failures: string[] = [];\n if (payloads.some((payload) => (payload as { parseError?: boolean }).parseError)) failures.push(`${route.path}: invalid JSON-LD`);\n if (route.indexing === 'index' && payloads.length === 0) failures.push(`${route.path}: no JSON-LD`);\n const ids: string[] = [];\n let referencesBusiness = false;\n const visit = (value: unknown) => {\n if (!value || typeof value !== 'object') return;\n if (Array.isArray(value)) { value.forEach(visit); return; }\n const node = value as Record<string, unknown>;\n const types = ([] as unknown[]).concat(node['@type'] ?? []).map(String);\n if (typeof node['@id'] === 'string') {\n if (node['@id'] === businessId) referencesBusiness = true;\n if (types.length > 0) ids.push(node['@id']);\n }\n if (businessId && types.some((type) => BUSINESS_TYPES.has(type)) && node['@id'] !== businessId) {\n failures.push(`${route.path}: business node @id ${String(node['@id'] ?? 'missing')} (expected ${businessId})`);\n }\n Object.values(node).forEach(visit);\n };\n payloads.forEach(visit);\n const duplicate = ids.find((id, index) => ids.indexOf(id) !== index);\n if (duplicate) failures.push(`${route.path}: JSON-LD repeats node ${duplicate}`);\n if (businessId && route.indexing === 'index' && payloads.length > 0 && !referencesBusiness) failures.push(`${route.path}: JSON-LD does not reference ${businessId}`);\n return failures;\n}\n\nfunction extractLinks(html: string): string[] {\n return [...html.matchAll(/<a\\b[^>]*\\bhref=[\"']([^\"']+)[\"']/gi)].map((match) => decodeXml(match[1]!));\n}\n\nfunction internalPath(href: string, base: string, origin: string): string | null {\n if (/^(?:mailto|tel|sms|javascript):/i.test(href) || href.startsWith('#')) return null;\n let url: URL;\n try { url = new URL(href, base); } catch { return null; }\n if (url.origin !== origin && !['127.0.0.1', 'localhost'].includes(url.hostname)) return null;\n if (ASSET_PATH.test(url.pathname) || url.pathname.startsWith('/api/') || url.pathname.startsWith('/_next/')) return null;\n return normalisePath(url.pathname);\n}\n\nfunction normalisePath(path: string): string {\n const pathname = path.split(/[?#]/)[0] || '/';\n return pathname.length > 1 ? pathname.replace(/\\/+$/, '') : '/';\n}\n\n/**\n * Absolute (`https://host`) and protocol-relative (`//host`) destinations leave\n * the site; browsers also read `/\\host` and `\\\\host` as protocol-relative.\n */\nexport function isExternalDestination(destination: string): boolean {\n return /^(?:[a-z][a-z0-9+.-]*:)?[\\\\/]{2}/i.test(destination.trim());\n}\n\nfunction decodeXml(value: string): string {\n return value.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '\"').replace(/'/g, \"'\");\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nasync function eachWithConcurrency<T>(items: readonly T[], limit: number, task: (item: T) => Promise<void>) {\n const queue = [...items];\n await Promise.all(Array.from({ length: Math.max(1, Math.min(limit, queue.length)) }, async () => {\n for (let item = queue.shift(); item !== undefined; item = queue.shift()) await task(item);\n }));\n}\n"]}
|
|
1
|
+
{"version":3,"file":"estate.js","sourceRoot":"","sources":["../src/estate.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The shared technical-estate journey for a Brandlab production build:\n *\n * // tests/e2e/estate.spec.ts\n * import { defineBrandlabEstateTests } from '@brandlab-digital/conformance/estate'\n * import { site } from '../../src/config/site'\n * import { routes } from '../../src/data/routes'\n * import { redirects } from '../../src/data/redirects'\n *\n * defineBrandlabEstateTests({ site, routes, redirects })\n *\n * It asserts the estate and its routes: the sitemap, each route's status,\n * canonical, indexing and breadcrumb JSON-LD (every item but the last names its\n * page, from 3.3.3), internal links, redirects, unknown slugs, the page families\n * rendered on request and robots.txt. Page and structured-data\n * quality is reported, never enforced,\n * by defineBrandlabPageQualityTests: a backend release keeps production's pages\n * as they are, which the comparison harness proves. Counts are always derived\n * from the current catalogue, never a historic constant.\n *\n * From 3.4.0 (the Brandlab on-page and location standard) the estate journey\n * also fails on: a sitemap that is not split by page family once the catalogue\n * spans families, or whose lastmod is not the route's content date; an\n * indexable page without a title, meta description or JSON-LD in its server HTML; FAQPage or\n * HowTo markup, or a rating on the business itself; a homepage without a\n * WebSite node (name and url); an unknown slug that does not answer 404 to GET\n * and HEAD; a nearby list on a location page that is not ranked by distance\n * between suburb centres; and a catalogue that adds indexable location pages\n * beyond the recorded capacity (`locationCapacity`). From 3.6.0 it also fails\n * on a service-area map (`<figure data-area-map>`) without a caption carrying\n * the CC BY boundary credit, with a link that is a tab stop or does not go to an\n * indexable catalogue page, with more than `areaMapMaxBytes` inline, or whose\n * base-layer file does not answer as SVG with the groups it uses. The page-quality journey\n * reports title, heading, description and HTML-size warnings, orphan pages,\n * links from indexable pages to noindex location pages, centerpiece\n * similarity (warn at 0.5, review list at 0.7) and the location review list\n * (location-review.json); pages on that list stay indexed.\n *\n * From 3.13.0 (client CI v2) a draft pull request sets BRANDLAB_ESTATE_SCOPE=sample:\n * the catalogue and redirect journeys check the hubs, the first and last route of\n * each kind, the routes changed files feed and a fixed-seed sample (estate-sample.ts),\n * and say so in an `estate-scope` annotation. Every other run crawls the full estate.\n * BRANDLAB_PAGE_QUALITY=skip skips the advisory crawl, which CI v2 runs on its own.\n */\nimport { mkdirSync, writeFileSync } from 'node:fs';\nimport { request as httpRequest } from 'node:http';\nimport { join } from 'node:path';\nimport { expect, test, type APIRequestContext } from '@playwright/test';\nimport {\n areaMapProblems,\n buildLocationReviewList,\n centerpieceSimilarity,\n checkLocationCapacity,\n descriptionLengthProblem,\n HTML_MAX_BYTES,\n headingTexts,\n loadBrandlabGeography,\n neighbourOrderProblems,\n parseSitemapEntries,\n SIMILARITY_REVIEW,\n SIMILARITY_WARN,\n sitemapFamilyProblems,\n sitemapLastmodProblems,\n structuredDataProblems,\n textBlocks,\n titleFormatProblems,\n titleHeadingProblems,\n type LocationCapacityRecord,\n type SimilarityPage,\n type SitemapFile,\n type SuburbCentreLookup,\n} from './page-standard.js';\nimport { extractSearchCertificationHtmlSnapshot } from './search-certification.js';\nimport { changedFilesFromEnv, estateScopeFromEnv, sampleBySeed, sampleEstateRoutes, type BrandlabEstateSampleOptions } from './estate-sample.js';\n\nexport {\n changedFilesFromEnv,\n changedFileStem,\n defaultRoutesForFile,\n estateScopeFromEnv,\n sampleBySeed,\n sampleEstateRoutes,\n type BrandlabEstateSample,\n type BrandlabEstateSampleOptions,\n type BrandlabEstateSampleRoute,\n type BrandlabEstateScope,\n} from './estate-sample.js';\n\nexport interface BrandlabEstateRoute {\n path: string;\n canonicalPath?: string;\n indexing: 'index' | 'noindex-follow' | 'noindex-nofollow';\n /** The route kind (a catalogue route has it): sitemap families and location checks read it. */\n kind?: string;\n id?: string;\n /** The catalogue parent: a location page other location pages sit under is a region page. */\n parentId?: string;\n /** The content date the sitemap's lastmod must carry. */\n lastSignificantChange?: string;\n locationDecision?: { indexing?: string; evidence?: readonly string[]; review?: string };\n}\n\nexport interface BrandlabEstateRedirect {\n source: string;\n destination: string;\n status: 301 | 302 | 303 | 307 | 308;\n /** Host-scoped alias rules are proved by the comparison harness host probes. */\n host?: string;\n}\n\n/**\n * A page family the site renders on request outside the catalogue: a dynamic\n * route that prerenders nothing and renders every page of its space (every\n * combination of its values) when it is first requested.\n */\nexport interface BrandlabEstateFamily {\n /** The app route, e.g. `/services/[service]/[location]`. */\n pattern: string;\n /** Every page of the family's space; catalogued pages of the route may be among them. */\n paths: readonly string[];\n /** The indexing its pages outside the catalogue render. */\n indexing: BrandlabEstateRoute['indexing'];\n}\n\nexport interface BrandlabEstateTestOptions {\n site: { canonicalUrl: string | URL };\n /** The route catalogue. A `/404` route is Next's not-found page and must answer 404. */\n routes: readonly BrandlabEstateRoute[];\n /**\n * The redirect table. A source with parameters (`/old/:slug`, `:path*`) is\n * requested with one sample segment per parameter and checked against its\n * destination filled in the same way; a parameter with its own regular\n * expression cannot be sampled and is listed as skipped.\n */\n redirects?: readonly BrandlabEstateRedirect[];\n /** Paths that must answer 404; defaults to one unknown slug under every catalogue parent. */\n notFoundPaths?: readonly string[];\n /** Also prove `<source>/` redirects straight to the destination (the shared helper emits these). */\n trailingSlashRedirects?: boolean;\n /**\n * Page families rendered on request outside the catalogue. Links into a\n * family's space count as live pages; one page of each family (outside the\n * catalogue where it has one) is checked for its status, canonical and\n * indexing; and a path of its pattern outside the space, one unknown value\n * per dynamic segment, must answer 404 with the site's not-found page rendered\n * on the server: the text an unknown top-level path's 404 page shows.\n */\n families?: readonly BrandlabEstateFamily[];\n /**\n * The site's recorded location capacity (site-core/location-policy). The\n * journey fails only when the catalogue holds more indexable location pages\n * than the capacity and the pages at record allow; without one it notes that\n * none is recorded.\n */\n locationCapacity?: LocationCapacityRecord | null;\n /** The business node's @id (default `<origin>/#business`); `false` when the site has none. */\n businessId?: string | false;\n /** The business facts record: the business node's name and telephone must match it. */\n business?: { name?: string; telephone?: string };\n /** A place's centre for neighbour order (default: the registry's suburb centres). */\n centreOf?: SuburbCentreLookup;\n /**\n * The site's estate plan (site-core `siteStrategy.estate`, 3.14.0): its public slugs map a location page to the\n * registry suburb it names (`ryde-suburb` → `ryde`) and mark region pages (`ryde`), which are not ranked by distance.\n */\n estate?: BrandlabEstateSlugPlan | null;\n /** The most inline markup one service-area map may carry (default 60 000 bytes, 3.6.0). */\n areaMapMaxBytes?: number;\n /**\n * The sampled crawl a draft pull request runs (`BRANDLAB_ESTATE_SCOPE=sample`, 3.13.0): how many routes and\n * redirects the fixed seed adds, the seed, and which routes a changed file feeds.\n */\n sample?: BrandlabEstateSampleOptions;\n concurrency?: number;\n timeout?: number;\n}\n\nexport interface BrandlabPageQualityTestOptions {\n site: { canonicalUrl: string | URL };\n routes: readonly BrandlabEstateRoute[];\n /** The @id every indexable page's graph references; defaults to `<origin>/#business`, `false` skips it. */\n businessId?: string | false;\n /** A place's centre for similarity siblings (default: the registry's suburb centres). */\n centreOf?: SuburbCentreLookup;\n /** The site's estate plan, as for the estate journey: public slugs resolve to the places they name. */\n estate?: BrandlabEstateSlugPlan | null;\n concurrency?: number;\n timeout?: number;\n}\n\nexport interface BrandlabPageQualityFinding {\n path: string;\n kind:\n | 'headings'\n | 'title'\n | 'title-format'\n | 'title-duplicate'\n | 'title-h1'\n | 'description'\n | 'description-length'\n | 'description-duplicate'\n | 'html-size'\n | 'similarity'\n | 'location-review'\n | 'orphan'\n | 'noindex-link'\n | 'og-url'\n | 'implementation-wording'\n | 'structured-data';\n detail: string;\n}\n\nconst LOCATION_KINDS = new Set(['location', 'service-location']);\n\n/** The public-slug part of site-core's SiteEstatePlan (mirrored: conformance compiles without site-core). */\nexport interface BrandlabEstateSlugPlan {\n slugs?: {\n /** Registry region slug → public slug, for example `{ 'ryde-area': 'ryde' }`. */\n regions?: Readonly<Record<string, string>>;\n /** Registry suburb slug → public slug, for example `{ ryde: 'ryde-suburb' }`. */\n suburbs?: Readonly<Record<string, string>>;\n };\n}\n\n/**\n * A location route's place: the registry suburb slug its last path segment names (through the estate plan's public\n * slugs, as site-core's `estatePublicSlug`), and whether it is a region page. A region page has no centre, so its\n * nearby lists are not ranked by distance: it is a region when other location pages sit under it, when its slug is a\n * region's public slug, or when its slug is a suburb's registry slug that the plan moved elsewhere (AA: `ryde`).\n */\nexport function estatePlaceResolver(\n routes: readonly BrandlabEstateRoute[],\n estate?: BrandlabEstateSlugPlan | null,\n): (route: BrandlabEstateRoute | undefined) => { slug: string; region: boolean } | undefined {\n const parents = new Set(routes.filter((route) => LOCATION_KINDS.has(route.kind ?? '')).map((route) => route.parentId));\n const regionSlugs = new Set(Object.values(estate?.slugs?.regions ?? {}));\n const suburbRenames = estate?.slugs?.suburbs ?? {};\n const suburbByPublic = new Map(Object.entries(suburbRenames).map(([registry, publicSlug]) => [publicSlug, registry]));\n return (route) => {\n if (!route || !LOCATION_KINDS.has(route.kind ?? '')) return undefined;\n const publicSlug = normalisePath(route.path).split('/').filter(Boolean).at(-1);\n if (!publicSlug) return undefined;\n const suburb = suburbByPublic.get(publicSlug);\n const region =\n (route.id !== undefined && parents.has(route.id)) ||\n regionSlugs.has(publicSlug) ||\n (suburb === undefined && Object.hasOwn(suburbRenames, publicSlug));\n return { slug: suburb ?? publicSlug, region };\n };\n}\n\n\nconst BUSINESS_TYPES = new Set([\n 'LocalBusiness', 'HomeAndConstructionBusiness', 'GeneralContractor', 'Plumber', 'Electrician',\n 'RoofingContractor', 'HousePainter', 'Locksmith', 'MovingCompany', 'HVACBusiness', 'ProfessionalService',\n]);\nconst UNKNOWN_SLUG = 'brandlab-estate-unknown-page';\nconst NOT_FOUND_ROUTE = '/404';\nconst PATTERN_SAMPLE = 'brandlab-estate-sample';\nconst ASSET_PATH = /\\.[a-z0-9]{2,5}$/i;\n\nexport function defineBrandlabEstateTests(options: BrandlabEstateTestOptions) {\n const origin = new URL(String(options.site.canonicalUrl)).origin;\n const canonical = (path: string) => new URL(path, `${origin}/`).href;\n const routes = options.routes;\n const knownPaths = new Set(routes.map((route) => normalisePath(route.path)));\n const redirects = (options.redirects ?? []).filter((rule) => !rule.host);\n const redirectBySource = new Map(\n redirects.filter((rule) => !isRedirectPattern(rule.source)).map((rule) => [normalisePath(rule.source), rule]),\n );\n const patternRedirects = redirects.flatMap((rule) => {\n const matcher = isRedirectPattern(rule.source) ? redirectSourceMatcher(rule.source) : undefined;\n return matcher ? [{ rule, matcher }] : [];\n });\n const findRedirect = (path: string) =>\n redirectBySource.get(path) ?? patternRedirects.find(({ matcher }) => matcher.test(path))?.rule;\n const timeout = options.timeout ?? 240_000;\n const families = options.families ?? [];\n const familyPaths = new Set(families.flatMap((family) => family.paths.map(normalisePath)));\n const routeByPath = new Map(routes.map((route) => [normalisePath(route.path), route]));\n const placeOfRoute = estatePlaceResolver(routes, options.estate);\n const homePath = normalisePath(routes.find((route) => route.kind === 'home')?.path ?? '/');\n // A draft pull request crawls a sample (BRANDLAB_ESTATE_SCOPE=sample); ready for review crawls every route.\n const scope = estateScopeFromEnv();\n const sample = sampleEstateRoutes(routes, { scope: scope.scope, changedFiles: changedFilesFromEnv(), ...options.sample });\n const scopeNote = [sample.summary, scope.note].filter(Boolean).join('; ');\n const crawledRedirects = scope.scope === 'sample' ? sampleBySeed(redirects, (rule) => rule.source, options.sample) : redirects;\n\n test.describe('Brandlab technical estate', () => {\n test('the sitemap lists exactly the indexable catalogue routes', async ({ request }) => {\n test.setTimeout(timeout);\n const listed = await readSitemap(request, '/sitemap.xml', origin);\n const expected = routes\n .filter((route) => route.indexing === 'index')\n .map((route) => canonical(route.canonicalPath ?? route.path));\n expect(listed.length, 'the sitemap repeats a URL').toBe(new Set(listed).size);\n expect([...listed].sort()).toEqual([...new Set(expected)].sort());\n });\n\n test('the sitemap is split by page family and dated by content, never by the build', async ({ request }, testInfo) => {\n test.setTimeout(timeout);\n const { index, files } = await readSitemapFiles(request, '/sitemap.xml', origin);\n const problems = [\n ...sitemapFamilyProblems({ index, files, routes, origin }),\n ...sitemapLastmodProblems(files.flatMap((file) => file.entries), routes, origin),\n ];\n await testInfo.attach('sitemap-files.json', {\n body: JSON.stringify(files.map((file) => ({ path: file.path, urls: file.entries.length })), null, 2),\n contentType: 'application/json',\n });\n expect(problems).toEqual([]);\n });\n\n test('location pages stay within the recorded capacity', async ({}, testInfo) => {\n const result = checkLocationCapacity(routes, options.locationCapacity);\n testInfo.annotations.push({ type: result.limit === null ? 'warning' : 'location-capacity', description: result.detail });\n expect(result.blocked, result.detail).toBe(false);\n });\n\n test('every catalogue route serves its canonical identity and links only to live pages', async ({ request }, testInfo) => {\n test.setTimeout(timeout);\n const centreOf = options.centreOf ?? (await loadBrandlabGeography()).centreOf;\n const failures: string[] = [];\n const internalLinks = new Map<string, string>();\n const checked: { path: string; canonical: string | null; jsonLd: number }[] = [];\n const areaMapLayers = new Map<string, { ids: Set<string>; from: string }>();\n testInfo.annotations.push({ type: 'estate-scope', description: scopeNote });\n await eachWithConcurrency(sample.routes, options.concurrency ?? 8, async (route) => {\n const [get, head] = await Promise.all([\n request.get(route.path, { maxRedirects: 0 }),\n request.head(route.path, { maxRedirects: 0 }),\n ]);\n // Next serves its not-found page at /404 with a 404 status.\n const notFound = normalisePath(route.path) === NOT_FOUND_ROUTE;\n const expectedStatus = notFound ? 404 : 200;\n if (get.status() !== expectedStatus || head.status() !== expectedStatus) {\n failures.push(`${route.path}: GET ${get.status()}, HEAD ${head.status()} (expected ${expectedStatus})`);\n return;\n }\n const html = await get.text();\n const snapshot = extractSearchCertificationHtmlSnapshot(html);\n const robots = `${snapshot.robots ?? ''} ${get.headers()['x-robots-tag'] ?? ''}`;\n if (notFound) {\n if (!/noindex/i.test(robots)) failures.push(`${route.path}: the not-found page is indexable`);\n checked.push({ path: route.path, canonical: snapshot.canonical, jsonLd: snapshot.jsonLd.length });\n return;\n }\n const expectedCanonical = canonical(route.canonicalPath ?? route.path);\n const canonicalTags = html.match(/<link\\b[^>]*\\brel=[\"']canonical[\"'][^>]*>/gi) ?? [];\n if (canonicalTags.length !== 1) failures.push(`${route.path}: ${canonicalTags.length} canonical links`);\n if (!snapshot.canonical || new URL(snapshot.canonical, origin).href !== expectedCanonical) {\n failures.push(`${route.path}: canonical ${snapshot.canonical ?? 'missing'} (expected ${expectedCanonical})`);\n }\n if (route.indexing === 'index' && /noindex/i.test(robots)) failures.push(`${route.path}: indexable route is noindex`);\n if (route.indexing !== 'index' && !/noindex/i.test(robots)) failures.push(`${route.path}: ${route.indexing} route is indexable`);\n for (const problem of breadcrumbListProblems(snapshot.jsonLd)) failures.push(`${route.path}: ${problem}`);\n if (route.indexing === 'index') {\n if (!snapshot.title) failures.push(`${route.path}: no <title> in the server HTML`);\n if (!snapshot.description) failures.push(`${route.path}: no meta description in the server HTML`);\n if (snapshot.jsonLd.length === 0) failures.push(`${route.path}: no JSON-LD in the server HTML`);\n }\n if (snapshot.jsonLd.some((payload) => (payload as { parseError?: boolean }).parseError)) failures.push(`${route.path}: invalid JSON-LD`);\n for (const problem of structuredDataProblems(snapshot.jsonLd, {\n origin,\n home: normalisePath(route.path) === homePath,\n businessId: options.businessId,\n business: options.business,\n })) failures.push(`${route.path}: ${problem}`);\n const place = placeOfRoute(route);\n if (place && !place.region && centreOf(place.slug)) {\n for (const problem of neighbourOrderProblems({\n html,\n origin: place.slug,\n pageUrl: expectedCanonical,\n placeOf: (path) => {\n const linked = placeOfRoute(routeByPath.get(path));\n return linked && !linked.region ? linked.slug : undefined;\n },\n centreOf,\n })) failures.push(`${route.path}: ${problem}`);\n }\n const maps = areaMapProblems({\n html,\n pageUrl: expectedCanonical,\n isIndexable: (path) => routeByPath.get(path)?.indexing === 'index',\n maxBytes: options.areaMapMaxBytes,\n });\n for (const problem of maps.problems) failures.push(`${route.path}: ${problem}`);\n for (const [path, ids] of maps.baseLayers) {\n const entry = areaMapLayers.get(path) ?? { ids: new Set<string>(), from: route.path };\n for (const id of ids) entry.ids.add(id);\n areaMapLayers.set(path, entry);\n }\n for (const href of extractLinks(html)) {\n const path = internalPath(href, expectedCanonical, origin);\n if (path && !internalLinks.has(path)) internalLinks.set(path, route.path);\n }\n checked.push({ path: route.path, canonical: snapshot.canonical, jsonLd: snapshot.jsonLd.length });\n });\n // Each service-area map's base layer is a cached SVG file holding the groups the page draws.\n for (const [path, { ids, from }] of [...areaMapLayers].sort(([a], [b]) => a.localeCompare(b))) {\n const response = await request.get(path, { maxRedirects: 0 });\n const type = response.headers()['content-type'] ?? '';\n if (response.status() !== 200 || !type.includes('image/svg+xml')) {\n failures.push(`${from}: the map's base layer ${path} answers ${response.status()} ${type || 'without a content type'}`);\n continue;\n }\n const svg = await response.text();\n for (const id of ids) if (!svg.includes(`id=\"${id}\"`)) failures.push(`${from}: the map's base layer ${path} has no group #${id}`);\n }\n for (const [path, from] of [...internalLinks].sort()) {\n if (knownPaths.has(path) || familyPaths.has(path)) continue;\n const redirect = findRedirect(path);\n if (redirect && isExternalDestination(redirect.destination)) continue;\n failures.push(redirect\n ? `${from}: links to ${path}, which redirects; link to ${redirect.destination} directly`\n : `${from}: links to ${path}, which is not a catalogue route`);\n }\n await testInfo.attach('technical-estate.json', {\n body: JSON.stringify({ routes: checked.sort((a, b) => a.path.localeCompare(b.path)), internalLinks: [...internalLinks.keys()].sort() }, null, 2),\n contentType: 'application/json',\n });\n expect(failures).toEqual([]);\n });\n\n test('every redirect resolves in one hop and keeps the query string', async ({ request }, testInfo) => {\n test.setTimeout(timeout);\n const failures: string[] = [];\n const skipped: string[] = [];\n if (scope.scope === 'sample') {\n testInfo.annotations.push({ type: 'estate-scope', description: `sample: ${crawledRedirects.length} of ${redirects.length} redirects (fixed seed); every redirect is checked when the pull request is ready for review` });\n }\n for (const rule of crawledRedirects) {\n const probe = redirectProbe(rule);\n if (!probe) {\n skipped.push(`${rule.source} → ${rule.destination}`);\n continue;\n }\n const sources = [probe.source, ...(options.trailingSlashRedirects === false || probe.source === '/' || probe.source.endsWith('/') ? [] : [`${probe.source}/`])];\n for (const source of sources) {\n for (const method of ['GET', 'HEAD'] as const) {\n const response = await request.fetch(`${source}?brandlab_estate=1`, { method, maxRedirects: 0 });\n const location = response.headers().location;\n const expectedStatus: number[] = source === probe.source ? [rule.status] : [301, 308];\n if (!expectedStatus.includes(response.status()) || !location) {\n failures.push(`${method} ${source}: ${response.status()} (expected ${expectedStatus.join(' or ')} to ${probe.destination})`);\n continue;\n }\n const target = new URL(location, origin);\n if (isExternalDestination(probe.destination)) {\n if (!target.href.startsWith(new URL(probe.destination, origin).href.replace(/\\/$/, ''))) failures.push(`${method} ${source}: Location ${location} (expected ${probe.destination})`);\n continue;\n }\n if (target.pathname !== new URL(probe.destination, origin).pathname) failures.push(`${method} ${source}: Location ${location} (expected ${probe.destination})`);\n if (target.searchParams.get('brandlab_estate') !== '1') failures.push(`${method} ${source}: the query string was dropped`);\n }\n }\n // A destination with parameters names many pages; the sample fills it with a page that does not exist.\n if (!isExternalDestination(probe.destination) && !probe.sampled) {\n const destination = await request.get(probe.destination, { maxRedirects: 0 });\n if (destination.status() !== 200) failures.push(`${rule.source}: destination ${probe.destination} answers ${destination.status()} (a chain or a missing page)`);\n }\n }\n if (skipped.length > 0) {\n testInfo.annotations.push({ type: 'skipped-redirects', description: `${skipped.length} redirect(s) with a parameter pattern that cannot be sampled: ${skipped.join('; ')}` });\n }\n expect(failures).toEqual([]);\n });\n\n if (families.length > 0) {\n test('every page family rendered on request serves its pages and answers 404 outside its space', async ({ request }) => {\n test.setTimeout(timeout);\n const failures: string[] = [];\n const reference = await request.get(`/${UNKNOWN_SLUG}`, { maxRedirects: 0 });\n const notFoundText = reference.status() === 404 ? bodyText(await reference.text()) : '';\n if (!notFoundText) failures.push(`/${UNKNOWN_SLUG}: ${reference.status()} with no server-rendered not-found page to compare with`);\n for (const family of families) {\n const sample = familySamplePath(family, knownPaths);\n if (!sample) {\n failures.push(`${family.pattern}: the family lists no page`);\n continue;\n }\n const response = await request.get(sample, { maxRedirects: 0 });\n if (response.status() !== 200) {\n failures.push(`${sample}: ${response.status()} (expected 200 for a page of ${family.pattern})`);\n } else {\n const html = await response.text();\n const snapshot = extractSearchCertificationHtmlSnapshot(html);\n const robots = `${snapshot.robots ?? ''} ${response.headers()['x-robots-tag'] ?? ''}`;\n const expectedCanonical = canonical(sample);\n if (!snapshot.canonical || new URL(snapshot.canonical, origin).href !== expectedCanonical) {\n failures.push(`${sample}: canonical ${snapshot.canonical ?? 'missing'} (expected ${expectedCanonical})`);\n }\n if (family.indexing === 'index' && /noindex/i.test(robots)) failures.push(`${sample}: the family's pages are indexable, this one is noindex`);\n if (family.indexing !== 'index' && !/noindex/i.test(robots)) failures.push(`${sample}: the family's pages are ${family.indexing}, this one is indexable`);\n }\n for (const outside of familyNotFoundPaths(family)) {\n const miss = await request.get(outside, { maxRedirects: 0 });\n if (miss.status() !== 404) {\n failures.push(`${outside}: ${miss.status()} (expected 404 outside ${family.pattern}'s space)`);\n continue;\n }\n const text = bodyText(await miss.text());\n if (notFoundText && text !== notFoundText) {\n failures.push(`${outside}: the 404 is not the site's not-found page rendered on the server (${text ? `it shows \"${text.slice(0, 80)}\"` : 'its body is empty until the browser renders it'})`);\n }\n }\n }\n expect(failures).toEqual([]);\n });\n }\n\n test('unknown slugs answer 404 instead of inventing pages', async ({ request }, testInfo) => {\n // A default probe a redirect rule covers (a wildcard such as /blog/:slug) is the redirect's to answer; the\n // redirect journey proves it. Paths the site lists itself are always probed.\n const { probes: paths, redirected } = options.notFoundPaths\n ? { probes: options.notFoundPaths, redirected: [] }\n : unknownSlugProbes(defaultNotFoundPaths(routes), (path) => Boolean(findRedirect(path)));\n for (const path of redirected) testInfo.annotations.push({ type: 'skipped', description: `${path}: a redirect rule answers it` });\n const failures: string[] = [];\n for (const path of paths) {\n const [get, head] = await Promise.all([\n request.get(path, { maxRedirects: 0 }),\n request.head(path, { maxRedirects: 0 }),\n ]);\n if (get.status() !== 404) failures.push(`${path}: GET ${get.status()} (expected 404)`);\n if (head.status() !== 404) failures.push(`${path}: HEAD ${head.status()} (expected 404)`);\n }\n expect(failures).toEqual([]);\n });\n\n test('robots.txt allows crawling and names the sitemap', async ({ request }) => {\n const response = await request.get('/robots.txt');\n expect(response.status()).toBe(200);\n const body = await response.text();\n expect(body).toMatch(new RegExp(`^sitemap:\\\\s*${escapeRegExp(`${origin}/sitemap.xml`)}\\\\s*$`, 'im'));\n expect(body).not.toMatch(/^disallow:\\s*\\/\\s*$/im);\n });\n\n test('a production deployment tells crawlers not to index any host but its canonical one', async ({ baseURL }) => {\n test.skip(process.env.VERCEL_ENV !== 'production', 'Only a production build (VERCEL_ENV=production, as CI builds it) answers other hosts with noindex.');\n const server = new URL(baseURL ?? 'http://127.0.0.1:3100/');\n const canonicalHost = new URL(origin).hostname;\n // The production *.vercel.app alias serves the full site; its pages must not be indexed.\n const alias = `${canonicalHost.split('.')[0]}-brandlab-e2e.vercel.app`;\n expect(await responseHeader(server, alias, '/', 'x-robots-tag'), `${alias}: X-Robots-Tag`).toBe('noindex');\n expect(await responseHeader(server, canonicalHost, '/', 'x-robots-tag'), `${canonicalHost}: X-Robots-Tag`).not.toMatch(/noindex/);\n });\n });\n}\n\n/**\n * Why a page's BreadcrumbList JSON-LD would fail Google's breadcrumb rich result (3.3.3): every\n * ListItem but the last needs its `item` (the page it names), as the shared builder requires;\n * Google reports \"Missing field item\" otherwise. Lists inside an `@graph` count; an empty list\n * has nothing to judge.\n */\nexport function breadcrumbListProblems(jsonLd: readonly unknown[]): string[] {\n const lists: Record<string, unknown>[] = [];\n const collect = (value: unknown) => {\n if (Array.isArray(value)) {\n value.forEach(collect);\n return;\n }\n if (!value || typeof value !== 'object') return;\n const node = value as Record<string, unknown>;\n const type = node['@type'];\n if (type === 'BreadcrumbList' || (Array.isArray(type) && type.includes('BreadcrumbList'))) lists.push(node);\n if (Array.isArray(node['@graph'])) collect(node['@graph']);\n };\n collect(jsonLd);\n const problems: string[] = [];\n for (const list of lists) {\n const items = Array.isArray(list.itemListElement) ? list.itemListElement : [];\n items.slice(0, -1).forEach((entry, index) => {\n const item = entry && typeof entry === 'object' ? (entry as Record<string, unknown>).item : undefined;\n const named = typeof item === 'string' ? item.trim() : item && typeof item === 'object' ? String((item as Record<string, unknown>)['@id'] ?? (item as Record<string, unknown>).url ?? '').trim() : '';\n if (named) return;\n const name = entry && typeof entry === 'object' ? (entry as Record<string, unknown>).name : undefined;\n problems.push(`BreadcrumbList item ${index + 1}${typeof name === 'string' && name.trim() ? ` (\"${name.trim()}\")` : ''} has no URL (item); only the last breadcrumb may omit it, or Google rejects the list`);\n });\n }\n return problems;\n}\n\n/** One response header for a request that names its own Host (the Playwright request context always sends the server's). */\nexport function responseHeader(server: URL, host: string, path: string, name: string): Promise<string | undefined> {\n return new Promise((resolve, reject) => {\n const request = httpRequest({ hostname: server.hostname, port: server.port || 80, path, method: 'GET', headers: { host, 'x-forwarded-proto': 'https' } }, (response) => {\n response.resume();\n const value = response.headers[name.toLowerCase()];\n resolve(Array.isArray(value) ? value.join(', ') : value);\n });\n request.on('error', reject);\n request.end();\n });\n}\n\n/**\n * Every `<loc>` in a sitemap, following one level of sitemap index. Nothing is\n * followed through a redirect, and with `origin` every nested sitemap must be\n * on that origin (it is then fetched from the build under test).\n */\nexport async function readSitemap(request: APIRequestContext, path: string, origin?: string): Promise<string[]> {\n const read = async (target: string) => {\n const response = await request.get(target, { maxRedirects: 0 });\n if (response.status() !== 200) throw new Error(`${target} answers ${response.status()}; a sitemap must answer 200 without redirecting.`);\n return response.text();\n };\n const xml = await read(path);\n const locations = extractSitemapLocations(xml);\n if (!/<sitemapindex\\b/i.test(xml)) return locations;\n const nested: string[] = [];\n for (const location of locations) {\n const url = new URL(location);\n if (origin && url.origin !== new URL(origin).origin) {\n throw new Error(`The sitemap index lists ${location}, which is not on ${new URL(origin).origin}.`);\n }\n nested.push(...extractSitemapLocations(await read(`${url.pathname}${url.search}`)));\n }\n return nested;\n}\n\n/**\n * The sitemap's URL files with their entries: the sitemap itself, or every\n * file a sitemap index lists (one level, same origin, no redirects).\n */\nexport async function readSitemapFiles(\n request: APIRequestContext,\n path: string,\n origin: string,\n): Promise<{ index: boolean; files: SitemapFile[] }> {\n const read = async (target: string) => {\n const response = await request.get(target, { maxRedirects: 0 });\n if (response.status() !== 200) throw new Error(`${target} answers ${response.status()}; a sitemap must answer 200 without redirecting.`);\n return response.text();\n };\n const xml = await read(path);\n if (!/<sitemapindex\\b/i.test(xml)) return { index: false, files: [{ path, entries: parseSitemapEntries(xml) }] };\n const files: SitemapFile[] = [];\n for (const location of extractSitemapLocations(xml)) {\n const url = new URL(location);\n if (url.origin !== new URL(origin).origin) throw new Error(`The sitemap index lists ${location}, which is not on ${new URL(origin).origin}.`);\n files.push({ path: url.pathname, entries: parseSitemapEntries(await read(`${url.pathname}${url.search}`)) });\n }\n return { index: true, files };\n}\n\nexport function extractSitemapLocations(xml: string): string[] {\n return [...xml.matchAll(/<loc>\\s*([^<\\s]+)\\s*<\\/loc>/gi)].map((match) =>\n new URL(decodeXml(match[1]!)).href);\n}\n\nexport function defaultNotFoundPaths(routes: readonly BrandlabEstateRoute[]): string[] {\n const parents = new Set(['']);\n for (const route of routes) {\n const segments = normalisePath(route.path).split('/').filter(Boolean);\n if (segments.length > 1) parents.add(`/${segments.slice(0, -1).join('/')}`);\n if (segments.length === 1) parents.add(`/${segments[0]}`);\n }\n return [...parents].sort().map((parent) => `${parent}/${UNKNOWN_SLUG}`);\n}\n\n/** The unknown-slug probes to request, apart from those a redirect rule answers. */\nexport function unknownSlugProbes(paths: readonly string[], redirects: (path: string) => boolean): { probes: string[]; redirected: string[] } {\n const probes: string[] = [];\n const redirected: string[] = [];\n for (const path of paths) (redirects(normalisePath(path)) ? redirected : probes).push(path);\n return { probes, redirected };\n}\n\n/** The page of a family its estate check opens: the first one outside the catalogue, else its first page. */\nexport function familySamplePath(family: Pick<BrandlabEstateFamily, 'paths'>, catalogue: ReadonlySet<string>): string | undefined {\n return family.paths.find((path) => !catalogue.has(normalisePath(path))) ?? family.paths[0];\n}\n\n/**\n * Paths of a family's pattern outside its space: a page of the family with one\n * dynamic segment at a time replaced by an unknown slug.\n */\nexport function familyNotFoundPaths(family: Pick<BrandlabEstateFamily, 'pattern' | 'paths'>): string[] {\n const first = family.paths[0];\n if (!first) return [];\n const parts = normalisePath(first).split('/');\n const segments = family.pattern.split('/');\n const paths = segments.flatMap((segment, index) => (/^\\[[^.\\]]/.test(segment) ? [parts.map((part, position) => (position === index ? UNKNOWN_SLUG : part)).join('/')] : []));\n const space = new Set(family.paths.map(normalisePath));\n return [...new Set(paths)].filter((path) => !space.has(path));\n}\n\n/**\n * The text a page shows before any script runs: its body without scripts,\n * styles and templates, tags removed and whitespace collapsed. Empty for the\n * document Next sends when it leaves a page to the browser to render.\n */\nexport function bodyText(html: string): string {\n const body = /<body\\b[^>]*>([\\s\\S]*?)(?:<\\/body>|$)/i.exec(html)?.[1] ?? (/<html\\b/i.test(html) ? '' : html);\n return decodeXml(body\n .replace(/<(script|style|template|noscript)\\b[\\s\\S]*?<\\/\\1>/gi, ' ')\n .replace(/<[^>]+>/g, ' '))\n .replace(/ /g, ' ')\n .replace(/\\s+/g, ' ')\n .trim();\n}\n\n/** A Next redirect path with parameters: `:name`, `:name*`, `:name+`, `:name?` or a regular-expression group. */\nexport function isRedirectPattern(path: string): boolean {\n return /:[A-Za-z_]\\w*|\\(/.test(path.replace(/^[a-z][a-z0-9+.-]*:\\/\\//i, ''));\n}\n\n/**\n * The request that proves a redirect rule: a pattern gets one sample segment\n * per parameter, in its source and destination alike. Undefined when a\n * parameter carries its own regular expression, which no sample can satisfy\n * with certainty.\n */\nexport function redirectProbe(rule: Pick<BrandlabEstateRedirect, 'source' | 'destination'>): { source: string; destination: string; sampled: boolean } | undefined {\n const sample = (path: string) => {\n if (!isRedirectPattern(path)) return path;\n // Keep an external destination's scheme and host; parameters live in the path.\n const origin = /^[a-z][a-z0-9+.-]*:\\/\\/[^/]*/i.exec(path)?.[0] ?? '';\n const rest = path.slice(origin.length);\n if (rest.includes('(')) return undefined;\n return `${origin}${rest.replace(/:[A-Za-z_]\\w*[*+?]?/g, PATTERN_SAMPLE)}`;\n };\n const source = sample(rule.source);\n const destination = sample(rule.destination);\n if (source === undefined || destination === undefined) return undefined;\n return { source, destination, sampled: isRedirectPattern(rule.destination) };\n}\n\n/** A matcher for paths a pattern source redirects, for internal-link checks. */\nfunction redirectSourceMatcher(source: string): RegExp | undefined {\n if (source.includes('(')) return undefined;\n const pattern = normalisePath(source).split(/(:[A-Za-z_]\\w*[*+?]?)/).map((part) => {\n const parameter = /^:[A-Za-z_]\\w*([*+?]?)$/.exec(part);\n if (!parameter) return escapeRegExp(part);\n return parameter[1] === '*' || parameter[1] === '+' ? '.+' : parameter[1] === '?' ? '[^/]*' : '[^/]+';\n }).join('');\n return new RegExp(`^${pattern}$`);\n}\n\n/**\n * The advisory page-quality journey: headings, title, description, og:url,\n * implementation wording and structured-data identity for every catalogue\n * page. It reports what it finds (page-quality.json and an annotation) and\n * never fails, because a backend release keeps production's pages as they\n * are; the comparison harness proves them unchanged.\n *\n * // tests/e2e/page-quality.spec.ts\n * defineBrandlabPageQualityTests({ site, routes })\n */\nexport function defineBrandlabPageQualityTests(options: BrandlabPageQualityTestOptions) {\n const origin = new URL(String(options.site.canonicalUrl)).origin;\n const canonical = (path: string) => new URL(path, `${origin}/`).href;\n const businessId = options.businessId ?? `${origin}/#business`;\n const timeout = options.timeout ?? 240_000;\n const routes = options.routes.filter((route) => normalisePath(route.path) !== NOT_FOUND_ROUTE);\n const routeByPath = new Map(routes.map((route) => [normalisePath(route.path), route]));\n const placeOfRoute = estatePlaceResolver(routes, options.estate);\n const run = pageQualityRunFromEnv();\n\n test.describe('Brandlab page quality (advisory)', () => {\n test('reports page and structured-data quality without failing', async ({ request }, testInfo) => {\n test.skip(!run.run, run.reason);\n test.setTimeout(timeout);\n const findings: BrandlabPageQualityFinding[] = [];\n const geography = await loadBrandlabGeography();\n const centreOf = options.centreOf ?? geography.centreOf;\n const titles = new Map<string, string[]>();\n const descriptions = new Map<string, string[]>();\n const similarityPages: SimilarityPage[] = [];\n const linksFrom = new Map<string, Set<string>>();\n await eachWithConcurrency(routes, options.concurrency ?? 8, async (route) => {\n const response = await request.get(route.path, { maxRedirects: 0 });\n // The estate journey owns status codes; quality is read from the pages that load.\n if (response.status() !== 200) return;\n const html = await response.text();\n const snapshot = extractSearchCertificationHtmlSnapshot(html);\n const add = (kind: BrandlabPageQualityFinding['kind'], detail: string) => findings.push({ path: route.path, kind, detail });\n const h1s = headingTexts(html);\n if (h1s.length !== 1) add('headings', `${h1s.length} h1 headings`);\n if (!snapshot.title) add('title', 'no title');\n if (!snapshot.description) add('description', 'no meta description');\n const indexable = route.indexing === 'index';\n if (indexable && snapshot.title) {\n const formatProblems = titleFormatProblems(snapshot.title);\n if (formatProblems.length > 0) add('title-format', `\"${snapshot.title}\": ${formatProblems.join('; ')}`);\n titles.set(snapshot.title, [...(titles.get(snapshot.title) ?? []), route.path]);\n const place = placeOfRoute(route);\n if (h1s.length === 1) {\n const problems = titleHeadingProblems(snapshot.title, h1s[0]!, place && !place.region ? geography.placeNames.get(place.slug) : undefined);\n if (problems.length > 0) add('title-h1', problems.join('; '));\n }\n }\n if (indexable && snapshot.description) {\n const problem = descriptionLengthProblem(snapshot.description);\n if (problem) add('description-length', problem);\n descriptions.set(snapshot.description, [...(descriptions.get(snapshot.description) ?? []), route.path]);\n }\n const bytes = Buffer.byteLength(html);\n if (bytes > HTML_MAX_BYTES) add('html-size', `${(bytes / 1_048_576).toFixed(2)} MB of HTML (investigate anything over 1 MB)`);\n const expectedCanonical = canonical(route.canonicalPath ?? route.path);\n const ogUrl = snapshot.openGraph['og:url'];\n if (ogUrl && new URL(ogUrl, origin).href !== expectedCanonical) add('og-url', `og:url ${ogUrl} is not the canonical URL`);\n if (snapshot.implementationCopyMatches.length > 0) add('implementation-wording', snapshot.implementationCopyMatches.join(', '));\n for (const failure of inspectStructuredData(route, snapshot.jsonLd, businessId)) {\n add('structured-data', failure.slice(route.path.length + 2));\n }\n const place = placeOfRoute(route)?.slug;\n if (indexable && place) similarityPages.push({ path: route.path, place, blocks: textBlocks(html).map(geography.maskPlaces) });\n linksFrom.set(normalisePath(route.path), pageLinkTargets(html, route.path, origin, expectedCanonical));\n });\n // Internal links: every indexable page needs a link from another page, and indexable pages link no noindex location page.\n const inbound = new Map<string, number>();\n for (const targets of linksFrom.values()) for (const target of targets) inbound.set(target, (inbound.get(target) ?? 0) + 1);\n findings.push(...noindexLinkFindings(linksFrom, routes));\n for (const route of routes) {\n const path = normalisePath(route.path);\n if (route.indexing === 'index' && route.kind !== 'home' && path !== '/' && linksFrom.has(path) && !inbound.get(path)) {\n findings.push({ path: route.path, kind: 'orphan', detail: 'no other catalogue page links to it' });\n }\n }\n for (const [title, paths] of titles) {\n if (paths.length > 1) for (const path of paths) findings.push({ path, kind: 'title-duplicate', detail: `\"${title}\" is also the title of ${paths.filter((other) => other !== path).slice(0, 3).join(', ')}${paths.length > 4 ? ' and others' : ''}` });\n }\n for (const [description, paths] of descriptions) {\n if (paths.length > 1) for (const path of paths) findings.push({ path, kind: 'description-duplicate', detail: `the meta description is shared with ${paths.length - 1} other page(s) (\"${description.slice(0, 60)}…\")` });\n }\n // Location pages: centerpiece similarity against near siblings, by route kind.\n const similarity = [...new Set(similarityPages.map((page) => routeByPath.get(normalisePath(page.path))?.kind))]\n .flatMap((kind) => centerpieceSimilarity(similarityPages.filter((page) => routeByPath.get(normalisePath(page.path))?.kind === kind), centreOf));\n for (const score of similarity) {\n if (score.score < SIMILARITY_WARN) continue;\n findings.push({\n path: score.path,\n kind: 'similarity',\n detail: `${score.score.toFixed(2)} of its page-specific phrases also appear on ${score.sibling ?? 'a near sibling'}${score.score >= SIMILARITY_REVIEW ? ' (at or above 0.7: on the review list; the page stays indexed)' : ' (at or above 0.5: add page-specific evidence)'}`,\n });\n }\n const reviewList = buildLocationReviewList(routes);\n const flagged = new Set(similarity.filter((score) => score.score >= SIMILARITY_REVIEW).map((score) => score.path));\n const review = [\n ...reviewList.map((item) => ({ ...item, reasons: [...item.reasons, ...(flagged.has(item.path) ? ['centerpiece similarity at or above 0.7'] : [])] })),\n ...[...flagged].filter((path) => !reviewList.some((item) => item.path === path)).map((path) => ({ path, evidence: routeByPath.get(normalisePath(path))?.locationDecision?.evidence ?? [], reasons: ['centerpiece similarity at or above 0.7'] })),\n ].sort((a, b) => a.path.localeCompare(b.path));\n for (const item of review) findings.push({ path: item.path, kind: 'location-review', detail: item.reasons.join('; ') });\n findings.sort((a, b) => a.path.localeCompare(b.path) || a.kind.localeCompare(b.kind));\n const byKind = Object.fromEntries(\n [...new Set(findings.map((finding) => finding.kind))].sort().map((kind) => [kind, findings.filter((finding) => finding.kind === kind).length]),\n );\n const reports = {\n 'page-quality.json': JSON.stringify({ pages: routes.length, findings: findings.length, byKind, details: findings }, null, 2),\n 'location-review.json': JSON.stringify({\n reviewed: review.length,\n note: 'Pages on the review list stay indexed. Each review ends in adding evidence, merging into the nearest owner or hiding with noindex, follow; merging and hiding are Romie\\'s decision.',\n similarity: similarity.sort((a, b) => b.score - a.score),\n review,\n }, null, 2),\n };\n for (const [name, body] of Object.entries(reports)) await testInfo.attach(name, { body, contentType: 'application/json' });\n // CI's page-quality run keeps the reports beside the ready report (BRANDLAB_PAGE_QUALITY_DIR=docs/ready).\n if (run.directory) {\n mkdirSync(run.directory, { recursive: true });\n for (const [name, body] of Object.entries(reports)) writeFileSync(join(run.directory, name), `${body}\\n`);\n }\n testInfo.annotations.push({\n type: 'advisory',\n description: `${findings.length} page-quality finding(s) across ${routes.length} page(s)${findings.length ? `: ${Object.entries(byKind).map(([kind, count]) => `${kind} ${count}`).join(', ')}` : ''}; see page-quality.json.`,\n });\n });\n });\n}\n\n/**\n * Whether the advisory page-quality crawl runs (3.13.0, client CI v2). CI v2 runs it on its own when a pull request\n * is ready for review, on a manual run and monthly for large estates, and sets `BRANDLAB_PAGE_QUALITY=skip` for the required journeys so\n * drafts and merges do not crawl every page twice. `BRANDLAB_PAGE_QUALITY_DIR` also writes its reports there.\n */\nexport function pageQualityRunFromEnv(env: NodeJS.ProcessEnv = process.env): { run: boolean; reason: string; directory?: string } {\n const directory = env.BRANDLAB_PAGE_QUALITY_DIR?.trim() || undefined;\n if ((env.BRANDLAB_PAGE_QUALITY ?? '').trim() === 'skip') {\n return { run: false, reason: 'The advisory page-quality crawl runs on its own in CI (ready for review, manual runs and monthly for large estates); BRANDLAB_PAGE_QUALITY=skip.' };\n }\n return { run: true, reason: '', ...(directory ? { directory } : {}) };\n}\n\nfunction inspectStructuredData(route: BrandlabEstateRoute, payloads: readonly unknown[], businessId: string | false): string[] {\n const failures: string[] = [];\n if (payloads.some((payload) => (payload as { parseError?: boolean }).parseError)) failures.push(`${route.path}: invalid JSON-LD`);\n if (route.indexing === 'index' && payloads.length === 0) failures.push(`${route.path}: no JSON-LD`);\n const ids: string[] = [];\n let referencesBusiness = false;\n const visit = (value: unknown) => {\n if (!value || typeof value !== 'object') return;\n if (Array.isArray(value)) { value.forEach(visit); return; }\n const node = value as Record<string, unknown>;\n const types = ([] as unknown[]).concat(node['@type'] ?? []).map(String);\n if (typeof node['@id'] === 'string') {\n if (node['@id'] === businessId) referencesBusiness = true;\n if (types.length > 0) ids.push(node['@id']);\n }\n if (businessId && types.some((type) => BUSINESS_TYPES.has(type)) && node['@id'] !== businessId) {\n failures.push(`${route.path}: business node @id ${String(node['@id'] ?? 'missing')} (expected ${businessId})`);\n }\n Object.values(node).forEach(visit);\n };\n payloads.forEach(visit);\n const duplicate = ids.find((id, index) => ids.indexOf(id) !== index);\n if (duplicate) failures.push(`${route.path}: JSON-LD repeats node ${duplicate}`);\n if (businessId && route.indexing === 'index' && payloads.length > 0 && !referencesBusiness) failures.push(`${route.path}: JSON-LD does not reference ${businessId}`);\n return failures;\n}\n\n/**\n * The internal pages a page's server HTML links, once each, without the page itself. Only anchors count: an area named\n * as plain text (a `Coverage` entry with no `href`, 3.15.0) is no link.\n */\nexport function pageLinkTargets(html: string, path: string, origin: string, base: string = new URL(path, `${origin}/`).href): Set<string> {\n const targets = new Set<string>();\n for (const href of extractLinks(html)) {\n const target = internalPath(href, base, origin);\n if (target && target !== normalisePath(path)) targets.add(target);\n }\n return targets;\n}\n\n/**\n * Indexable pages that link a noindex location page (D4: list a place whose page waits for its wave as plain text,\n * as site-core's `coverageEntries` does). `linksFrom` maps each page to the pages it links.\n */\nexport function noindexLinkFindings(\n linksFrom: ReadonlyMap<string, ReadonlySet<string>>,\n routes: readonly Pick<BrandlabEstateRoute, 'path' | 'indexing' | 'kind'>[],\n): BrandlabPageQualityFinding[] {\n const routeByPath = new Map(routes.map((route) => [normalisePath(route.path), route]));\n const findings: BrandlabPageQualityFinding[] = [];\n for (const [from, targets] of linksFrom) {\n if (routeByPath.get(from)?.indexing !== 'index') continue;\n for (const target of targets) {\n const linked = routeByPath.get(target);\n if (linked && linked.indexing !== 'index' && LOCATION_KINDS.has(linked.kind ?? '')) {\n findings.push({ path: from, kind: 'noindex-link', detail: `links to ${target}, a noindex location page (list unindexed places as plain text)` });\n }\n }\n }\n return findings;\n}\n\nfunction extractLinks(html: string): string[] {\n return [...html.matchAll(/<a\\b[^>]*\\bhref=[\"']([^\"']+)[\"']/gi)].map((match) => decodeXml(match[1]!));\n}\n\nfunction internalPath(href: string, base: string, origin: string): string | null {\n if (/^(?:mailto|tel|sms|javascript):/i.test(href) || href.startsWith('#')) return null;\n let url: URL;\n try { url = new URL(href, base); } catch { return null; }\n if (url.origin !== origin && !['127.0.0.1', 'localhost'].includes(url.hostname)) return null;\n if (ASSET_PATH.test(url.pathname) || url.pathname.startsWith('/api/') || url.pathname.startsWith('/_next/')) return null;\n return normalisePath(url.pathname);\n}\n\nfunction normalisePath(path: string): string {\n const pathname = path.split(/[?#]/)[0] || '/';\n return pathname.length > 1 ? pathname.replace(/\\/+$/, '') : '/';\n}\n\n/**\n * Absolute (`https://host`) and protocol-relative (`//host`) destinations leave\n * the site; browsers also read `/\\host` and `\\\\host` as protocol-relative.\n */\nexport function isExternalDestination(destination: string): boolean {\n return /^(?:[a-z][a-z0-9+.-]*:)?[\\\\/]{2}/i.test(destination.trim());\n}\n\nfunction decodeXml(value: string): string {\n return value.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '\"').replace(/'/g, \"'\");\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nasync function eachWithConcurrency<T>(items: readonly T[], limit: number, task: (item: T) => Promise<void>) {\n const queue = [...items];\n await Promise.all(Array.from({ length: Math.max(1, Math.min(limit, queue.length)) }, async () => {\n for (let item = queue.shift(); item !== undefined; item = queue.shift()) await task(item);\n }));\n}\n"]}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The media manifest snapshot (3.15.0): a site whose `src/data/media.ts` is computed (gallery entries spread in from
|
|
3
|
+
* its gallery data, for example) records the manifest as plain JSON, so the ready gate's T6 can read every entry
|
|
4
|
+
* without running the site's code. Like the estate plan snapshot it is deterministic (entries by id, keys sorted, no
|
|
5
|
+
* timestamp) and carries a hash of the files it was written from (`src/data` by default), so T6 fails a stale one.
|
|
6
|
+
*
|
|
7
|
+
* // tests/data/mediaSnapshot.test.ts
|
|
8
|
+
* import { writeMediaSnapshot } from '@brandlab-digital/conformance/media-snapshot'
|
|
9
|
+
* import { media } from '@/data/media'
|
|
10
|
+
*
|
|
11
|
+
* it('records the media manifest for the ready gate', () => {
|
|
12
|
+
* const { changed } = writeMediaSnapshot(media, { projectRoot: process.cwd() })
|
|
13
|
+
* if (process.env.CI) expect(changed).toBe(false)
|
|
14
|
+
* })
|
|
15
|
+
*
|
|
16
|
+
* Node only: it reads and writes files.
|
|
17
|
+
*/
|
|
18
|
+
import { type EstatePlanSnapshotOptions } from "./estate-snapshot.js";
|
|
19
|
+
/** Where the snapshot lives, relative to the project root. */
|
|
20
|
+
export declare const MEDIA_SNAPSHOT_FILE = "src/data/media.generated.json";
|
|
21
|
+
export declare const MEDIA_SNAPSHOT_KIND = "brandlab-media-snapshot";
|
|
22
|
+
export declare const MEDIA_SNAPSHOT_VERSION = 1;
|
|
23
|
+
type JsonValue = string | number | boolean | null | JsonValue[] | {
|
|
24
|
+
[key: string]: JsonValue;
|
|
25
|
+
};
|
|
26
|
+
/** One manifest entry as `defineMedia` holds it: `src` and the rest of its fields. */
|
|
27
|
+
export interface MediaSnapshotEntry {
|
|
28
|
+
readonly src: string;
|
|
29
|
+
readonly [field: string]: unknown;
|
|
30
|
+
}
|
|
31
|
+
export interface MediaSnapshot {
|
|
32
|
+
readonly kind: typeof MEDIA_SNAPSHOT_KIND;
|
|
33
|
+
readonly version: typeof MEDIA_SNAPSHOT_VERSION;
|
|
34
|
+
readonly sources: {
|
|
35
|
+
readonly paths: readonly string[];
|
|
36
|
+
readonly sha256: string;
|
|
37
|
+
};
|
|
38
|
+
/** Entries by id, in id order, each with its keys sorted. */
|
|
39
|
+
readonly media: Readonly<Record<string, Readonly<Record<string, JsonValue>>>>;
|
|
40
|
+
}
|
|
41
|
+
/** The snapshot for a media manifest: every entry in canonical form, with the sources' hash. */
|
|
42
|
+
export declare function mediaSnapshot(media: Readonly<Record<string, MediaSnapshotEntry>>, options: EstatePlanSnapshotOptions): MediaSnapshot;
|
|
43
|
+
/**
|
|
44
|
+
* Writes `src/data/media.generated.json` when its content differs; `changed` says whether it did. Run it from the
|
|
45
|
+
* site's tests so the snapshot follows media.ts, and commit the file.
|
|
46
|
+
*/
|
|
47
|
+
export declare function writeMediaSnapshot(media: Readonly<Record<string, MediaSnapshotEntry>>, options: EstatePlanSnapshotOptions): {
|
|
48
|
+
readonly path: string;
|
|
49
|
+
readonly changed: boolean;
|
|
50
|
+
readonly snapshot: MediaSnapshot;
|
|
51
|
+
};
|
|
52
|
+
export {};
|
|
53
|
+
//# sourceMappingURL=media-snapshot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"media-snapshot.d.ts","sourceRoot":"","sources":["../src/media-snapshot.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAgE,KAAK,yBAAyB,EAAE,MAAM,sBAAsB,CAAC;AAEpI,8DAA8D;AAC9D,eAAO,MAAM,mBAAmB,kCAAkC,CAAC;AACnE,eAAO,MAAM,mBAAmB,4BAA4B,CAAC;AAC7D,eAAO,MAAM,sBAAsB,IAAI,CAAC;AAExC,KAAK,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,EAAE,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC;AAE/F,sFAAsF;AACtF,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;CACnC;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,OAAO,mBAAmB,CAAC;IAC1C,QAAQ,CAAC,OAAO,EAAE,OAAO,sBAAsB,CAAC;IAChD,QAAQ,CAAC,OAAO,EAAE;QAAE,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IACjF,6DAA6D;IAC7D,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;CAC/E;AAqBD,gGAAgG;AAChG,wBAAgB,aAAa,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC,EAAE,OAAO,EAAE,yBAAyB,GAAG,aAAa,CAcpI;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC,EACnD,OAAO,EAAE,yBAAyB,GACjC;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAA;CAAE,CAGxF"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The media manifest snapshot (3.15.0): a site whose `src/data/media.ts` is computed (gallery entries spread in from
|
|
3
|
+
* its gallery data, for example) records the manifest as plain JSON, so the ready gate's T6 can read every entry
|
|
4
|
+
* without running the site's code. Like the estate plan snapshot it is deterministic (entries by id, keys sorted, no
|
|
5
|
+
* timestamp) and carries a hash of the files it was written from (`src/data` by default), so T6 fails a stale one.
|
|
6
|
+
*
|
|
7
|
+
* // tests/data/mediaSnapshot.test.ts
|
|
8
|
+
* import { writeMediaSnapshot } from '@brandlab-digital/conformance/media-snapshot'
|
|
9
|
+
* import { media } from '@/data/media'
|
|
10
|
+
*
|
|
11
|
+
* it('records the media manifest for the ready gate', () => {
|
|
12
|
+
* const { changed } = writeMediaSnapshot(media, { projectRoot: process.cwd() })
|
|
13
|
+
* if (process.env.CI) expect(changed).toBe(false)
|
|
14
|
+
* })
|
|
15
|
+
*
|
|
16
|
+
* Node only: it reads and writes files.
|
|
17
|
+
*/
|
|
18
|
+
import { estatePlanSourceHash, snapshotSourcePaths, writeSnapshotFile } from "./estate-snapshot.js";
|
|
19
|
+
/** Where the snapshot lives, relative to the project root. */
|
|
20
|
+
export const MEDIA_SNAPSHOT_FILE = "src/data/media.generated.json";
|
|
21
|
+
export const MEDIA_SNAPSHOT_KIND = "brandlab-media-snapshot";
|
|
22
|
+
export const MEDIA_SNAPSHOT_VERSION = 1;
|
|
23
|
+
function byKey(entries) {
|
|
24
|
+
return entries.sort(([left], [right]) => (left < right ? -1 : left > right ? 1 : 0));
|
|
25
|
+
}
|
|
26
|
+
/** Plain JSON with sorted keys; values JSON cannot hold (undefined, functions) are left out. */
|
|
27
|
+
function canonical(value) {
|
|
28
|
+
if (value === null || typeof value === "string" || typeof value === "boolean")
|
|
29
|
+
return value;
|
|
30
|
+
if (typeof value === "number")
|
|
31
|
+
return Number.isFinite(value) ? value : undefined;
|
|
32
|
+
if (Array.isArray(value))
|
|
33
|
+
return value.map((item) => canonical(item) ?? null);
|
|
34
|
+
if (typeof value === "object") {
|
|
35
|
+
const entries = Object.entries(value).flatMap(([key, item]) => {
|
|
36
|
+
const plain = canonical(item);
|
|
37
|
+
return plain === undefined ? [] : [[key, plain]];
|
|
38
|
+
});
|
|
39
|
+
return Object.fromEntries(byKey(entries));
|
|
40
|
+
}
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
/** The snapshot for a media manifest: every entry in canonical form, with the sources' hash. */
|
|
44
|
+
export function mediaSnapshot(media, options) {
|
|
45
|
+
const paths = snapshotSourcePaths(options.sources);
|
|
46
|
+
const entries = byKey(Object.entries(media).map(([id, entry]) => {
|
|
47
|
+
if (!entry || typeof entry.src !== "string" || entry.src === "")
|
|
48
|
+
throw new Error(`media.${id} has no src.`);
|
|
49
|
+
return [id, canonical(entry)];
|
|
50
|
+
}));
|
|
51
|
+
return {
|
|
52
|
+
kind: MEDIA_SNAPSHOT_KIND,
|
|
53
|
+
version: MEDIA_SNAPSHOT_VERSION,
|
|
54
|
+
sources: { paths, sha256: estatePlanSourceHash(options.projectRoot, paths) },
|
|
55
|
+
media: Object.fromEntries(entries),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Writes `src/data/media.generated.json` when its content differs; `changed` says whether it did. Run it from the
|
|
60
|
+
* site's tests so the snapshot follows media.ts, and commit the file.
|
|
61
|
+
*/
|
|
62
|
+
export function writeMediaSnapshot(media, options) {
|
|
63
|
+
const snapshot = mediaSnapshot(media, options);
|
|
64
|
+
return { ...writeSnapshotFile(options.projectRoot, MEDIA_SNAPSHOT_FILE, `${JSON.stringify(snapshot, null, 2)}\n`), snapshot };
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=media-snapshot.js.map
|