diff --git a/.prettierignore b/.prettierignore index 3084333940..290784db84 100644 --- a/.prettierignore +++ b/.prettierignore @@ -18,6 +18,8 @@ __pycache__/ /source/npm/qsharp/lib/ /source/npm/qsharp/src/*.generated.* /source/npm/qsharp/test/**/*.snapshot.* +/source/npm/qsharp/rz-array.json +/source/npm/qsharp/rz-details.json /source/pip/ /source/pip/src/**/*.html /source/qdk_package/ diff --git a/package-lock.json b/package-lock.json index b90ca7341d..4d4f5cbf73 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,7 @@ "@types/markdown-it": "^14.1.2", "@types/mocha": "^10.0.10", "@types/node": "^22.14", + "@types/three": "^0.184.1", "@types/vscode": "1.100.0", "@types/vscode-webview": "^1.57.5", "@vscode/codicons": "^0.0.45", @@ -46,6 +47,7 @@ "preact": "^10.29.1", "prettier": "^3.8.1", "punycode": "^2.3.1", + "three": "^0.184.0", "typescript": "5.6.3", "typescript-eslint": "^8.58.2", "url": "^0.11.4", @@ -380,6 +382,13 @@ "node": ">=20.19.0" } }, + "node_modules/@dimforge/rapier3d-compat": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@dimforge/rapier3d-compat/-/rapier3d-compat-0.12.0.tgz", + "integrity": "sha512-uekIGetywIgopfD97oDL5PfeezkFpNhwlzlaEYNOA0N6ghdsOvh/HYjSMek5Q2O1PYvRSDFcqFVJl4r4ZBwOow==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.26.0", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.26.0.tgz", @@ -1804,6 +1813,13 @@ "node": ">=18" } }, + "node_modules/@tweenjs/tween.js": { + "version": "23.1.3", + "resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-23.1.3.tgz", + "integrity": "sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/chai": { "version": "5.2.3", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", @@ -1892,6 +1908,28 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/stats.js": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.4.tgz", + "integrity": "sha512-jIBvWWShCvlBqBNIZt0KAshWpvSjhkwkEu4ZUcASoAvhmrgAUI2t1dXrjSL4xXVLB4FznPrIsX3nKXFl/Dt4vA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/three": { + "version": "0.184.1", + "resolved": "https://registry.npmjs.org/@types/three/-/three-0.184.1.tgz", + "integrity": "sha512-6q4VdiqVsrTRqmk62/BnlcAvIrnDM0zf2ZDVKI5kZiniWrSaOHaQzmbp+BNzoggc/8tgW412pL//wZIxu2PPTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@dimforge/rapier3d-compat": "~0.12.0", + "@tweenjs/tween.js": "~23.1.3", + "@types/stats.js": "*", + "@types/webxr": ">=0.5.17", + "fflate": "~0.8.2", + "meshoptimizer": "~1.1.1" + } + }, "node_modules/@types/trusted-types": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", @@ -1914,6 +1952,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/webxr": { + "version": "0.5.24", + "resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.24.tgz", + "integrity": "sha512-h8fgEd/DpoS9CBrjEQXR+dIDraopAEfu4wYVNY2tEPwk60stPWhvZMf4Foo5FakuQ7HFZoa8WceaWFervK2Ovg==", + "dev": true, + "license": "MIT" + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "8.58.2", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.58.2.tgz", @@ -3608,6 +3653,13 @@ } } }, + "node_modules/fflate": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.3.tgz", + "integrity": "sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==", + "dev": true, + "license": "MIT" + }, "node_modules/file-entry-cache": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", @@ -4688,6 +4740,13 @@ "node": ">= 0.8" } }, + "node_modules/meshoptimizer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/meshoptimizer/-/meshoptimizer-1.1.1.tgz", + "integrity": "sha512-oRFNWJRDA/WTrVj7NWvqa5HqE1t9MYDj2VaWirQCzCCrAd2GHrqR/sQezCxiWATPNlKTcRaPRHPJwIRoPBAp5g==", + "dev": true, + "license": "MIT" + }, "node_modules/mime-db": { "version": "1.54.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", @@ -6099,6 +6158,13 @@ "b4a": "^1.6.4" } }, + "node_modules/three": { + "version": "0.184.0", + "resolved": "https://registry.npmjs.org/three/-/three-0.184.0.tgz", + "integrity": "sha512-wtTRjG92pM5eUg/KuUnHsqSAlPM296brTOcLgMRqEeylYTh/CdtvKUvCyyCQTzFuStieWxvZb8mVTMvdPyUpxg==", + "dev": true, + "license": "MIT" + }, "node_modules/through2": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", diff --git a/package.json b/package.json index e239dca4d9..59b4325a63 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "@types/markdown-it": "^14.1.2", "@types/mocha": "^10.0.10", "@types/node": "^22.14", + "@types/three": "^0.184.1", "@types/vscode": "1.100.0", "@types/vscode-webview": "^1.57.5", "@vscode/codicons": "^0.0.45", @@ -51,6 +52,7 @@ "preact": "^10.29.1", "prettier": "^3.8.1", "punycode": "^2.3.1", + "three": "^0.184.0", "typescript": "5.6.3", "typescript-eslint": "^8.58.2", "url": "^0.11.4", diff --git a/source/npm/qsharp/package.json b/source/npm/qsharp/package.json index 50fcbbe4d4..46ba3ee1dc 100644 --- a/source/npm/qsharp/package.json +++ b/source/npm/qsharp/package.json @@ -24,7 +24,8 @@ "./katas-md": "./dist/katas-md.js", "./state-viz": "./ux/circuit-vis/state-viz/worker/index.ts", "./ux": "./ux/index.ts", - "./qdk-theme.css": "./ux/qdk-theme.css" + "./qdk-theme.css": "./ux/qdk-theme.css", + "./rz-array.json": "./rz-array.json" }, "scripts": { "build": "npm run docs && npm run generate && npm run build:tsc && npm run build:ux", @@ -34,7 +35,8 @@ "build:tsc": "node ../../../node_modules/typescript/bin/tsc -p ./src/tsconfig.json", "build:ux": "node ../../../node_modules/typescript/bin/tsc -p ./ux/tsconfig.json", "tsc:watch": "node ../../../node_modules/typescript/bin/tsc -p ./src/tsconfig.json --watch --preserveWatchOutput", - "test": "node --test" + "test": "node --test", + "rz": "node ../../../node_modules/typescript/bin/tsc -p ./tools/tsconfig.json && node ./dist/tools/rz-synthesis.js" }, "type": "module", "files": [ diff --git a/source/npm/qsharp/rz-array.json b/source/npm/qsharp/rz-array.json new file mode 100644 index 0000000000..b5a7eddfcc --- /dev/null +++ b/source/npm/qsharp/rz-array.json @@ -0,0 +1,1258 @@ +[ + "", + "HtHtHTHTHTHTHtHtHTHTHtHtHTHtHTHTHTHtHTHtHTHTHtHtHTHTHtHtHtHtHtHtHX", + "HtHTHTHTHTHtHtHtHtHtHtHTHTHtHTHtHtHTHTHtHtHTHtHtHtHTHtHtHtHtHtHtHXST", + "HTHTHtHtHtHTHtHtHtHtHTHtHtHtHtHTHtHtHtHTHtHtHtHtHTHtHtHTHS", + "HTHTHTHTHTHtHTHTHTHTHTHtHtHTHtHTHTHTHTHtHtHTHtHTHtHtHtHTHtHTHtHST", + "HtHtHTHtHtHTHtHtHtHtHtHTHtHtHtHTHtHtHtHtHtHTHtHtHTHtHtHST", + "HtHTHTHTHTHtHTHTHTHTHtHTHtHTHtHTHTHTHTHTHTHTHtHtHtHtHTHtHtHs", + "HTHTHtHtHtHtHtHTHtHtHtHTHtHTHTHtHtHtHTHtHtHtHTHtHtHTHtHtHtHTHtHs", + "HTHTHTHTHtHtHTHtHTHtHTHtHTHtHTHtHtHTHtHTHtHtHtHTHtHtHtHTHtHtHtHt", + "HTHTHtHtHTHTHTHTHtHTHTHTHtHTHTHTHtHtHTHtHTHtHTHTHTHtHtHTHtHZ", + "HtHTHTHTHTHtHtHtHtHTHTHTHTHtHtHtHtHTHtHTHtHtHTHtHTHtHtHTHtHtHXZT", + "HTHTHTHTHtHtHtHTHTHTHtHTHTHTHTHTHTHTHtHTHTHTHtHtHtHTHTHTHTH", + "HtHtHTHTHtHtHTHTHTHTHTHtHtHTHtHtHtHTHtHtHTHTHTHTHtHTHTHTHTHTHTHXST", + "HtHtHTHTHTHtHtHtHtHTHTHTHTHTHTHtHtHTHtHTHtHtHtHTHtHTHtHTHTHtHtHXt", + "HTHTHTHTHTHtHtHTHtHTHtHtHTHTHTHtHtHTHtHTHtHTHtHtHtHTHTHTHTHXs", + "HtHtHTHTHTHTHtHtHTHTHTHtHTHtHtHTHtHTHTHTHtHtHTHTHTHTHtHtH", + "HtHTHtHTHtHtHTHtHTHTHTHTHTHtHTHTHtHtHtHTHTHTHtHTHtHtHTHtHtHtHtHt", + "HTHTHTHtHtHtHTHTHTHTHtHtHTHTHtHtHTHTHtHtHtHtHTHTHTHtHtHtHXZ", + "HtHTHtHtHTHTHTHTHTHTHTHTHtHTHTHTHtHtHtHTHtHTHTHTHTHTHTHtHtHTHXS", + "HTHtHtHTHTHtHtHtHTHTHtHTHTHtHTHtHtHtHtHtHTHTHtHTHtHTHtHTHtHtHtHZT", + "HtHtHTHTHtHtHtHtHTHTHtHtHtHtHtHTHTHtHTHtHtHtHXs", + "HtHtHTHTHTHTHTHtHTHTHTHtHtHtHTHTHtHTHtHTHTHtHtHTHTHtHtHtHtHtHtHtHs", + "HTHtHtHTHTHtHTHtHTHTHtHtHtHTHTHtHtHtHtHtHtHTHtHtHtHTHtHtHtHZ", + "HtHTHTHTHtHtHtHTHTHtHTHtHtHtHTHtHTHTHtHtHtHtHTHtHTHtHtHtHXs", + "HTHtHtHTHTHtHTHtHTHtHTHtHtHTHtHTHtHTHtHTHtHTHTHtHTHTHtHtHtH", + "HtHTHTHtHtHtHtHtHTHTHtHTHtHtHTHTHtHtHtHTHTHtHtHtHTHtHTHTHtHtHtHXZT", + "HTHTHTHtHtHtHTHtHTHtHTHtHtHtHTHTHTHtHTHtHTHtHTHTHTHtHtHtHXT", + "HTHtHtHtHTHTHtHtHtHTHtHtHtHtHtHtHtHtHTHtHtHTHtHTHtHtHtHtHtHtHtHtHt", + "HTHTHTHTHtHtHTHTHtHTHTHTHTHTHTHTHtHtHTHTHTHTHtHTHtHtHtHtHtHTH", + "HTHTHtHtHTHTHTHtHTHtHTHTHtHtHtHTHTHtHtHTHtHTHtHtHTHtHTHtHtHtHXT", + "HTHTHTHTHTHTHtHTHtHtHTHtHTHtHTHtHTHtHTHtHtHTHtHTHTHTHTHTHTHs", + "HtHTHtHtHTHTHTHtHTHTHtHTHTHTHTHtHtHtHTHTHtHTHTHtHtHtHtHTHtHTHXZ", + "HTHtHTHtHtHtHtHtHTHtHtHtHtHTHtHtHtHTHtHTHTHTHtHTHTHTHtHtHtHtHtHXs", + "HtHtHTHtHtHtHtHtHTHTHtHTHtHTHTHtHTHtHTHTHtHtHtHtHtHTHtHtHST", + "HTHTHtHTHtHTHtHTHtHTHtHTHtHTHtHTHTHtHTHtHtHTHTHTHtHtHtHtHtHtHtHtHt", + "HtHtHTHTHtHTHtHTHTHTHtHTHTHTHtHTHtHtHTHTHtHtHTHtHTHtHTHtHtHXST", + "HTHTHtHTHtHtHTHTHtHTHtHtHtHTHtHtHtHTHtHTHTHtHtHTHtHTHTHST", + "HtHTHTHTHTHTHTHTHtHtHTHtHTHtHTHtHTHTHtHTHtHtHTHTHTHtHtHtHtHXZ", + "HTHTHTHtHtHTHTHTHTHtHTHtHTHTHtHTHTHTHtHtHtHtHtHTHtHTHTHtHtHTHtHZT", + "HTHTHtHtHTHtHTHtHTHtHtHtHTHtHTHtHTHTHTHtHTHtHTHtHTHTHtHtHXT", + "HTHtHtHtHtHTHtHTHTHtHtHTHTHTHTHTHTHtHtHTHTHtHTHtHtHtHtHTHs", + "HTHtHTHTHTHtHtHTHtHtHtHTHtHtHtHTHTHtHTHTHTHtHTHTHTHtHtHTHtHtHtHT", + "HtHtHTHTHTHtHtHTHTHTHTHTHTHTHTHTHTHTHTHTHtHtHTHTHTHtHtH", + "HtHTHtHTHTHTHtHtHtHTHTHtHTHTHtHTHTHtHtHTHtHtHtHtHtHTHTHTHXZ", + "HtHtHTHtHTHTHTHtHTHtHTHtHTHTHTHtHtHTHTHtHtHTHtHTHtHtHtHtHXZ", + "HTHTHtHtHTHtHtHtHTHtHtHTHTHtHTHTHtHtHTHtHTHtHTHtHTHTHTHTHtHtHtH", + "HtHTHTHtHtHtHtHTHtHtHtHTHtHtHtHtHtHTHTHtHtHtHTHTHTHTHTHTHTHXS", + "HtHTHTHtHtHTHtHTHtHtHtHtHtHTHTHtHtHTHtHtHTHtHTHtHTHTHTHtHTHtHtHt", + "HTHTHtHtHTHTHTHTHTHTHTHTHtHTHtHtHtHTHTHtHtHtHtHTHtHTHTHTHTHTHTHZ", + "HtHTHTHTHtHtHtHTHTHTHtHtHtHTHtHTHtHTHTHtHTHTHtHtHTHtHtHtHtHXs", + "HTHtHTHtHTHTHTHTHtHtHTHTHtHtHTHTHtHtHTHTHtHtHTHtHTHTHTHTHTHXt", + "HTHtHtHTHTHTHtHTHtHTHTHtHtHtHTHTHtHtHTHTHtHTHtHTHTHtHTHtHtHtHZT", + "HtHTHTHtHTHTHTHTHtHtHTHTHtHTHTHTHTHtHtHtHtHtHTHTHtHtHtHTHtHtHs", + "HTHTHTHtHtHtHtHtHTHTHTHTHtHtHTHtHtHtHTHTHtHTHtHtHTHtHTHtHtHTHtHS", + "HTHTHTHtHTHTHtHTHTHTHTHTHtHtHtHTHtHtHtHtHtHTHTHtHTHTHTHXS", + "HtHTHtHtHTHTHtHTHtHtHtHtHtHTHtHTHtHTHtHtHtHtHTHTHtHTHTHtHtHtHtHT", + "HtHtHTHtHTHTHTHTHTHtHTHTHTHTHtHTHtHTHTHtHtHtHTHTHtHTHTHTHTHTHTHTHXZ", + "HTHTHTHtHTHTHtHtHTHtHtHTHtHtHtHtHtHtHTHTHTHtHTHTHtHTHtHtHtHtHt", + "HtHtHTHTHTHtHtHtHTHtHTHTHTHtHtHtHtHTHTHtHtHTHtHtHtHtHtHtHtHTHtHXST", + "HtHTHtHtHTHtHtHTHTHtHTHTHTHTHtHTHTHTHTHtHTHTHtHtHTHtHtHTHtHs", + "HtHTHTHTHtHTHtHtHTHtHtHtHTHTHTHtHTHtHtHTHtHtHTHTHTHTHtHtHtHtHtHT", + "HtHtHtHtHtHTHtHTHTHtHtHtHTHTHtHtHTHTHTHtHtHTHtHTHTHTHTHTHXS", + "HTHTHTHtHtHtHtHTHtHtHtHTHtHtHTHtHtHtHTHTHTHtHTHTHTHtHTHtHtHTHtHt", + "HTHTHTHTHtHtHtHTHTHTHTHtHTHtHTHTHTHTHtHtHTHTHtHTHtHTHtHTHtHtHZT", + "HTHtHtHtHTHtHtHtHtHtHTHtHtHtHTHtHTHtHTHTHtHtHTHtHtHTHTHtHtHXs", + "HtHtHtHTHTHTHTHtHtHtHTHTHTHtHtHtHtHtHTHTHtHtHTHtHTHtHtHtHtHZT", + "HtHTHTHtHTHtHtHtHTHTHtHTHTHtHTHtHTHtHTHTHtHTHTHtHtHtHTHtHTHTHtHZT", + "HtHtHtHTHtHtHtHtHtHtHtHtHtHTHtHtHtHTHtHtHtHtHtHtHtHtHtHTHtHtHtHZT", + "HTHtHtHTHtHtHTHTHtHTHtHTHTHTHtHTHTHTHTHtHtHtHtHTHtHTHtHtHtHtHtHtHT", + "HTHTHtHTHtHtHTHtHtHTHtHtHtHTHTHTHtHtHtHTHtHtHtHtHtHtHtHTHtHTHtHZT", + "HtHTHtHtHTHTHTHTHtHTHtHTHtHTHtHtHtHtHTHTHtHTHX", + "HTHtHtHTHTHtHTHtHtHtHtHTHtHtHTHtHTHTHTHTHtHTHTHtHTHtHtHtHtHtHtHXST", + "HTHtHtHTHtHTHtHTHtHTHtHtHTHtHTHtHTHTHtHTHTHTHTHtHTHtHtHtHXs", + "HtHtHTHTHTHtHTHTHtHtHTHtHTHtHtHTHtHTHtHtHTHTHtHTHTHTHtHtHZ", + "HTHtHtHtHTHtHtHTHTHTHTHtHTHTHTHTHtHTHTHTHTHtHtHTHtHtHtHTHs", + "HtHtHTHtHtHTHtHtHtHTHtHtHtHTHTHTHTHTHtHtHTHtHTHtHtHTHTHST", + "HTHTHtHTHTHtHTHtHTHTHTHtHtHtHTHTHtHtHtHTHtHTHtHtHTHTHTHtHtHTHtHs", + "HtHtHtHtHTHTHtHtHtHTHtHTHTHTHtHtHtHtHTHtHTHTHtHtHTHTHtHTHTHtHtHX", + "HTHTHtHtHTHTHTHTHTHtHTHTHtHtHTHtHTHtHTHTHTHtHTHTHtHTHtHTHtHtHXS", + "HTHtHtHTHTHtHTHtHTHTHTHtHtHTHTHTHTHTHTHtHTHTHTHtHtHtHtHtHtHTHST", + "HtHtHTHTHtHTHTHtHtHTHTHtHTHtHtHtHtHTHTHTHtHTHtHtHtHTHTHtHtHtHtHXT", + "HTHtHtHtHTHTHTHTHTHtHTHTHtHTHTHtHtHTHtHtHtHtHtHTHTHtHTHTHtHtHtHST", + "HtHtHTHTHtHTHtHTHTHtHtHtHtHtHTHTHTHtHTHTHTHtHTHTHtHTHTHs", + "HTHTHtHTHTHTHtHtHTHtHTHTHTHtHTHtHtHtHTHtHTHTHtHtHtHTHtHtHXt", + "HtHTHTHtHTHTHTHtHtHTHTHTHTHTHtHtHtHtHtHTHTHtHtHtHTHtHtHTHXT", + "HtHTHTHtHTHtHTHtHTHtHTHTHtHTHtHTHtHtHTHtHtHtHtHTHtHTHTHTHXST", + "HtHTHTHtHtHTHtHTHTHTHTHtHTHTHtHTHtHtHtHtHTHtHtHTHtHTHTHTHTHTHTHXs", + "HtHtHtHTHTHtHTHtHtHtHtHtHtHtHtHTHtHTHTHtHtHtHZT", + "HTHtHtHtHtHTHTHTHtHtHtHTHtHtHTHtHtHTHtHtHtHTHtHTHtHTHtHtHtHtHtHZ", + "HTHtHtHtHtHTHTHTHtHtHtHtHTHtHTHTHtHTHTHTHTHtHtHTHtHtHTHtHtHtHtHtH", + "HtHTHtHtHtHTHtHTHtHTHtHTHtHtHtHTHtHtHtHTHtHTHtHTHtHTHtHtHtHTHtHZ", + "HtHtHTHTHTHTHtHTHTHtHtHtHTHTHTHTHTHTHTHtHtHtHTHTHtHTHTHTHTHtHtHZ", + "HTHTHTHtHtHtHtHTHTHTHtHtHtHTHTHTHTHTHtHtHTHTHtHTHtHTHTHTHTHZ", + "HTHtHtHTHTHtHtHtHTHTHtHtHtHtHtHtHTHtHtHtHTHtHTHtHtHtHTHtHtHXST", + "HTHTHtHTHtHTHtHTHtHtHTHTHtHtHtHtHTHtHTHtHtHtHtHTHTHTHtHtHtHtHZ", + "HTHtHTHTHtHTHtHtHtHTHtHtHtHTHTHTHtHTHTHtHTHTHTHtHTHTHTHTHtHtHtHS", + "HtHTHtHTHTHTHTHTHTHtHTHtHtHtHtHTHTHtHtHTHTHtHTHtHTHTHtHtHtHtHtHtHXS", + "HtHTHtHTHtHtHTHtHTHTHtHtHtHTHTHTHTHtHTHTHtHTHTHTHtHtHtHtHTHtHtH", + "HtHtHtHTHTHTHtHtHTHTHTHtHTHtHtHtHTHtHTHTHTHtHtHTHTHTHtHtHtHST", + "HtHTHTHtHTHTHtHTHTHTHTHtHTHTHtHTHtHtHTHTHtHtHtHTHtHTHtHTHtHtHtHXs", + "HTHTHTHTHtHTHtHtHTHtHtHtHTHTHTHTHTHTHtHTHTHtHTHTHtHtHTHtHtHtHS", + "HTHTHtHTHtHtHtHtHtHTHtHtHtHtHTHtHTHtHtHTHTHTHtHtHTHtHtHtHtHtHtHtHXZT", + "HtHTHtHTHTHtHtHtHTHTHtHTHtHtHtHtHtHtHtHTHtHTHtHtHtHtHTHTHtHtHtH", + "HTHTHTHtHTHTHtHtHtHtHtHTHtHtHtHTHTHTHTHTHtHTHTHtHTHTHTHXt", + "HTHtHTHTHtHTHtHTHTHtHTHtHtHTHTHTHtHTHTHtHtHtHtHTHTHTHTHTHtHtHtHt", + "HtHTHtHtHTHtHTHTHtHtHtHtHTHTHTHTHtHTHtHTHTHTHtHtHTHtHTHtHtHtHs", + "HTHTHtHTHTHtHTHTHTHtHTHTHtHtHTHtHtHtHTHTHtHtHtHTHtHTHTHtHtHtHXt", + "HtHTHtHTHtHtHtHtHTHTHtHtHTHTHtHtHTHTHtHtHTHTHtHTHtHtHtHtHtHXS", + "HTHtHtHtHTHTHTHtHtHtHTHTHTHtHTHtHTHtHtHTHtHtHTHTHtHTHTHTHTHXST", + "HtHtHTHTHtHtHtHtHtHtHtHtHTHtHTHTHTHtHtHTHTHTHTHtHTHtHtHtHtHtHtHZT", + "HtHTHTHTHTHtHTHTHTHTHTHTHtHtHtHTHTHtHtHTHtHTHtHtHtHtHtHTHTHtHtHS", + "HTHtHtHTHTHTHTHtHTHTHTHtHTHTHTHTHTHtHtHTHTHTHtHtHtHtHtHtHtHXt", + "HTHTHTHtHtHtHtHTHtHTHtHTHtHTHTHtHtHTHtHtHTHTHtHTHTHTHtHTHTHtHtHT", + "HTHTHtHTHtHtHtHTHtHTHtHTHtHtHtHTHTHtHtHTHTHtHTHtHTHTHTHTHXZT", + "HtHTHtHtHTHtHTHtHtHtHTHTHtHtHtHTHTHTHtHtHTHtHtHTHtHtHtHtHT", + "HTHTHtHtHtHTHTHtHtHtHtHtHtHtHtHtHtHtHtHtHTHTHtHtHtHTHTHT", + "HTHTHTHtHTHTHtHtHtHTHtHtHtHTHtHtHTHTHTHtHTHTHTHtHTHTHtHtHtHTHtH", + "HTHTHtHTHtHtHtHtHTHTHtHtHTHtHTHtHTHTHtHtHTHTHTHTHtHTHtHtHXt", + "HTHtHtHTHTHTHTHTHTHTHtHTHTHTHTHTHTHtHTHTHTHTHTHTHTHtHtHTHZ", + "HTHtHTHTHtHtHTHtHTHTHTHTHTHtHtHtHTHtHtHTHtHTHtHtHtHtHTHTHtHtHtHZ", + "HTHtHtHtHtHtHtHtHTHTHtHTHtHTHtHTHtHtHTHtHTHTHtHtHtHTHTHTHTHXZT", + "HtHtHTHtHTHTHtHtHTHtHTHTHTHtHTHTHTHtHTHtHtHTHTHtHTHtHtHs", + "HtHtHTHtHTHtHTHtHtHTHTHtHtHTHtHTHTHTHtHTHTHTHtHTHtHTHTHtHtHXs", + "HtHtHTHtHTHtHTHtHTHtHTHtHTHtHTHtHtHTHtHTHTHtHtHtHTHTHTHTHTHTHTHTHS", + "HtHTHTHTHtHTHtHTHTHtHtHtHtHtHTHTHTHTHTHtHtHTHtHTHtHtHtHTHXS", + "HTHTHTHtHTHtHTHTHTHtHTHtHtHtHTHtHtHTHTHTHTHtHTHTHtHtHTHtHtHtHtHS", + "HtHtHtHTHTHtHTHTHTHtHtHtHTHtHTHTHtHTHTHtHtHtHTHTHtHTHtHtHtHtHT", + "HtHtHtHtHtHtHTHtHTHTHtHTHtHTHtHTHtHTHtHTHTHtHTHtHtHtHtHtHtHST", + "HTHtHTHTHTHTHTHtHtHtHtHtHTHTHtHtHTHtHtHTHTHTHTHTHtHTHTHtHtHTHZ", + "HtHTHTHTHTHTHtHTHtHtHtHtHTHTHtHtHtHtHtHtHtHTHtHtHTHTHtHtHtHtHT", + "HtHTHTHTHtHtHTHTHTHtHTHTHTHTHTHTHTHTHtHTHTHtHTHtHTHTHTHTHTHTHTHTHS", + "HtHtHtHTHTHTHtHTHtHTHtHTHTHTHtHtHtHTHtHTHtHTHtHtHtHTHTHTHX", + "HtHtHTHTHtHTHtHTHTHtHtHtHtHTHTHtHtHTHtHtHTHTHtHTHTHTHTHtHtHTHtHXZ", + "HTHTHtHtHTHTHTHTHTHTHTHTHtHtHtHtHtHtHtHtHtHtHTHTHTHtHtHTHtHT", + "HTHtHtHtHTHTHTHtHtHTHtHTHTHTHtHTHtHtHTHTHTHTHtHTHtHTHTHTHXST", + "HTHTHtHtHTHTHTHTHTHtHtHTHtHtHTHTHtHTHtHTHtHtHtHTHtHtHtHTHtHZT", + "HTHTHtHtHtHtHtHTHtHtHtHTHTHTHtHtHTHtHTHtHtHTHTHtHtHTHTHTHTHTHTHTHST", + "HtHtHtHTHtHTHTHtHtHtHtHtHTHTHtHtHtHtHTHTHtHtHXST", + "HTHTHtHtHTHTHtHTHTHtHtHtHTHTHTHTHtHTHtHTHTHtHtHtHtHtHtHtHtHTHtHZ", + "HtHtHTHTHtHTHtHTHtHtHtHtHTHtHtHTHtHtHtHTHtHTHtHTHtHTHTHtHtHtHST", + "HtHtHtHTHTHTHtHtHtHtHTHTHtHtHTHTHtHtHTHTHTHTHtHtHtHTHTHTHXZT", + "HtHTHtHTHTHTHtHtHtHtHTHtHtHTHtHtHTHTHTHtHTHtHTHTHTHTHtHtHtHtHtHS", + "HtHTHTHtHTHtHtHTHTHtHTHTHTHTHtHtHtHtHTHtHtHTHTHtHTHtHtHTHXZT", + "HTHTHTHTHtHtHtHTHtHTHtHTHtHtHTHTHTHtHtHTHtHTHtHtHTHTHTHTHTHXST", + "HtHtHTHtHTHTHTHtHTHTHTHtHTHtHtHtHtHtHTHTHTHTHTHtHtHtHTHtHtHtHtHtHX", + "HTHTHtHtHTHTHtHtHtHtHtHTHTHtHTHTHTHtHTHTHtHtHtHtHTHtHtHtHtHtHtHXs", + "HtHtHtHtHTHTHTHtHtHtHTHtHtHtHtHtHtHtHTHtHtHtHTHTHTHtHtHtHtHT", + "HTHtHtHtHTHTHTHTHTHtHtHtHtHtHTHtHTHTHtHTHtHtHTHtHTHTHtHTHtHtH", + "HTHtHtHTHTHtHTHtHtHtHTHtHtHtHTHtHtHTHTHTHTHTHTHtHTHTHtHtHtHZT", + "HTHTHTHtHTHTHTHtHTHTHTHtHTHtHTHTHtHTHtHTHtHTHtHTHtHTHTHtHtHtHtHS", + "HTHtHtHTHtHTHtHtHtHTHtHtHtHtHTHTHtHTHTHTHtHTHTHTHtHtHtHTHtHtHtHST", + "HtHTHTHTHtHTHtHtHTHtHTHtHTHtHtHtHtHtHtHtHTHtHTHTHTHtHTHtHtHST", + "HTHTHtHTHTHtHTHTHTHTHTHtHTHTHTHtHTHTHTHTHTHtHTHTHtHTHTHs", + "HTHtHTHtHTHTHTHtHTHtHTHTHtHtHtHtHTHtHTHTHtHtHtHtHtHTHtHtHtHtHtHs", + "HTHtHtHTHtHtHtHTHtHTHTHTHtHTHtHtHtHTHtHtHtHTHtHTHTHTHtHtHXST", + "HTHTHtHTHTHtHtHTHTHtHtHtHTHtHTHtHtHTHTHtHTHtHTHtHtHTHTHtHtHtHtHXt", + "HtHtHtHTHtHTHTHtHtHTHTHtHTHtHtHtHtHtHtHtHtHtHtHTHTHTHtHtHtHtHtHtH", + "T", + "HtHtHTHTHTHTHtHtHTHTHtHtHTHtHTHTHTHtHTHtHTHTHtHtHTHTHtHtHtHtHtHtHXT", + "HtHTHTHTHTHtHtHtHtHtHtHTHTHtHTHtHtHTHTHtHtHTHtHtHtHTHtHtHtHtHtHtHXZ", + "HTHTHtHtHtHTHtHtHtHtHTHtHtHtHtHTHtHtHtHTHtHtHtHtHTHtHtHTHST", + "HTHTHTHTHTHtHTHTHTHTHTHtHtHTHtHTHTHTHTHtHtHTHtHTHtHtHtHTHtHTHtHZ", + "HtHtHTHtHtHTHtHtHtHtHtHTHtHtHtHTHtHtHtHtHtHTHtHtHTHtHtHZ", + "HtHTHTHTHTHtHTHTHTHTHtHTHtHTHtHTHTHTHTHTHTHTHtHtHtHtHTHtHtHt", + "HTHTHtHtHtHtHtHTHtHtHtHTHtHTHTHtHtHtHTHtHtHtHTHtHtHTHtHtHtHTHtHt", + "HTHTHTHTHtHtHTHtHTHtHTHtHTHtHTHtHtHTHtHTHtHtHtHTHtHtHtHTHtHtHtH", + "HTHTHtHtHTHTHTHTHtHTHTHTHtHTHTHTHtHtHTHtHTHtHTHTHTHtHtHTHtHZT", + "HtHTHTHTHTHtHtHtHtHTHTHTHTHtHtHtHtHTHtHTHtHtHTHtHTHtHtHTHtHtHXs", + "HTHTHTHTHtHtHtHTHTHTHtHTHTHTHTHTHTHTHtHTHTHTHtHtHtHTHTHTHTHT", + "HtHtHTHTHtHtHTHTHTHTHTHtHtHTHtHtHtHTHtHtHTHTHTHTHtHTHTHTHTHTHTHXZ", + "HtHtHTHTHTHtHtHtHtHTHTHTHTHTHTHtHtHTHtHTHtHtHtHTHtHTHtHTHTHtHtHX", + "HTHTHTHTHTHtHtHTHtHTHtHtHTHTHTHtHtHTHtHTHtHTHtHtHtHTHTHTHTHXt", + "HtHtHTHTHTHTHtHtHTHTHTHtHTHtHtHTHtHTHTHTHtHtHTHTHTHTHtHtHT", + "HtHTHtHTHtHtHTHtHTHTHTHTHTHtHTHTHtHtHtHTHTHTHtHTHtHtHTHtHtHtHtH", + "HTHTHTHtHtHtHTHTHTHTHtHtHTHTHtHtHTHTHtHtHtHtHTHTHTHtHtHtHXZT", + "HtHTHtHtHTHTHTHTHTHTHTHTHtHTHTHTHtHtHtHTHtHTHTHTHTHTHTHtHtHTHXST", + "HTHtHtHTHTHtHtHtHTHTHtHTHTHtHTHtHtHtHtHtHTHTHtHTHtHTHtHTHtHtHtHs", + "HtHtHTHTHtHtHtHtHTHTHtHtHtHtHtHTHTHtHTHtHtHtHXt", + "HtHtHTHTHTHTHTHtHTHTHTHtHtHtHTHTHtHTHtHTHTHtHtHTHTHtHtHtHtHtHtHtHt", + "HTHtHtHTHTHtHTHtHTHTHtHtHtHTHTHtHtHtHtHtHtHTHtHtHtHTHtHtHtHZT", + "HtHTHTHTHtHtHtHTHTHtHTHtHtHtHTHtHTHTHtHtHtHtHTHtHTHtHtHtHXt", + "HTHtHtHTHTHtHTHtHTHtHTHtHtHTHtHTHtHTHtHTHtHTHTHtHTHTHtHtHtHT", + "HtHTHTHtHtHtHtHtHTHTHtHTHtHtHTHTHtHtHtHTHTHtHtHtHTHtHTHTHtHtHtHXs", + "HTHTHTHtHtHtHTHtHTHtHTHtHtHtHTHTHTHtHTHtHTHtHTHTHTHtHtHtHXS", + "HTHtHtHtHTHTHtHtHtHTHtHtHtHtHtHtHtHtHTHtHtHTHtHTHtHtHtHtHtHtHtHtH", + "HTHTHTHTHtHtHTHTHtHTHTHTHTHTHTHTHtHtHTHTHTHTHtHTHtHtHtHtHtHTHT", + "HTHTHtHtHTHTHTHtHTHtHTHTHtHtHtHTHTHtHtHTHtHTHtHtHTHtHTHtHtHtHXS", + "HTHTHTHTHTHTHtHTHtHtHTHtHTHtHTHtHTHtHTHtHtHTHtHTHTHTHTHTHTHt", + "HtHTHtHtHTHTHTHtHTHTHtHTHTHTHTHtHtHtHTHTHtHTHTHtHtHtHtHTHtHTHXZT", + "HTHtHTHtHtHtHtHtHTHtHtHtHtHTHtHtHtHTHtHTHTHTHtHTHTHTHtHtHtHtHtHXt", + "HtHtHTHtHtHtHtHtHTHTHtHTHtHTHTHtHTHtHTHTHtHtHtHtHtHTHtHtHZ", + "HTHTHtHTHtHTHtHTHtHTHtHTHtHTHtHTHTHtHTHtHtHTHTHTHtHtHtHtHtHtHtHtH", + "HtHtHTHTHtHTHtHTHTHTHtHTHTHTHtHTHtHtHTHTHtHtHTHtHTHtHTHtHtHXZ", + "HTHTHtHTHtHtHTHTHtHTHtHtHtHTHtHtHtHTHtHTHTHtHtHTHtHTHTHZ", + "HtHTHTHTHTHTHTHTHtHtHTHtHTHtHTHtHTHTHtHTHtHtHTHTHTHtHtHtHtHXZT", + "HTHTHTHtHtHTHTHTHTHtHTHtHTHTHtHTHTHTHtHtHtHtHtHTHtHTHTHtHtHTHtHs", + "HTHTHtHtHTHtHTHtHTHtHtHtHTHtHTHtHTHTHTHtHTHtHTHtHTHTHtHtHXS", + "HTHtHtHtHtHTHtHTHTHtHtHTHTHTHTHTHTHtHtHTHTHtHTHtHtHtHtHTHt", + "HTHtHTHTHTHtHtHTHtHtHtHTHtHtHtHTHTHtHTHTHTHtHTHTHTHtHtHTHtHtHtHS", + "HtHtHTHTHTHtHtHTHTHTHTHTHTHTHTHTHTHTHTHTHtHtHTHTHTHtHtHT", + "HtHTHtHTHTHTHtHtHtHTHTHtHTHTHtHTHTHtHtHTHtHtHtHtHtHTHTHTHXZT", + "HtHtHTHtHTHTHTHtHTHtHTHtHTHTHTHtHtHTHTHtHtHTHtHTHtHtHtHtHXZT", + "HTHTHtHtHTHtHtHtHTHtHtHTHTHtHTHTHtHtHTHtHTHtHTHtHTHTHTHTHtHtHtHT", + "HtHTHTHtHtHtHtHTHtHtHtHTHtHtHtHtHtHTHTHtHtHtHTHTHTHTHTHTHTHXST", + "HtHTHTHtHtHTHtHTHtHtHtHtHtHTHTHtHtHTHtHtHTHtHTHtHTHTHTHtHTHtHtH", + "HTHTHtHtHTHTHTHTHTHTHTHTHtHTHtHtHtHTHTHtHtHtHtHTHtHTHTHTHTHTHTHZT", + "HtHTHTHTHtHtHtHTHTHTHtHtHtHTHtHTHtHTHTHtHTHTHtHtHTHtHtHtHtHXt", + "HTHtHTHtHTHTHTHTHtHtHTHTHtHtHTHTHtHtHTHTHtHtHTHtHTHTHTHTHTHX", + "HTHtHtHTHTHTHtHTHtHTHTHtHtHtHTHTHtHtHTHTHtHTHtHTHTHtHTHtHtHtHs", + "HtHTHTHtHTHTHTHTHtHtHTHTHtHTHTHTHTHtHtHtHtHtHTHTHtHtHtHTHtHtHt", + "HTHTHTHtHtHtHtHtHTHTHTHTHtHtHTHtHtHtHTHTHtHTHtHtHTHtHTHtHtHTHtHST", + "HTHTHTHtHTHTHtHTHTHTHTHTHtHtHtHTHtHtHtHtHtHTHTHtHTHTHTHXST", + "HtHTHtHtHTHTHtHTHtHtHtHtHtHTHtHTHtHTHtHtHtHtHTHTHtHTHTHtHtHtHtHS", + "HtHtHTHtHTHTHTHTHTHtHTHTHTHTHtHTHtHTHTHtHtHtHTHTHtHTHTHTHTHTHTHTHXZT", + "HTHTHTHtHTHTHtHtHTHtHtHTHtHtHtHtHtHtHTHTHTHtHTHTHtHTHtHtHtHtH", + "HtHtHTHTHTHtHtHtHTHtHTHTHTHtHtHtHtHTHTHtHtHTHtHtHtHtHtHtHtHTHtHXZ", + "HtHTHtHtHTHtHtHTHTHtHTHTHTHTHtHTHTHTHTHtHTHTHtHtHTHtHtHTHtHt", + "HtHTHTHTHtHTHtHtHTHtHtHtHTHTHTHtHTHtHtHTHtHtHTHTHTHTHtHtHtHtHtHS", + "HtHtHtHtHtHTHtHTHTHtHtHtHTHTHtHtHTHTHTHtHtHTHtHTHTHTHTHTHXST", + "HTHTHTHtHtHtHtHTHtHtHtHTHtHtHTHtHtHtHTHTHTHtHTHTHTHtHTHtHtHTHtH", + "HTHTHTHTHtHtHtHTHTHTHTHtHTHtHTHTHTHTHtHtHTHTHtHTHtHTHtHTHtHtHs", + "HTHtHtHtHTHtHtHtHtHtHTHtHtHtHTHtHTHtHTHTHtHtHTHtHtHTHTHtHtHXt", + "HtHtHtHTHTHTHTHtHtHtHTHTHTHtHtHtHtHtHTHTHtHtHTHtHTHtHtHtHtHs", + "HtHTHTHtHTHtHtHtHTHTHtHTHTHtHTHtHTHtHTHTHtHTHTHtHtHtHTHtHTHTHtHs", + "HtHtHtHTHtHtHtHtHtHtHtHtHtHTHtHtHtHTHtHtHtHtHtHtHtHtHtHTHtHtHtHs", + "HTHtHtHTHtHtHTHTHtHTHtHTHTHTHtHTHTHTHTHtHtHtHtHTHtHTHtHtHtHtHtHtHS", + "HTHTHtHTHtHtHTHtHtHTHtHtHtHTHTHTHtHtHtHTHtHtHtHtHtHtHtHTHtHTHtHs", + "HtHTHtHtHTHTHTHTHtHTHtHTHtHTHtHtHtHtHTHTHtHTHXT", + "HTHtHtHTHTHtHTHtHtHtHtHTHtHtHTHtHTHTHTHTHtHTHTHtHTHtHtHtHtHtHtHXZ", + "HTHtHtHTHtHTHtHTHtHTHtHtHTHtHTHtHTHTHtHTHTHTHTHtHTHtHtHtHXt", + "HtHtHTHTHTHtHTHTHtHtHTHtHTHtHtHTHtHTHtHtHTHTHtHTHTHTHtHtHZT", + "HTHtHtHtHTHtHtHTHTHTHTHtHTHTHTHTHtHTHTHTHTHtHtHTHtHtHtHTHt", + "HtHtHTHtHtHTHtHtHtHTHtHtHtHTHTHTHTHTHtHtHTHtHTHtHtHTHTHZ", + "HTHTHtHTHTHtHTHtHTHTHTHtHtHtHTHTHtHtHtHTHtHTHtHtHTHTHTHtHtHTHtHt", + "HtHtHtHtHTHTHtHtHtHTHtHTHTHTHtHtHtHtHTHtHTHTHtHtHTHTHtHTHTHtHtHXT", + "HTHTHtHtHTHTHTHTHTHtHTHTHtHtHTHtHTHtHTHTHTHtHTHTHtHTHtHTHtHtHXST", + "HTHtHtHTHTHtHTHtHTHTHTHtHtHTHTHTHTHTHTHtHTHTHTHtHtHtHtHtHtHTHZ", + "HtHtHTHTHtHTHTHtHtHTHTHtHTHtHtHtHtHTHTHTHtHTHtHtHtHTHTHtHtHtHtHXS", + "HTHtHtHtHTHTHTHTHTHtHTHTHtHTHTHtHtHTHtHtHtHtHtHTHTHtHTHTHtHtHtHZ", + "HtHtHTHTHtHTHtHTHTHtHtHtHtHtHTHTHTHtHTHTHTHtHTHTHtHTHTHt", + "HTHTHtHTHTHTHtHtHTHtHTHTHTHtHTHtHtHtHTHtHTHTHtHtHtHTHtHtHX", + "HtHTHTHtHTHTHTHtHtHTHTHTHTHTHtHtHtHtHtHTHTHtHtHtHTHtHtHTHXS", + "HtHTHTHtHTHtHTHtHTHtHTHTHtHTHtHTHtHtHTHtHtHtHtHTHtHTHTHTHXZ", + "HtHTHTHtHtHTHtHTHTHTHTHtHTHTHtHTHtHtHtHtHTHtHtHTHtHTHTHTHTHTHTHXt", + "HtHtHtHTHTHtHTHtHtHtHtHtHtHtHtHTHtHTHTHtHtHtHs", + "HTHtHtHtHtHTHTHTHtHtHtHTHtHtHTHtHtHTHtHtHtHTHtHTHtHTHtHtHtHtHtHZT", + "HTHtHtHtHtHTHTHTHtHtHtHtHTHtHTHTHtHTHTHTHTHtHtHTHtHtHTHtHtHtHtHtHT", + "HtHTHtHtHtHTHtHTHtHTHtHTHtHtHtHTHtHtHtHTHtHTHtHTHtHTHtHtHtHTHtHZT", + "HtHtHTHTHTHTHtHTHTHtHtHtHTHTHTHTHTHTHTHtHtHtHTHTHtHTHTHTHTHtHtHZT", + "HTHTHTHtHtHtHtHTHTHTHtHtHtHTHTHTHTHTHtHtHTHTHtHTHtHTHTHTHTHZT", + "HTHtHtHTHTHtHtHtHTHTHtHtHtHtHtHtHTHtHtHtHTHtHTHtHtHtHTHtHtHXZ", + "HTHTHtHTHtHTHtHTHtHtHTHTHtHtHtHtHTHtHTHtHtHtHtHTHTHTHtHtHtHtHZT", + "HTHtHTHTHtHTHtHtHtHTHtHtHtHTHTHTHtHTHTHtHTHTHTHtHTHTHTHTHtHtHtHST", + "HtHTHtHTHTHTHTHTHTHtHTHtHtHtHtHTHTHtHtHTHTHtHTHtHTHTHtHtHtHtHtHtHXST", + "HtHTHtHTHtHtHTHtHTHTHtHtHtHTHTHTHTHtHTHTHtHTHTHTHtHtHtHtHTHtHtHT", + "HtHtHtHTHTHTHtHtHTHTHTHtHTHtHtHtHTHtHTHTHTHtHtHTHTHTHtHtHtHZ", + "HtHTHTHtHTHTHtHTHTHTHTHtHTHTHtHTHtHtHTHTHtHtHtHTHtHTHtHTHtHtHtHXt", + "HTHTHTHTHtHTHtHtHTHtHtHtHTHTHTHTHTHTHtHTHTHtHTHTHtHtHTHtHtHtHST", + "HTHTHtHTHtHtHtHtHtHTHtHtHtHtHTHtHTHtHtHTHTHTHtHtHTHtHtHtHtHtHtHtHXs", + "HtHTHtHTHTHtHtHtHTHTHtHTHtHtHtHtHtHtHtHTHtHTHtHtHtHtHTHTHtHtHtHT", + "HTHTHTHtHTHTHtHtHtHtHtHTHtHtHtHTHTHTHTHTHtHTHTHtHTHTHTHX", + "HTHtHTHTHtHTHtHTHTHtHTHtHtHTHTHTHtHTHTHtHtHtHtHTHTHTHTHTHtHtHtH", + "HtHTHtHtHTHtHTHTHtHtHtHtHTHTHTHTHtHTHtHTHTHTHtHtHTHtHTHtHtHtHt", + "HTHTHtHTHTHtHTHTHTHtHTHTHtHtHTHtHtHtHTHTHtHtHtHTHtHTHTHtHtHtHX", + "HtHTHtHTHtHtHtHtHTHTHtHtHTHTHtHtHTHTHtHtHTHTHtHTHtHtHtHtHtHXST", + "HTHtHtHtHTHTHTHtHtHtHTHTHTHtHTHtHTHtHtHTHtHtHTHTHtHTHTHTHTHXZ", + "HtHtHTHTHtHtHtHtHtHtHtHtHTHtHTHTHTHtHtHTHTHTHTHtHTHtHtHtHtHtHtHs", + "HtHTHTHTHTHtHTHTHTHTHTHTHtHtHtHTHTHtHtHTHtHTHtHtHtHtHtHTHTHtHtHST", + "HTHtHtHTHTHTHTHtHTHTHTHtHTHTHTHTHTHtHtHTHTHTHtHtHtHtHtHtHtHX", + "HTHTHTHtHtHtHtHTHtHTHtHTHtHTHTHtHtHTHtHtHTHTHtHTHTHTHtHTHTHtHtHS", + "HTHTHtHTHtHtHtHTHtHTHtHTHtHtHtHTHTHtHtHTHTHtHTHtHTHTHTHTHXs", + "HtHTHtHtHTHtHTHtHtHtHTHTHtHtHtHTHTHTHtHtHTHtHtHTHtHtHtHtHS", + "HTHTHtHtHtHTHTHtHtHtHtHtHtHtHtHtHtHtHtHtHTHTHtHtHtHTHTHS", + "HTHTHTHtHTHTHtHtHtHTHtHtHtHTHtHtHTHTHTHtHTHTHTHtHTHTHtHtHtHTHtHT", + "HTHTHtHTHtHtHtHtHTHTHtHtHTHtHTHtHTHTHtHtHTHTHTHTHtHTHtHtHX", + "HTHtHtHTHTHTHTHTHTHTHtHTHTHTHTHTHTHtHTHTHTHTHTHTHTHtHtHTHZT", + "HTHtHTHTHtHtHTHtHTHTHTHTHTHtHtHtHTHtHtHTHtHTHtHtHtHtHTHTHtHtHtHZT", + "HTHtHtHtHtHtHtHtHTHTHtHTHtHTHtHTHtHtHTHtHTHTHtHtHtHTHTHTHTHXs", + "HtHtHTHtHTHTHtHtHTHtHTHTHTHtHTHTHTHtHTHtHtHTHTHtHTHtHtHt", + "HtHtHTHtHTHtHTHtHtHTHTHtHtHTHtHTHTHTHtHTHTHTHtHTHtHTHTHtHtHXt", + "HtHtHTHtHTHtHTHtHTHtHTHtHTHtHTHtHtHTHtHTHTHtHtHtHTHTHTHTHTHTHTHTHST", + "HtHTHTHTHtHTHtHTHTHtHtHtHtHtHTHTHTHTHTHtHtHTHtHTHtHtHtHTHXST", + "HTHTHTHtHTHtHTHTHTHtHTHtHtHtHTHtHtHTHTHTHTHtHTHTHtHtHTHtHtHtHtHST", + "HtHtHtHTHTHtHTHTHTHtHtHtHTHtHTHTHtHTHTHtHtHtHTHTHtHTHtHtHtHtHS", + "HtHtHtHtHtHtHTHtHTHTHtHTHtHTHtHTHtHTHtHTHTHtHTHtHtHtHtHtHtHZ", + "HTHtHTHTHTHTHTHtHtHtHtHtHTHTHtHtHTHtHtHTHTHTHTHTHtHTHTHtHtHTHZT", + "HtHTHTHTHTHTHtHTHtHtHtHtHTHTHtHtHtHtHtHtHtHTHtHtHTHTHtHtHtHtHS", + "HtHTHTHTHtHtHTHTHTHtHTHTHTHTHTHTHTHTHtHTHTHtHTHtHTHTHTHTHTHTHTHTHST", + "HtHtHtHTHTHTHtHTHtHTHtHTHTHTHtHtHtHTHtHTHtHTHtHtHtHTHTHTHXT", + "HtHtHTHTHtHTHtHTHTHtHtHtHtHTHTHtHtHTHtHtHTHTHtHTHTHTHTHtHtHTHtHXZT", + "HTHTHtHtHTHTHTHTHTHTHTHTHtHtHtHtHtHtHtHtHtHtHTHTHTHtHtHTHtHS", + "HTHtHtHtHTHTHTHtHtHTHtHTHTHTHtHTHtHtHTHTHTHTHtHTHtHTHTHTHXZ", + "HTHTHtHtHTHTHTHTHTHtHtHTHtHtHTHTHtHTHtHTHtHtHtHTHtHtHtHTHtHs", + "HTHTHtHtHtHtHtHTHtHtHtHTHTHTHtHtHTHtHTHtHtHTHTHtHtHTHTHTHTHTHTHTHZ", + "HtHtHtHTHtHTHTHtHtHtHtHtHTHTHtHtHtHtHTHTHtHtHXZ", + "HTHTHtHtHTHTHtHTHTHtHtHtHTHTHTHTHtHTHtHTHTHtHtHtHtHtHtHtHtHTHtHZT", + "HtHtHTHTHtHTHtHTHtHtHtHtHTHtHtHTHtHtHtHTHtHTHtHTHtHTHTHtHtHtHZ", + "HtHtHtHTHTHTHtHtHtHtHTHTHtHtHTHTHtHtHTHTHTHTHtHtHtHTHTHTHXs", + "HtHTHtHTHTHTHtHtHtHtHTHtHtHTHtHtHTHTHTHtHTHtHTHTHTHTHtHtHtHtHtHST", + "HtHTHTHtHTHtHtHTHTHtHTHTHTHTHtHtHtHtHTHtHtHTHTHtHTHtHtHTHXs", + "HTHTHTHTHtHtHtHTHtHTHtHTHtHtHTHTHTHtHtHTHtHTHtHtHTHTHTHTHTHXZ", + "HtHtHTHtHTHTHTHtHTHTHTHtHTHtHtHtHtHtHTHTHTHTHTHtHtHtHTHtHtHtHtHtHXT", + "HTHTHtHtHTHTHtHtHtHtHtHTHTHtHTHTHTHtHTHTHtHtHtHtHTHtHtHtHtHtHtHXt", + "HtHtHtHtHTHTHTHtHtHtHTHtHtHtHtHtHtHtHTHtHtHtHTHTHTHtHtHtHtHS", + "HTHtHtHtHTHTHTHTHTHtHtHtHtHtHTHtHTHTHtHTHtHtHTHtHTHTHtHTHtHtHT", + "HTHtHtHTHTHtHTHtHtHtHTHtHtHtHTHtHtHTHTHTHTHTHTHtHTHTHtHtHtHs", + "HTHTHTHtHTHTHTHtHTHTHTHtHTHtHTHTHtHTHtHTHtHTHtHTHtHTHTHtHtHtHtHST", + "HTHtHtHTHtHTHtHtHtHTHtHtHtHtHTHTHtHTHTHTHtHTHTHTHtHtHtHTHtHtHtHZ", + "HtHTHTHTHtHTHtHtHTHtHTHtHTHtHtHtHtHtHtHtHTHtHTHTHTHtHTHtHtHZ", + "HTHTHtHTHTHtHTHTHTHTHTHtHTHTHTHtHTHTHTHTHTHtHTHTHtHTHTHt", + "HTHtHTHtHTHTHTHtHTHtHTHTHtHtHtHtHTHtHTHTHtHtHtHtHtHTHtHtHtHtHtHt", + "HTHtHtHTHtHtHtHTHtHTHTHTHtHTHtHtHtHTHtHtHtHTHtHTHTHTHtHtHXZ", + "HTHTHtHTHTHtHtHTHTHtHtHtHTHtHTHtHtHTHTHtHTHtHTHtHtHTHTHtHtHtHtHX", + "HtHtHtHTHtHTHTHtHtHTHTHtHTHtHtHtHtHtHtHtHtHtHtHTHTHTHtHtHtHtHtHtHT", + "S", + "HtHtHTHTHTHTHtHtHTHTHtHtHTHtHTHTHTHtHTHtHTHTHtHtHTHTHtHtHtHtHtHtHXS", + "HtHTHTHTHTHtHtHtHtHtHtHTHTHtHTHtHtHTHTHtHtHTHtHtHtHTHtHtHtHtHtHtHXZT", + "HTHTHtHtHtHTHtHtHtHtHTHtHtHtHtHTHtHtHtHTHtHtHtHtHTHtHtHTHZ", + "HTHTHTHTHTHtHTHTHTHTHTHtHtHTHtHTHTHTHTHtHtHTHtHTHtHtHtHTHtHTHtHZT", + "HtHtHTHtHtHTHtHtHtHtHtHTHtHtHtHTHtHtHtHtHtHTHtHtHTHtHtHZT", + "HtHTHTHTHTHtHTHTHTHTHtHTHtHTHtHTHTHTHTHTHTHTHtHtHtHtHTHtHtH", + "HTHTHtHtHtHtHtHTHtHtHtHTHtHTHTHtHtHtHTHtHtHtHTHtHtHTHtHtHtHTHtH", + "HTHTHTHTHtHtHTHtHTHtHTHtHTHtHTHtHtHTHtHTHtHtHtHTHtHtHtHTHtHtHtHT", + "HTHTHtHtHTHTHTHTHtHTHTHTHtHTHTHTHtHtHTHtHTHtHTHTHTHtHtHTHtHs", + "HtHTHTHTHTHtHtHtHtHTHTHTHTHtHtHtHtHTHtHTHtHtHTHtHTHtHtHTHtHtHXt", + "HTHTHTHTHtHtHtHTHTHTHtHTHTHTHTHTHTHTHtHTHTHTHtHtHtHTHTHTHTHS", + "HtHtHTHTHtHtHTHTHTHTHTHtHtHTHtHtHtHTHtHtHTHTHTHTHtHTHTHTHTHTHTHXZT", + "HtHtHTHTHTHtHtHtHtHTHTHTHTHTHTHtHtHTHtHTHtHtHtHTHtHTHtHTHTHtHtHXT", + "HTHTHTHTHTHtHtHTHtHTHtHtHTHTHTHtHtHTHtHTHtHTHtHtHtHTHTHTHTHX", + "HtHtHTHTHTHTHtHtHTHTHTHtHTHtHtHTHtHTHTHTHtHtHTHTHTHTHtHtHS", + "HtHTHtHTHtHtHTHtHTHTHTHTHTHtHTHTHtHtHtHTHTHTHtHTHtHtHTHtHtHtHtHT", + "HTHTHTHtHtHtHTHTHTHTHtHtHTHTHtHtHTHTHtHtHtHtHTHTHTHtHtHtHXs", + "HtHTHtHtHTHTHTHTHTHTHTHTHtHTHTHTHtHtHtHTHtHTHTHTHTHTHTHtHtHTHXZ", + "HTHtHtHTHTHtHtHtHTHTHtHTHTHtHTHtHtHtHtHtHTHTHtHTHtHTHtHTHtHtHtHt", + "HtHtHTHTHtHtHtHtHTHTHtHtHtHtHtHTHTHtHTHtHtHtHX", + "HtHtHTHTHTHTHTHtHTHTHTHtHtHtHTHTHtHTHtHTHTHtHtHTHTHtHtHtHtHtHtHtH", + "HTHtHtHTHTHtHTHtHTHTHtHtHtHTHTHtHtHtHtHtHtHTHtHtHtHTHtHtHtHs", + "HtHTHTHTHtHtHtHTHTHtHTHtHtHtHTHtHTHTHtHtHtHtHTHtHTHtHtHtHX", + "HTHtHtHTHTHtHTHtHTHtHTHtHtHTHtHTHtHTHtHTHtHTHTHtHTHTHtHtHtHS", + "HtHTHTHtHtHtHtHtHTHTHtHTHtHtHTHTHtHtHtHTHTHtHtHtHTHtHTHTHtHtHtHXt", + "HTHTHTHtHtHtHTHtHTHtHTHtHtHtHTHTHTHtHTHtHTHtHTHTHTHtHtHtHXST", + "HTHtHtHtHTHTHtHtHtHTHtHtHtHtHtHtHtHtHTHtHtHTHtHTHtHtHtHtHtHtHtHtHT", + "HTHTHTHTHtHtHTHTHtHTHTHTHTHTHTHTHtHtHTHTHTHTHtHTHtHtHtHtHtHTHS", + "HTHTHtHtHTHTHTHtHTHtHTHTHtHtHtHTHTHtHtHTHtHTHtHtHTHtHTHtHtHtHXST", + "HTHTHTHTHTHTHtHTHtHtHTHtHTHtHTHtHTHtHTHtHtHTHtHTHTHTHTHTHTH", + "HtHTHtHtHTHTHTHtHTHTHtHTHTHTHTHtHtHtHTHTHtHTHTHtHtHtHtHTHtHTHXs", + "HTHtHTHtHtHtHtHtHTHtHtHtHtHTHtHtHtHTHtHTHTHTHtHTHTHTHtHtHtHtHtHX", + "HtHtHTHtHtHtHtHtHTHTHtHTHtHTHTHtHTHtHTHTHtHtHtHtHtHTHtHtHZT", + "HTHTHtHTHtHTHtHTHtHTHtHTHtHTHtHTHTHtHTHtHtHTHTHTHtHtHtHtHtHtHtHtHT", + "HtHtHTHTHtHTHtHTHTHTHtHTHTHTHtHTHtHtHTHTHtHtHTHtHTHtHTHtHtHXZT", + "HTHTHtHTHtHtHTHTHtHTHtHtHtHTHtHtHtHTHtHTHTHtHtHTHtHTHTHZT", + "HtHTHTHTHTHTHTHTHtHtHTHtHTHtHTHtHTHTHtHTHtHtHTHTHTHtHtHtHtHXs", + "HTHTHTHtHtHTHTHTHTHtHTHtHTHTHtHTHTHTHtHtHtHtHtHTHtHTHTHtHtHTHtHt", + "HTHTHtHtHTHtHTHtHTHtHtHtHTHtHTHtHTHTHTHtHTHtHTHtHTHTHtHtHXST", + "HTHtHtHtHtHTHtHTHTHtHtHTHTHTHTHTHTHtHtHTHTHtHTHtHtHtHtHTH", + "HTHtHTHTHTHtHtHTHtHtHtHTHtHtHtHTHTHtHTHTHTHtHTHTHTHtHtHTHtHtHtHST", + "HtHtHTHTHTHtHtHTHTHTHTHTHTHTHTHTHTHTHTHTHtHtHTHTHTHtHtHS", + "HtHTHtHTHTHTHtHtHtHTHTHtHTHTHtHTHTHtHtHTHtHtHtHtHtHTHTHTHXs", + "HtHtHTHtHTHTHTHtHTHtHTHtHTHTHTHtHtHTHTHtHtHTHtHTHtHtHtHtHXs", + "HTHTHtHtHTHtHtHtHTHtHtHTHTHtHTHTHtHtHTHtHTHtHTHtHTHTHTHTHtHtHtHS", + "HtHTHTHtHtHtHtHTHtHtHtHTHtHtHtHtHtHTHTHtHtHtHTHTHTHTHTHTHTHXZ", + "HtHTHTHtHtHTHtHTHtHtHtHtHtHTHTHtHtHTHtHtHTHtHTHtHTHTHTHtHTHtHtHT", + "HTHTHtHtHTHTHTHTHTHTHTHTHtHTHtHtHtHTHTHtHtHtHtHTHtHTHTHTHTHTHTHs", + "HtHTHTHTHtHtHtHTHTHTHtHtHtHTHtHTHtHTHTHtHTHTHtHtHTHtHtHtHtHX", + "HTHtHTHtHTHTHTHTHtHtHTHTHtHtHTHTHtHtHTHTHtHtHTHtHTHTHTHTHTHXT", + "HTHtHtHTHTHTHtHTHtHTHTHtHtHtHTHTHtHtHTHTHtHTHtHTHTHtHTHtHtHtHt", + "HtHTHTHtHTHTHTHTHtHtHTHTHtHTHTHTHTHtHtHtHtHtHTHTHtHtHtHTHtHtH", + "HTHTHTHtHtHtHtHtHTHTHTHTHtHtHTHtHtHtHTHTHtHTHtHtHTHtHTHtHtHTHtHZ", + "HTHTHTHtHTHTHtHTHTHTHTHTHtHtHtHTHtHtHtHtHtHTHTHtHTHTHTHXZ", + "HtHTHtHtHTHTHtHTHtHtHtHtHtHTHtHTHtHTHtHtHtHtHTHTHtHTHTHtHtHtHtHST", + "HtHtHTHtHTHTHTHTHTHtHTHTHTHTHtHTHtHTHTHtHtHtHTHTHtHTHTHTHTHTHTHTHXs", + "HTHTHTHtHTHTHtHtHTHtHtHTHtHtHtHtHtHtHTHTHTHtHTHTHtHTHtHtHtHtHT", + "HtHtHTHTHTHtHtHtHTHtHTHTHTHtHtHtHtHTHTHtHtHTHtHtHtHtHtHtHtHTHtHXZT", + "HtHTHtHtHTHtHtHTHTHtHTHTHTHTHtHTHTHTHTHtHTHTHtHtHTHtHtHTHtH", + "HtHTHTHTHtHTHtHtHTHtHtHtHTHTHTHtHTHtHtHTHtHtHTHTHTHTHtHtHtHtHtHST", + "HtHtHtHtHtHTHtHTHTHtHtHtHTHTHtHtHTHTHTHtHtHTHtHTHTHTHTHTHXZ", + "HTHTHTHtHtHtHtHTHtHtHtHTHtHtHTHtHtHtHTHTHTHtHTHTHTHtHTHtHtHTHtHT", + "HTHTHTHTHtHtHtHTHTHTHTHtHTHtHTHTHTHTHtHtHTHTHtHTHtHTHtHTHtHtHt", + "HTHtHtHtHTHtHtHtHtHtHTHtHtHtHTHtHTHtHTHTHtHtHTHtHtHTHTHtHtHX", + "HtHtHtHTHTHTHTHtHtHtHTHTHTHtHtHtHtHtHTHTHtHtHTHtHTHtHtHtHtHt", + "HtHTHTHtHTHtHtHtHTHTHtHTHTHtHTHtHTHtHTHTHtHTHTHtHtHtHTHtHTHTHtHt", + "HtHtHtHTHtHtHtHtHtHtHtHtHtHTHtHtHtHTHtHtHtHtHtHtHtHtHtHTHtHtHtHt", + "HTHtHtHTHtHtHTHTHtHTHtHTHTHTHtHTHTHTHTHtHtHtHtHTHtHTHtHtHtHtHtHtHST", + "HTHTHtHTHtHtHTHtHtHTHtHtHtHTHTHTHtHtHtHTHtHtHtHtHtHtHtHTHtHTHtHt", + "HtHTHtHtHTHTHTHTHtHTHtHTHtHTHtHtHtHtHTHTHtHTHXS", + "HTHtHtHTHTHtHTHtHtHtHtHTHtHtHTHtHTHTHTHTHtHTHTHtHTHtHtHtHtHtHtHXZT", + "HTHtHtHTHtHTHtHTHtHTHtHtHTHtHTHtHTHTHtHTHTHTHTHtHTHtHtHtHX", + "HtHtHTHTHTHtHTHTHtHtHTHtHTHtHtHTHtHTHtHtHTHTHtHTHTHTHtHtHs", + "HTHtHtHtHTHtHtHTHTHTHTHtHTHTHTHTHtHTHTHTHTHtHtHTHtHtHtHTH", + "HtHtHTHtHtHTHtHtHtHTHtHtHtHTHTHTHTHTHtHtHTHtHTHtHtHTHTHZT", + "HTHTHtHTHTHtHTHtHTHTHTHtHtHtHTHTHtHtHtHTHtHTHtHtHTHTHTHtHtHTHtH", + "HtHtHtHtHTHTHtHtHtHTHtHTHTHTHtHtHtHtHTHtHTHTHtHtHTHTHtHTHTHtHtHXS", + "HTHTHtHtHTHTHTHTHTHtHTHTHtHtHTHtHTHtHTHTHTHtHTHTHtHTHtHTHtHtHXZ", + "HTHtHtHTHTHtHTHtHTHTHTHtHtHTHTHTHTHTHTHtHTHTHTHtHtHtHtHtHtHTHZT", + "HtHtHTHTHtHTHTHtHtHTHTHtHTHtHtHtHtHTHTHTHtHTHtHtHtHTHTHtHtHtHtHXST", + "HTHtHtHtHTHTHTHTHTHtHTHTHtHTHTHtHtHTHtHtHtHtHtHTHTHtHTHTHtHtHtHZT", + "HtHtHTHTHtHTHtHTHTHtHtHtHtHtHTHTHTHtHTHTHTHtHTHTHtHTHTH", + "HTHTHtHTHTHTHtHtHTHtHTHTHTHtHTHtHtHtHTHtHTHTHtHtHtHTHtHtHXT", + "HtHTHTHtHTHTHTHtHtHTHTHTHTHTHtHtHtHtHtHTHTHtHtHtHTHtHtHTHXST", + "HtHTHTHtHTHtHTHtHTHtHTHTHtHTHtHTHtHtHTHtHtHtHtHTHtHTHTHTHXZT", + "HtHTHTHtHtHTHtHTHTHTHTHtHTHTHtHTHtHtHtHtHTHtHtHTHtHTHTHTHTHTHTHX", + "HtHtHtHTHTHtHTHtHtHtHtHtHtHtHtHTHtHTHTHtHtHtHt", + "HTHtHtHtHtHTHTHTHtHtHtHTHtHtHTHtHtHTHtHtHtHTHtHTHtHTHtHtHtHtHtHs", + "HTHtHtHtHtHTHTHTHtHtHtHtHTHtHTHTHtHTHTHTHTHtHtHTHtHtHTHtHtHtHtHtHS", + "HtHTHtHtHtHTHtHTHtHTHtHTHtHtHtHTHtHtHtHTHtHTHtHTHtHTHtHtHtHTHtHs", + "HtHtHTHTHTHTHtHTHTHtHtHtHTHTHTHTHTHTHTHtHtHtHTHTHtHTHTHTHTHtHtHs", + "HTHTHTHtHtHtHtHTHTHTHtHtHtHTHTHTHTHTHtHtHTHTHtHTHtHTHTHTHTHs", + "HTHtHtHTHTHtHtHtHTHTHtHtHtHtHtHtHTHtHtHtHTHtHTHtHtHtHTHtHtHXZT", + "HTHTHtHTHtHTHtHTHtHtHTHTHtHtHtHtHTHtHTHtHtHtHtHTHTHTHtHtHtHtHs", + "HTHtHTHTHtHTHtHtHtHTHtHtHtHTHTHTHtHTHTHtHTHTHTHtHTHTHTHTHtHtHtHZ", + "HtHTHtHTHTHTHTHTHTHtHTHtHtHtHtHTHTHtHtHTHTHtHTHtHTHTHtHtHtHtHtHtHXZ", + "HtHTHtHTHtHtHTHtHTHTHtHtHtHTHTHTHTHtHTHTHtHTHTHTHtHtHtHtHTHtHtHS", + "HtHtHtHTHTHTHtHtHTHTHTHtHTHtHtHtHTHtHTHTHTHtHtHTHTHTHtHtHtHZT", + "HtHTHTHtHTHTHtHTHTHTHTHtHTHTHtHTHtHtHTHTHtHtHtHTHtHTHtHTHtHtHtHX", + "HTHTHTHTHtHTHtHtHTHtHtHtHTHTHTHTHTHTHtHTHTHtHTHTHtHtHTHtHtHtHZ", + "HTHTHtHTHtHtHtHtHtHTHtHtHtHtHTHtHTHtHtHTHTHTHtHtHTHtHtHtHtHtHtHtHXt", + "HtHTHtHTHTHtHtHtHTHTHtHTHtHtHtHtHtHtHtHTHtHTHtHtHtHtHTHTHtHtHtHS", + "HTHTHTHtHTHTHtHtHtHtHtHTHtHtHtHTHTHTHTHTHtHTHTHtHTHTHTHXT", + "HTHtHTHTHtHTHtHTHTHtHTHtHtHTHTHTHtHTHTHtHtHtHtHTHTHTHTHTHtHtHtHT", + "HtHTHtHtHTHtHTHTHtHtHtHtHTHTHTHTHtHTHtHTHTHTHtHtHTHtHTHtHtHtH", + "HTHTHtHTHTHtHTHTHTHtHTHTHtHtHTHtHtHtHTHTHtHtHtHTHtHTHTHtHtHtHXT", + "HtHTHtHTHtHtHtHtHTHTHtHtHTHTHtHtHTHTHtHtHTHTHtHTHtHtHtHtHtHXZ", + "HTHtHtHtHTHTHTHtHtHtHTHTHTHtHTHtHTHtHtHTHtHtHTHTHtHTHTHTHTHXZT", + "HtHtHTHTHtHtHtHtHtHtHtHtHTHtHTHTHTHtHtHTHTHTHTHtHTHtHtHtHtHtHtHt", + "HtHTHTHTHTHtHTHTHTHTHTHTHtHtHtHTHTHtHtHTHtHTHtHtHtHtHtHTHTHtHtHZ", + "HTHtHtHTHTHTHTHtHTHTHTHtHTHTHTHTHTHtHtHTHTHTHtHtHtHtHtHtHtHXT", + "HTHTHTHtHtHtHtHTHtHTHtHTHtHTHTHtHtHTHtHtHTHTHtHTHTHTHtHTHTHtHtHST", + "HTHTHtHTHtHtHtHTHtHTHtHTHtHtHtHTHTHtHtHTHTHtHTHtHTHTHTHTHXt", + "HtHTHtHtHTHtHTHtHtHtHTHTHtHtHtHTHTHTHtHtHTHtHtHTHtHtHtHtHST", + "HTHTHtHtHtHTHTHtHtHtHtHtHtHtHtHtHtHtHtHtHTHTHtHtHtHTHTHST", + "HTHTHTHtHTHTHtHtHtHTHtHtHtHTHtHtHTHTHTHtHTHTHTHtHTHTHtHtHtHTHtHS", + "HTHTHtHTHtHtHtHtHTHTHtHtHTHtHTHtHTHTHtHtHTHTHTHTHtHTHtHtHXT", + "HTHtHtHTHTHTHTHTHTHTHtHTHTHTHTHTHTHtHTHTHTHTHTHTHTHtHtHTHs", + "HTHtHTHTHtHtHTHtHTHTHTHTHTHtHtHtHTHtHtHTHtHTHtHtHtHtHTHTHtHtHtHs", + "HTHtHtHtHtHtHtHtHTHTHtHTHtHTHtHTHtHtHTHtHTHTHtHtHtHTHTHTHTHXt", + "HtHtHTHtHTHTHtHtHTHtHTHTHTHtHTHTHTHtHTHtHtHTHTHtHTHtHtH", + "HtHtHTHtHTHtHTHtHtHTHTHtHtHTHtHTHTHTHtHTHTHTHtHTHtHTHTHtHtHX", + "HtHtHTHtHTHtHTHtHTHtHTHtHTHtHTHtHtHTHtHTHTHtHtHtHTHTHTHTHTHTHTHTHZ", + "HtHTHTHTHtHTHtHTHTHtHtHtHtHtHTHTHTHTHTHtHtHTHtHTHtHtHtHTHXZ", + "HTHTHTHtHTHtHTHTHTHtHTHtHtHtHTHtHtHTHTHTHTHtHTHTHtHtHTHtHtHtHtHZ", + "HtHtHtHTHTHtHTHTHTHtHtHtHTHtHTHTHtHTHTHtHtHtHTHTHtHTHtHtHtHtHST", + "HtHtHtHtHtHtHTHtHTHTHtHTHtHTHtHTHtHTHtHTHTHtHTHtHtHtHtHtHtHZT", + "HTHtHTHTHTHTHTHtHtHtHtHtHTHTHtHtHTHtHtHTHTHTHTHTHtHTHTHtHtHTHs", + "HtHTHTHTHTHTHtHTHtHtHtHtHTHTHtHtHtHtHtHtHtHTHtHtHTHTHtHtHtHtHST", + "HtHTHTHTHtHtHTHTHTHtHTHTHTHTHTHTHTHTHtHTHTHtHTHtHTHTHTHTHTHTHTHTHZ", + "HtHtHtHTHTHTHtHTHtHTHtHTHTHTHtHtHtHTHtHTHtHTHtHtHtHTHTHTHXS", + "HtHtHTHTHtHTHtHTHTHtHtHtHtHTHTHtHtHTHtHtHTHTHtHTHTHTHTHtHtHTHtHXs", + "HTHTHtHtHTHTHTHTHTHTHTHTHtHtHtHtHtHtHtHtHtHtHTHTHTHtHtHTHtHST", + "HTHtHtHtHTHTHTHtHtHTHtHTHTHTHtHTHtHtHTHTHTHTHtHTHtHTHTHTHXZT", + "HTHTHtHtHTHTHTHTHTHtHtHTHtHtHTHTHtHTHtHTHtHtHtHTHtHtHtHTHtHt", + "HTHTHtHtHtHtHtHTHtHtHtHTHTHTHtHtHTHtHTHtHtHTHTHtHtHTHTHTHTHTHTHTHZT", + "HtHtHtHTHtHTHTHtHtHtHtHtHTHTHtHtHtHtHTHTHtHtHXZT", + "HTHTHtHtHTHTHtHTHTHtHtHtHTHTHTHTHtHTHtHTHTHtHtHtHtHtHtHtHtHTHtHs", + "HtHtHTHTHtHTHtHTHtHtHtHtHTHtHtHTHtHtHtHTHtHTHtHTHtHTHTHtHtHtHZT", + "HtHtHtHTHTHTHtHtHtHtHTHTHtHtHTHTHtHtHTHTHTHTHtHtHtHTHTHTHXt", + "HtHTHtHTHTHTHtHtHtHtHTHtHtHTHtHtHTHTHTHtHTHtHTHTHTHTHtHtHtHtHtHZ", + "HtHTHTHtHTHtHtHTHTHtHTHTHTHTHtHtHtHtHTHtHtHTHTHtHTHtHtHTHXt", + "HTHTHTHTHtHtHtHTHtHTHtHTHtHtHTHTHTHtHtHTHtHTHtHtHTHTHTHTHTHXZT", + "HtHtHTHtHTHTHTHtHTHTHTHtHTHtHtHtHtHtHTHTHTHTHTHtHtHtHTHtHtHtHtHtHXS", + "HTHTHtHtHTHTHtHtHtHtHtHTHTHtHTHTHTHtHTHTHtHtHtHtHTHtHtHtHtHtHtHX", + "HtHtHtHtHTHTHTHtHtHtHTHtHtHtHtHtHtHtHTHtHtHtHTHTHTHtHtHtHtHST", + "HTHtHtHtHTHTHTHTHTHtHtHtHtHtHTHtHTHTHtHTHtHtHTHtHTHTHtHTHtHtHS", + "HTHtHtHTHTHtHTHtHtHtHTHtHtHtHTHtHtHTHTHTHTHTHTHtHTHTHtHtHtHt", + "HTHTHTHtHTHTHTHtHTHTHTHtHTHtHTHTHtHTHtHTHtHTHtHTHtHTHTHtHtHtHtHZ", + "HTHtHtHTHtHTHtHtHtHTHtHtHtHtHTHTHtHTHTHTHtHTHTHTHtHtHtHTHtHtHtHZT", + "HtHTHTHTHtHTHtHtHTHtHTHtHTHtHtHtHtHtHtHtHTHtHTHTHTHtHTHtHtHZT", + "HTHTHtHTHTHtHTHTHTHTHTHtHTHTHTHtHTHTHTHTHTHtHTHTHtHTHTH", + "HTHtHTHtHTHTHTHtHTHtHTHTHtHtHtHtHTHtHTHTHtHtHtHtHtHTHtHtHtHtHtH", + "HTHtHtHTHtHtHtHTHtHTHTHTHtHTHtHtHtHTHtHtHtHTHtHTHTHTHtHtHXZT", + "HTHTHtHTHTHtHtHTHTHtHtHtHTHtHTHtHtHTHTHtHTHtHTHtHtHTHTHtHtHtHtHXT", + "HtHtHtHTHtHTHTHtHtHTHTHtHTHtHtHtHtHtHtHtHtHtHtHTHTHTHtHtHtHtHtHtHS", + "ST", + "HtHtHTHTHTHTHtHtHTHTHtHtHTHtHTHTHTHtHTHtHTHTHtHtHTHTHtHtHtHtHtHtHXST", + "HtHTHTHTHTHtHtHtHtHtHtHTHTHtHTHtHtHTHTHtHtHTHtHtHtHTHtHtHtHtHtHtHXs", + "HTHTHtHtHtHTHtHtHtHtHTHtHtHtHtHTHtHtHtHTHtHtHtHtHTHtHtHTHZT", + "HTHTHTHTHTHtHTHTHTHTHTHtHtHTHtHTHTHTHTHtHtHTHtHTHtHtHtHTHtHTHtHs", + "HtHtHTHtHtHTHtHtHtHtHtHTHtHtHtHTHtHtHtHtHtHTHtHtHTHtHtHs", + "HtHTHTHTHTHtHTHTHTHTHtHTHtHTHtHTHTHTHTHTHTHTHtHtHtHtHTHtHtHT", + "HTHTHtHtHtHtHtHTHtHtHtHTHtHTHTHtHtHtHTHtHtHtHTHtHtHTHtHtHtHTHtHT", + "HTHTHTHTHtHtHTHtHTHtHTHtHTHtHTHtHtHTHtHTHtHtHtHTHtHtHtHTHtHtHtHS", + "HTHTHtHtHTHTHTHTHtHTHTHTHtHTHTHTHtHtHTHtHTHtHTHTHTHtHtHTHtHt", + "HtHTHTHTHTHtHtHtHtHTHTHTHTHtHtHtHtHTHtHTHtHtHTHtHTHtHtHTHtHtHX", + "HTHTHTHTHtHtHtHTHTHTHtHTHTHTHTHTHTHTHtHTHTHTHtHtHtHTHTHTHTHST", + "HtHtHTHTHtHtHTHTHTHTHTHtHtHTHtHtHtHTHtHtHTHTHTHTHtHTHTHTHTHTHTHXs", + "HtHtHTHTHTHtHtHtHtHTHTHTHTHTHTHtHtHTHtHTHtHtHtHTHtHTHtHTHTHtHtHXS", + "HTHTHTHTHTHtHtHTHtHTHtHtHTHTHTHtHtHTHtHTHtHTHtHtHtHTHTHTHTHXT", + "HtHtHTHTHTHTHtHtHTHTHTHtHTHtHtHTHtHTHTHTHtHtHTHTHTHTHtHtHST", + "HtHTHtHTHtHtHTHtHTHTHTHTHTHtHTHTHtHtHtHTHTHTHtHTHtHtHTHtHtHtHtHS", + "HTHTHTHtHtHtHTHTHTHTHtHtHTHTHtHtHTHTHtHtHtHtHTHTHTHtHtHtHXt", + "HtHTHtHtHTHTHTHTHTHTHTHTHtHTHTHTHtHtHtHTHtHTHTHTHTHTHTHtHtHTHXZT", + "HTHtHtHTHTHtHtHtHTHTHtHTHTHtHTHtHtHtHtHtHTHTHtHTHtHTHtHTHtHtHtH", + "HtHtHTHTHtHtHtHtHTHTHtHtHtHtHtHTHTHtHTHtHtHtHXT", + "HtHtHTHTHTHTHTHtHTHTHTHtHtHtHTHTHtHTHtHTHTHtHtHTHTHtHtHtHtHtHtHtHT", + "HTHtHtHTHTHtHTHtHTHTHtHtHtHTHTHtHtHtHtHtHtHTHtHtHtHTHtHtHtHt", + "HtHTHTHTHtHtHtHTHTHtHTHtHtHtHTHtHTHTHtHtHtHtHTHtHTHtHtHtHXT", + "HTHtHtHTHTHtHTHtHTHtHTHtHtHTHtHTHtHTHtHTHtHTHTHtHTHTHtHtHtHST", + "HtHTHTHtHtHtHtHtHTHTHtHTHtHtHTHTHtHtHtHTHTHtHtHtHTHtHTHTHtHtHtHX", + "HTHTHTHtHtHtHTHtHTHtHTHtHtHtHTHTHTHtHTHtHTHtHTHTHTHtHtHtHXZ", + "HTHtHtHtHTHTHtHtHtHTHtHtHtHtHtHtHtHtHTHtHtHTHtHTHtHtHtHtHtHtHtHtHS", + "HTHTHTHTHtHtHTHTHtHTHTHTHTHTHTHTHtHtHTHTHTHTHtHTHtHtHtHtHtHTHST", + "HTHTHtHtHTHTHTHtHTHtHTHTHtHtHtHTHTHtHtHTHtHTHtHtHTHtHTHtHtHtHXZ", + "HTHTHTHTHTHTHtHTHtHtHTHtHTHtHTHtHTHtHTHtHtHTHtHTHTHTHTHTHTHT", + "HtHTHtHtHTHTHTHtHTHTHtHTHTHTHTHtHtHtHTHTHtHTHTHtHtHtHtHTHtHTHXt", + "HTHtHTHtHtHtHtHtHTHtHtHtHtHTHtHtHtHTHtHTHTHTHtHTHTHTHtHtHtHtHtHXT", + "HtHtHTHtHtHtHtHtHTHTHtHTHtHTHTHtHTHtHTHTHtHtHtHtHtHTHtHtHs", + "HTHTHtHTHtHTHtHTHtHTHtHTHtHTHtHTHTHtHTHtHtHTHTHTHtHtHtHtHtHtHtHtHS", + "HtHtHTHTHtHTHtHTHTHTHtHTHTHTHtHTHtHtHTHTHtHtHTHtHTHtHTHtHtHXs", + "HTHTHtHTHtHtHTHTHtHTHtHtHtHTHtHtHtHTHtHTHTHtHtHTHtHTHTHs", + "HtHTHTHTHTHTHTHTHtHtHTHtHTHtHTHtHTHTHtHTHtHtHTHTHTHtHtHtHtHXt", + "HTHTHTHtHtHTHTHTHTHtHTHtHTHTHtHTHTHTHtHtHtHtHtHTHtHTHTHtHtHTHtH", + "HTHTHtHtHTHtHTHtHTHtHtHtHTHtHTHtHTHTHTHtHTHtHTHtHTHTHtHtHXZ", + "HTHtHtHtHtHTHtHTHTHtHtHTHTHTHTHTHTHtHtHTHTHtHTHtHtHtHtHTHT", + "HTHtHTHTHTHtHtHTHtHtHtHTHtHtHtHTHTHtHTHTHTHtHTHTHTHtHtHTHtHtHtHZ", + "HtHtHTHTHTHtHtHTHTHTHTHTHTHTHTHTHTHTHTHTHtHtHTHTHTHtHtHST", + "HtHTHtHTHTHTHtHtHtHTHTHtHTHTHtHTHTHtHtHTHtHtHtHtHtHTHTHTHXt", + "HtHtHTHtHTHTHTHtHTHtHTHtHTHTHTHtHtHTHTHtHtHTHtHTHtHtHtHtHXt", + "HTHTHtHtHTHtHtHtHTHtHtHTHTHtHTHTHtHtHTHtHTHtHTHtHTHTHTHTHtHtHtHST", + "HtHTHTHtHtHtHtHTHtHtHtHTHtHtHtHtHtHTHTHtHtHtHTHTHTHTHTHTHTHXZT", + "HtHTHTHtHtHTHtHTHtHtHtHtHtHTHTHtHtHTHtHtHTHtHTHtHTHTHTHtHTHtHtHS", + "HTHTHtHtHTHTHTHTHTHTHTHTHtHTHtHtHtHTHTHtHtHtHtHTHtHTHTHTHTHTHTHt", + "HtHTHTHTHtHtHtHTHTHTHtHtHtHTHtHTHtHTHTHtHTHTHtHtHTHtHtHtHtHXT", + "HTHtHTHtHTHTHTHTHtHtHTHTHtHtHTHTHtHtHTHTHtHtHTHtHTHTHTHTHTHXS", + "HTHtHtHTHTHTHtHTHtHTHTHtHtHtHTHTHtHtHTHTHtHTHtHTHTHtHTHtHtHtH", + "HtHTHTHtHTHTHTHTHtHtHTHTHtHTHTHTHTHtHtHtHtHtHTHTHtHtHtHTHtHtHT", + "HTHTHTHtHtHtHtHtHTHTHTHTHtHtHTHtHtHtHTHTHtHTHtHtHTHtHTHtHtHTHtHZT", + "HTHTHTHtHTHTHtHTHTHTHTHTHtHtHtHTHtHtHtHtHtHTHTHtHTHTHTHXZT", + "HtHTHtHtHTHTHtHTHtHtHtHtHtHTHtHTHtHTHtHtHtHtHTHTHtHTHTHtHtHtHtHZ", + "HtHtHTHtHTHTHTHTHTHtHTHTHTHTHtHTHtHTHTHtHtHtHTHTHtHTHTHTHTHTHTHTHXt", + "HTHTHTHtHTHTHtHtHTHtHtHTHtHtHtHtHtHtHTHTHTHtHTHTHtHTHtHtHtHtHS", + "HtHtHTHTHTHtHtHtHTHtHTHTHTHtHtHtHtHTHTHtHtHTHtHtHtHtHtHtHtHTHtHXs", + "HtHTHtHtHTHtHtHTHTHtHTHTHTHTHtHTHTHTHTHtHTHTHtHtHTHtHtHTHtHT", + "HtHTHTHTHtHTHtHtHTHtHtHtHTHTHTHtHTHtHtHTHtHtHTHTHTHTHtHtHtHtHtHZ", + "HtHtHtHtHtHTHtHTHTHtHtHtHTHTHtHtHTHTHTHtHtHTHtHTHTHTHTHTHXZT", + "HTHTHTHtHtHtHtHTHtHtHtHTHtHtHTHtHtHtHTHTHTHtHTHTHTHtHTHtHtHTHtHS", + "HTHTHTHTHtHtHtHTHTHTHTHtHTHtHTHTHTHTHtHtHTHTHtHTHtHTHtHTHtHtH", + "HTHtHtHtHTHtHtHtHtHtHTHtHtHtHTHtHTHtHTHTHtHtHTHtHtHTHTHtHtHXT", + "HtHtHtHTHTHTHTHtHtHtHTHTHTHtHtHtHtHtHTHTHtHtHTHtHTHtHtHtHtH", + "HtHTHTHtHTHtHtHtHTHTHtHTHTHtHTHtHTHtHTHTHtHTHTHtHtHtHTHtHTHTHtH", + "HtHtHtHTHtHtHtHtHtHtHtHtHtHTHtHtHtHTHtHtHtHtHtHtHtHtHtHTHtHtHtH", + "HTHtHtHTHtHtHTHTHtHTHtHTHTHTHtHTHTHTHTHtHtHtHtHTHtHTHtHtHtHtHtHtHZ", + "HTHTHtHTHtHtHTHtHtHTHtHtHtHTHTHTHtHtHtHTHtHtHtHtHtHtHtHTHtHTHtH", + "HtHTHtHtHTHTHTHTHtHTHtHTHtHTHtHtHtHtHTHTHtHTHXST", + "HTHtHtHTHTHtHTHtHtHtHtHTHtHtHTHtHTHTHTHTHtHTHTHtHTHtHtHtHtHtHtHXs", + "HTHtHtHTHtHTHtHTHtHTHtHtHTHtHTHtHTHTHtHTHTHTHTHtHTHtHtHtHXT", + "HtHtHTHTHTHtHTHTHtHtHTHtHTHtHtHTHtHTHtHtHTHTHtHTHTHTHtHtHt", + "HTHtHtHtHTHtHtHTHTHTHTHtHTHTHTHTHtHTHTHTHTHtHtHTHtHtHtHTHT", + "HtHtHTHtHtHTHtHtHtHTHtHtHtHTHTHTHTHTHtHtHTHtHTHtHtHTHTHs", + "HTHTHtHTHTHtHTHtHTHTHTHtHtHtHTHTHtHtHtHTHtHTHtHtHTHTHTHtHtHTHtHT", + "HtHtHtHtHTHTHtHtHtHTHtHTHTHTHtHtHtHtHTHtHTHTHtHtHTHTHtHTHTHtHtHXST", + "HTHTHtHtHTHTHTHTHTHtHTHTHtHtHTHtHTHtHTHTHTHtHTHTHtHTHtHTHtHtHXZT", + "HTHtHtHTHTHtHTHtHTHTHTHtHtHTHTHTHTHTHTHtHTHTHTHtHtHtHtHtHtHTHs", + "HtHtHTHTHtHTHTHtHtHTHTHtHTHtHtHtHtHTHTHTHtHTHtHtHtHTHTHtHtHtHtHXZ", + "HTHtHtHtHTHTHTHTHTHtHTHTHtHTHTHtHtHTHtHtHtHtHtHTHTHtHTHTHtHtHtHs", + "HtHtHTHTHtHTHtHTHTHtHtHtHtHtHTHTHTHtHTHTHTHtHTHTHtHTHTHT", + "HTHTHtHTHTHTHtHtHTHtHTHTHTHtHTHtHtHtHTHtHTHTHtHtHtHTHtHtHXS", + "HtHTHTHtHTHTHTHtHtHTHTHTHTHTHtHtHtHtHtHTHTHtHtHtHTHtHtHTHXZ", + "HtHTHTHtHTHtHTHtHTHtHTHTHtHTHtHTHtHtHTHtHtHtHtHTHtHTHTHTHXs", + "HtHTHTHtHtHTHtHTHTHTHTHtHTHTHtHTHtHtHtHtHTHtHtHTHtHTHTHTHTHTHTHXT", + "HtHtHtHTHTHtHTHtHtHtHtHtHtHtHtHTHtHTHTHtHtHtH", + "HTHtHtHtHtHTHTHTHtHtHtHTHtHtHTHtHtHTHtHtHtHTHtHTHtHTHtHtHtHtHtHt", + "HTHtHtHtHtHTHTHTHtHtHtHtHTHtHTHTHtHTHTHTHTHtHtHTHtHtHTHtHtHtHtHtHST", + "HtHTHtHtHtHTHtHTHtHTHtHTHtHtHtHTHtHtHtHTHtHTHtHTHtHTHtHtHtHTHtHt", + "HtHtHTHTHTHTHtHTHTHtHtHtHTHTHTHTHTHTHTHtHtHtHTHTHtHTHTHTHTHtHtHt", + "HTHTHTHtHtHtHtHTHTHTHtHtHtHTHTHTHTHTHtHtHTHTHtHTHtHTHTHTHTHt", + "HTHtHtHTHTHtHtHtHTHTHtHtHtHtHtHtHTHtHtHtHTHtHTHtHtHtHTHtHtHXs", + "HTHTHtHTHtHTHtHTHtHtHTHTHtHtHtHtHTHtHTHtHtHtHtHTHTHTHtHtHtHtHt", + "HTHtHTHTHtHTHtHtHtHTHtHtHtHTHTHTHtHTHTHtHTHTHTHtHTHTHTHTHtHtHtHZT", + "HtHTHtHTHTHTHTHTHTHtHTHtHtHtHtHTHTHtHtHTHTHtHTHtHTHTHtHtHtHtHtHtHXZT", + "HtHTHtHTHtHtHTHtHTHTHtHtHtHTHTHTHTHtHTHTHtHTHTHTHtHtHtHtHTHtHtHST", + "HtHtHtHTHTHTHtHtHTHTHTHtHTHtHtHtHTHtHTHTHTHtHtHTHTHTHtHtHtHs", + "HtHTHTHtHTHTHtHTHTHTHTHtHTHTHtHTHtHtHTHTHtHtHtHTHtHTHtHTHtHtHtHXT", + "HTHTHTHTHtHTHtHtHTHtHtHtHTHTHTHTHTHTHtHTHTHtHTHTHtHtHTHtHtHtHZT", + "HTHTHtHTHtHtHtHtHtHTHtHtHtHtHTHtHTHtHtHTHTHTHtHtHTHtHtHtHtHtHtHtHX", + "HtHTHtHTHTHtHtHtHTHTHtHTHtHtHtHtHtHtHtHTHtHTHtHtHtHtHTHTHtHtHtHST", + "HTHTHTHtHTHTHtHtHtHtHtHTHtHtHtHTHTHTHTHTHtHTHTHtHTHTHTHXS", + "HTHtHTHTHtHTHtHTHTHtHTHtHtHTHTHTHtHTHTHtHtHtHtHTHTHTHTHTHtHtHtHS", + "HtHTHtHtHTHtHTHTHtHtHtHtHTHTHTHTHtHTHtHTHTHTHtHtHTHtHTHtHtHtHT", + "HTHTHtHTHTHtHTHTHTHtHTHTHtHtHTHtHtHtHTHTHtHtHtHTHtHTHTHtHtHtHXS", + "HtHTHtHTHtHtHtHtHTHTHtHtHTHTHtHtHTHTHtHtHTHTHtHTHtHtHtHtHtHXZT", + "HTHtHtHtHTHTHTHtHtHtHTHTHTHtHTHtHTHtHtHTHtHtHTHTHtHTHTHTHTHXs", + "HtHtHTHTHtHtHtHtHtHtHtHtHTHtHTHTHTHtHtHTHTHTHTHtHTHtHtHtHtHtHtH", + "HtHTHTHTHTHtHTHTHTHTHTHTHtHtHtHTHTHtHtHTHtHTHtHtHtHtHtHTHTHtHtHZT", + "HTHtHtHTHTHTHTHtHTHTHTHtHTHTHTHTHTHtHtHTHTHTHtHtHtHtHtHtHtHXS", + "HTHTHTHtHtHtHtHTHtHTHtHTHtHTHTHtHtHTHtHtHTHTHtHTHTHTHtHTHTHtHtHZ", + "HTHTHtHTHtHtHtHTHtHTHtHTHtHtHtHTHTHtHtHTHTHtHTHtHTHTHTHTHX", + "HtHTHtHtHTHtHTHtHtHtHTHTHtHtHtHTHTHTHtHtHTHtHtHTHtHtHtHtHZ", + "HTHTHtHtHtHTHTHtHtHtHtHtHtHtHtHtHtHtHtHtHTHTHtHtHtHTHTHZ", + "HTHTHTHtHTHTHtHtHtHTHtHtHtHTHtHtHTHTHTHtHTHTHTHtHTHTHtHtHtHTHtHST", + "HTHTHtHTHtHtHtHtHTHTHtHtHTHtHTHtHTHTHtHtHTHTHTHTHtHTHtHtHXS", + "HTHtHtHTHTHTHTHTHTHTHtHTHTHTHTHTHTHtHTHTHTHTHTHTHTHtHtHTHt", + "HTHtHTHTHtHtHTHtHTHTHTHTHTHtHtHtHTHtHtHTHtHTHtHtHtHtHTHTHtHtHtHt", + "HTHtHtHtHtHtHtHtHTHTHtHTHtHTHtHTHtHtHTHtHTHTHtHtHtHTHTHTHTHX", + "HtHtHTHtHTHTHtHtHTHtHTHTHTHtHTHTHTHtHTHtHtHTHTHtHTHtHtHT", + "HtHtHTHtHTHtHTHtHtHTHTHtHtHTHtHTHTHTHtHTHTHTHtHTHtHTHTHtHtHXT", + "HtHtHTHtHTHtHTHtHTHtHTHtHTHtHTHtHtHTHtHTHTHtHtHtHTHTHTHTHTHTHTHTHZT", + "HtHTHTHTHtHTHtHTHTHtHtHtHtHtHTHTHTHTHTHtHtHTHtHTHtHtHtHTHXZT", + "HTHTHTHtHTHtHTHTHTHtHTHtHtHtHTHtHtHTHTHTHTHtHTHTHtHtHTHtHtHtHtHZT", + "HtHtHtHTHTHtHTHTHTHtHtHtHTHtHTHTHtHTHTHtHtHtHTHTHtHTHtHtHtHtHZ", + "HtHtHtHtHtHtHTHtHTHTHtHTHtHTHtHTHtHTHtHTHTHtHTHtHtHtHtHtHtHs", + "HTHtHTHTHTHTHTHtHtHtHtHtHTHTHtHtHTHtHtHTHTHTHTHTHtHTHTHtHtHTHt", + "HtHTHTHTHTHTHtHTHtHtHtHtHTHTHtHtHtHtHtHtHtHTHtHtHTHTHtHtHtHtHZ", + "HtHTHTHTHtHtHTHTHTHtHTHTHTHTHTHTHTHTHtHTHTHtHTHtHTHTHTHTHTHTHTHTHZT", + "HtHtHtHTHTHTHtHTHtHTHtHTHTHTHtHtHtHTHtHTHtHTHtHtHtHTHTHTHXST", + "HtHtHTHTHtHTHtHTHTHtHtHtHtHTHTHtHtHTHtHtHTHTHtHTHTHTHTHtHtHTHtHXt", + "HTHTHtHtHTHTHTHTHTHTHTHTHtHtHtHtHtHtHtHtHtHtHTHTHTHtHtHTHtHZ", + "HTHtHtHtHTHTHTHtHtHTHtHTHTHTHtHTHtHtHTHTHTHTHtHTHtHTHTHTHXs", + "HTHTHtHtHTHTHTHTHTHtHtHTHtHtHTHTHtHTHtHTHtHtHtHTHtHtHtHTHtH", + "HTHTHtHtHtHtHtHTHtHtHtHTHTHTHtHtHTHtHTHtHtHTHTHtHtHTHTHTHTHTHTHTHs", + "HtHtHtHTHtHTHTHtHtHtHtHtHTHTHtHtHtHtHTHTHtHtHXs", + "HTHTHtHtHTHTHtHTHTHtHtHtHTHTHTHTHtHTHtHTHTHtHtHtHtHtHtHtHtHTHtHt", + "HtHtHTHTHtHTHtHTHtHtHtHtHTHtHtHTHtHtHtHTHtHTHtHTHtHTHTHtHtHtHs", + "HtHtHtHTHTHTHtHtHtHtHTHTHtHtHTHTHtHtHTHTHTHTHtHtHtHTHTHTHX", + "HtHTHtHTHTHTHtHtHtHtHTHtHtHTHtHtHTHTHTHtHTHtHTHTHTHTHtHtHtHtHtHZT", + "HtHTHTHtHTHtHtHTHTHtHTHTHTHTHtHtHtHtHTHtHtHTHTHtHTHtHtHTHX", + "HTHTHTHTHtHtHtHTHtHTHtHTHtHtHTHTHTHtHtHTHtHTHtHtHTHTHTHTHTHXs", + "HtHtHTHtHTHTHTHtHTHTHTHtHTHtHtHtHtHtHTHTHTHTHTHtHtHtHTHtHtHtHtHtHXST", + "HTHTHtHtHTHTHtHtHtHtHtHTHTHtHTHTHTHtHTHTHtHtHtHtHTHtHtHtHtHtHtHXT", + "HtHtHtHtHTHTHTHtHtHtHTHtHtHtHtHtHtHtHTHtHtHtHTHTHTHtHtHtHtHZ", + "HTHtHtHtHTHTHTHTHTHtHtHtHtHtHTHtHTHTHtHTHtHtHTHtHTHTHtHTHtHtHST", + "HTHtHtHTHTHtHTHtHtHtHTHtHtHtHTHtHtHTHTHTHTHTHTHtHTHTHtHtHtH", + "HTHTHTHtHTHTHTHtHTHTHTHtHTHtHTHTHtHTHtHTHtHTHtHTHtHTHTHtHtHtHtHZT", + "HTHtHtHTHtHTHtHtHtHTHtHtHtHtHTHTHtHTHTHTHtHTHTHTHtHtHtHTHtHtHtHs", + "HtHTHTHTHtHTHtHtHTHtHTHtHTHtHtHtHtHtHtHtHTHtHTHTHTHtHTHtHtHs", + "HTHTHtHTHTHtHTHTHTHTHTHtHTHTHTHtHTHTHTHTHTHtHTHTHtHTHTHT", + "HTHtHTHtHTHTHTHtHTHtHTHTHtHtHtHtHTHtHTHTHtHtHtHtHtHTHtHtHtHtHtHT", + "HTHtHtHTHtHtHtHTHtHTHTHTHtHTHtHtHtHTHtHtHtHTHtHTHTHTHtHtHXs", + "HTHTHtHTHTHtHtHTHTHtHtHtHTHtHTHtHtHTHTHtHTHtHTHtHtHTHTHtHtHtHtHXS", + "HtHtHtHTHtHTHTHtHtHTHTHtHTHtHtHtHtHtHtHtHtHtHtHTHTHTHtHtHtHtHtHtHST", + "Z", + "HtHtHTHTHTHTHtHtHTHTHtHtHTHtHTHTHTHtHTHtHTHTHtHtHTHTHtHtHtHtHtHtHXZ", + "HtHTHTHTHTHtHtHtHtHtHtHTHTHtHTHtHtHTHTHtHtHTHtHtHtHTHtHtHtHtHtHtHXt", + "HTHTHtHtHtHTHtHtHtHtHTHtHtHtHtHTHtHtHtHTHtHtHtHtHTHtHtHTHs", + "HTHTHTHTHTHtHTHTHTHTHTHtHtHTHtHTHTHTHTHtHtHTHtHTHtHtHtHTHtHTHtHt", + "HtHtHTHtHtHTHtHtHtHtHtHTHtHtHtHTHtHtHtHtHtHTHtHtHTHtHtHt", + "HtHTHTHTHTHtHTHTHTHTHtHTHtHTHtHTHTHTHTHTHTHTHtHtHtHtHTHtHtHS", + "HTHTHtHtHtHtHtHTHtHtHtHTHtHTHTHtHtHtHTHtHtHtHTHtHtHTHtHtHtHTHtHS", + "HTHTHTHTHtHtHTHtHTHtHTHtHTHtHTHtHtHTHtHTHtHtHtHTHtHtHtHTHtHtHtHST", + "HTHTHtHtHTHTHTHTHtHTHTHTHtHTHTHTHtHtHTHtHTHtHTHTHTHtHtHTHtH", + "HtHTHTHTHTHtHtHtHtHTHTHTHTHtHtHtHtHTHtHTHtHtHTHtHTHtHtHTHtHtHXT", + "HTHTHTHTHtHtHtHTHTHTHtHTHTHTHTHTHTHTHtHTHTHTHtHtHtHTHTHTHTHZ", + "HtHtHTHTHtHtHTHTHTHTHTHtHtHTHtHtHtHTHtHtHTHTHTHTHtHTHTHTHTHTHTHXt", + "HtHtHTHTHTHtHtHtHtHTHTHTHTHTHTHtHtHTHtHTHtHtHtHTHtHTHtHTHTHtHtHXST", + "HTHTHTHTHTHtHtHTHtHTHtHtHTHTHTHtHtHTHtHTHtHTHtHtHtHTHTHTHTHXS", + "HtHtHTHTHTHTHtHtHTHTHTHtHTHtHtHTHtHTHTHTHtHtHTHTHTHTHtHtHZ", + "HtHTHtHTHtHtHTHtHTHTHTHTHTHtHTHTHtHtHtHTHTHTHtHTHtHtHTHtHtHtHtHST", + "HTHTHTHtHtHtHTHTHTHTHtHtHTHTHtHtHTHTHtHtHtHtHTHTHTHtHtHtHX", + "HtHTHtHtHTHTHTHTHTHTHTHTHtHTHTHTHtHtHtHTHtHTHTHTHTHTHTHtHtHTHXs", + "HTHtHtHTHTHtHtHtHTHTHtHTHTHtHTHtHtHtHtHtHTHTHtHTHtHTHtHTHtHtHtHT", + "HtHtHTHTHtHtHtHtHTHTHtHtHtHtHtHTHTHtHTHtHtHtHXS", + "HtHtHTHTHTHTHTHtHTHTHTHtHtHtHTHTHtHTHtHTHTHtHtHTHTHtHtHtHtHtHtHtHS", + "HTHtHtHTHTHtHTHtHTHTHtHtHtHTHTHtHtHtHtHtHtHTHtHtHtHTHtHtHtH", + "HtHTHTHTHtHtHtHTHTHtHTHtHtHtHTHtHTHTHtHtHtHtHTHtHTHtHtHtHXS", + "HTHtHtHTHTHtHTHtHTHtHTHtHtHTHtHTHtHTHtHTHtHTHTHtHTHTHtHtHtHZ", + "HtHTHTHtHtHtHtHtHTHTHtHTHtHtHTHTHtHtHtHTHTHtHtHtHTHtHTHTHtHtHtHXT", + "HTHTHTHtHtHtHTHtHTHtHTHtHtHtHTHTHTHtHTHtHTHtHTHTHTHtHtHtHXZT", + "HTHtHtHtHTHTHtHtHtHTHtHtHtHtHtHtHtHtHTHtHtHTHtHTHtHtHtHtHtHtHtHtHST", + "HTHTHTHTHtHtHTHTHtHTHTHTHTHTHTHTHtHtHTHTHTHTHtHTHtHtHtHtHtHTHZ", + "HTHTHtHtHTHTHTHtHTHtHTHTHtHtHtHTHTHtHtHTHtHTHtHtHTHtHTHtHtHtHXZT", + "HTHTHTHTHTHTHtHTHtHtHTHtHTHtHTHtHTHtHTHtHtHTHtHTHTHTHTHTHTHS", + "HtHTHtHtHTHTHTHtHTHTHtHTHTHTHTHtHtHtHTHTHtHTHTHtHtHtHtHTHtHTHX", + "HTHtHTHtHtHtHtHtHTHtHtHtHtHTHtHtHtHTHtHTHTHTHtHTHTHTHtHtHtHtHtHXS", + "HtHtHTHtHtHtHtHtHTHTHtHTHtHTHTHtHTHtHTHTHtHtHtHtHtHTHtHtHt", + "HTHTHtHTHtHTHtHTHtHTHtHTHtHTHtHTHTHtHTHtHtHTHTHTHtHtHtHtHtHtHtHtHST", + "HtHtHTHTHtHTHtHTHTHTHtHTHTHTHtHTHtHtHTHTHtHtHTHtHTHtHTHtHtHXt", + "HTHTHtHTHtHtHTHTHtHTHtHtHtHTHtHtHtHTHtHTHTHtHtHTHtHTHTHt", + "HtHTHTHTHTHTHTHTHtHtHTHtHTHtHTHtHTHTHtHTHtHtHTHTHTHtHtHtHtHX", + "HTHTHTHtHtHTHTHTHTHtHTHtHTHTHtHTHTHTHtHtHtHtHtHTHtHTHTHtHtHTHtHT", + "HTHTHtHtHTHtHTHtHTHtHtHtHTHtHTHtHTHTHTHtHTHtHTHtHTHTHtHtHXZT", + "HTHtHtHtHtHTHtHTHTHtHtHTHTHTHTHTHTHtHtHTHTHtHTHtHtHtHtHTHS", + "HTHtHTHTHTHtHtHTHtHtHtHTHtHtHtHTHTHtHTHTHTHtHTHTHTHtHtHTHtHtHtHZT", + "HtHtHTHTHTHtHtHTHTHTHTHTHTHTHTHTHTHTHTHTHtHtHTHTHTHtHtHZ", + "HtHTHtHTHTHTHtHtHtHTHTHtHTHTHtHTHTHtHtHTHtHtHtHtHtHTHTHTHX", + "HtHtHTHtHTHTHTHtHTHtHTHtHTHTHTHtHtHTHTHtHtHTHtHTHtHtHtHtHX", + "HTHTHtHtHTHtHtHtHTHtHtHTHTHtHTHTHtHtHTHtHTHtHTHtHTHTHTHTHtHtHtHZ", + "HtHTHTHtHtHtHtHTHtHtHtHTHtHtHtHtHtHTHTHtHtHtHTHTHTHTHTHTHTHXs", + "HtHTHTHtHtHTHtHTHtHtHtHtHtHTHTHtHtHTHtHtHTHtHTHtHTHTHTHtHTHtHtHST", + "HTHTHtHtHTHTHTHTHTHTHTHTHtHTHtHtHtHTHTHtHtHtHtHTHtHTHTHTHTHTHTH", + "HtHTHTHTHtHtHtHTHTHTHtHtHtHTHtHTHtHTHTHtHTHTHtHtHTHtHtHtHtHXS", + "HTHtHTHtHTHTHTHTHtHtHTHTHtHtHTHTHtHtHTHTHtHtHTHtHTHTHTHTHTHXST", + "HTHtHtHTHTHTHtHTHtHTHTHtHtHtHTHTHtHtHTHTHtHTHtHTHTHtHTHtHtHtHT", + "HtHTHTHtHTHTHTHTHtHtHTHTHtHTHTHTHTHtHtHtHtHtHTHTHtHtHtHTHtHtHS", + "HTHTHTHtHtHtHtHtHTHTHTHTHtHtHTHtHtHtHTHTHtHTHtHtHTHtHTHtHtHTHtHs", + "HTHTHTHtHTHTHtHTHTHTHTHTHtHtHtHTHtHtHtHtHtHTHTHtHTHTHTHXs", + "HtHTHtHtHTHTHtHTHtHtHtHtHtHTHtHTHtHTHtHtHtHtHTHTHtHTHTHtHtHtHtHZT", + "HtHtHTHtHTHTHTHTHTHtHTHTHTHTHtHTHtHTHTHtHtHtHTHTHtHTHTHTHTHTHTHTHX", + "HTHTHTHtHTHTHtHtHTHtHtHTHtHtHtHtHtHtHTHTHTHtHTHTHtHTHtHtHtHtHST", + "HtHtHTHTHTHtHtHtHTHtHTHTHTHtHtHtHtHTHTHtHtHTHtHtHtHtHtHtHtHTHtHXt", + "HtHTHtHtHTHtHtHTHTHtHTHTHTHTHtHTHTHTHTHtHTHTHtHtHTHtHtHTHtHS", + "HtHTHTHTHtHTHtHtHTHtHtHtHTHTHTHtHTHtHtHTHtHtHTHTHTHTHtHtHtHtHtHZT", + "HtHtHtHtHtHTHtHTHTHtHtHtHTHTHtHtHTHTHTHtHtHTHtHTHTHTHTHTHXs", + "HTHTHTHtHtHtHtHTHtHtHtHTHtHtHTHtHtHtHTHTHTHtHTHTHTHtHTHtHtHTHtHST", + "HTHTHTHTHtHtHtHTHTHTHTHtHTHtHTHTHTHTHtHtHTHTHtHTHtHTHtHTHtHtHT", + "HTHtHtHtHTHtHtHtHtHtHTHtHtHtHTHtHTHtHTHTHtHtHTHtHtHTHTHtHtHXS", + "HtHtHtHTHTHTHTHtHtHtHTHTHTHtHtHtHtHtHTHTHtHtHTHtHTHtHtHtHtHT", + "HtHTHTHtHTHtHtHtHTHTHtHTHTHtHTHtHTHtHTHTHtHTHTHtHtHtHTHtHTHTHtHT", + "HtHtHtHTHtHtHtHtHtHtHtHtHtHTHtHtHtHTHtHtHtHtHtHtHtHtHtHTHtHtHtHT", + "HTHtHtHTHtHtHTHTHtHTHtHTHTHTHtHTHTHTHTHtHtHtHtHTHtHTHtHtHtHtHtHtHZT", + "HTHTHtHTHtHtHTHtHtHTHtHtHtHTHTHTHtHtHtHTHtHtHtHtHtHtHtHTHtHTHtHT", + "HtHTHtHtHTHTHTHTHtHTHtHTHtHTHtHtHtHtHTHTHtHTHXZ", + "HTHtHtHTHTHtHTHtHtHtHtHTHtHtHTHtHTHTHTHTHtHTHTHtHTHtHtHtHtHtHtHXt", + "HTHtHtHTHtHTHtHTHtHTHtHtHTHtHTHtHTHTHtHTHTHTHTHtHTHtHtHtHXS", + "HtHtHTHTHTHtHTHTHtHtHTHtHTHtHtHTHtHTHtHtHTHTHtHTHTHTHtHtH", + "HTHtHtHtHTHtHtHTHTHTHTHtHTHTHTHTHtHTHTHTHTHtHtHTHtHtHtHTHS", + "HtHtHTHtHtHTHtHtHtHTHtHtHtHTHTHTHTHTHtHtHTHtHTHtHtHTHTHt", + "HTHTHtHTHTHtHTHtHTHTHTHtHtHtHTHTHtHtHtHTHtHTHtHtHTHTHTHtHtHTHtHS", + "HtHtHtHtHTHTHtHtHtHTHtHTHTHTHtHtHtHtHTHtHTHTHtHtHTHTHtHTHTHtHtHXZ", + "HTHTHtHtHTHTHTHTHTHtHTHTHtHtHTHtHTHtHTHTHTHtHTHTHtHTHtHTHtHtHXs", + "HTHtHtHTHTHtHTHtHTHTHTHtHtHTHTHTHTHTHTHtHTHTHTHtHtHtHtHtHtHTHt", + "HtHtHTHTHtHTHTHtHtHTHTHtHTHtHtHtHtHTHTHTHtHTHtHtHtHTHTHtHtHtHtHXZT", + "HTHtHtHtHTHTHTHTHTHtHTHTHtHTHTHtHtHTHtHtHtHtHtHTHTHtHTHTHtHtHtHt", + "HtHtHTHTHtHTHtHTHTHtHtHtHtHtHTHTHTHtHTHTHTHtHTHTHtHTHTHS", + "HTHTHtHTHTHTHtHtHTHtHTHTHTHtHTHtHtHtHTHtHTHTHtHtHtHTHtHtHXST", + "HtHTHTHtHTHTHTHtHtHTHTHTHTHTHtHtHtHtHtHTHTHtHtHtHTHtHtHTHXZT", + "HtHTHTHtHTHtHTHtHTHtHTHTHtHTHtHTHtHtHTHtHtHtHtHTHtHTHTHTHXt", + "HtHTHTHtHtHTHtHTHTHTHTHtHTHTHtHTHtHtHtHtHTHtHtHTHtHTHTHTHTHTHTHXS", + "HtHtHtHTHTHtHTHtHtHtHtHtHtHtHtHTHtHTHTHtHtHtHT", + "HTHtHtHtHtHTHTHTHtHtHtHTHtHtHTHtHtHTHtHtHtHTHtHTHtHTHtHtHtHtHtH", + "HTHtHtHtHtHTHTHTHtHtHtHtHTHtHTHTHtHTHTHTHTHtHtHTHtHtHTHtHtHtHtHtHZ", + "HtHTHtHtHtHTHtHTHtHTHtHTHtHtHtHTHtHtHtHTHtHTHtHTHtHTHtHtHtHTHtH", + "HtHtHTHTHTHTHtHTHTHtHtHtHTHTHTHTHTHTHTHtHtHtHTHTHtHTHTHTHTHtHtH", + "HTHTHTHtHtHtHtHTHTHTHtHtHtHTHTHTHTHTHtHtHTHTHtHTHtHTHTHTHTH", + "HTHtHtHTHTHtHtHtHTHTHtHtHtHtHtHtHTHtHtHtHTHtHTHtHtHtHTHtHtHXt", + "HTHTHtHTHtHTHtHTHtHtHTHTHtHtHtHtHTHtHTHtHtHtHtHTHTHTHtHtHtHtH", + "HTHtHTHTHtHTHtHtHtHTHtHtHtHTHTHTHtHTHTHtHTHTHTHtHTHTHTHTHtHtHtHs", + "HtHTHtHTHTHTHTHTHTHtHTHtHtHtHtHTHTHtHtHTHTHtHTHtHTHTHtHtHtHtHtHtHXs", + "HtHTHtHTHtHtHTHtHTHTHtHtHtHTHTHTHTHtHTHTHtHTHTHTHtHtHtHtHTHtHtHZ", + "HtHtHtHTHTHTHtHtHTHTHTHtHTHtHtHtHTHtHTHTHTHtHtHTHTHTHtHtHtHt", + "HtHTHTHtHTHTHtHTHTHTHTHtHTHTHtHTHtHtHTHTHtHtHtHTHtHTHtHTHtHtHtHXS", + "HTHTHTHTHtHTHtHtHTHtHtHtHTHTHTHTHTHTHtHTHTHtHTHTHtHtHTHtHtHtHs", + "HTHTHtHTHtHtHtHtHtHTHtHtHtHtHTHtHTHtHtHTHTHTHtHtHTHtHtHtHtHtHtHtHXT", + "HtHTHtHTHTHtHtHtHTHTHtHTHtHtHtHtHtHtHtHTHtHTHtHtHtHtHTHTHtHtHtHZ", + "HTHTHTHtHTHTHtHtHtHtHtHTHtHtHtHTHTHTHTHTHtHTHTHtHTHTHTHXST", + "HTHtHTHTHtHTHtHTHTHtHTHtHtHTHTHTHtHTHTHtHtHtHtHTHTHTHTHTHtHtHtHST", + "HtHTHtHtHTHtHTHTHtHtHtHtHTHTHTHTHtHTHtHTHTHTHtHtHTHtHTHtHtHtHS", + "HTHTHtHTHTHtHTHTHTHtHTHTHtHtHTHtHtHtHTHTHtHtHtHTHtHTHTHtHtHtHXST", + "HtHTHtHTHtHtHtHtHTHTHtHtHTHTHtHtHTHTHtHtHTHTHtHTHtHtHtHtHtHXs", + "HTHtHtHtHTHTHTHtHtHtHTHTHTHtHTHtHTHtHtHTHtHtHTHTHtHTHTHTHTHXt", + "HtHtHTHTHtHtHtHtHtHtHtHtHTHtHTHTHTHtHtHTHTHTHTHtHTHtHtHtHtHtHtHT", + "HtHTHTHTHTHtHTHTHTHTHTHTHtHtHtHTHTHtHtHTHtHTHtHtHtHtHtHTHTHtHtHs", + "HTHtHtHTHTHTHTHtHTHTHTHtHTHTHTHTHTHtHtHTHTHTHtHtHtHtHtHtHtHXST", + "HTHTHTHtHtHtHtHTHtHTHtHTHtHTHTHtHtHTHtHtHTHTHtHTHTHTHtHTHTHtHtHZT", + "HTHTHtHTHtHtHtHTHtHTHtHTHtHtHtHTHTHtHtHTHTHtHTHtHTHTHTHTHXT", + "HtHTHtHtHTHtHTHtHtHtHTHTHtHtHtHTHTHTHtHtHTHtHtHTHtHtHtHtHZT", + "HTHTHtHtHtHTHTHtHtHtHtHtHtHtHtHtHtHtHtHtHTHTHtHtHtHTHTHZT", + "HTHTHTHtHTHTHtHtHtHTHtHtHtHTHtHtHTHTHTHtHTHTHTHtHTHTHtHtHtHTHtHZ", + "HTHTHtHTHtHtHtHtHTHTHtHtHTHtHTHtHTHTHtHtHTHTHTHTHtHTHtHtHXST", + "HTHtHtHTHTHTHTHTHTHTHtHTHTHTHTHTHTHtHTHTHTHTHTHTHTHtHtHTH", + "HTHtHTHTHtHtHTHtHTHTHTHTHTHtHtHtHTHtHtHTHtHTHtHtHtHtHTHTHtHtHtH", + "HTHtHtHtHtHtHtHtHTHTHtHTHtHTHtHTHtHtHTHtHTHTHtHtHtHTHTHTHTHXT", + "HtHtHTHtHTHTHtHtHTHtHTHTHTHtHTHTHTHtHTHtHtHTHTHtHTHtHtHS", + "HtHtHTHtHTHtHTHtHtHTHTHtHtHTHtHTHTHTHtHTHTHTHtHTHtHTHTHtHtHXS", + "HtHtHTHtHTHtHTHtHTHtHTHtHTHtHTHtHtHTHtHTHTHtHtHtHTHTHTHTHTHTHTHTHs", + "HtHTHTHTHtHTHtHTHTHtHtHtHtHtHTHTHTHTHTHtHtHTHtHTHtHtHtHTHXs", + "HTHTHTHtHTHtHTHTHTHtHTHtHtHtHTHtHtHTHTHTHTHtHTHTHtHtHTHtHtHtHtHs", + "HtHtHtHTHTHtHTHTHTHtHtHtHTHtHTHTHtHTHTHtHtHtHTHTHtHTHtHtHtHtHZT", + "HtHtHtHtHtHtHTHtHTHTHtHTHtHTHtHTHtHTHtHTHTHtHTHtHtHtHtHtHtHt", + "HTHtHTHTHTHTHTHtHtHtHtHtHTHTHtHtHTHtHtHTHTHTHTHTHtHTHTHtHtHTH", + "HtHTHTHTHTHTHtHTHtHtHtHtHTHTHtHtHtHtHtHtHtHTHtHtHTHTHtHtHtHtHZT", + "HtHTHTHTHtHtHTHTHTHtHTHTHTHTHTHTHTHTHtHTHTHtHTHtHTHTHTHTHTHTHTHTHs", + "HtHtHtHTHTHTHtHTHtHTHtHTHTHTHtHtHtHTHtHTHtHTHtHtHtHTHTHTHXZ", + "HtHtHTHTHtHTHtHTHTHtHtHtHtHTHTHtHtHTHtHtHTHTHtHTHTHTHTHtHtHTHtHX", + "HTHTHtHtHTHTHTHTHTHTHTHTHtHtHtHtHtHtHtHtHtHtHTHTHTHtHtHTHtHZT", + "HTHtHtHtHTHTHTHtHtHTHtHTHTHTHtHTHtHtHTHTHTHTHtHTHtHTHTHTHXt", + "HTHTHtHtHTHTHTHTHTHtHtHTHtHtHTHTHtHTHtHTHtHtHtHTHtHtHtHTHtHT", + "HTHTHtHtHtHtHtHTHtHtHtHTHTHTHtHtHTHtHTHtHtHTHTHtHtHTHTHTHTHTHTHTHt", + "HtHtHtHTHtHTHTHtHtHtHtHtHTHTHtHtHtHtHTHTHtHtHXt", + "HTHTHtHtHTHTHtHTHTHtHtHtHTHTHTHTHtHTHtHTHTHtHtHtHtHtHtHtHtHTHtH", + "HtHtHTHTHtHTHtHTHtHtHtHtHTHtHtHTHtHtHtHTHtHTHtHTHtHTHTHtHtHtHt", + "HtHtHtHTHTHTHtHtHtHtHTHTHtHtHTHTHtHtHTHTHTHTHtHtHtHTHTHTHXT", + "HtHTHtHTHTHTHtHtHtHtHTHtHtHTHtHtHTHTHTHtHTHtHTHTHTHTHtHtHtHtHtHs", + "HtHTHTHtHTHtHtHTHTHtHTHTHTHTHtHtHtHtHTHtHtHTHTHtHTHtHtHTHXT", + "HTHTHTHTHtHtHtHTHtHTHtHTHtHtHTHTHTHtHtHTHtHTHtHtHTHTHTHTHTHXt", + "HtHtHTHtHTHTHTHtHTHTHTHtHTHtHtHtHtHtHTHTHTHTHTHtHtHtHTHtHtHtHtHtHXZ", + "HTHTHtHtHTHTHtHtHtHtHtHTHTHtHTHTHTHtHTHTHtHtHtHtHTHtHtHtHtHtHtHXS", + "HtHtHtHtHTHTHTHtHtHtHTHtHtHtHtHtHtHtHTHtHtHtHTHTHTHtHtHtHtHZT", + "HTHtHtHtHTHTHTHTHTHtHtHtHtHtHTHtHTHTHtHTHtHtHTHtHTHTHtHTHtHtHZ", + "HTHtHtHTHTHtHTHtHtHtHTHtHtHtHTHtHtHTHTHTHTHTHTHtHTHTHtHtHtHT", + "HTHTHTHtHTHTHTHtHTHTHTHtHTHtHTHTHtHTHtHTHtHTHtHTHtHTHTHtHtHtHtHs", + "HTHtHtHTHtHTHtHtHtHTHtHtHtHtHTHTHtHTHTHTHtHTHTHTHtHtHtHTHtHtHtHt", + "HtHTHTHTHtHTHtHtHTHtHTHtHTHtHtHtHtHtHtHtHTHtHTHTHTHtHTHtHtHt", + "HTHTHtHTHTHtHTHTHTHTHTHtHTHTHTHtHTHTHTHTHTHtHTHTHtHTHTHS", + "HTHtHTHtHTHTHTHtHTHtHTHTHtHtHtHtHTHtHTHTHtHtHtHtHtHTHtHtHtHtHtHS", + "HTHtHtHTHtHtHtHTHtHTHTHTHtHTHtHtHtHTHtHtHtHTHtHTHTHTHtHtHXt", + "HTHTHtHTHTHtHtHTHTHtHtHtHTHtHTHtHtHTHTHtHTHtHTHtHtHTHTHtHtHtHtHXST", + "HtHtHtHTHtHTHTHtHtHTHTHtHTHtHtHtHtHtHtHtHtHtHtHTHTHTHtHtHtHtHtHtHZ", + "ZT", + "HtHtHTHTHTHTHtHtHTHTHtHtHTHtHTHTHTHtHTHtHTHTHtHtHTHTHtHtHtHtHtHtHXZT", + "HtHTHTHTHTHtHtHtHtHtHtHTHTHtHTHtHtHTHTHtHtHTHtHtHtHTHtHtHtHtHtHtHX", + "HTHTHtHtHtHTHtHtHtHtHTHtHtHtHtHTHtHtHtHTHtHtHtHtHTHtHtHTHt", + "HTHTHTHTHTHtHTHTHTHTHTHtHtHTHtHTHTHTHTHtHtHTHtHTHtHtHtHTHtHTHtH", + "HtHtHTHtHtHTHtHtHtHtHtHTHtHtHtHTHtHtHtHtHtHTHtHtHTHtHtH", + "HtHTHTHTHTHtHTHTHTHTHtHTHtHTHtHTHTHTHTHTHTHTHtHtHtHtHTHtHtHST", + "HTHTHtHtHtHtHtHTHtHtHtHTHtHTHTHtHtHtHTHtHtHtHTHtHtHTHtHtHtHTHtHST", + "HTHTHTHTHtHtHTHtHTHtHTHtHTHtHTHtHtHTHtHTHtHtHtHTHtHtHtHTHtHtHtHZ", + "HTHTHtHtHTHTHTHTHtHTHTHTHtHTHTHTHtHtHTHtHTHtHTHTHTHtHtHTHtHT", + "HtHTHTHTHTHtHtHtHtHTHTHTHTHtHtHtHtHTHtHTHtHtHTHtHTHtHtHTHtHtHXS", + "HTHTHTHTHtHtHtHTHTHTHtHTHTHTHTHTHTHTHtHTHTHTHtHtHtHTHTHTHTHZT", + "HtHtHTHTHtHtHTHTHTHTHTHtHtHTHtHtHtHTHtHtHTHTHTHTHtHTHTHTHTHTHTHX", + "HtHtHTHTHTHtHtHtHtHTHTHTHTHTHTHtHtHTHtHTHtHtHtHTHtHTHtHTHTHtHtHXZ", + "HTHTHTHTHTHtHtHTHtHTHtHtHTHTHTHtHtHTHtHTHtHTHtHtHtHTHTHTHTHXST", + "HtHtHTHTHTHTHtHtHTHTHTHtHTHtHtHTHtHTHTHTHtHtHTHTHTHTHtHtHZT", + "HtHTHtHTHtHtHTHtHTHTHTHTHTHtHTHTHtHtHtHTHTHTHtHTHtHtHTHtHtHtHtHZ", + "HTHTHTHtHtHtHTHTHTHTHtHtHTHTHtHtHTHTHtHtHtHtHTHTHTHtHtHtHXT", + "HtHTHtHtHTHTHTHTHTHTHTHTHtHTHTHTHtHtHtHTHtHTHTHTHTHTHTHtHtHTHXt", + "HTHtHtHTHTHtHtHtHTHTHtHTHTHtHTHtHtHtHtHtHTHTHtHTHtHTHtHTHtHtHtHS", + "HtHtHTHTHtHtHtHtHTHTHtHtHtHtHtHTHTHtHTHtHtHtHXST", + "HtHtHTHTHTHTHTHtHTHTHTHtHtHtHTHTHtHTHtHTHTHtHtHTHTHtHtHtHtHtHtHtHST", + "HTHtHtHTHTHtHTHtHTHTHtHtHtHTHTHtHtHtHtHtHtHTHtHtHtHTHtHtHtHT", + "HtHTHTHTHtHtHtHTHTHtHTHtHtHtHTHtHTHTHtHtHtHtHTHtHTHtHtHtHXST", + "HTHtHtHTHTHtHTHtHTHtHTHtHtHTHtHTHtHTHtHTHtHTHTHtHTHTHtHtHtHZT", + "HtHTHTHtHtHtHtHtHTHTHtHTHtHtHTHTHtHtHtHTHTHtHtHtHTHtHTHTHtHtHtHXS", + "HTHTHTHtHtHtHTHtHTHtHTHtHtHtHTHTHTHtHTHtHTHtHTHTHTHtHtHtHXs", + "HTHtHtHtHTHTHtHtHtHTHtHtHtHtHtHtHtHtHTHtHtHTHtHTHtHtHtHtHtHtHtHtHZ", + "HTHTHTHTHtHtHTHTHtHTHTHTHTHTHTHTHtHtHTHTHTHTHtHTHtHtHtHtHtHTHZT", + "HTHTHtHtHTHTHTHtHTHtHTHTHtHtHtHTHTHtHtHTHtHTHtHtHTHtHTHtHtHtHXs", + "HTHTHTHTHTHTHtHTHtHtHTHtHTHtHTHtHTHtHTHtHtHTHtHTHTHTHTHTHTHST", + "HtHTHtHtHTHTHTHtHTHTHtHTHTHTHTHtHtHtHTHTHtHTHTHtHtHtHtHTHtHTHXT", + "HTHtHTHtHtHtHtHtHTHtHtHtHtHTHtHtHtHTHtHTHTHTHtHTHTHTHtHtHtHtHtHXST", + "HtHtHTHtHtHtHtHtHTHTHtHTHtHTHTHtHTHtHTHTHtHtHtHtHtHTHtHtH", + "HTHTHtHTHtHTHtHTHtHTHtHTHtHTHtHTHTHtHTHtHtHTHTHTHtHtHtHtHtHtHtHtHZ", + "HtHtHTHTHtHTHtHTHTHTHtHTHTHTHtHTHtHtHTHTHtHtHTHtHTHtHTHtHtHX", + "HTHTHtHTHtHtHTHTHtHTHtHtHtHTHtHtHtHTHtHTHTHtHtHTHtHTHTH", + "HtHTHTHTHTHTHTHTHtHtHTHtHTHtHTHtHTHTHtHTHtHtHTHTHTHtHtHtHtHXT", + "HTHTHTHtHtHTHTHTHTHtHTHtHTHTHtHTHTHTHtHtHtHtHtHTHtHTHTHtHtHTHtHS", + "HTHTHtHtHTHtHTHtHTHtHtHtHTHtHTHtHTHTHTHtHTHtHTHtHTHTHtHtHXs", + "HTHtHtHtHtHTHtHTHTHtHtHTHTHTHTHTHTHtHtHTHTHtHTHtHtHtHtHTHST", + "HTHtHTHTHTHtHtHTHtHtHtHTHtHtHtHTHTHtHTHTHTHtHTHTHTHtHtHTHtHtHtHs", + "HtHtHTHTHTHtHtHTHTHTHTHTHTHTHTHTHTHTHTHTHtHtHTHTHTHtHtHZT", + "HtHTHtHTHTHTHtHtHtHTHTHtHTHTHtHTHTHtHtHTHtHtHtHtHtHTHTHTHXT", + "HtHtHTHtHTHTHTHtHTHtHTHtHTHTHTHtHtHTHTHtHtHTHtHTHtHtHtHtHXT", + "HTHTHtHtHTHtHtHtHTHtHtHTHTHtHTHTHtHtHTHtHTHtHTHtHTHTHTHTHtHtHtHZT", + "HtHTHTHtHtHtHtHTHtHtHtHTHtHtHtHtHtHTHTHtHtHtHTHTHTHTHTHTHTHXt", + "HtHTHTHtHtHTHtHTHtHtHtHtHtHTHTHtHtHTHtHtHTHtHTHtHTHTHTHtHTHtHtHZ", + "HTHTHtHtHTHTHTHTHTHTHTHTHtHTHtHtHtHTHTHtHtHtHtHTHtHTHTHTHTHTHTHT", + "HtHTHTHTHtHtHtHTHTHTHtHtHtHTHtHTHtHTHTHtHTHTHtHtHTHtHtHtHtHXST", + "HTHtHTHtHTHTHTHTHtHtHTHTHtHtHTHTHtHtHTHTHtHtHTHtHTHTHTHTHTHXZ", + "HTHtHtHTHTHTHtHTHtHTHTHtHtHtHTHTHtHtHTHTHtHTHtHTHTHtHTHtHtHtHS", + "HtHTHTHtHTHTHTHTHtHtHTHTHtHTHTHTHTHtHtHtHtHtHTHTHtHtHtHTHtHtHST", + "HTHTHTHtHtHtHtHtHTHTHTHTHtHtHTHtHtHtHTHTHtHTHtHtHTHtHTHtHtHTHtHt", + "HTHTHTHtHTHTHtHTHTHTHTHTHtHtHtHTHtHtHtHtHtHTHTHtHTHTHTHXt", + "HtHTHtHtHTHTHtHTHtHtHtHtHtHTHtHTHtHTHtHtHtHtHTHTHtHTHTHtHtHtHtHs", + "HtHtHTHtHTHTHTHTHTHtHTHTHTHTHtHTHtHTHTHtHtHtHTHTHtHTHTHTHTHTHTHTHXT", + "HTHTHTHtHTHTHtHtHTHtHtHTHtHtHtHtHtHtHTHTHTHtHTHTHtHTHtHtHtHtHZ", + "HtHtHTHTHTHtHtHtHTHtHTHTHTHtHtHtHtHTHTHtHtHTHtHtHtHtHtHtHtHTHtHX", + "HtHTHtHtHTHtHtHTHTHtHTHTHTHTHtHTHTHTHTHtHTHTHtHtHTHtHtHTHtHST", + "HtHTHTHTHtHTHtHtHTHtHtHtHTHTHTHtHTHtHtHTHtHtHTHTHTHTHtHtHtHtHtHs", + "HtHtHtHtHtHTHtHTHTHtHtHtHTHTHtHtHTHTHTHtHtHTHtHTHTHTHTHTHXt", + "HTHTHTHtHtHtHtHTHtHtHtHTHtHtHTHtHtHtHTHTHTHtHTHTHTHtHTHtHtHTHtHZ", + "HTHTHTHTHtHtHtHTHTHTHTHtHTHtHTHTHTHTHtHtHTHTHtHTHtHTHtHTHtHtHS", + "HTHtHtHtHTHtHtHtHtHtHTHtHtHtHTHtHTHtHTHTHtHtHTHtHtHTHTHtHtHXST", + "HtHtHtHTHTHTHTHtHtHtHTHTHTHtHtHtHtHtHTHTHtHtHTHtHTHtHtHtHtHS", + "HtHTHTHtHTHtHtHtHTHTHtHTHTHtHTHtHTHtHTHTHtHTHTHtHtHtHTHtHTHTHtHS", + "HtHtHtHTHtHtHtHtHtHtHtHtHtHTHtHtHtHTHtHtHtHtHtHtHtHtHtHTHtHtHtHS", + "HTHtHtHTHtHtHTHTHtHTHtHTHTHTHtHTHTHTHTHtHtHtHtHTHtHTHtHtHtHtHtHtHs", + "HTHTHtHTHtHtHTHtHtHTHtHtHtHTHTHTHtHtHtHTHtHtHtHtHtHtHtHTHtHTHtHS", + "HtHTHtHtHTHTHTHTHtHTHtHTHtHTHtHtHtHtHTHTHtHTHXZT", + "HTHtHtHTHTHtHTHtHtHtHtHTHtHtHTHtHTHTHTHTHtHTHTHtHTHtHtHtHtHtHtHX", + "HTHtHtHTHtHTHtHTHtHTHtHtHTHtHTHtHTHTHtHTHTHTHTHtHTHtHtHtHXST", + "HtHtHTHTHTHtHTHTHtHtHTHtHTHtHtHTHtHTHtHtHTHTHtHTHTHTHtHtHT", + "HTHtHtHtHTHtHtHTHTHTHTHtHTHTHTHTHtHTHTHTHTHtHtHTHtHtHtHTHST", + "HtHtHTHtHtHTHtHtHtHTHtHtHtHTHTHTHTHTHtHtHTHtHTHtHtHTHTH", + "HTHTHtHTHTHtHTHtHTHTHTHtHtHtHTHTHtHtHtHTHtHTHtHtHTHTHTHtHtHTHtHST", + "HtHtHtHtHTHTHtHtHtHTHtHTHTHTHtHtHtHtHTHtHTHTHtHtHTHTHtHTHTHtHtHXZT", + "HTHTHtHtHTHTHTHTHTHtHTHTHtHtHTHtHTHtHTHTHTHtHTHTHtHTHtHTHtHtHXt", + "HTHtHtHTHTHtHTHtHTHTHTHtHtHTHTHTHTHTHTHtHTHTHTHtHtHtHtHtHtHTH", + "HtHtHTHTHtHTHTHtHtHTHTHtHTHtHtHtHtHTHTHTHtHTHtHtHtHTHTHtHtHtHtHXs", + "HTHtHtHtHTHTHTHTHTHtHTHTHtHTHTHtHtHTHtHtHtHtHtHTHTHtHTHTHtHtHtH", + "HtHtHTHTHtHTHtHTHTHtHtHtHtHtHTHTHTHtHTHTHTHtHTHTHtHTHTHST", + "HTHTHtHTHTHTHtHtHTHtHTHTHTHtHTHtHtHtHTHtHTHTHtHtHtHTHtHtHXZ", + "HtHTHTHtHTHTHTHtHtHTHTHTHTHTHtHtHtHtHtHTHTHtHtHtHTHtHtHTHXs", + "HtHTHTHtHTHtHTHtHTHtHTHTHtHTHtHTHtHtHTHtHtHtHtHTHtHTHTHTHX", + "HtHTHTHtHtHTHtHTHTHTHTHtHTHTHtHTHtHtHtHtHTHtHtHTHtHTHTHTHTHTHTHXST", + "HtHtHtHTHTHtHTHtHtHtHtHtHtHtHtHTHtHTHTHtHtHtHS", + "HTHtHtHtHtHTHTHTHtHtHtHTHtHtHTHtHtHTHtHtHtHTHtHTHtHTHtHtHtHtHtHT", + "HTHtHtHtHtHTHTHTHtHtHtHtHTHtHTHTHtHTHTHTHTHtHtHTHtHtHTHtHtHtHtHtHZT", + "HtHTHtHtHtHTHtHTHtHTHtHTHtHtHtHTHtHtHtHTHtHTHtHTHtHTHtHtHtHTHtHT", + "HtHtHTHTHTHTHtHTHTHtHtHtHTHTHTHTHTHTHTHtHtHtHTHTHtHTHTHTHTHtHtHT", + "HTHTHTHtHtHtHtHTHTHTHtHtHtHTHTHTHTHTHtHtHTHTHtHTHtHTHTHTHTHT", + "HTHtHtHTHTHtHtHtHTHTHtHtHtHtHtHtHTHtHtHtHTHtHTHtHtHtHTHtHtHX", + "HTHTHtHTHtHTHtHTHtHtHTHTHtHtHtHtHTHtHTHtHtHtHtHTHTHTHtHtHtHtHT", + "HTHtHTHTHtHTHtHtHtHTHtHtHtHTHTHTHtHTHTHtHTHTHTHtHTHTHTHTHtHtHtHt", + "HtHTHtHTHTHTHTHTHTHtHTHtHtHtHtHTHTHtHtHTHTHtHTHtHTHTHtHtHtHtHtHtHXt", + "HtHTHtHTHtHtHTHtHTHTHtHtHtHTHTHTHTHtHTHTHtHTHTHTHtHtHtHtHTHtHtHZT", + "HtHtHtHTHTHTHtHtHTHTHTHtHTHtHtHtHTHtHTHTHTHtHtHTHTHTHtHtHtH", + "HtHTHTHtHTHTHtHTHTHTHTHtHTHTHtHTHtHtHTHTHtHtHtHTHtHTHtHTHtHtHtHXST", + "HTHTHTHTHtHTHtHtHTHtHtHtHTHTHTHTHTHTHtHTHTHtHTHTHtHtHTHtHtHtHt", + "HTHTHtHTHtHtHtHtHtHTHtHtHtHtHTHtHTHtHtHTHTHTHtHtHTHtHtHtHtHtHtHtHXS", + "HtHTHtHTHTHtHtHtHTHTHtHTHtHtHtHtHtHtHtHTHtHTHtHtHtHtHTHTHtHtHtHZT", + "HTHTHTHtHTHTHtHtHtHtHtHTHtHtHtHTHTHTHTHTHtHTHTHtHTHTHTHXZ", + "HTHtHTHTHtHTHtHTHTHtHTHtHtHTHTHTHtHTHTHtHtHtHtHTHTHTHTHTHtHtHtHZ", + "HtHTHtHtHTHtHTHTHtHtHtHtHTHTHTHTHtHTHtHTHTHTHtHtHTHtHTHtHtHtHST", + "HTHTHtHTHTHtHTHTHTHtHTHTHtHtHTHtHtHtHTHTHtHtHtHTHtHTHTHtHtHtHXZ", + "HtHTHtHTHtHtHtHtHTHTHtHtHTHTHtHtHTHTHtHtHTHTHtHTHtHtHtHtHtHXt", + "HTHtHtHtHTHTHTHtHtHtHTHTHTHtHTHtHTHtHtHTHtHtHTHTHtHTHTHTHTHX", + "HtHtHTHTHtHtHtHtHtHtHtHtHTHtHTHTHTHtHtHTHTHTHTHtHTHtHtHtHtHtHtHS", + "HtHTHTHTHTHtHTHTHTHTHTHTHtHtHtHTHTHtHtHTHtHTHtHtHtHtHtHTHTHtHtHt", + "HTHtHtHTHTHTHTHtHTHTHTHtHTHTHTHTHTHtHtHTHTHTHtHtHtHtHtHtHtHXZ", + "HTHTHTHtHtHtHtHTHtHTHtHTHtHTHTHtHtHTHtHtHTHTHtHTHTHTHtHTHTHtHtHs", + "HTHTHtHTHtHtHtHTHtHTHtHTHtHtHtHTHTHtHtHTHTHtHTHtHTHTHTHTHXS", + "HtHTHtHtHTHtHTHtHtHtHTHTHtHtHtHTHTHTHtHtHTHtHtHTHtHtHtHtHs", + "HTHTHtHtHtHTHTHtHtHtHtHtHtHtHtHtHtHtHtHtHTHTHtHtHtHTHTHs", + "HTHTHTHtHTHTHtHtHtHTHtHtHtHTHtHtHTHTHTHtHTHTHTHtHTHTHtHtHtHTHtHZT", + "HTHTHtHTHtHtHtHtHTHTHtHtHTHtHTHtHTHTHtHtHTHTHTHTHtHTHtHtHXZ", + "HTHtHtHTHTHTHTHTHTHTHtHTHTHTHTHTHTHtHTHTHTHTHTHTHTHtHtHTHT", + "HTHtHTHTHtHtHTHtHTHTHTHTHTHtHtHtHTHtHtHTHtHTHtHtHtHtHTHTHtHtHtHT", + "HTHtHtHtHtHtHtHtHTHTHtHTHtHTHtHTHtHtHTHtHTHTHtHtHtHTHTHTHTHXS", + "HtHtHTHtHTHTHtHtHTHtHTHTHTHtHTHTHTHtHTHtHtHTHTHtHTHtHtHST", + "HtHtHTHtHTHtHTHtHtHTHTHtHtHTHtHTHTHTHtHTHTHTHtHTHtHTHTHtHtHXST", + "HtHtHTHtHTHtHTHtHTHtHTHtHTHtHTHtHtHTHtHTHTHtHtHtHTHTHTHTHTHTHTHTHt", + "HtHTHTHTHtHTHtHTHTHtHtHtHtHtHTHTHTHTHTHtHtHTHtHTHtHtHtHTHXt", + "HTHTHTHtHTHtHTHTHTHtHTHtHtHtHTHtHtHTHTHTHTHtHTHTHtHtHTHtHtHtHtHt", + "HtHtHtHTHTHtHTHTHTHtHtHtHTHtHTHTHtHTHTHtHtHtHTHTHtHTHtHtHtHtHs", + "HtHtHtHtHtHtHTHtHTHTHtHTHtHTHtHTHtHTHtHTHTHtHTHtHtHtHtHtHtH", + "HTHtHTHTHTHTHTHtHtHtHtHtHTHTHtHtHTHtHtHTHTHTHTHTHtHTHTHtHtHTHT", + "HtHTHTHTHTHTHtHTHtHtHtHtHTHTHtHtHtHtHtHtHtHTHtHtHTHTHtHtHtHtHs", + "HtHTHTHTHtHtHTHTHTHtHTHTHTHTHTHTHTHTHtHTHTHtHTHtHTHTHTHTHTHTHTHTHt", + "HtHtHtHTHTHTHtHTHtHTHtHTHTHTHtHtHtHTHtHTHtHTHtHtHtHTHTHTHXZT", + "HtHtHTHTHtHTHtHTHTHtHtHtHtHTHTHtHtHTHtHtHTHTHtHTHTHTHTHtHtHTHtHXT", + "HTHTHtHtHTHTHTHTHTHTHTHTHtHtHtHtHtHtHtHtHtHtHTHTHTHtHtHTHtHs", + "HTHtHtHtHTHTHTHtHtHTHtHTHTHTHtHTHtHtHTHTHTHTHtHTHtHTHTHTHX", + "HTHTHtHtHTHTHTHTHTHtHtHTHtHtHTHTHtHTHtHTHtHtHtHTHtHtHtHTHtHS", + "HTHTHtHtHtHtHtHTHtHtHtHTHTHTHtHtHTHtHTHtHtHTHTHtHtHTHTHTHTHTHTHTH", + "HtHtHtHTHtHTHTHtHtHtHtHtHTHTHtHtHtHtHTHTHtHtHX", + "HTHTHtHtHTHTHtHTHTHtHtHtHTHTHTHTHtHTHtHTHTHtHtHtHtHtHtHtHtHTHtHT", + "HtHtHTHTHtHTHtHTHtHtHtHtHTHtHtHTHtHtHtHTHtHTHtHTHtHTHTHtHtHtH", + "HtHtHtHTHTHTHtHtHtHtHTHTHtHtHTHTHtHtHTHTHTHTHtHtHtHTHTHTHXS", + "HtHTHtHTHTHTHtHtHtHtHTHtHtHTHtHtHTHTHTHtHTHtHTHTHTHTHtHtHtHtHtHt", + "HtHTHTHtHTHtHtHTHTHtHTHTHTHTHtHtHtHtHTHtHtHTHTHtHTHtHtHTHXS", + "HTHTHTHTHtHtHtHTHtHTHtHTHtHtHTHTHTHtHtHTHtHTHtHtHTHTHTHTHTHX", + "HtHtHTHtHTHTHTHtHTHTHTHtHTHtHtHtHtHtHTHTHTHTHTHtHtHtHTHtHtHtHtHtHXZT", + "HTHTHtHtHTHTHtHtHtHtHtHTHTHtHTHTHTHtHTHTHtHtHtHtHTHtHtHtHtHtHtHXST", + "HtHtHtHtHTHTHTHtHtHtHTHtHtHtHtHtHtHtHTHtHtHtHTHTHTHtHtHtHtHs", + "HTHtHtHtHTHTHTHTHTHtHtHtHtHtHTHtHTHTHtHTHtHtHTHtHTHTHtHTHtHtHZT", + "HTHtHtHTHTHtHTHtHtHtHTHtHtHtHTHtHtHTHTHTHTHTHTHtHTHTHtHtHtHS", + "HTHTHTHtHTHTHTHtHTHTHTHtHTHtHTHTHtHTHtHTHtHTHtHTHtHTHTHtHtHtHtHt", + "HTHtHtHTHtHTHtHtHtHTHtHtHtHtHTHTHtHTHTHTHtHTHTHTHtHtHtHTHtHtHtH", + "HtHTHTHTHtHTHtHtHTHtHTHtHTHtHtHtHtHtHtHtHTHtHTHTHTHtHTHtHtH", + "HTHTHtHTHTHtHTHTHTHTHTHtHTHTHTHtHTHTHTHTHTHtHTHTHtHTHTHST", + "HTHtHTHtHTHTHTHtHTHtHTHTHtHtHtHtHTHtHTHTHtHtHtHtHtHTHtHtHtHtHtHST", + "HTHtHtHTHtHtHtHTHtHTHTHTHtHTHtHtHtHTHtHtHtHTHtHTHTHTHtHtHX", + "HTHTHtHTHTHtHtHTHTHtHtHtHTHtHTHtHtHTHTHtHTHtHTHtHtHTHTHtHtHtHtHXZ", + "HtHtHtHTHtHTHTHtHtHTHTHtHTHtHtHtHtHtHtHtHtHtHtHTHTHTHtHtHtHtHtHtHZT", + "s", + "HtHtHTHTHTHTHtHtHTHTHtHtHTHtHTHTHTHtHTHtHTHTHtHtHTHTHtHtHtHtHtHtHXs", + "HtHTHTHTHTHtHtHtHtHtHtHTHTHtHTHtHtHTHTHtHtHTHtHtHtHTHtHtHtHtHtHtHXT", + "HTHTHtHtHtHTHtHtHtHtHTHtHtHtHtHTHtHtHtHTHtHtHtHtHTHtHtHTH", + "HTHTHTHTHTHtHTHTHTHTHTHtHtHTHtHTHTHTHTHtHtHTHtHTHtHtHtHTHtHTHtHT", + "HtHtHTHtHtHTHtHtHtHtHtHTHtHtHtHTHtHtHtHtHtHTHtHtHTHtHtHT", + "HtHTHTHTHTHtHTHTHTHTHtHTHtHTHtHTHTHTHTHTHTHTHtHtHtHtHTHtHtHZ", + "HTHTHtHtHtHtHtHTHtHtHtHTHtHTHTHtHtHtHTHtHtHtHTHtHtHTHtHtHtHTHtHZ", + "HTHTHTHTHtHtHTHtHTHtHTHtHTHtHTHtHtHTHtHTHtHtHtHTHtHtHtHTHtHtHtHZT", + "HTHTHtHtHTHTHTHTHtHTHTHTHtHTHTHTHtHtHTHtHTHtHTHTHTHtHtHTHtHS", + "HtHTHTHTHTHtHtHtHtHTHTHTHTHtHtHtHtHTHtHTHtHtHTHtHTHtHtHTHtHtHXST", + "HTHTHTHTHtHtHtHTHTHTHtHTHTHTHTHTHTHTHtHTHTHTHtHtHtHTHTHTHTHs", + "HtHtHTHTHtHtHTHTHTHTHTHtHtHTHtHtHtHTHtHtHTHTHTHTHtHTHTHTHTHTHTHXT", + "HtHtHTHTHTHtHtHtHtHTHTHTHTHTHTHtHtHTHtHTHtHtHtHTHtHTHtHTHTHtHtHXZT", + "HTHTHTHTHTHtHtHTHtHTHtHtHTHTHTHtHtHTHtHTHtHTHtHtHtHTHTHTHTHXZ", + "HtHtHTHTHTHTHtHtHTHTHTHtHTHtHtHTHtHTHTHTHtHtHTHTHTHTHtHtHs", + "HtHTHtHTHtHtHTHtHTHTHTHTHTHtHTHTHtHtHtHTHTHTHtHTHtHtHTHtHtHtHtHZT", + "HTHTHTHtHtHtHTHTHTHTHtHtHTHTHtHtHTHTHtHtHtHtHTHTHTHtHtHtHXS", + "HtHTHtHtHTHTHTHTHTHTHTHTHtHTHTHTHtHtHtHTHtHTHTHTHTHTHTHtHtHTHX", + "HTHtHtHTHTHtHtHtHTHTHtHTHTHtHTHtHtHtHtHtHTHTHtHTHtHTHtHTHtHtHtHST", + "HtHtHTHTHtHtHtHtHTHTHtHtHtHtHtHTHTHtHTHtHtHtHXZ", + "HtHtHTHTHTHTHTHtHTHTHTHtHtHtHTHTHtHTHtHTHTHtHtHTHTHtHtHtHtHtHtHtHZ", + "HTHtHtHTHTHtHTHtHTHTHtHtHtHTHTHtHtHtHtHtHtHTHtHtHtHTHtHtHtHS", + "HtHTHTHTHtHtHtHTHTHtHTHtHtHtHTHtHTHTHtHtHtHtHTHtHTHtHtHtHXZ", + "HTHtHtHTHTHtHTHtHTHtHTHtHtHTHtHTHtHTHtHTHtHTHTHtHTHTHtHtHtHs", + "HtHTHTHtHtHtHtHtHTHTHtHTHtHtHTHTHtHtHtHTHTHtHtHtHTHtHTHTHtHtHtHXST", + "HTHTHTHtHtHtHTHtHTHtHTHtHtHtHTHTHTHtHTHtHTHtHTHTHTHtHtHtHXt", + "HTHtHtHtHTHTHtHtHtHTHtHtHtHtHtHtHtHtHTHtHtHTHtHTHtHtHtHtHtHtHtHtHZT", + "HTHTHTHTHtHtHTHTHtHTHTHTHTHTHTHTHtHtHTHTHTHTHtHTHtHtHtHtHtHTHs", + "HTHTHtHtHTHTHTHtHTHtHTHTHtHtHtHTHTHtHtHTHtHTHtHtHTHtHTHtHtHtHXt", + "HTHTHTHTHTHTHtHTHtHtHTHtHTHtHTHtHTHtHTHtHtHTHtHTHTHTHTHTHTHZ", + "HtHTHtHtHTHTHTHtHTHTHtHTHTHTHTHtHtHtHTHTHtHTHTHtHtHtHtHTHtHTHXS", + "HTHtHTHtHtHtHtHtHTHtHtHtHtHTHtHtHtHTHtHTHTHTHtHTHTHTHtHtHtHtHtHXZ", + "HtHtHTHtHtHtHtHtHTHTHtHTHtHTHTHtHTHtHTHTHtHtHtHtHtHTHtHtHT", + "HTHTHtHTHtHTHtHTHtHTHtHTHtHTHtHTHTHtHTHtHtHTHTHTHtHtHtHtHtHtHtHtHZT", + "HtHtHTHTHtHTHtHTHTHTHtHTHTHTHtHTHtHtHTHTHtHtHTHtHTHtHTHtHtHXT", + "HTHTHtHTHtHtHTHTHtHTHtHtHtHTHtHtHtHTHtHTHTHtHtHTHtHTHTHT", + "HtHTHTHTHTHTHTHTHtHtHTHtHTHtHTHtHTHTHtHTHtHtHTHTHTHtHtHtHtHXS", + "HTHTHTHtHtHTHTHTHTHtHTHtHTHTHtHTHTHTHtHtHtHtHtHTHtHTHTHtHtHTHtHST", + "HTHTHtHtHTHtHTHtHTHtHtHtHTHtHTHtHTHTHTHtHTHtHTHtHTHTHtHtHXt", + "HTHtHtHtHtHTHtHTHTHtHtHTHTHTHTHTHTHtHtHTHTHtHTHtHtHtHtHTHZ", + "HTHtHTHTHTHtHtHTHtHtHtHTHtHtHtHTHTHtHTHTHTHtHTHTHTHtHtHTHtHtHtHt", + "HtHtHTHTHTHtHtHTHTHTHTHTHTHTHTHTHTHTHTHTHtHtHTHTHTHtHtHs", + "HtHTHtHTHTHTHtHtHtHTHTHtHTHTHtHTHTHtHtHTHtHtHtHtHtHTHTHTHXS", + "HtHtHTHtHTHTHTHtHTHtHTHtHTHTHTHtHtHTHTHtHtHTHtHTHtHtHtHtHXS", + "HTHTHtHtHTHtHtHtHTHtHtHTHTHtHTHTHtHtHTHtHTHtHTHtHTHTHTHTHtHtHtHs", + "HtHTHTHtHtHtHtHTHtHtHtHTHtHtHtHtHtHTHTHtHtHtHTHTHTHTHTHTHTHX", + "HtHTHTHtHtHTHtHTHtHtHtHtHtHTHTHtHtHTHtHtHTHtHTHtHTHTHTHtHTHtHtHZT", + "HTHTHtHtHTHTHTHTHTHTHTHTHtHTHtHtHtHTHTHtHtHtHtHTHtHTHTHTHTHTHTHS", + "HtHTHTHTHtHtHtHTHTHTHtHtHtHTHtHTHtHTHTHtHTHTHtHtHTHtHtHtHtHXZ", + "HTHtHTHtHTHTHTHTHtHtHTHTHtHtHTHTHtHtHTHTHtHtHTHtHTHTHTHTHTHXZT", + "HTHtHtHTHTHTHtHTHtHTHTHtHtHtHTHTHtHtHTHTHtHTHtHTHTHtHTHtHtHtHST", + "HtHTHTHtHTHTHTHTHtHtHTHTHtHTHTHTHTHtHtHtHtHtHTHTHtHtHtHTHtHtHZ", + "HTHTHTHtHtHtHtHtHTHTHTHTHtHtHTHtHtHtHTHTHtHTHtHtHTHtHTHtHtHTHtH", + "HTHTHTHtHTHTHtHTHTHTHTHTHtHtHtHTHtHtHtHtHtHTHTHtHTHTHTHX", + "HtHTHtHtHTHTHtHTHtHtHtHtHtHTHtHTHtHTHtHtHtHtHTHTHtHTHTHtHtHtHtHt", + "HtHtHTHtHTHTHTHTHTHtHTHTHTHTHtHTHtHTHTHtHtHtHTHTHtHTHTHTHTHTHTHTHXS", + "HTHTHTHtHTHTHtHtHTHtHtHTHtHtHtHtHtHtHTHTHTHtHTHTHtHTHtHtHtHtHZT", + "HtHtHTHTHTHtHtHtHTHtHTHTHTHtHtHtHtHTHTHtHtHTHtHtHtHtHtHtHtHTHtHXT", + "HtHTHtHtHTHtHtHTHTHtHTHTHTHTHtHTHTHTHTHtHTHTHtHtHTHtHtHTHtHZ", + "HtHTHTHTHtHTHtHtHTHtHtHtHTHTHTHtHTHtHtHTHtHtHTHTHTHTHtHtHtHtHtHt", + "HtHtHtHtHtHTHtHTHTHtHtHtHTHTHtHtHTHTHTHtHtHTHtHTHTHTHTHTHX", + "HTHTHTHtHtHtHtHTHtHtHtHTHtHtHTHtHtHtHTHTHTHtHTHTHTHtHTHtHtHTHtHZT", + "HTHTHTHTHtHtHtHTHTHTHTHtHTHtHTHTHTHTHtHtHTHTHtHTHtHTHtHTHtHtHST", + "HTHtHtHtHTHtHtHtHtHtHTHtHtHtHTHtHTHtHTHTHtHtHTHtHtHTHTHtHtHXZ", + "HtHtHtHTHTHTHTHtHtHtHTHTHTHtHtHtHtHtHTHTHtHtHTHtHTHtHtHtHtHST", + "HtHTHTHtHTHtHtHtHTHTHtHTHTHtHTHtHTHtHTHTHtHTHTHtHtHtHTHtHTHTHtHST", + "HtHtHtHTHtHtHtHtHtHtHtHtHtHTHtHtHtHTHtHtHtHtHtHtHtHtHtHTHtHtHtHST", + "HTHtHtHTHtHtHTHTHtHTHtHTHTHTHtHTHTHTHTHtHtHtHtHTHtHTHtHtHtHtHtHtHt", + "HTHTHtHTHtHtHTHtHtHTHtHtHtHTHTHTHtHtHtHTHtHtHtHtHtHtHtHTHtHTHtHST", + "HtHTHtHtHTHTHTHTHtHTHtHTHtHTHtHtHtHtHTHTHtHTHXs", + "HTHtHtHTHTHtHTHtHtHtHtHTHtHtHTHtHTHTHTHTHtHTHTHtHTHtHtHtHtHtHtHXT", + "HTHtHtHTHtHTHtHTHtHTHtHtHTHtHTHtHTHTHtHTHTHTHTHtHTHtHtHtHXZ", + "HtHtHTHTHTHtHTHTHtHtHTHtHTHtHtHTHtHTHtHtHTHTHtHTHTHTHtHtHS", + "HTHtHtHtHTHtHtHTHTHTHTHtHTHTHTHTHtHTHTHTHTHtHtHTHtHtHtHTHZ", + "HtHtHTHtHtHTHtHtHtHTHtHtHtHTHTHTHTHTHtHtHTHtHTHtHtHTHTHT", + "HTHTHtHTHTHtHTHtHTHTHTHtHtHtHTHTHtHtHtHTHtHTHtHtHTHTHTHtHtHTHtHZ", + "HtHtHtHtHTHTHtHtHtHTHtHTHTHTHtHtHtHtHTHtHTHTHtHtHTHTHtHTHTHtHtHXs", + "HTHTHtHtHTHTHTHTHTHtHTHTHtHtHTHtHTHtHTHTHTHtHTHTHtHTHtHTHtHtHX", + "HTHtHtHTHTHtHTHtHTHTHTHtHtHTHTHTHTHTHTHtHTHTHTHtHtHtHtHtHtHTHT", + "HtHtHTHTHtHTHTHtHtHTHTHtHTHtHtHtHtHTHTHTHtHTHtHtHtHTHTHtHtHtHtHXt", + "HTHtHtHtHTHTHTHTHTHtHTHTHtHTHTHtHtHTHtHtHtHtHtHTHTHtHTHTHtHtHtHT", + "HtHtHTHTHtHTHtHTHTHtHtHtHtHtHTHTHTHtHTHTHTHtHTHTHtHTHTHZ", + "HTHTHtHTHTHTHtHtHTHtHTHTHTHtHTHtHtHtHTHtHTHTHtHtHtHTHtHtHXZT", + "HtHTHTHtHTHTHTHtHtHTHTHTHTHTHtHtHtHtHtHTHTHtHtHtHTHtHtHTHXt", + "HtHTHTHtHTHtHTHtHTHtHTHTHtHTHtHTHtHtHTHtHtHtHtHTHtHTHTHTHXT", + "HtHTHTHtHtHTHtHTHTHTHTHtHTHTHtHTHtHtHtHtHTHtHtHTHtHTHTHTHTHTHTHXZ", + "HtHtHtHTHTHtHTHtHtHtHtHtHtHtHtHTHtHTHTHtHtHtHST", + "HTHtHtHtHtHTHTHTHtHtHtHTHtHtHTHtHtHTHtHtHtHTHtHTHtHTHtHtHtHtHtHS", + "HTHtHtHtHtHTHTHTHtHtHtHtHTHtHTHTHtHTHTHTHTHtHtHTHtHtHTHtHtHtHtHtHs", + "HtHTHtHtHtHTHtHTHtHTHtHTHtHtHtHTHtHtHtHTHtHTHtHTHtHTHtHtHtHTHtHS", + "HtHtHTHTHTHTHtHTHTHtHtHtHTHTHTHTHTHTHTHtHtHtHTHTHtHTHTHTHTHtHtHS", + "HTHTHTHtHtHtHtHTHTHTHtHtHtHTHTHTHTHTHtHtHTHTHtHTHtHTHTHTHTHS", + "HTHtHtHTHTHtHtHtHTHTHtHtHtHtHtHtHTHtHtHtHTHtHTHtHtHtHTHtHtHXT", + "HTHTHtHTHtHTHtHTHtHtHTHTHtHtHtHtHTHtHTHtHtHtHtHTHTHTHtHtHtHtHS", + "HTHtHTHTHtHTHtHtHtHTHtHtHtHTHTHTHtHTHTHtHTHTHTHtHTHTHTHTHtHtHtH", + "HtHTHtHTHTHTHTHTHTHtHTHtHtHtHtHTHTHtHtHTHTHtHTHtHTHTHtHtHtHtHtHtHX", + "HtHTHtHTHtHtHTHtHTHTHtHtHtHTHTHTHTHtHTHTHtHTHTHTHtHtHtHtHTHtHtHs", + "HtHtHtHTHTHTHtHtHTHTHTHtHTHtHtHtHTHtHTHTHTHtHtHTHTHTHtHtHtHT", + "HtHTHTHtHTHTHtHTHTHTHTHtHTHTHtHTHtHtHTHTHtHtHtHTHtHTHtHTHtHtHtHXZ", + "HTHTHTHTHtHTHtHtHTHtHtHtHTHTHTHTHTHTHtHTHTHtHTHTHtHtHTHtHtHtH", + "HTHTHtHTHtHtHtHtHtHTHtHtHtHtHTHtHTHtHtHTHTHTHtHtHTHtHtHtHtHtHtHtHXST", + "HtHTHtHTHTHtHtHtHTHTHtHTHtHtHtHtHtHtHtHTHtHTHtHtHtHtHTHTHtHtHtHs", + "HTHTHTHtHTHTHtHtHtHtHtHTHtHtHtHTHTHTHTHTHtHTHTHtHTHTHTHXZT", + "HTHtHTHTHtHTHtHTHTHtHTHtHtHTHTHTHtHTHTHtHtHtHtHTHTHTHTHTHtHtHtHZT", + "HtHTHtHtHTHtHTHTHtHtHtHtHTHTHTHTHtHTHtHTHTHTHtHtHTHtHTHtHtHtHZ", + "HTHTHtHTHTHtHTHTHTHtHTHTHtHtHTHtHtHtHTHTHtHtHtHTHtHTHTHtHtHtHXZT", + "HtHTHtHTHtHtHtHtHTHTHtHtHTHTHtHtHTHTHtHtHTHTHtHTHtHtHtHtHtHX", + "HTHtHtHtHTHTHTHtHtHtHTHTHTHtHTHtHTHtHtHTHtHtHTHTHtHTHTHTHTHXT", + "HtHtHTHTHtHtHtHtHtHtHtHtHTHtHTHTHTHtHtHTHTHTHTHtHTHtHtHtHtHtHtHST", + "HtHTHTHTHTHtHTHTHTHTHTHTHtHtHtHTHTHtHtHTHtHTHtHtHtHtHtHTHTHtHtH", + "HTHtHtHTHTHTHTHtHTHTHTHtHTHTHTHTHTHtHtHTHTHTHtHtHtHtHtHtHtHXZT", + "HTHTHTHtHtHtHtHTHtHTHtHTHtHTHTHtHtHTHtHtHTHTHtHTHTHTHtHTHTHtHtHt", + "HTHTHtHTHtHtHtHTHtHTHtHTHtHtHtHTHTHtHtHTHTHtHTHtHTHTHTHTHXST", + "HtHTHtHtHTHtHTHtHtHtHTHTHtHtHtHTHTHTHtHtHTHtHtHTHtHtHtHtHt", + "HTHTHtHtHtHTHTHtHtHtHtHtHtHtHtHtHtHtHtHtHTHTHtHtHtHTHTHt", + "HTHTHTHtHTHTHtHtHtHTHtHtHtHTHtHtHTHTHTHtHTHTHTHtHTHTHtHtHtHTHtHs", + "HTHTHtHTHtHtHtHtHTHTHtHtHTHtHTHtHTHTHtHtHTHTHTHTHtHTHtHtHXZT", + "HTHtHtHTHTHTHTHTHTHTHtHTHTHTHTHTHTHtHTHTHTHTHTHTHTHtHtHTHS", + "HTHtHTHTHtHtHTHtHTHTHTHTHTHtHtHtHTHtHtHTHtHTHtHtHtHtHTHTHtHtHtHS", + "HTHtHtHtHtHtHtHtHTHTHtHTHtHTHtHTHtHtHTHtHTHTHtHtHtHTHTHTHTHXST", + "HtHtHTHtHTHTHtHtHTHtHTHTHTHtHTHTHTHtHTHtHtHTHTHtHTHtHtHZ", + "HtHtHTHtHTHtHTHtHtHTHTHtHtHTHtHTHTHTHtHTHTHTHtHTHtHTHTHtHtHXZ", + "HtHtHTHtHTHtHTHtHTHtHTHtHTHtHTHtHtHTHtHTHTHtHtHtHTHTHTHTHTHTHTHTH", + "HtHTHTHTHtHTHtHTHTHtHtHtHtHtHTHTHTHTHTHtHtHTHtHTHtHtHtHTHX", + "HTHTHTHtHTHtHTHTHTHtHTHtHtHtHTHtHtHTHTHTHTHtHTHTHtHtHTHtHtHtHtH", + "HtHtHtHTHTHtHTHTHTHtHtHtHTHtHTHTHtHTHTHtHtHtHTHTHtHTHtHtHtHtHt", + "HtHtHtHtHtHtHTHtHTHTHtHTHtHTHtHTHtHTHtHTHTHtHTHtHtHtHtHtHtHT", + "HTHtHTHTHTHTHTHtHtHtHtHtHTHTHtHtHTHtHtHTHTHTHTHTHtHTHTHtHtHTHS", + "HtHTHTHTHTHTHtHTHtHtHtHtHTHTHtHtHtHtHtHtHtHTHtHtHTHTHtHtHtHtHt", + "HtHTHTHTHtHtHTHTHTHtHTHTHTHTHTHTHTHTHtHTHTHtHTHtHTHTHTHTHTHTHTHTH", + "HtHtHtHTHTHTHtHTHtHTHtHTHTHTHtHtHtHTHtHTHtHTHtHtHtHTHTHTHXs", + "HtHtHTHTHtHTHtHTHTHtHtHtHtHTHTHtHtHTHtHtHTHTHtHTHTHTHTHtHtHTHtHXS", + "HTHTHtHtHTHTHTHTHTHTHTHTHtHtHtHtHtHtHtHtHtHtHTHTHTHtHtHTHtHt", + "HTHtHtHtHTHTHTHtHtHTHtHTHTHTHtHTHtHtHTHTHTHTHtHTHtHTHTHTHXT", + "HTHTHtHtHTHTHTHTHTHtHtHTHtHtHTHTHtHTHtHTHtHtHtHTHtHtHtHTHtHST", + "HTHTHtHtHtHtHtHTHtHtHtHTHTHTHtHtHTHtHTHtHtHTHTHtHtHTHTHTHTHTHTHTHT", + "HtHtHtHTHtHTHTHtHtHtHtHtHTHTHtHtHtHtHTHTHtHtHXT", + "HTHTHtHtHTHTHtHTHTHtHtHtHTHTHTHTHtHTHtHTHTHtHtHtHtHtHtHtHtHTHtHS", + "HtHtHTHTHtHTHtHTHtHtHtHtHTHtHtHTHtHtHtHTHtHTHtHTHtHTHTHtHtHtHT", + "HtHtHtHTHTHTHtHtHtHtHTHTHtHtHTHTHtHtHTHTHTHTHtHtHtHTHTHTHXST", + "HtHTHtHTHTHTHtHtHtHtHTHtHtHTHtHtHTHTHTHtHTHtHTHTHTHTHtHtHtHtHtH", + "HtHTHTHtHTHtHtHTHTHtHTHTHTHTHtHtHtHtHTHtHtHTHTHtHTHtHtHTHXST", + "HTHTHTHTHtHtHtHTHtHTHtHTHtHtHTHTHTHtHtHTHtHTHtHtHTHTHTHTHTHXT", + "HtHtHTHtHTHTHTHtHTHTHTHtHTHtHtHtHtHtHTHTHTHTHTHtHtHtHTHtHtHtHtHtHXs", + "HTHTHtHtHTHTHtHtHtHtHtHTHTHtHTHTHTHtHTHTHtHtHtHtHTHtHtHtHtHtHtHXZ", + "HtHtHtHtHTHTHTHtHtHtHTHtHtHtHtHtHtHtHTHtHtHtHTHTHTHtHtHtHtHt", + "HTHtHtHtHTHTHTHTHTHtHtHtHtHtHTHtHTHTHtHTHtHtHTHtHTHTHtHTHtHtHs", + "HTHtHtHTHTHtHTHtHtHtHTHtHtHtHTHtHtHTHTHTHTHTHTHtHTHTHtHtHtHST", + "HTHTHTHtHTHTHTHtHTHTHTHtHTHtHTHTHtHTHtHTHtHTHtHTHtHTHTHtHtHtHtH", + "HTHtHtHTHtHTHtHtHtHTHtHtHtHtHTHTHtHTHTHTHtHTHTHTHtHtHtHTHtHtHtHT", + "HtHTHTHTHtHTHtHtHTHtHTHtHTHtHtHtHtHtHtHtHTHtHTHTHTHtHTHtHtHT", + "HTHTHtHTHTHtHTHTHTHTHTHtHTHTHTHtHTHTHTHTHTHtHTHTHtHTHTHZ", + "HTHtHTHtHTHTHTHtHTHtHTHTHtHtHtHtHTHtHTHTHtHtHtHtHtHTHtHtHtHtHtHZ", + "HTHtHtHTHtHtHtHTHtHTHTHTHtHTHtHtHtHTHtHtHtHTHtHTHTHTHtHtHXT", + "HTHTHtHTHTHtHtHTHTHtHtHtHTHtHTHtHtHTHTHtHTHtHTHtHtHTHTHtHtHtHtHXZT", + "HtHtHtHTHtHTHTHtHtHTHTHtHTHtHtHtHtHtHtHtHtHtHtHTHTHTHtHtHtHtHtHtHs", + "t", + "HtHtHTHTHTHTHtHtHTHTHtHtHTHtHTHTHTHtHTHtHTHTHtHtHTHTHtHtHtHtHtHtHXt", + "HtHTHTHTHTHtHtHtHtHtHtHTHTHtHTHtHtHTHTHtHtHTHtHtHtHTHtHtHtHtHtHtHXS", + "HTHTHtHtHtHTHtHtHtHtHTHtHtHtHtHTHtHtHtHTHtHtHtHtHTHtHtHTHT", + "HTHTHTHTHTHtHTHTHTHTHTHtHtHTHtHTHTHTHTHtHtHTHtHTHtHtHtHTHtHTHtHS", + "HtHtHTHtHtHTHtHtHtHtHtHTHtHtHtHTHtHtHtHtHtHTHtHtHTHtHtHS", + "HtHTHTHTHTHtHTHTHTHTHtHTHtHTHtHTHTHTHTHTHTHTHtHtHtHtHTHtHtHZT", + "HTHTHtHtHtHtHtHTHtHtHtHTHtHTHTHtHtHtHTHtHtHtHTHtHtHTHtHtHtHTHtHZT", + "HTHTHTHTHtHtHTHtHTHtHTHtHTHtHTHtHtHTHtHTHtHtHtHTHtHtHtHTHtHtHtHs", + "HTHTHtHtHTHTHTHTHtHTHTHTHtHTHTHTHtHtHTHtHTHtHTHTHTHtHtHTHtHST", + "HtHTHTHTHTHtHtHtHtHTHTHTHTHtHtHtHtHTHtHTHtHtHTHtHTHtHtHTHtHtHXZ", + "HTHTHTHTHtHtHtHTHTHTHtHTHTHTHTHTHTHTHtHTHTHTHtHtHtHTHTHTHTHt", + "HtHtHTHTHtHtHTHTHTHTHTHtHtHTHtHtHtHTHtHtHTHTHTHTHtHTHTHTHTHTHTHXS", + "HtHtHTHTHTHtHtHtHtHTHTHTHTHTHTHtHtHTHtHTHtHtHtHTHtHTHtHTHTHtHtHXs", + "HTHTHTHTHTHtHtHTHtHTHtHtHTHTHTHtHtHTHtHTHtHTHtHtHtHTHTHTHTHXZT", + "HtHtHTHTHTHTHtHtHTHTHTHtHTHtHtHTHtHTHTHTHtHtHTHTHTHTHtHtHt", + "HtHTHtHTHtHtHTHtHTHTHTHTHTHtHTHTHtHtHtHTHTHTHtHTHtHtHTHtHtHtHtHs", + "HTHTHTHtHtHtHTHTHTHTHtHtHTHTHtHtHTHTHtHtHtHtHTHTHTHtHtHtHXST", + "HtHTHtHtHTHTHTHTHTHTHTHTHtHTHTHTHtHtHtHTHtHTHTHTHTHTHTHtHtHTHXT", + "HTHtHtHTHTHtHtHtHTHTHtHTHTHtHTHtHtHtHtHtHTHTHtHTHtHTHtHTHtHtHtHZ", + "HtHtHTHTHtHtHtHtHTHTHtHtHtHtHtHTHTHtHTHtHtHtHXZT", + "HtHtHTHTHTHTHTHtHTHTHTHtHtHtHTHTHtHTHtHTHTHtHtHTHTHtHtHtHtHtHtHtHZT", + "HTHtHtHTHTHtHTHtHTHTHtHtHtHTHTHtHtHtHtHtHtHTHtHtHtHTHtHtHtHST", + "HtHTHTHTHtHtHtHTHTHtHTHtHtHtHTHtHTHTHtHtHtHtHTHtHTHtHtHtHXZT", + "HTHtHtHTHTHtHTHtHTHtHTHtHtHTHtHTHtHTHtHTHtHTHTHtHTHTHtHtHtHt", + "HtHTHTHtHtHtHtHtHTHTHtHTHtHtHTHTHtHtHtHTHTHtHtHtHTHtHTHTHtHtHtHXZ", + "HTHTHTHtHtHtHTHtHTHtHTHtHtHtHTHTHTHtHTHtHTHtHTHTHTHtHtHtHX", + "HTHtHtHtHTHTHtHtHtHTHtHtHtHtHtHtHtHtHTHtHtHTHtHTHtHtHtHtHtHtHtHtHs", + "HTHTHTHTHtHtHTHTHtHTHTHTHTHTHTHTHtHtHTHTHTHTHtHTHtHtHtHtHtHTHt", + "HTHTHtHtHTHTHTHtHTHtHTHTHtHtHtHTHTHtHtHTHtHTHtHtHTHtHTHtHtHtHX", + "HTHTHTHTHTHTHtHTHtHtHTHtHTHtHTHtHTHtHTHtHtHTHtHTHTHTHTHTHTHZT", + "HtHTHtHtHTHTHTHtHTHTHtHTHTHTHTHtHtHtHTHTHtHTHTHtHtHtHtHTHtHTHXST", + "HTHtHTHtHtHtHtHtHTHtHtHtHtHTHtHtHtHTHtHTHTHTHtHTHTHTHtHtHtHtHtHXZT", + "HtHtHTHtHtHtHtHtHTHTHtHTHtHTHTHtHTHtHTHTHtHtHtHtHtHTHtHtHS", + "HTHTHtHTHtHTHtHTHtHTHtHTHtHTHtHTHTHtHTHtHtHTHTHTHtHtHtHtHtHtHtHtHs", + "HtHtHTHTHtHTHtHTHTHTHtHTHTHTHtHTHtHtHTHTHtHtHTHtHTHtHTHtHtHXS", + "HTHTHtHTHtHtHTHTHtHTHtHtHtHTHtHtHtHTHtHTHTHtHtHTHtHTHTHS", + "HtHTHTHTHTHTHTHTHtHtHTHtHTHtHTHtHTHTHtHTHtHtHTHTHTHtHtHtHtHXST", + "HTHTHTHtHtHTHTHTHTHtHTHtHTHTHtHTHTHTHtHtHtHtHtHTHtHTHTHtHtHTHtHZ", + "HTHTHtHtHTHtHTHtHTHtHtHtHTHtHTHtHTHTHTHtHTHtHTHtHTHTHtHtHX", + "HTHtHtHtHtHTHtHTHTHtHtHTHTHTHTHTHTHtHtHTHTHtHTHtHtHtHtHTHZT", + "HTHtHTHTHTHtHtHTHtHtHtHTHtHtHtHTHTHtHTHTHTHtHTHTHTHtHtHTHtHtHtH", + "HtHtHTHTHTHtHtHTHTHTHTHTHTHTHTHTHTHTHTHTHtHtHTHTHTHtHtHt", + "HtHTHtHTHTHTHtHtHtHTHTHtHTHTHtHTHTHtHtHTHtHtHtHtHtHTHTHTHXST", + "HtHtHTHtHTHTHTHtHTHtHTHtHTHTHTHtHtHTHTHtHtHTHtHTHtHtHtHtHXST", + "HTHTHtHtHTHtHtHtHTHtHtHTHTHtHTHTHtHtHTHtHTHtHTHtHTHTHTHTHtHtHtHt", + "HtHTHTHtHtHtHtHTHtHtHtHTHtHtHtHtHtHTHTHtHtHtHTHTHTHTHTHTHTHXT", + "HtHTHTHtHtHTHtHTHtHtHtHtHtHTHTHtHtHTHtHtHTHtHTHtHTHTHTHtHTHtHtHs", + "HTHTHtHtHTHTHTHTHTHTHTHTHtHTHtHtHtHTHTHtHtHtHtHTHtHTHTHTHTHTHTHST", + "HtHTHTHTHtHtHtHTHTHTHtHtHtHTHtHTHtHTHTHtHTHTHtHtHTHtHtHtHtHXZT", + "HTHtHTHtHTHTHTHTHtHtHTHTHtHtHTHTHtHtHTHTHtHtHTHtHTHTHTHTHTHXs", + "HTHtHtHTHTHTHtHTHtHTHTHtHtHtHTHTHtHtHTHTHtHTHtHTHTHtHTHtHtHtHZ", + "HtHTHTHtHTHTHTHTHtHtHTHTHtHTHTHTHTHtHtHtHtHtHTHTHtHtHtHTHtHtHZT", + "HTHTHTHtHtHtHtHtHTHTHTHTHtHtHTHtHtHtHTHTHtHTHtHtHTHtHTHtHtHTHtHT", + "HTHTHTHtHTHTHtHTHTHTHTHTHtHtHtHTHtHtHtHtHtHTHTHtHTHTHTHXT", + "HtHTHtHtHTHTHtHTHtHtHtHtHtHTHtHTHtHTHtHtHtHtHTHTHtHTHTHtHtHtHtH", + "HtHtHTHtHTHTHTHTHTHtHTHTHTHTHtHTHtHTHTHtHtHtHTHTHtHTHTHTHTHTHTHTHXST", + "HTHTHTHtHTHTHtHtHTHtHtHTHtHtHtHtHtHtHTHTHTHtHTHTHtHTHtHtHtHtHs", + "HtHtHTHTHTHtHtHtHTHtHTHTHTHtHtHtHtHTHTHtHtHTHtHtHtHtHtHtHtHTHtHXS", + "HtHTHtHtHTHtHtHTHTHtHTHTHTHTHtHTHTHTHTHtHTHTHtHtHTHtHtHTHtHZT", + "HtHTHTHTHtHTHtHtHTHtHtHtHTHTHTHtHTHtHtHTHtHtHTHTHTHTHtHtHtHtHtH", + "HtHtHtHtHtHTHtHTHTHtHtHtHTHTHtHtHTHTHTHtHtHTHtHTHTHTHTHTHXT", + "HTHTHTHtHtHtHtHTHtHtHtHTHtHtHTHtHtHtHTHTHTHtHTHTHTHtHTHtHtHTHtHs", + "HTHTHTHTHtHtHtHTHTHTHTHtHTHtHTHTHTHTHtHtHTHTHtHTHtHTHtHTHtHtHZ", + "HTHtHtHtHTHtHtHtHtHtHTHtHtHtHTHtHTHtHTHTHtHtHTHtHtHTHTHtHtHXZT", + "HtHtHtHTHTHTHTHtHtHtHTHTHTHtHtHtHtHtHTHTHtHtHTHtHTHtHtHtHtHZ", + "HtHTHTHtHTHtHtHtHTHTHtHTHTHtHTHtHTHtHTHTHtHTHTHtHtHtHTHtHTHTHtHZ", + "HtHtHtHTHtHtHtHtHtHtHtHtHtHTHtHtHtHTHtHtHtHtHtHtHtHtHtHTHtHtHtHZ", + "HTHtHtHTHtHtHTHTHtHTHtHTHTHTHtHTHTHTHTHtHtHtHtHTHtHTHtHtHtHtHtHtH", + "HTHTHtHTHtHtHTHtHtHTHtHtHtHTHTHTHtHtHtHTHtHtHtHtHtHtHtHTHtHTHtHZ", + "HtHTHtHtHTHTHTHTHtHTHtHTHtHTHtHtHtHtHTHTHtHTHXt", + "HTHtHtHTHTHtHTHtHtHtHtHTHtHtHTHtHTHTHTHTHtHTHTHtHTHtHtHtHtHtHtHXS", + "HTHtHtHTHtHTHtHTHtHTHtHtHTHtHTHtHTHTHtHTHTHTHTHtHTHtHtHtHXZT", + "HtHtHTHTHTHtHTHTHtHtHTHtHTHtHtHTHtHTHtHtHTHTHtHTHTHTHtHtHST", + "HTHtHtHtHTHtHtHTHTHTHTHtHTHTHTHTHtHTHTHTHTHtHtHTHtHtHtHTHZT", + "HtHtHTHtHtHTHtHtHtHTHtHtHtHTHTHTHTHTHtHtHTHtHTHtHtHTHTHS", + "HTHTHtHTHTHtHTHtHTHTHTHtHtHtHTHTHtHtHtHTHtHTHtHtHTHTHTHtHtHTHtHZT", + "HtHtHtHtHTHTHtHtHtHTHtHTHTHTHtHtHtHtHTHtHTHTHtHtHTHTHtHTHTHtHtHXt", + "HTHTHtHtHTHTHTHTHTHtHTHTHtHtHTHtHTHtHTHTHTHtHTHTHtHTHtHTHtHtHXT", + "HTHtHtHTHTHtHTHtHTHTHTHtHtHTHTHTHTHTHTHtHTHTHTHtHtHtHtHtHtHTHS", + "HtHtHTHTHtHTHTHtHtHTHTHtHTHtHtHtHtHTHTHTHtHTHtHtHtHTHTHtHtHtHtHX", + "HTHtHtHtHTHTHTHTHTHtHTHTHtHTHTHtHtHTHtHtHtHtHtHTHTHtHTHTHtHtHtHS", + "HtHtHTHTHtHTHtHTHTHtHtHtHtHtHTHTHTHtHTHTHTHtHTHTHtHTHTHZT", + "HTHTHtHTHTHTHtHtHTHtHTHTHTHtHTHtHtHtHTHtHTHTHtHtHtHTHtHtHXs", + "HtHTHTHtHTHTHTHtHtHTHTHTHTHTHtHtHtHtHtHTHTHtHtHtHTHtHtHTHX", + "HtHTHTHtHTHtHTHtHTHtHTHTHtHTHtHTHtHtHTHtHtHtHtHTHtHTHTHTHXS", + "HtHTHTHtHtHTHtHTHTHTHTHtHTHTHtHTHtHtHtHtHTHtHtHTHtHTHTHTHTHTHTHXZT", + "HtHtHtHTHTHtHTHtHtHtHtHtHtHtHtHTHtHTHTHtHtHtHZ", + "HTHtHtHtHtHTHTHTHtHtHtHTHtHtHTHtHtHTHtHtHtHTHtHTHtHTHtHtHtHtHtHST", + "HTHtHtHtHtHTHTHTHtHtHtHtHTHtHTHTHtHTHTHTHTHtHtHTHtHtHTHtHtHtHtHtHt", + "HtHTHtHtHtHTHtHTHtHTHtHTHtHtHtHTHtHtHtHTHtHTHtHTHtHTHtHtHtHTHtHST", + "HtHtHTHTHTHTHtHTHTHtHtHtHTHTHTHTHTHTHTHtHtHtHTHTHtHTHTHTHTHtHtHST", + "HTHTHTHtHtHtHtHTHTHTHtHtHtHTHTHTHTHTHtHtHTHTHtHTHtHTHTHTHTHST", + "HTHtHtHTHTHtHtHtHTHTHtHtHtHtHtHtHTHtHtHtHTHtHTHtHtHtHTHtHtHXS", + "HTHTHtHTHtHTHtHTHtHtHTHTHtHtHtHtHTHtHTHtHtHtHtHTHTHTHtHtHtHtHST", + "HTHtHTHTHtHTHtHtHtHTHtHtHtHTHTHTHtHTHTHtHTHTHTHtHTHTHTHTHtHtHtHT", + "HtHTHtHTHTHTHTHTHTHtHTHtHtHtHtHTHTHtHtHTHTHtHTHtHTHTHtHtHtHtHtHtHXT", + "HtHTHtHTHtHtHTHtHTHTHtHtHtHTHTHTHTHtHTHTHtHTHTHTHtHtHtHtHTHtHtHt", + "HtHtHtHTHTHTHtHtHTHTHTHtHTHtHtHtHTHtHTHTHTHtHtHTHTHTHtHtHtHS", + "HtHTHTHtHTHTHtHTHTHTHTHtHTHTHtHTHtHtHTHTHtHtHtHTHtHTHtHTHtHtHtHXZT", + "HTHTHTHTHtHTHtHtHTHtHtHtHTHTHTHTHTHTHtHTHTHtHTHTHtHtHTHtHtHtHT", + "HTHTHtHTHtHtHtHtHtHTHtHtHtHtHTHtHTHtHtHTHTHTHtHtHTHtHtHtHtHtHtHtHXZ", + "HtHTHtHTHTHtHtHtHTHTHtHTHtHtHtHtHtHtHtHTHtHTHtHtHtHtHTHTHtHtHtHt", + "HTHTHTHtHTHTHtHtHtHtHtHTHtHtHtHTHTHTHTHTHtHTHTHtHTHTHTHXs", + "HTHtHTHTHtHTHtHTHTHtHTHtHtHTHTHTHtHTHTHtHtHtHtHTHTHTHTHTHtHtHtHs", + "HtHTHtHtHTHtHTHTHtHtHtHtHTHTHTHTHtHTHtHTHTHTHtHtHTHtHTHtHtHtHZT", + "HTHTHtHTHTHtHTHTHTHtHTHTHtHtHTHtHtHtHTHTHtHtHtHTHtHTHTHtHtHtHXs", + "HtHTHtHTHtHtHtHtHTHTHtHtHTHTHtHtHTHTHtHtHTHTHtHTHtHtHtHtHtHXT", + "HTHtHtHtHTHTHTHtHtHtHTHTHTHtHTHtHTHtHtHTHtHtHTHTHtHTHTHTHTHXS", + "HtHtHTHTHtHtHtHtHtHtHtHtHTHtHTHTHTHtHtHTHTHTHTHtHTHtHtHtHtHtHtHZ", + "HtHTHTHTHTHtHTHTHTHTHTHTHtHtHtHTHTHtHtHTHtHTHtHtHtHtHtHTHTHtHtHT", + "HTHtHtHTHTHTHTHtHTHTHTHtHTHTHTHTHTHtHtHTHTHTHtHtHtHtHtHtHtHXs", + "HTHTHTHtHtHtHtHTHtHTHtHTHtHTHTHtHtHTHtHtHTHTHtHTHTHTHtHTHTHtHtH", + "HTHTHtHTHtHtHtHTHtHTHtHTHtHtHtHTHTHtHtHTHTHtHTHtHTHTHTHTHXZ", + "HtHTHtHtHTHtHTHtHtHtHTHTHtHtHtHTHTHTHtHtHTHtHtHTHtHtHtHtH", + "HTHTHtHtHtHTHTHtHtHtHtHtHtHtHtHtHtHtHtHtHTHTHtHtHtHTHTH", + "HTHTHTHtHTHTHtHtHtHTHtHtHtHTHtHtHTHTHTHtHTHTHTHtHTHTHtHtHtHTHtHt", + "HTHTHtHTHtHtHtHtHTHTHtHtHTHtHTHtHTHTHtHtHTHTHTHTHtHTHtHtHXs", + "HTHtHtHTHTHTHTHTHTHTHtHTHTHTHTHTHTHtHTHTHTHTHTHTHTHtHtHTHST", + "HTHtHTHTHtHtHTHtHTHTHTHTHTHtHtHtHTHtHtHTHtHTHtHtHtHtHTHTHtHtHtHST", + "HTHtHtHtHtHtHtHtHTHTHtHTHtHTHtHTHtHtHTHtHTHTHtHtHtHTHTHTHTHXZ", + "HtHtHTHtHTHTHtHtHTHtHTHTHTHtHTHTHTHtHTHtHtHTHTHtHTHtHtHZT", + "HtHtHTHtHTHtHTHtHtHTHTHtHtHTHtHTHTHTHtHTHTHTHtHTHtHTHTHtHtHXZT", + "HtHtHTHtHTHtHTHtHTHtHTHtHTHtHTHtHtHTHtHTHTHtHtHtHTHTHTHTHTHTHTHTHT", + "HtHTHTHTHtHTHtHTHTHtHtHtHtHtHTHTHTHTHTHtHtHTHtHTHtHtHtHTHXT", + "HTHTHTHtHTHtHTHTHTHtHTHtHtHtHTHtHtHTHTHTHTHtHTHTHtHtHTHtHtHtHtHT", + "HtHtHtHTHTHtHTHTHTHtHtHtHTHtHTHTHtHTHTHtHtHtHTHTHtHTHtHtHtHtH", + "HtHtHtHtHtHtHTHtHTHTHtHTHtHTHtHTHtHTHtHTHTHtHTHtHtHtHtHtHtHS", + "HTHtHTHTHTHTHTHtHtHtHtHtHTHTHtHtHTHtHtHTHTHTHTHTHtHTHTHtHtHTHST", + "HtHTHTHTHTHTHtHTHtHtHtHtHTHTHtHtHtHtHtHtHtHTHtHtHTHTHtHtHtHtH", + "HtHTHTHTHtHtHTHTHTHtHTHTHTHTHTHTHTHTHtHTHTHtHTHtHTHTHTHTHTHTHTHTHT", + "HtHtHtHTHTHTHtHTHtHTHtHTHTHTHtHtHtHTHtHTHtHTHtHtHtHTHTHTHXt", + "HtHtHTHTHtHTHtHTHTHtHtHtHtHTHTHtHtHTHtHtHTHTHtHTHTHTHTHtHtHTHtHXST", + "HTHTHtHtHTHTHTHTHTHTHTHTHtHtHtHtHtHtHtHtHtHtHTHTHTHtHtHTHtH", + "HTHtHtHtHTHTHTHtHtHTHtHTHTHTHtHTHtHtHTHTHTHTHtHTHtHTHTHTHXS", + "HTHTHtHtHTHTHTHTHTHtHtHTHtHtHTHTHtHTHtHTHtHtHtHTHtHtHtHTHtHZ", + "HTHTHtHtHtHtHtHTHtHtHtHTHTHTHtHtHTHtHTHtHtHTHTHtHtHTHTHTHTHTHTHTHS", + "HtHtHtHTHtHTHTHtHtHtHtHtHTHTHtHtHtHtHTHTHtHtHXS", + "HTHTHtHtHTHTHtHTHTHtHtHtHTHTHTHTHtHTHtHTHTHtHtHtHtHtHtHtHtHTHtHST", + "HtHtHTHTHtHTHtHTHtHtHtHtHTHtHtHTHtHtHtHTHtHTHtHTHtHTHTHtHtHtHS", + "HtHtHtHTHTHTHtHtHtHtHTHTHtHtHTHTHtHtHTHTHTHTHtHtHtHTHTHTHXZ", + "HtHTHtHTHTHTHtHtHtHtHTHtHtHTHtHtHTHTHTHtHTHtHTHTHTHTHtHtHtHtHtHT", + "HtHTHTHtHTHtHtHTHTHtHTHTHTHTHtHtHtHtHTHtHtHTHTHtHTHtHtHTHXZ", + "HTHTHTHTHtHtHtHTHtHTHtHTHtHtHTHTHTHtHtHTHtHTHtHtHTHTHTHTHTHXS", + "HtHtHTHtHTHTHTHtHTHTHTHtHTHtHtHtHtHtHTHTHTHTHTHtHtHtHTHtHtHtHtHtHXt", + "HTHTHtHtHTHTHtHtHtHtHtHTHTHtHTHTHTHtHTHTHtHtHtHtHTHtHtHtHtHtHtHXZT", + "HtHtHtHtHTHTHTHtHtHtHTHtHtHtHtHtHtHtHTHtHtHtHTHTHTHtHtHtHtH", + "HTHtHtHtHTHTHTHTHTHtHtHtHtHtHTHtHTHTHtHTHtHtHTHtHTHTHtHTHtHtHt", + "HTHtHtHTHTHtHTHtHtHtHTHtHtHtHTHtHtHTHTHTHTHTHTHtHTHTHtHtHtHZ", + "HTHTHTHtHTHTHTHtHTHTHTHtHTHtHTHTHtHTHtHTHtHTHtHTHtHTHTHtHtHtHtHT", + "HTHtHtHTHtHTHtHtHtHTHtHtHtHtHTHTHtHTHTHTHtHTHTHTHtHtHtHTHtHtHtHS", + "HtHTHTHTHtHTHtHtHTHtHTHtHTHtHtHtHtHtHtHtHTHtHTHTHTHtHTHtHtHS", + "HTHTHtHTHTHtHTHTHTHTHTHtHTHTHTHtHTHTHTHTHTHtHTHTHtHTHTHZT", + "HTHtHTHtHTHTHTHtHTHtHTHTHtHtHtHtHTHtHTHTHtHtHtHtHtHTHtHtHtHtHtHZT", + "HTHtHtHTHtHtHtHTHtHTHTHTHtHTHtHtHtHTHtHtHtHTHtHTHTHTHtHtHXS", + "HTHTHtHTHTHtHtHTHTHtHtHtHTHtHTHtHtHTHTHtHTHtHTHtHtHTHTHtHtHtHtHXs", + "HtHtHtHTHtHTHTHtHtHTHTHtHTHtHtHtHtHtHtHtHtHtHtHTHTHTHtHtHtHtHtHtHt" +] \ No newline at end of file diff --git a/source/npm/qsharp/rz-details.json b/source/npm/qsharp/rz-details.json new file mode 100644 index 0000000000..226f5ff968 --- /dev/null +++ b/source/npm/qsharp/rz-details.json @@ -0,0 +1,944 @@ +[ + { + "phase": 0, + "gates": "", + "matrix": "[[1,0],[0,1]]", + "offset": 0 + }, + { + "phase": 0.006797366324771015, + "gates": "HtHtHTHTHTHTHtHtHTHTHtHtHTHtHTHTHTHtHTHtHTHTHtHtHTHTHtHtHtHtHtHtHX", + "matrix": "[[0.7047-0.7095i,0+0.0001i],[0.0001+0i,0.7095-0.7047i]]", + "offset": 0.0000778670871819516 + }, + { + "phase": 3.9370117484448643, + "gates": "HtHTHTHTHTHtHtHtHtHtHtHTHTHtHTHtHtHTHTHtHtHTHtHtHtHTHtHtHtHtHtHtHX", + "matrix": "[[0.9258+0.378i,0.0001-0i],[-0+0.0001i,-0.378-0.9258i]]", + "offset": 0.00006879341188349906 + }, + { + "phase": 4.724912789000288, + "gates": "HTHTHtHtHtHTHtHtHtHtHTHtHtHtHtHTHtHtHtHTHtHtHtHtHTHtHtHTH", + "matrix": "[[-0.7115-0.7027i,-0.0001+0.0005i],[0.0001+0.0005i,-0.7115+0.7027i]]", + "offset": 0.0004970758555279916 + }, + { + "phase": 3.9494891283931364, + "gates": "HTHTHTHTHTHtHTHTHTHTHTHtHtHTHtHTHTHTHTHtHtHTHtHTHtHtHtHTHtHTHtH", + "matrix": "[[-0.715-0.6991i,-0.0001+0i],[0.0001-0i,-0.0112+0.9999i]]", + "offset": 0.0000622479028673667 + }, + { + "phase": 3.9533793468878455, + "gates": "HtHtHTHtHtHTHtHtHtHtHtHTHtHtHtHTHtHtHtHtHtHTHtHtHTHtHtH", + "matrix": "[[-0.0132-0.9999i,-0.0001+0.0003i],[-0.0001+0.0003i,-0.7164+0.6977i]]", + "offset": 0.0003004867581136003 + }, + { + "phase": 1.6009221525507646, + "gates": "HtHTHTHTHTHtHTHTHTHTHtHTHtHTHtHTHTHTHTHTHTHTHtHtHtHtHTHtHtH", + "matrix": "[[-0.3687+0.9295i,0.0001-0.0001i],[-0.0001+0i,-0.918-0.3966i]]", + "offset": 0.00012968740202717738 + }, + { + "phase": 1.6062863314202884, + "gates": "HTHTHtHtHtHtHtHTHtHtHtHTHtHTHTHtHtHtHTHtHtHtHTHtHtHTHtHtHtHTHtH", + "matrix": "[[-0.399-0.9169i,0-0.0002i],[-0.0001+0.0002i,0.9305-0.3662i]]", + "offset": 0.00019367357111501623 + }, + { + "phase": 0.8246060624793068, + "gates": "HTHTHTHTHtHtHTHtHTHtHTHtHTHtHTHtHtHTHtHTHtHtHtHTHtHtHtHTHtHtHtH", + "matrix": "[[-0.7208-0.6931i,-0.0003+0i],[-0.0003+0.0002i,0.0196-0.9998i]]", + "offset": 0.0003510793138919119 + }, + { + "phase": 3.184228900499537, + "gates": "HTHTHtHtHTHTHTHTHtHTHTHTHtHTHTHTHtHtHTHtHTHtHTHTHTHtHtHTHtH", + "matrix": "[[0.4023+0.9155i,-0-0.0002i],[-0.0001-0.0001i,-0.3629-0.9318i]]", + "offset": 0.00017977048264604067 + }, + { + "phase": 2.40580148083754, + "gates": "HtHTHTHTHTHtHtHtHtHTHTHTHTHtHtHtHtHTHtHTHtHtHTHtHTHtHtHTHtHtHX", + "matrix": "[[-0.9331-0.3597i,-0-0.0005i],[-0+0.0005i,0.9331-0.3597i]]", + "offset": 0.00046241614374407664 + }, + { + "phase": 0.053044119174433524, + "gates": "HTHTHTHTHtHtHtHTHTHTHtHTHTHTHTHTHTHTHtHTHTHTHtHtHtHTHTHTHTH", + "matrix": "[[-0.358+0.9337i,0.0001+0.0001i],[0.0001+0.0001i,-0.407+0.9134i]]", + "offset": 0.00016089850040265497 + }, + { + "phase": 3.9851048842843015, + "gates": "HtHtHTHTHtHtHTHTHTHTHTHtHtHTHtHtHtHTHtHtHTHTHTHTHtHTHTHTHTHTHTHX", + "matrix": "[[0.6863-0.7274i,-0.0002+0.0003i],[-0.0004-0.0001i,-0.9996-0.0291i]]", + "offset": 0.00036194391950827886 + }, + { + "phase": 0.8488647765485232, + "gates": "HtHtHTHTHTHtHtHtHtHTHTHTHTHTHTHtHtHTHtHTHtHtHtHTHtHTHtHTHTHtHtHX", + "matrix": "[[0.7292+0.6843i,0.0002-0.0002i],[0.0003-0i,-0.0317+0.9995i]]", + "offset": 0.0002884701977161536 + }, + { + "phase": 1.6415898723269784, + "gates": "HTHTHTHTHTHtHtHTHtHTHtHtHTHTHTHtHtHTHtHTHtHTHtHtHtHTHTHTHTHX", + "matrix": "[[-0.9098+0.4151i,-0-0.0001i],[0.0001-0.0001i,-0.3497-0.9368i]]", + "offset": 0.00010199457817341455 + }, + { + "phase": 0.07277941771757232, + "gates": "HtHtHTHTHTHTHtHtHTHTHTHtHTHtHtHTHtHTHTHTHtHtHTHTHTHTHtHtH", + "matrix": "[[0.9993-0.0364i,0.0001i],[0.0001i,0.9993+0.0364i]]", + "offset": 0.00006737107437143244 + }, + { + "phase": 0.8661388226553006, + "gates": "HtHTHtHTHtHtHTHtHTHTHTHTHTHtHTHTHtHtHtHTHTHTHtHTHtHtHTHtHtHtHtH", + "matrix": "[[0.678-0.7351i,-0-0.0002i],[-0.0001-0.0002i,0.9992+0.0404i]]", + "offset": 0.00019020979380808613 + }, + { + "phase": 3.224182852290718, + "gates": "HTHTHTHtHtHtHTHTHTHTHtHtHTHTHtHtHTHTHtHtHtHtHTHTHTHtHtHtHX", + "matrix": "[[0.0413+0.9991i,0.0003],[-0.0003,0.0413-0.9991i]]", + "offset": 0.00025788197788424575 + }, + { + "phase": 4.802771075685884, + "gates": "HtHTHtHtHTHTHTHTHTHTHTHTHtHTHTHTHtHtHtHTHtHTHTHTHTHTHTHtHtHTHX", + "matrix": "[[0.0452+0.999i,0.0001+0i],[-0-0.0001i,0.999+0.0452i]]", + "offset": 0.0001493210196068204 + }, + { + "phase": 2.453103528045708, + "gates": "HTHtHtHTHTHtHtHtHTHTHtHTHTHtHTHtHtHtHtHtHTHTHtHTHtHTHtHTHtHtHtH", + "matrix": "[[-0.9988+0.0484i,0.0001+0.0002i],[-0-0.0002i,0.7405-0.672i]]", + "offset": 0.0001936690541284997 + }, + { + "phase": 1.6705999047745534, + "gates": "HtHtHTHTHtHtHtHtHTHTHtHtHtHtHtHTHTHtHTHtHtHtHX", + "matrix": "[[0.671-0.7415i,0.0007-0.0005i],[-0.0007-0.0005i,0.671+0.7415i]]", + "offset": 0.000796668988636733 + }, + { + "phase": 1.6747414250880717, + "gates": "HtHtHTHTHTHTHTHtHTHTHTHtHtHtHTHTHtHTHtHTHTHtHtHTHTHtHtHtHtHtHtHtH", + "matrix": "[[0.9986-0.0519i,0-0.0001i],[0.0001-0i,-0.0519+0.9986i]]", + "offset": 0.00012143194023799926 + }, + { + "phase": 3.251226017246133, + "gates": "HTHtHtHTHTHtHTHtHTHTHtHtHtHTHTHtHtHtHtHtHtHTHtHtHtHTHtHtHtH", + "matrix": "[[0.4327+0.9015i,0+0.0002i],[0.0001+0.0001i,-0.3315-0.9435i]]", + "offset": 0.00017975817069720796 + }, + { + "phase": 1.6859613247588514, + "gates": "HtHTHTHTHtHtHtHTHTHtHTHtHtHtHTHtHTHTHtHtHtHtHTHtHTHtHtHtHX", + "matrix": "[[0.9983-0.0576i,0.0003+0.0001i],[-0.0001-0.0003i,-0.0576+0.9983i]]", + "offset": 0.00036364631627993634 + }, + { + "phase": 0.11888156868631689, + "gates": "HTHtHtHTHTHtHTHtHTHtHTHtHtHTHtHTHtHTHtHTHtHTHTHtHTHTHtHtHtH", + "matrix": "[[0.8995-0.4369i,0.0001+0.0001i],[0+0.0002i,0.945-0.3271i]]", + "offset": 0.00017974019190128608 + }, + { + "phase": 2.478772749056702, + "gates": "HtHTHTHtHtHtHtHtHTHTHtHTHtHtHTHTHtHtHtHTHTHtHtHtHTHtHTHTHtHtHtHX", + "matrix": "[[-0.7491-0.6625i,-0-0.0001i],[-0.0001+0i,0.9981+0.0613i]]", + "offset": 0.00008079919060435989 + }, + { + "phase": 5.62671955134298, + "gates": "HTHTHTHtHtHtHTHtHTHtHTHtHtHtHTHTHTHtHTHtHTHtHTHTHTHtHtHtHX", + "matrix": "[[-0.9466-0.3224i,-0.0003],[0.0003,-0.9466+0.3224i]]", + "offset": 0.00025785207825477287 + }, + { + "phase": 0.920385392247465, + "gates": "HTHtHtHtHTHTHtHtHtHTHtHtHtHtHtHtHtHtHTHtHtHTHtHTHtHtHtHtHtHtHtHtH", + "matrix": "[[-0.9476-0.3195i,0.0002+0.0001i],[-0.0001-0.0002i,-0.3195-0.9476i]]", + "offset": 0.0001631981015671402 + }, + { + "phase": 0.13981893170147042, + "gates": "HTHTHTHTHtHtHTHTHtHTHTHTHTHTHTHTHtHtHTHTHTHTHtHTHtHtHtHtHtHTH", + "matrix": "[[0.0699+0.9976i,-0+0.0001i],[-0-0.0001i,-0.0699+0.9976i]]", + "offset": 0.00008251047507953408 + }, + { + "phase": 5.6439883758881635, + "gates": "HTHTHtHtHTHTHTHtHTHtHTHTHtHtHtHTHTHtHtHTHtHTHtHtHTHtHTHtHtHtHX", + "matrix": "[[0.8935-0.4491i,0-0.0001i],[-0.0001+0i,0.4491-0.8935i]]", + "offset": 0.0001493157179971004 + }, + { + "phase": 1.71959072079745, + "gates": "HTHTHTHTHTHTHtHTHtHtHTHtHTHtHTHtHTHtHTHtHtHTHtHTHTHTHTHTHTH", + "matrix": "[[0.8929-0.4503i,0.0001-0.0002i],[0.0001-0.0002i,0.313+0.9498i]]", + "offset": 0.0002640271995224015 + }, + { + "phase": 3.297214397596548, + "gates": "HtHTHtHtHTHTHTHtHTHTHtHTHTHTHTHtHtHtHTHTHtHTHTHtHtHtHtHTHtHTHX", + "matrix": "[[0.65-0.7599i,0.0002-0.0002i],[0.0002-0.0002i,-0.7599+0.65i]]", + "offset": 0.0003258466849760435 + }, + { + "phase": 1.729240875964991, + "gates": "HTHtHTHtHtHtHtHtHTHtHtHtHtHTHtHtHtHTHtHTHTHTHtHTHTHTHtHtHtHtHtHX", + "matrix": "[[0.9513+0.3084i,-0.0003-0.0001i],[-0.0001+0.0003i,-0.4546+0.8907i]]", + "offset": 0.00031921732251623865 + }, + { + "phase": 4.090794752815733, + "gates": "HtHtHTHtHtHtHtHtHTHTHtHTHtHTHTHtHTHtHTHTHtHtHtHtHtHTHtHtH", + "matrix": "[[0.8895-0.457i,0.0001],[0.0001,-0.8895-0.457i]]", + "offset": 0.0000673398957722982 + }, + { + "phase": 0.9537570322066369, + "gates": "HTHTHtHTHtHTHtHTHtHTHtHTHtHTHtHTHTHtHTHtHtHTHTHTHtHtHtHtHtHtHtHtH", + "matrix": "[[-0.8884+0.459i,-0.0001-0i],[0.0001-0i,-0.8884-0.459i]]", + "offset": 0.00007783586832078935 + }, + { + "phase": 4.103508737720375, + "gates": "HtHtHTHTHtHTHtHTHTHTHtHTHTHTHtHTHtHtHTHTHtHtHTHtHTHtHTHtHtHX", + "matrix": "[[-0.9961+0.0881i,0.0001-0i],[0.0001+0.0001i,0.642+0.7667i]]", + "offset": 0.0001019889629230744 + }, + { + "phase": 4.105344187621654, + "gates": "HTHTHtHTHtHtHTHTHtHTHtHtHtHTHtHtHtHTHtHTHTHtHtHTHtHTHTH", + "matrix": "[[0.7673+0.6413i,0+0i],[0+0i,0.0891-0.996i]]", + "offset": 0.000051567699239651094 + }, + { + "phase": 3.327471373174413, + "gates": "HtHTHTHTHTHTHTHTHtHtHTHtHTHtHTHtHTHTHtHTHtHtHTHTHTHtHtHtHtHX", + "matrix": "[[-0.4668-0.8844i,0.0001-0.0001i],[-0.0002+0i,0.2953+0.9554i]]", + "offset": 0.00017977212934506352 + }, + { + "phase": 2.5445081376823837, + "gates": "HTHTHTHtHtHTHTHTHTHtHTHtHTHTHtHTHTHTHtHtHtHtHtHTHtHTHTHtHtHTHtH", + "matrix": "[[0.9956-0.094i,0+0.0001i],[-0-0.0001i,-0.7705+0.6375i]]", + "offset": 0.00006225245462643032 + }, + { + "phase": 5.692389043078397, + "gates": "HTHTHtHtHTHtHTHtHTHtHtHtHTHtHTHtHTHTHTHtHTHtHTHtHTHTHtHtHX", + "matrix": "[[-0.9567-0.2911i,-0.0003],[0.0003,-0.9567+0.2911i]]", + "offset": 0.0002579004484009042 + }, + { + "phase": 1.7720002297126953, + "gates": "HTHtHtHtHtHTHtHTHTHtHtHTHTHTHTHTHTHtHtHTHTHtHTHtHtHtHtHTH", + "matrix": "[[-0.7745-0.6325i,0.0003],[0.0003,0.7745-0.6325i]]", + "offset": 0.0002578548154108116 + }, + { + "phase": 5.703870368656178, + "gates": "HTHtHTHTHTHtHtHTHtHtHtHTHtHtHtHTHTHtHTHTHTHtHTHTHTHtHtHTHtHtHtH", + "matrix": "[[0.9947-0.1029i,-0.0003+0.0001i],[0.0003-0.0001i,0.7761-0.6306i]]", + "offset": 0.0003627025281841022 + }, + { + "phase": 0.21019480503801002, + "gates": "HtHtHTHTHTHtHtHTHTHTHTHTHTHTHTHTHTHTHTHTHtHtHTHTHTHtHtH", + "matrix": "[[0.4775+0.8786i,0.0003-0.0001i],[0.0003-0.0001i,0.2837+0.9589i]]", + "offset": 0.0003004870645264724 + }, + { + "phase": 3.354462815092597, + "gates": "HtHTHtHTHTHTHtHtHtHTHTHtHTHTHtHTHTHtHtHTHtHtHtHtHtHTHTHTHX", + "matrix": "[[-0.1062-0.9943i,0.0005-0.0001i],[-0.0005-0.0001i,-0.1062+0.9943i]]", + "offset": 0.0004970860914308363 + }, + { + "phase": 3.3599912896916955, + "gates": "HtHtHTHtHTHTHTHtHTHtHTHtHTHTHTHtHtHTHTHtHtHTHtHTHtHtHtHtHX", + "matrix": "[[0.78+0.6258i,0-0.0001i],[-0.0001+0i,-0.6258-0.78i]]", + "offset": 0.00011667364945193624 + }, + { + "phase": 0.2226729752237646, + "gates": "HTHTHtHtHTHtHtHtHTHtHtHTHTHtHTHTHtHtHTHtHTHtHTHtHTHTHTHTHtHtHtH", + "matrix": "[[-0.8756+0.483i,0.0003+0.0001i],[-0.0002+0.0003i,-0.9607+0.2777i]]", + "offset": 0.00034727025256318803 + }, + { + "phase": 4.943927317674555, + "gates": "HtHTHTHtHtHtHtHTHtHtHtHTHtHtHtHtHtHTHTHtHtHtHTHTHTHTHTHTHTHX", + "matrix": "[[0.4868+0.8735i,0.0003+0.0002i],[-0.0004-0.0001i,0.9619-0.2734i]]", + "offset": 0.0003918923454938493 + }, + { + "phase": 1.018412491234184, + "gates": "HtHTHTHtHtHTHtHTHtHtHtHtHtHTHTHtHtHTHtHtHTHtHTHtHTHTHTHtHTHtHtH", + "matrix": "[[-0.7845-0.6201i,-0.0001-0i],[-0+0.0001i,0.1162-0.9932i]]", + "offset": 0.00007214598561368627 + }, + { + "phase": 3.3793290321250997, + "gates": "HTHTHtHtHTHTHTHTHTHTHTHTHtHTHtHtHtHTHTHtHtHtHtHTHtHTHTHTHTHTHTH", + "matrix": "[[-0.2704+0.9627i,-0.0002-0.0002i],[0.0003+0i,0.4895-0.872i]]", + "offset": 0.0003162570238222237 + }, + { + "phase": 1.816017468912723, + "gates": "HtHTHTHTHtHtHtHTHTHTHtHtHtHTHtHTHtHTHTHtHTHTHtHtHTHtHtHtHtHX", + "matrix": "[[0.8701-0.4928i,-0.0001-0.0001i],[0.0002+0i,0.2668+0.9637i]]", + "offset": 0.0001797321752625048 + }, + { + "phase": 1.0338039381464226, + "gates": "HTHtHTHtHTHTHTHTHtHtHTHTHtHtHTHTHtHtHTHTHtHtHTHtHTHTHTHTHTHX", + "matrix": "[[-0.7893-0.6141i,-0.0002+0.0001i],[-0.0002+0.0001i,0.1239-0.9923i]]", + "offset": 0.0002124657562602609 + }, + { + "phase": 2.6109355255154845, + "gates": "HTHtHtHTHTHTHtHTHtHTHTHtHtHtHTHTHtHtHTHTHtHTHtHTHTHtHTHtHtHtH", + "matrix": "[[0.965+0.2622i,-0.0002-0i],[-0.0002+0i,-0.965+0.2622i]]", + "offset": 0.00023487804939671312 + }, + { + "phase": 1.831268095125588, + "gates": "HtHTHTHtHTHTHTHTHtHtHTHTHtHTHTHTHTHtHtHtHtHtHTHTHtHtHtHTHtHtH", + "matrix": "[[0.7929+0.6093i,0+0.0003i],[0-0.0003i,-0.7929+0.6093i]]", + "offset": 0.0003011344147437865 + }, + { + "phase": 4.978857639444061, + "gates": "HTHTHTHtHtHtHtHtHTHTHTHTHtHtHTHtHtHtHTHTHtHTHtHtHTHtHTHtHtHTHtH", + "matrix": "[[0.8649-0.502i,-0+0.0001i],[0-0.0001i,-0.2566-0.9665i]]", + "offset": 0.00006224206134816504 + }, + { + "phase": 4.982532856232487, + "gates": "HTHTHTHtHTHTHtHTHTHTHTHTHtHtHtHTHtHtHtHtHtHTHTHtHTHTHTHX", + "matrix": "[[0.5036+0.8639i,0.0002+0i],[-0.0001-0.0001i,0.967-0.2548i]]", + "offset": 0.00018341653940881505 + }, + { + "phase": 5.774085396971339, + "gates": "HtHTHtHtHTHTHtHTHtHtHtHtHtHTHtHTHtHTHtHtHtHtHTHTHtHTHTHtHtHtHtH", + "matrix": "[[0.9905-0.1377i,-0.0003-0.0001i],[0.0001-0.0003i,0.7977-0.603i]]", + "offset": 0.0003192600625435521 + }, + { + "phase": 3.4238741756323448, + "gates": "HtHtHTHtHTHTHTHTHTHtHTHTHTHTHtHTHtHTHTHtHtHtHTHTHtHTHTHTHTHTHTHTHX", + "matrix": "[[-0.9901+0.1407i,-0.0003-0.0001i],[-0.0003+0.0001i,0.9901+0.1407i]]", + "offset": 0.00032410165723333745 + }, + { + "phase": 1.072227504013627, + "gates": "HTHTHTHtHTHTHtHtHTHtHtHTHtHtHtHtHtHtHTHTHTHtHTHTHtHTHtHtHtHtH", + "matrix": "[[0.8597-0.5108i,0.0002-0.0001i],[-0.0002-0.0001i,0.8597+0.5108i]]", + "offset": 0.00022078582428444808 + }, + { + "phase": 4.218047128630147, + "gates": "HtHtHTHTHTHtHtHtHTHtHTHTHTHtHtHtHtHTHTHtHtHTHtHtHtHtHtHtHtHTHtHX", + "matrix": "[[0.5971-0.8022i,-0+0.0001i],[-0.0001-0i,-0.9894-0.145i]]", + "offset": 0.00008082316983637322 + }, + { + "phase": 1.8642607124527955, + "gates": "HtHTHtHtHTHtHtHTHTHtHTHTHTHTHtHTHTHTHTHtHTHTHtHtHTHtHtHTHtH", + "matrix": "[[0.9699+0.2435i,-0.0003+0.0001i],[-0.0003+0.0001i,-0.5136+0.858i]]", + "offset": 0.00033693177310920686 + }, + { + "phase": 5.799742119738522, + "gates": "HtHTHTHTHtHTHtHtHTHtHtHtHTHTHTHtHTHtHtHTHtHtHTHTHTHTHtHtHtHtHtH", + "matrix": "[[0.5927-0.8054i,-0.0001+0.0001i],[-0-0.0001i,0.1504-0.9886i]]", + "offset": 0.00010777519688616777 + }, + { + "phase": 5.01939110344904, + "gates": "HtHtHtHtHtHTHtHTHTHtHtHtHTHTHtHtHTHTHTHtHtHTHtHTHTHTHTHTHX", + "matrix": "[[0.8069+0.5907i,-0.0003],[0.0003,0.8069-0.5907i]]", + "offset": 0.0002578914903068519 + }, + { + "phase": 1.0935157424897066, + "gates": "HTHTHTHtHtHtHtHTHtHtHtHTHtHtHTHtHtHtHTHTHTHtHTHTHTHtHTHtHtHTHtH", + "matrix": "[[-0.1535-0.9882i,-0+0.0001i],[0-0.0001i,0.8072-0.5902i]]", + "offset": 0.00006224795005712051 + }, + { + "phase": 2.672813320312269, + "gates": "HTHTHTHTHtHtHtHTHTHTHTHtHTHtHTHTHTHTHtHtHTHTHtHTHtHTHtHTHtHtH", + "matrix": "[[-0.852+0.5235i,-0.0002+0i],[-0+0.0002i,0.5235-0.852i]]", + "offset": 0.00019917302668380425 + }, + { + "phase": 1.8917560450760698, + "gates": "HTHtHtHtHTHtHtHtHtHtHTHtHtHtHTHtHTHtHTHTHtHtHTHtHtHTHTHtHtHX", + "matrix": "[[-0.9732-0.2301i,-0.0001+0.0001i],[-0.0001+0i,0.5254-0.8509i]]", + "offset": 0.0001297051543322817 + }, + { + "phase": 2.6798412261383193, + "gates": "HtHtHtHTHTHTHTHtHtHtHTHTHTHtHtHtHtHtHTHTHtHtHTHtHTHtHtHtHtH", + "matrix": "[[0.5839-0.8118i,-0.0001-0.0004i],[0.0004-0.0002i,-0.1611+0.9869i]]", + "offset": 0.00041891182434749294 + }, + { + "phase": 2.6848005148383782, + "gates": "HtHTHTHtHTHtHtHtHTHTHtHTHTHtHTHtHTHtHTHTHtHTHTHtHtHtHTHtHTHTHtH", + "matrix": "[[-0.5819+0.8132i,-0+0i],[-0+0i,0.1636-0.9865i]]", + "offset": 0.00002577235682046646 + }, + { + "phase": 2.690139996029986, + "gates": "HtHtHtHTHtHtHtHtHtHtHtHtHtHTHtHtHtHTHtHtHtHtHtHtHtHtHtHTHtHtHtH", + "matrix": "[[-0.5798+0.8148i,0.0001-0.0003i],[0.0001-0.0003i,0.1662-0.9861i]]", + "offset": 0.0002747215555262731 + }, + { + "phase": 5.839813597163463, + "gates": "HTHtHtHTHtHtHTHTHtHTHtHTHTHTHtHTHTHTHTHtHtHtHtHTHtHTHtHtHtHtHtHtH", + "matrix": "[[-0.9755-0.2199i,0.001-0.0005i],[-0.001-0.0005i,-0.9755+0.2199i]]", + "offset": 0.0010784505852097926 + }, + { + "phase": 2.7019133294363376, + "gates": "HTHTHtHTHtHtHTHtHtHTHtHtHtHTHTHTHtHtHtHTHtHtHtHtHtHtHtHTHtHTHtH", + "matrix": "[[-0.172-0.9851i,-0.0002-0.0002i],[-0-0.0003i,0.5749+0.8182i]]", + "offset": 0.00032129943555189407 + }, + { + "phase": 0.35184363519655015, + "gates": "HtHTHtHtHTHTHTHTHtHTHtHTHtHTHtHtHtHtHTHTHtHTHX", + "matrix": "[[-0.9846+0.175i,0.0005],[-0.0005,-0.9846-0.175i]]", + "offset": 0.0004599570550449239 + }, + { + "phase": 4.281565907428632, + "gates": "HTHtHtHTHTHtHTHtHtHtHtHTHtHtHTHtHTHTHTHTHtHTHTHtHTHtHtHtHtHtHtHX", + "matrix": "[[0.8207+0.5713i,0-0.0001i],[-0.0001-0.0001i,0.1764-0.9843i]]", + "offset": 0.0001078028603312531 + }, + { + "phase": 1.9287078815144763, + "gates": "HTHtHtHTHtHTHtHTHtHTHtHtHTHtHTHtHTHTHtHTHTHTHTHtHTHtHtHtHX", + "matrix": "[[0.5699-0.8217i,0.0003-0.0002i],[-0.0003-0.0002i,0.5699+0.8217i]]", + "offset": 0.0003758930843753156 + }, + { + "phase": 3.50843868362632, + "gates": "HtHtHTHTHTHtHTHTHtHtHTHtHTHtHtHTHtHTHtHtHTHTHtHTHTHTHtHtH", + "matrix": "[[0.9832-0.1824i,0.0001],[0.0001,-0.9832-0.1824i]]", + "offset": 0.00006734665618243356 + }, + { + "phase": 1.9434679722829395, + "gates": "HTHtHtHtHTHtHtHTHTHTHTHtHTHTHTHTHtHTHTHTHTHtHtHTHtHtHtHTH", + "matrix": "[[-0.5639+0.8259i,0.0003i],[0.0003i,-0.5639-0.8259i]]", + "offset": 0.00025787882506376683 + }, + { + "phase": 4.3028590988097575, + "gates": "HtHtHTHtHtHTHtHtHtHTHtHtHtHTHTHTHTHTHtHtHTHtHTHtHtHTHTH", + "matrix": "[[0.9824-0.1868i,0.0002+0i],[0.0001+0.0001i,-0.5625-0.8268i]]", + "offset": 0.00018342195908008807 + }, + { + "phase": 1.9523976282627624, + "gates": "HTHTHtHTHTHtHTHtHTHTHTHtHtHtHTHTHtHtHtHTHtHTHtHtHTHTHTHtHtHTHtH", + "matrix": "[[0.8345-0.5509i,-0.0001+0.0001i],[0+0.0001i,0.2005+0.9797i]]", + "offset": 0.00013912458922238902 + }, + { + "phase": 0.3868949175035912, + "gates": "HtHtHtHtHTHTHtHtHtHTHtHTHTHTHtHtHtHtHTHtHTHTHtHtHTHTHtHTHTHtHtHX", + "matrix": "[[0.8331-0.5532i,-0.0002+0.0001i],[0.0002-0.0001i,0.9802-0.1979i]]", + "offset": 0.0002140173778844243 + }, + { + "phase": 5.100807237806366, + "gates": "HTHTHtHtHTHTHTHTHTHtHTHTHtHtHTHtHTHtHTHTHTHtHTHTHtHTHtHTHtHtHX", + "matrix": "[[-0.9812+0.193i,-0.0001+0.0003i],[0.0003-0.0001i,-0.193+0.9812i]]", + "offset": 0.00037035209778622574 + }, + { + "phase": 4.32397071011278, + "gates": "HTHtHtHTHTHtHTHtHTHTHTHtHtHTHTHTHTHTHTHtHTHTHTHtHtHtHtHtHtHTH", + "matrix": "[[0.5573+0.8303i,0.0001-0.0003i],[-0.0001-0.0003i,0.5573-0.8303i]]", + "offset": 0.0003703795652718583 + }, + { + "phase": 5.8962903911231646, + "gates": "HtHtHTHTHtHTHTHtHtHTHTHtHTHtHtHtHtHTHTHTHtHTHtHtHtHTHTHtHtHtHtHX", + "matrix": "[[0.9802-0.1979i,-0.0002+0.0001i],[0.0002-0.0001i,0.8331-0.5532i]]", + "offset": 0.0002140745866025612 + }, + { + "phase": 4.330787678916824, + "gates": "HTHtHtHtHTHTHTHTHTHtHTHTHtHTHTHtHtHTHtHtHtHtHtHTHTHtHTHTHtHtHtH", + "matrix": "[[0.8345+0.5509i,0.0001+0.0001i],[-0+0.0001i,0.2005-0.9797i]]", + "offset": 0.00013912458922238902 + }, + { + "phase": 1.980326236231007, + "gates": "HtHtHTHTHtHTHtHTHTHtHtHtHtHtHTHTHTHtHTHTHTHtHTHTHtHTHTH", + "matrix": "[[0.9824+0.1868i,0.0001-0.0001i],[0.0002-0i,-0.5625+0.8268i]]", + "offset": 0.00018341108404991042 + }, + { + "phase": 1.1981246813068536, + "gates": "HTHTHtHTHTHTHtHtHTHtHTHTHTHtHTHtHtHtHTHtHTHTHtHtHtHTHtHtHX", + "matrix": "[[0.8259-0.5639i,-0.0003],[0.0003,0.8259+0.5639i]]", + "offset": 0.00025787882506376683 + }, + { + "phase": 5.916339277143059, + "gates": "HtHTHTHtHTHTHTHtHtHTHTHTHTHTHtHtHtHtHtHTHTHtHtHtHTHtHtHTHX", + "matrix": "[[0.9832+0.1824i,-0.0001],[0.0001,0.9832-0.1824i]]", + "offset": 0.00006734665618243356 + }, + { + "phase": 4.3544774256651095, + "gates": "HtHTHTHtHTHtHTHtHTHtHTHTHtHTHtHTHtHtHTHtHtHtHtHTHtHTHTHTHX", + "matrix": "[[0.5699+0.8217i,0.0003+0.0002i],[-0.0003+0.0002i,0.5699-0.8217i]]", + "offset": 0.0003758930843753156 + }, + { + "phase": 2.0016193997509535, + "gates": "HtHTHTHtHtHTHtHTHTHTHTHtHTHTHtHTHtHtHtHtHTHtHtHTHtHTHTHTHTHTHTHX", + "matrix": "[[0.8207-0.5713i,0+0.0001i],[-0.0001+0.0001i,0.1764+0.9843i]]", + "offset": 0.0001078028603312531 + }, + { + "phase": 2.7897490183932425, + "gates": "HtHtHtHTHTHtHTHtHtHtHtHtHtHtHtHTHtHTHTHtHtHtH", + "matrix": "[[0.8199-0.5724i,0.0003-0.0003i],[0.0003-0.0003i,-0.5724+0.8199i]]", + "offset": 0.00045995705504505715 + }, + { + "phase": 3.5812719777432487, + "gates": "HTHtHtHtHtHTHTHTHtHtHtHTHtHtHTHtHtHTHtHtHtHTHtHTHtHTHtHtHtHtHtH", + "matrix": "[[0.9851+0.172i,-0.0002-0.0002i],[-0.0003-0i,-0.8182-0.5749i]]", + "offset": 0.00032129943555189407 + }, + { + "phase": 0.4475352650410329, + "gates": "HTHtHtHtHtHTHTHTHtHtHtHtHTHtHTHTHtHTHTHTHTHtHtHTHtHtHTHtHtHtHtHtH", + "matrix": "[[0.5326-0.8464i,-0.0008-0.0008i],[-0.0008-0.0008i,0.8464-0.5326i]]", + "offset": 0.0011778860763035923 + }, + { + "phase": 3.5930453111496004, + "gates": "HtHTHtHtHtHTHtHTHtHTHtHTHtHtHtHTHtHtHtHTHtHTHtHTHtHTHtHtHtHTHtH", + "matrix": "[[-0.5798-0.8148i,-0.0001-0.0003i],[-0.0001-0.0003i,0.1662+0.9861i]]", + "offset": 0.0002747215555262731 + }, + { + "phase": 3.598384792341208, + "gates": "HtHtHTHTHTHTHtHTHTHtHtHtHTHTHTHTHTHTHTHtHtHtHTHTHtHTHTHTHTHtHtH", + "matrix": "[[0.5819+0.8132i,-0-0i],[-0-0i,-0.1636-0.9865i]]", + "offset": 0.000025772356820493007 + }, + { + "phase": 3.603344081041267, + "gates": "HTHTHTHtHtHtHtHTHTHTHtHtHtHTHTHTHTHTHtHtHTHTHtHTHtHTHTHTHTH", + "matrix": "[[0.5839+0.8118i,-0.0001+0.0004i],[0.0004+0.0002i,-0.1611-0.9869i]]", + "offset": 0.00041891182434749294 + }, + { + "phase": 4.3914292466231295, + "gates": "HTHtHtHTHTHtHtHtHTHTHtHtHtHtHtHtHTHtHtHtHTHtHTHtHtHtHTHtHtHX", + "matrix": "[[0.2301+0.9732i,-0+0.0001i],[-0.0001+0.0001i,0.8509-0.5254i]]", + "offset": 0.00012969096484849582 + }, + { + "phase": 3.6103720516177233, + "gates": "HTHTHtHTHtHTHtHTHtHtHTHTHtHtHtHtHTHtHTHtHtHtHtHTHTHTHtHtHtHtH", + "matrix": "[[-0.852-0.5235i,-0-0.0002i],[-0.0002-0i,0.5235+0.852i]]", + "offset": 0.00019918088107595333 + }, + { + "phase": 5.189669564689879, + "gates": "HTHtHTHTHtHTHtHtHtHTHtHtHtHTHTHTHtHTHTHtHTHTHTHtHTHTHTHTHtHtHtH", + "matrix": "[[-0.1535+0.9882i,0+0.0001i],[-0-0.0001i,0.8072+0.5902i]]", + "offset": 0.00006224795005712051 + }, + { + "phase": 5.190200140239329, + "gates": "HtHTHtHTHTHTHTHTHTHtHTHtHtHtHtHTHTHtHtHTHTHtHTHtHTHTHtHtHtHtHtHtHX", + "matrix": "[[-0.9716+0.2366i,0.0002-0i],[-0+0.0002i,-0.2366+0.9716i]]", + "offset": 0.00015734503839920288 + }, + { + "phase": 0.483443196806152, + "gates": "HtHTHtHTHtHtHTHtHTHTHtHtHtHTHTHTHTHtHTHTHtHTHTHTHtHtHtHtHTHtHtH", + "matrix": "[[0.8054-0.5927i,-0.0001-0i],[0.0001-0.0001i,0.9886-0.1504i]]", + "offset": 0.00010780263398794807 + }, + { + "phase": 4.418924594726791, + "gates": "HtHtHtHTHTHTHtHtHTHTHTHtHTHtHtHtHTHtHTHTHTHtHtHTHTHTHtHtHtH", + "matrix": "[[0.858+0.5136i,0.0001+0.0003i],[0.0001+0.0003i,0.2435-0.9699i]]", + "offset": 0.00033693264542966817 + }, + { + "phase": 2.065138178549439, + "gates": "HtHTHTHtHTHTHtHTHTHTHTHtHTHTHtHTHtHtHTHTHtHtHtHTHtHTHtHTHtHtHtHX", + "matrix": "[[0.5971+0.8022i,0+0.0001i],[0.0001-0i,-0.9894+0.145i]]", + "offset": 0.00008082316983637322 + }, + { + "phase": 5.210957838250015, + "gates": "HTHTHTHTHtHTHtHtHTHtHtHtHTHTHTHTHTHTHtHTHTHtHTHTHtHtHTHtHtHtH", + "matrix": "[[0.8597+0.5108i,-0.0002+0.0001i],[0.0002+0.0001i,0.8597-0.5108i]]", + "offset": 0.00022076143782847333 + }, + { + "phase": 2.8593111315472415, + "gates": "HTHTHtHTHtHtHtHtHtHTHtHtHtHtHTHtHTHtHtHTHTHTHtHtHTHtHtHtHtHtHtHtHX", + "matrix": "[[-0.9901-0.1407i,-0.0003+0.0001i],[-0.0003-0.0001i,0.9901-0.1407i]]", + "offset": 0.00032410165723333745 + }, + { + "phase": 0.5090999035362176, + "gates": "HtHTHtHTHTHtHtHtHTHTHtHTHtHtHtHtHtHtHtHTHtHTHtHtHtHtHTHTHtHtHtH", + "matrix": "[[0.1377-0.9905i,-0.0003+0.0001i],[-0.0001-0.0003i,0.603-0.7977i]]", + "offset": 0.00031924275370701717 + }, + { + "phase": 1.3006523900898121, + "gates": "HTHTHTHtHTHTHtHtHtHtHtHTHtHtHtHTHTHTHTHTHtHTHTHtHTHTHTHX", + "matrix": "[[0.967-0.2548i,0.0002+0i],[-0.0001-0.0001i,0.5036+0.8639i]]", + "offset": 0.00018343591918503253 + }, + { + "phase": 1.304327667735525, + "gates": "HTHtHTHTHtHTHtHTHTHtHTHtHtHTHTHTHtHTHTHtHtHtHtHTHTHTHTHTHtHtHtH", + "matrix": "[[0.8649+0.502i,0+0.0001i],[-0-0.0001i,-0.2566+0.9665i]]", + "offset": 0.00006224206134816504 + }, + { + "phase": 2.0981297085330395, + "gates": "HtHTHtHtHTHtHTHTHtHtHtHtHTHTHTHTHtHTHtHTHTHTHtHtHTHtHTHtHtHtH", + "matrix": "[[0.9654-0.2606i,-0.0002+0i],[-0+0.0002i,-0.2606+0.9654i]]", + "offset": 0.00024432727625112107 + }, + { + "phase": 1.3175063701609497, + "gates": "HTHTHtHTHTHtHTHTHTHtHTHTHtHtHTHtHtHtHTHTHtHtHtHTHtHTHTHtHtHtHX", + "matrix": "[[0.7908-0.6121i,0.0001-0.0002i],[-0.0001-0.0002i,0.7908+0.6121i]]", + "offset": 0.00025710889136413385 + }, + { + "phase": 5.249381369033164, + "gates": "HtHTHtHTHtHtHtHtHTHTHtHtHTHTHtHtHTHTHtHtHTHTHtHTHtHtHtHtHtHX", + "matrix": "[[-0.7893+0.6141i,-0.0002-0.0001i],[-0.0002-0.0001i,0.1239+0.9923i]]", + "offset": 0.0002124657562602609 + }, + { + "phase": 4.467167838266863, + "gates": "HTHtHtHtHTHTHTHtHtHtHTHTHTHtHTHtHTHtHtHTHtHtHTHTHtHTHTHTHTHX", + "matrix": "[[0.8701+0.4928i,-0.0001+0.0001i],[0.0002-0i,0.2668-0.9637i]]", + "offset": 0.0001797321752625048 + }, + { + "phase": 2.9038562750544865, + "gates": "HtHtHTHTHtHtHtHtHtHtHtHtHTHtHTHTHTHtHtHTHTHTHTHtHTHtHtHtHtHtHtH", + "matrix": "[[-0.2704-0.9627i,-0.0002+0.0002i],[0.0003-0i,0.4895+0.872i]]", + "offset": 0.0003162570238222237 + }, + { + "phase": 5.2647728028789125, + "gates": "HtHTHTHTHTHtHTHTHTHTHTHTHtHtHtHTHTHtHtHTHtHTHtHtHtHtHtHTHTHtHtH", + "matrix": "[[0.6201+0.7845i,0.0001-0i],[-0-0.0001i,0.9932-0.1162i]]", + "offset": 0.00007208873298033892 + }, + { + "phase": 1.3392579895050316, + "gates": "HTHtHtHTHTHTHTHtHTHTHTHtHTHTHTHTHTHtHtHTHTHTHtHtHtHtHtHtHtHX", + "matrix": "[[0.4868-0.8735i,0.0003-0.0002i],[-0.0004+0.0001i,0.9619+0.2734i]]", + "offset": 0.0003918923454938493 + }, + { + "phase": 6.060512261113363, + "gates": "HTHTHTHtHtHtHtHTHtHTHtHTHtHTHTHtHtHTHtHtHTHTHtHTHTHTHtHTHTHtHtH", + "matrix": "[[-0.8756-0.483i,-0.0002-0.0003i],[0.0003-0.0001i,-0.9607-0.2777i]]", + "offset": 0.0003472757254054363 + }, + { + "phase": 2.9231940174878908, + "gates": "HTHTHtHTHtHtHtHTHtHTHtHTHtHtHtHTHTHtHtHTHTHtHTHtHTHTHTHTHX", + "matrix": "[[0.78-0.6258i,0+0.0001i],[-0.0001-0i,-0.6258+0.78i]]", + "offset": 0.00011667364945193624 + }, + { + "phase": 6.070315178877224, + "gates": "HtHTHtHtHTHtHTHtHtHtHTHTHtHtHtHTHTHTHtHtHTHtHtHTHtHtHtHtH", + "matrix": "[[0.1062-0.9943i,0.0005-0.0001i],[0.0005+0.0001i,-0.1062-0.9943i]]", + "offset": 0.0004970784771746163 + }, + { + "phase": 6.072990502141576, + "gates": "HTHTHtHtHtHTHTHtHtHtHtHtHtHtHtHtHtHtHtHtHTHTHtHtHtHTHTH", + "matrix": "[[0.4775-0.8786i,0.0003+0.0001i],[0.0003+0.0001i,0.2837-0.9589i]]", + "offset": 0.0003004870645264724 + }, + { + "phase": 0.5793149385234083, + "gates": "HTHTHTHtHTHTHtHtHtHTHtHtHtHTHtHtHTHTHTHtHTHTHTHtHTHTHtHtHtHTHtH", + "matrix": "[[0.9947+0.1029i,0.0003+0.0001i],[-0.0003-0.0001i,0.7761+0.6306i]]", + "offset": 0.0003627025281841022 + }, + { + "phase": 1.3695924238770978, + "gates": "HTHTHtHTHtHtHtHtHTHTHtHtHTHtHTHtHTHTHtHtHTHTHTHTHtHTHtHtHX", + "matrix": "[[-0.7745+0.6325i,-0.0003],[0.0003,-0.7745-0.6325i]]", + "offset": 0.0002578548154108116 + }, + { + "phase": 3.732388917690982, + "gates": "HTHtHtHTHTHTHTHTHTHTHtHTHTHTHTHTHTHtHTHTHTHTHTHTHTHtHtHTH", + "matrix": "[[-0.9567+0.2911i,0.0003],[0.0003,0.9567+0.2911i]]", + "offset": 0.0002579004484009042 + }, + { + "phase": 3.7386771694972025, + "gates": "HTHtHTHTHtHtHTHtHTHTHTHTHTHtHtHtHTHtHtHTHtHTHtHtHtHtHTHTHtHtHtH", + "matrix": "[[0.9956+0.094i,-0+0.0001i],[0-0.0001i,-0.7705-0.6375i]]", + "offset": 0.00006225245462643032 + }, + { + "phase": 2.955713934005173, + "gates": "HTHtHtHtHtHtHtHtHTHTHtHTHtHTHtHTHtHtHTHtHTHTHtHtHtHTHTHTHTHX", + "matrix": "[[-0.4668+0.8844i,0.0001+0.0001i],[-0.0002-0i,0.2953-0.9554i]]", + "offset": 0.00017977212934506352 + }, + { + "phase": 2.1778411195579324, + "gates": "HtHtHTHtHTHTHtHtHTHtHTHTHTHtHTHTHTHtHTHtHtHTHTHtHTHtHtH", + "matrix": "[[0.7673-0.6413i,0-0i],[0-0i,0.0891+0.996i]]", + "offset": 0.000051567699239651094 + }, + { + "phase": 2.1796765500287423, + "gates": "HtHtHTHtHTHtHTHtHtHTHTHtHtHTHtHTHTHTHtHTHTHTHtHTHtHTHTHtHtHX", + "matrix": "[[0.642+0.7667i,0.0001-0i],[0.0001+0.0001i,-0.9961+0.0881i]]", + "offset": 0.00010201997074209408 + }, + { + "phase": 5.329428274972949, + "gates": "HtHtHTHtHTHtHTHtHTHtHTHtHTHtHTHtHtHTHtHTHTHtHtHtHTHTHTHTHTHTHTHTH", + "matrix": "[[-0.8884-0.459i,-0.0001+0i],[0.0001+0i,-0.8884+0.459i]]", + "offset": 0.00007783586832078935 + }, + { + "phase": 5.333983207953646, + "gates": "HtHTHTHTHtHTHtHTHTHtHtHtHtHtHTHTHTHTHTHtHtHTHtHTHtHtHtHTHX", + "matrix": "[[-0.8895-0.457i,0.0001],[-0.0001,-0.8895+0.457i]]", + "offset": 0.0000673398957722982 + }, + { + "phase": 5.337296063756592, + "gates": "HTHTHTHtHTHtHTHTHTHtHTHtHtHtHTHtHtHTHTHTHTHtHTHTHtHtHTHtHtHtHtH", + "matrix": "[[-0.6482-0.7615i,-0.0002+0.0003i],[-0+0.0003i,-0.9968+0.0802i]]", + "offset": 0.00035108727849328695 + }, + { + "phase": 6.127563574504543, + "gates": "HtHtHtHTHTHtHTHTHTHtHtHtHTHtHTHTHtHTHTHtHtHtHTHTHtHTHtHtHtHtH", + "matrix": "[[0.997+0.0777i,-0.0003-0i],[0.0003-0i,0.997-0.0777i]]", + "offset": 0.0003258457111841655 + }, + { + "phase": 4.563594586382136, + "gates": "HtHtHtHtHtHtHTHtHTHTHtHTHtHTHtHTHtHTHtHTHTHtHTHtHtHtHtHtHtH", + "matrix": "[[0.8929+0.4503i,0.0001+0.0002i],[0.0001+0.0002i,0.313-0.9498i]]", + "offset": 0.0002640271995224015 + }, + { + "phase": 3.7807895719801685, + "gates": "HTHtHTHTHTHTHTHtHtHtHtHtHTHTHtHtHTHtHtHTHTHTHTHTHtHTHTHtHtHTH", + "matrix": "[[0.3142+0.9494i,-0.0001-0.0001i],[0.0001-0.0001i,0.3142-0.9494i]]", + "offset": 0.00014932094101439324 + }, + { + "phase": 6.143366373306217, + "gates": "HtHTHTHTHTHTHtHTHtHtHtHtHTHTHtHtHtHtHtHtHtHTHtHtHTHTHtHtHtHtH", + "matrix": "[[0.0699-0.9976i,-0+0.0001i],[-0-0.0001i,-0.0699-0.9976i]]", + "offset": 0.0000825065236582256 + }, + { + "phase": 5.362799914932121, + "gates": "HtHTHTHTHtHtHTHTHTHtHTHTHTHTHTHTHTHTHtHTHTHtHTHtHTHTHTHTHTHTHTHTH", + "matrix": "[[-0.9476+0.3195i,0.0002-0.0001i],[-0.0001+0.0002i,-0.3195+0.9476i]]", + "offset": 0.0001631981015671402 + }, + { + "phase": 0.6564657558366065, + "gates": "HtHtHtHTHTHTHtHTHtHTHtHTHTHTHtHtHtHTHtHTHtHTHtHtHtHTHTHTHX", + "matrix": "[[-0.9466+0.3224i,-0.0003],[0.0003,-0.9466-0.3224i]]", + "offset": 0.00025785207825477287 + }, + { + "phase": 3.804412558122884, + "gates": "HtHtHTHTHtHTHtHTHTHtHtHtHtHTHTHtHtHTHtHtHTHTHtHTHTHTHTHtHtHTHtHX", + "matrix": "[[-0.7491+0.6625i,0-0.0001i],[0.0001+0i,0.9981-0.0613i]]", + "offset": 0.00008079919060435989 + }, + { + "phase": 6.1643037384932695, + "gates": "HTHTHtHtHTHTHTHTHTHTHTHTHtHtHtHtHtHtHtHtHtHtHTHTHTHtHtHTHtH", + "matrix": "[[0.945-0.3271i,0+0.0002i],[0.0001+0.0001i,0.8995-0.4369i]]", + "offset": 0.00017974186232668 + }, + { + "phase": 4.597223982420735, + "gates": "HTHtHtHtHTHTHTHtHtHTHtHTHTHTHtHTHtHtHTHTHTHTHtHTHtHTHTHTHX", + "matrix": "[[0.9983+0.0576i,0.0003-0.0001i],[-0.0001+0.0003i,-0.0576-0.9983i]]", + "offset": 0.00036364631627993634 + }, + { + "phase": 3.031959289933453, + "gates": "HTHTHtHtHTHTHTHTHTHtHtHTHtHtHTHTHtHTHtHTHtHtHtHTHtHtHtHTHtH", + "matrix": "[[0.3315+0.9435i,-0.0001-0.0001i],[-0-0.0002i,-0.4327-0.9015i]]", + "offset": 0.00017978728985155998 + }, + { + "phase": 4.608443882091515, + "gates": "HTHTHtHtHtHtHtHTHtHtHtHTHTHTHtHtHTHtHTHtHtHTHTHtHtHTHTHTHTHTHTHTH", + "matrix": "[[0.9986+0.0519i,0+0.0001i],[0.0001+0i,-0.0519-0.9986i]]", + "offset": 0.00012143194023799926 + }, + { + "phase": 4.612585402405033, + "gates": "HtHtHtHTHtHTHTHtHtHtHtHtHTHTHtHtHtHtHTHTHtHtHX", + "matrix": "[[0.671+0.7415i,0.0007-0.0005i],[-0.0007-0.0005i,0.671-0.7415i]]", + "offset": 0.0007966689886370347 + }, + { + "phase": 3.830081779133878, + "gates": "HTHTHtHtHTHTHtHTHTHtHtHtHTHTHTHTHtHTHtHTHTHtHtHtHtHtHtHtHtHTHtH", + "matrix": "[[0.9988+0.0484i,0.0001-0.0002i],[-0+0.0002i,-0.7405-0.672i]]", + "offset": 0.0001936690541284997 + }, + { + "phase": 4.622006836560892, + "gates": "HtHtHTHTHtHTHtHTHtHtHtHtHTHtHtHTHtHtHtHTHtHTHtHTHtHTHTHtHtHtH", + "matrix": "[[0.7383-0.6744i,-0.0001+0.0001i],[-0.0001-0.0001i,-0.7383-0.6744i]]", + "offset": 0.0001493254637478075 + }, + { + "phase": 3.0590024548888683, + "gates": "HtHtHtHTHTHTHtHtHtHtHTHTHtHtHTHTHtHtHTHTHTHTHtHtHtHTHTHTHX", + "matrix": "[[0.0413-0.9991i,0.0003],[-0.0003,0.0413+0.9991i]]", + "offset": 0.00025788197788424575 + }, + { + "phase": 5.417046441963183, + "gates": "HtHTHtHTHTHTHtHtHtHtHTHtHtHTHtHtHTHTHTHtHTHtHTHTHTHTHtHtHtHtHtH", + "matrix": "[[0.7351-0.678i,-0.0002-0.0001i],[-0.0002-0i,-0.0404-0.9992i]]", + "offset": 0.00019022037761155574 + }, + { + "phase": 3.0688132358722204, + "gates": "HtHTHTHtHTHtHtHTHTHtHTHTHTHTHtHtHtHtHTHtHtHTHTHtHTHtHtHTHX", + "matrix": "[[-0.0364+0.9993i,-0.0001],[0.0001,-0.0364-0.9993i]]", + "offset": 0.00006737107437143244 + }, + { + "phase": 4.641595395924654, + "gates": "HTHTHTHTHtHtHtHTHtHTHtHTHtHtHTHTHTHtHtHTHtHTHtHtHTHTHTHTHTHX", + "matrix": "[[-0.3497-0.9368i,-0-0.0001i],[0.0001-0.0001i,-0.9098+0.4151i]]", + "offset": 0.00010200231523946558 + }, + { + "phase": 0.7216912723172444, + "gates": "HtHtHTHtHTHTHTHtHTHTHTHtHTHtHtHtHtHtHTHTHTHTHTHtHtHtHTHtHtHtHtHtHX", + "matrix": "[[-0.3531-0.9356i,0.0001-0i],[0.0001+0i,0.3531-0.9356i]]", + "offset": 0.00007784561433668027 + }, + { + "phase": 2.2980804228952847, + "gates": "HTHTHtHtHTHTHtHtHtHtHtHTHTHtHTHTHTHtHTHTHtHtHtHtHTHtHtHtHtHtHtHX", + "matrix": "[[0.6863+0.7274i,-0.0002-0.0003i],[-0.0004+0.0001i,-0.9996+0.0291i]]", + "offset": 0.00036194391950827886 + }, + { + "phase": 6.2301411880051525, + "gates": "HtHtHtHtHTHTHTHtHtHtHTHtHtHtHtHtHtHtHTHtHtHtHTHTHTHtHtHtHtH", + "matrix": "[[-0.358-0.9337i,0.0001-0.0001i],[0.0001-0.0001i,-0.407-0.9134i]]", + "offset": 0.00016089850040265497 + }, + { + "phase": 0.7357912101026716, + "gates": "HTHtHtHtHTHTHTHTHTHtHtHtHtHtHTHtHTHTHtHTHtHtHTHtHTHTHtHTHtHtH", + "matrix": "[[0.9141+0.4055i,-0.0003+0.0004i],[-0.0004+0.0003i,0.4055+0.9141i]]", + "offset": 0.0004624081231701203 + }, + { + "phase": 3.098956406680048, + "gates": "HTHtHtHTHTHtHTHtHtHtHTHtHtHtHTHtHtHTHTHTHTHTHTHtHTHTHtHtHtH", + "matrix": "[[0.3629+0.9318i,0.0001+0.0001i],[0+0.0002i,-0.4023-0.9155i]]", + "offset": 0.00017977220895511628 + }, + { + "phase": 5.45857924084102, + "gates": "HTHTHTHtHTHTHTHtHTHTHTHtHTHtHTHTHtHTHtHTHtHTHtHTHtHTHTHtHtHtHtH", + "matrix": "[[-0.7208+0.6931i,-0.0003-0.0002i],[-0.0003-0i,0.0196+0.9998i]]", + "offset": 0.0003510990602884475 + }, + { + "phase": 4.676898975759298, + "gates": "HTHtHtHTHtHTHtHtHtHTHtHtHtHtHTHTHtHTHTHTHtHTHTHTHtHtHtHTHtHtHtH", + "matrix": "[[-0.399+0.9169i,-0-0.0002i],[0.0001+0.0002i,0.9305+0.3662i]]", + "offset": 0.00019367357111501623 + }, + { + "phase": 4.682263123367977, + "gates": "HtHTHTHTHtHTHtHtHTHtHTHtHTHtHtHtHtHtHtHtHTHtHTHTHTHtHTHtHtH", + "matrix": "[[0.3966-0.918i,0.0001+0.0001i],[-0-0.0001i,-0.9295-0.3687i]]", + "offset": 0.00012969782044684015 + }, + { + "phase": 2.3298059602917407, + "gates": "HTHTHtHTHTHtHTHTHTHTHTHtHTHTHTHtHTHTHTHTHTHtHTHTHtHTHTH", + "matrix": "[[-0.0132+0.9999i,-0.0001-0.0003i],[-0.0001-0.0003i,-0.7164-0.6977i]]", + "offset": 0.0003004867581136003 + }, + { + "phase": 2.33369617878645, + "gates": "HTHtHTHtHTHTHTHtHTHtHTHTHtHtHtHtHTHtHTHTHtHtHtHtHtHTHtHtHtHtHtH", + "matrix": "[[-0.715+0.6991i,0.0001+0i],[-0.0001-0i,-0.0112-0.9999i]]", + "offset": 0.0000622479028673667 + }, + { + "phase": 4.699865171769091, + "gates": "HTHtHtHTHtHtHtHTHtHTHTHTHtHTHtHtHtHTHtHtHtHTHtHTHTHTHtHtHX", + "matrix": "[[-0.7115+0.7027i,0.0001+0.0005i],[0.0001-0.0005i,0.7115+0.7027i]]", + "offset": 0.0004970758555279916 + }, + { + "phase": 1.5632051087086962, + "gates": "HTHTHtHTHTHtHtHTHTHtHtHtHTHtHTHtHtHTHTHtHTHtHTHtHtHTHTHtHtHtHtHX", + "matrix": "[[-0.9253+0.3792i,-0.0001+0.0001i],[0+0.0002i,-0.3862-0.9224i]]", + "offset": 0.00015883899015687483 + }, + { + "phase": 0.7815327751182338, + "gates": "HtHtHtHTHtHTHTHtHtHTHTHtHTHtHtHtHtHtHtHtHtHtHtHTHTHTHtHtHtHtHtHtH", + "matrix": "[[0.3845-0.9231i,0+0.0001i],[0.0001+0i,0.9231-0.3845i]]", + "offset": 0.00013886290022106196 + } +] \ No newline at end of file diff --git a/source/npm/qsharp/test/bloch.mjs b/source/npm/qsharp/test/bloch.mjs new file mode 100644 index 0000000000..1be31631ef --- /dev/null +++ b/source/npm/qsharp/test/bloch.mjs @@ -0,0 +1,325 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import assert from "node:assert"; +import { describe, it } from "node:test"; + +import { + Ident, + PauliX, + PauliY, + PauliZ, + Hadamard, + SGate, + TGate, + Cplx, + vec2, + m2x2, + Ket0, + Ket1, + KetPlus, + KetMinus, + KetPlusI, + KetMinusI, + Rotations, + compare, +} from "../dist/ux/cplx.js"; +import { + VALID_GATE_CODES, + MAX_GATE_SEQUENCE_LENGTH, + sanitizeGateSequence, +} from "../dist/ux/bloch/blochGates.js"; +import { Vector3 } from "three"; + +describe("Gate combos", () => { + it("HZH† = X", () => { + const HZHt = Hadamard.mul(PauliZ).mul(Hadamard.adjoint()); + assert(HZHt.compare(PauliX)); + }); + + it("SS† = I", () => { + const SSt = SGate.mul(SGate.adjoint()); + assert(SSt.compare(Ident)); + }); + + it("TT = S", () => { + const TT = TGate.mul(TGate); + assert(TT.compare(SGate)); + }); + + it("transposes", () => { + const yTranspose = m2x2("0,i,-i,0"); + assert(PauliY.transpose().compare(yTranspose)); + }); +}); + +describe("Gate application", () => { + it("Applies Hadamard to |0>", () => { + const result = Hadamard.mulVec2(Ket0); + assert(result.compare(KetPlus)); + }); + + it("Applies ZH to |0>", () => { + const result = PauliZ.mulVec2(Hadamard.mulVec2(Ket0)); + + assert(result.compare(KetMinus)); + }); + + it("Applies XH to |0>", () => { + const result = PauliX.mulVec2(Hadamard.mulVec2(Ket0)); + + assert(result.compare(KetPlus)); + }); + + it("Applies X to |0>", () => { + const result = PauliX.mulVec2(Ket0); + assert(result.compare(Ket1)); + }); + + it("Applies Y to |0>", () => { + const result = PauliY.mulVec2(Ket0); + const expected = vec2("0,i"); + assert(result.compare(expected)); + }); + + it("|0> lands in |+i> after Hadamard and SGate", () => { + const Xplus = Hadamard.mulVec2(Ket0); + const result = SGate.mulVec2(Xplus); + assert(result.compare(KetPlusI)); + }); + + it("|1> lands in |-i> after Hadamard and SGate", () => { + const Xneg = Hadamard.mulVec2(Ket1); + const result = SGate.mulVec2(Xneg); + assert(result.compare(KetMinusI)); + }); +}); + +describe("Math tests", () => { + it("Checks tolerance inside bounds", () => { + const a = new Cplx(1.0000002, 0); + assert(Ident.a.compare(a)); + }); + + it("Checks tolerance outside bounds", () => { + const a = new Cplx(1.000002, 0); + assert(!Ident.a.compare(a)); + }); + + it("Checks matrix equality", () => { + const mx = m2x2("1,0,0,1"); + assert(mx.compare(Ident)); + }); + + it("Checks matrix inequality", () => { + const mx = m2x2("1,0,0,i"); + assert(!mx.compare(Ident)); + }); + + it("Accurately converts to and from polar", () => { + const c1 = new Cplx(3.14, 2); + const pol = c1.toPolar(); + const c2 = Cplx.fromPolar(pol.magnitude, pol.phase); + assert(c1.compare(c2)); + }); + + it("Checks the string representation of a complex number", () => { + let a = new Cplx(1, 1); + assert(a.toString() === "1+i"); + + a = new Cplx(1, -1); + assert(a.toString() === "1-i"); + + a = new Cplx(1, 0); + assert(a.toString() === "1"); + + a = new Cplx(0, 1); + assert(a.toString() === "i"); + + a = new Cplx(0, -1); + assert(a.toString() === "-i"); + + a = new Cplx(0, 0); + assert(a.toString() === "0"); + + a = new Cplx(1, 1e-10); + assert(a.toString() === "1"); + + a = new Cplx(-1e-9, 1); + assert(a.toString() === "i"); + + a = new Cplx(1, 1).mul(Math.SQRT1_2); + assert(a.toString() === "0.7071+0.7071i"); + }); +}); + +describe("Rotation tests", () => { + it("Rotates by X", () => { + const qubit = new Rotations(50); + assert(qubit.gates.length === 0); + qubit.rotateX(); + assert(qubit.gates.length === 1); + assert(qubit.gates[0].path.length === 50); + const pos = qubit.currPosition; + assert(compare(pos.w, 0)); + assert(compare(pos.x, 0)); + assert(compare(pos.y, 0)); + assert(compare(pos.z, 1)); + }); + + it("Rotates by H", () => { + const qubit = new Rotations(); + qubit.rotateH(); + const pos = qubit.currPosition; + assert(compare(pos.w, 0)); + assert(compare(pos.x, 0)); + assert(compare(pos.y, Math.SQRT1_2)); + assert(compare(pos.z, Math.SQRT1_2)); + }); + + it("Rotates by H then T twice", () => { + const qubit = new Rotations(50); + qubit.rotateH(); + qubit.rotateZ(Math.PI / 4); + qubit.rotateZ(Math.PI / 4); + assert(qubit.gates[0].name === "H"); + assert(qubit.gates[1].name === "T"); + assert(qubit.gates[1].path.length === 12); + assert(qubit.gates[2].name === "T"); + + const zeroPos = new Vector3(0, 1, 0); + zeroPos.applyQuaternion(qubit.currPosition); + + assert(compare(zeroPos.x, 1)); + assert(compare(zeroPos.y, 0)); + assert(compare(zeroPos.z, 0)); + }); + + it("Gets the path length of Pi", () => { + const qubit = new Rotations(); + qubit.rotateH(); // Put the point on the equator + + // Calculate the path length of rotating half way around the Bloch Z axis + const pathLen = qubit.getPathLength(new Vector3(0, 1, 0), Math.PI); + assert(compare(pathLen, Math.PI)); + }); + + it("Gets the path length of 0", () => { + const qubit = new Rotations(); + + // Calculate the path length of rotating half way around the Bloch Z axis + const pathLen = qubit.getPathLength(new Vector3(0, 1, 0), Math.PI); + assert(compare(pathLen, 0)); + }); + + it("Gets the path length of a T gate", () => { + const qubit = new Rotations(); + qubit.rotateH(); // Put the point on the equator + qubit.rotateZ(Math.PI / 4); // Rotate by T + + // Calculate the path length of rotating by T again + const pathLen = qubit.getPathLength(new Vector3(0, 1, 0), Math.PI / 4); + assert(compare(pathLen, Math.PI / 4)); + }); + + it("Gets the path length of a Y rotation after a T gate", () => { + const qubit = new Rotations(); + qubit.rotateH(); // Put the point on the equator + qubit.rotateZ(Math.PI / 4); // Rotate by T + + // Calculate the path length of rotating around the Bloch X axis + const pathLen = qubit.getPathLength(new Vector3(0, 0, 2), Math.PI); + + // Radius is 1 / sqrt 2, and circumference is Pi + const expected = Math.PI * Math.SQRT1_2; + assert(compare(pathLen, expected)); + }); + + it("Rotates by -T", () => { + const qubit = new Rotations(64); + qubit.rotateH(); + const minusTDistance = qubit.getPathLength( + new Vector3(0, 1, 0), + -Math.PI / 4, + ); + assert(compare(minusTDistance, Math.PI / 4)); + + qubit.rotateZ(-Math.PI / 4); + assert(qubit.gates[1].path.length === 16); + + const bitPos = new Vector3(0, 1, 0); + bitPos.applyQuaternion(qubit.currPosition); + assert(compare(bitPos.x, -Math.SQRT1_2)); + assert(compare(bitPos.y, 0)); + assert(compare(bitPos.z, Math.SQRT1_2)); + }); +}); + +describe("It has correct path entries", () => { + it("returns the first point", () => { + const qubit = new Rotations(64); + qubit.rotateY(); + assert(qubit.gates.length === 1); + assert(qubit.gates[0].path.length === 64); + + const after1Percent = qubit.getRotationAtPercent(qubit.gates[0], 0.01); + assert(after1Percent.path.length === 1); + + const after50Percent = qubit.getRotationAtPercent(qubit.gates[0], 0.49); + assert(after50Percent.path.length === 32); + + const after99Percent = qubit.getRotationAtPercent(qubit.gates[0], 0.99); + assert(after99Percent.path.length === 64); + }); +}); + +describe("sanitizeGateSequence", () => { + it("passes through a valid sequence unchanged", () => { + const r = sanitizeGateSequence("XYZHSsTt"); + assert.strictEqual(r.gates, "XYZHSsTt"); + assert.strictEqual(r.modified, false); + }); + + it("returns empty for falsy input", () => { + for (const v of ["", undefined, null]) { + const r = sanitizeGateSequence(v); + assert.strictEqual(r.gates, ""); + assert.strictEqual(r.modified, false); + } + }); + + it("strips unknown characters and reports modification", () => { + // Includes a mix of clearly invalid chars (space, punctuation, digit, + // unicode) interleaved with valid gates. Note that lowercase `s` and + // `t` are themselves valid (S† and T†), so this string deliberately + // avoids them. + const r = sanitizeGateSequence("X y Z h
1\u2603"); + assert.strictEqual(r.gates, "XZ"); + assert.strictEqual(r.modified, true); + }); + + it("preserves case-sensitive variants (S vs s, T vs t)", () => { + const r = sanitizeGateSequence("SsTtSsTt"); + assert.strictEqual(r.gates, "SsTtSsTt"); + assert.strictEqual(r.modified, false); + }); + + it("caps length at MAX_GATE_SEQUENCE_LENGTH", () => { + const overflow = "X".repeat(MAX_GATE_SEQUENCE_LENGTH + 5); + const r = sanitizeGateSequence(overflow); + assert.strictEqual(r.gates.length, MAX_GATE_SEQUENCE_LENGTH); + assert.strictEqual(r.modified, true); + }); + + it("counts both filtering and capping toward modified", () => { + // Mostly noise with a few valid gates that don't exceed the cap; + // length still differs from the input, so modified is true. + const r = sanitizeGateSequence("..X..Y..Z.."); + assert.strictEqual(r.gates, "XYZ"); + assert.strictEqual(r.modified, true); + }); + + it("VALID_GATE_CODES contains exactly the supported gates", () => { + assert.strictEqual(VALID_GATE_CODES, "XYZHSsTt"); + }); +}); diff --git a/source/npm/qsharp/tools/rz-synthesis.ts b/source/npm/qsharp/tools/rz-synthesis.ts new file mode 100644 index 0000000000..f3bf7fe208 --- /dev/null +++ b/source/npm/qsharp/tools/rz-synthesis.ts @@ -0,0 +1,323 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/* +Generator source for checked-in Rz synthesis lookup artifacts. + +This script regenerates: + - source/npm/qsharp/rz-array.json + - source/npm/qsharp/rz-details.json + +It is intentionally not on the normal build path. Keep this file in-repo so +the lookup data remains reproducible when synthesis parameters are updated. + +Run with: npm run rz +*/ + +import { compare, Hadamard, Ident, M2x2, PauliX, TGate } from "../ux/cplx.js"; +import { writeFileSync } from "node:fs"; + +// The below two constants define how many points in a 2*PI circle we want to find, and the +// tolerance for error off the plane (i.e. how much it may affect the 0 or 1 magnitude). + +// An epsilon of 0.002 takes about 500M tries to find 1256 points, mostly containing around 50 - 60 gates +// An epsilon of 0.001 takes about 4.4B tries to find 1256 points, mostly containing around 64 gates +const points = Math.floor(Math.PI * 2 * 200); // 1256 points around the sphere +const epsilon = 0.001; + +// We only find 1/8 of the total points, as the other 7/8 can be derived from the 1/8 using a simple +// T, S, ST, Z, ZT, S*, or T* addition, which is cheaper than any further Hadamard + T sequences. +if (points % 8 !== 0) throw "Points must be a multiple of 8"; +const phaseCount = points / 8; +let phaseCountFound = 0; + +// We store the the calculated matrices in a buffer for all permutations up to 2^24 operations. +// That way once the buffer is full, we can check beyond 2^24 operations by multiplying the pre-calculated matrices. +// +// i.e. If A is a matrix after multiplying "HTHTHT...", and B is a matrix after multiplying "HtHtHt...", +// then B.mul(A) is just one matrix multiplication that is equivalent to "HTHTHT...HtHtHt..." +// +// To optimize space and avoid saving the list of operations, we can simply map the index to a list of operations. +// The power of 2 indicates how many operations are in that index, i.e. +// - Indices 0 & 1 have 1 op (2 permutations) +// - Indices 2, 3, 4, 5 have 2 ops (4 permutations) +// - Index 6, 7, 8, 9, 10, 11, 12, 13 have 3 ops (8 permutations) +// - etc. +// The Math.log(x) function returns 0 for 1, 1 for 2, 2 for 4, 3 for 8, etc. +const opCountForIndex = (x: number) => Math.floor(Math.log2(x + 2)); +const startIndexForOpCount = (ops: number) => 2 ** ops - 2; + +function indexToOpSequence(idx: number): string[] { + // We'll use op 'A' to indicate H then T, and 'B' to indicate H then T_adjoint. + const result: string[] = []; + const ops = opCountForIndex(idx); + // Once we know how many ops we have, we can just iterate through the bits of the index + for (let i = 0; i < ops; i++) { + if (idx & 0x01) { + result.push("A"); + } else { + result.push("B"); + } + idx >>= 1; + } + + return result; +} + +// Convert the op sequence (which may include 'A' and 'B') to the unitary gate sequence (which +// may include H, X, etc.). We'll also remove any HH sequences as they are no-ops. +function opSequenceToGateSequence(seq: string[]): string { + return seq + .map((op) => (op === "A" ? "HT" : op === "B" ? "Ht" : op)) + .join("") + .replace(/HH/g, ""); +} + +// Pre-calculate the matrix for the Hadamard and T / T_adjoint sequences +const Aseq = TGate.mul(Hadamard); +const Bseq = TGate.adjoint().mul(Hadamard); + +const MatrixLenBytes = 4 * 2 * 4; // 4 bytes in a float, 2 floats in a complex, 4 complex values in a 2x2 matrix +const EntryCount = startIndexForOpCount(25); // Test up to 2^24 permutations + +console.log(`Matrix entries to pre-calculate: ${EntryCount}`); +console.log(`Using an epsilon of ${epsilon}`); +console.log(`Phases to find: ${phaseCount}`); + +// Buffer (and view) for the pre-calculated matrices +const entryBuffer = new ArrayBuffer(EntryCount * MatrixLenBytes); +const bufferView = new DataView(entryBuffer); + +const phaseEntries: Array<{ + phase: number; + sequence: string; + matrix: M2x2; + offset: number; +}> = []; + +// This is called once we find what looks like a valid Rz to see if we should save it. +function onPhaseFound(phase: number, ops: string[], matrix: M2x2) { + const phaseIdx = Math.round((phase * points) / (2 * Math.PI)); + const segment = phaseIdx % phaseCount; + + if ( + phaseEntries[segment] === undefined || + matrix.b.mag() * 1.25 < phaseEntries[segment].offset // 25% error improvement is worth extra gates + ) { + // Track if we found a new phase point + if (phaseEntries[segment] === undefined) ++phaseCountFound; + phaseEntries[segment] = { + phase, + sequence: opSequenceToGateSequence(ops), + matrix, + offset: matrix.b.mag(), + }; + checkEntry(phaseEntries[segment]); + } +} + +// Validate if the phase entry is correct as we go (mainly for debugging/verification) +function checkEntry(entry: { phase: number; sequence: string; matrix: M2x2 }) { + let state = Ident.mul(1); + for (const gate of entry.sequence) { + if (gate === "H") { + state = Hadamard.mul(state); + } else if (gate === "X") { + state = PauliX.mul(state); + } else if (gate === "T") { + state = TGate.mul(state); + } else if (gate === "t") { + state = TGate.adjoint().mul(state); + } + } + if (!state.isDiagonal(epsilon)) { + console.error(`offset error: `, entry); + } + if (!compare(state.phase(), entry.phase, epsilon)) { + console.error(`Phase mismatch: ${state.phase()} != ${entry.phase}`, entry); + } +} + +function writeMatrixToBuffer(idx: number, matrix: M2x2) { + const offset = idx * MatrixLenBytes; + bufferView.setFloat32(offset + 0, matrix.a.re); + bufferView.setFloat32(offset + 4, matrix.a.im); + bufferView.setFloat32(offset + 8, matrix.b.re); + bufferView.setFloat32(offset + 12, matrix.b.im); + bufferView.setFloat32(offset + 16, matrix.c.re); + bufferView.setFloat32(offset + 20, matrix.c.im); + bufferView.setFloat32(offset + 24, matrix.d.re); + bufferView.setFloat32(offset + 28, matrix.d.im); +} + +// Rather than return a new matrix, which means allocating a new object, we'll just update +// an existing one passed as a parameter. This is a bit faster and saves on memory allocation +// if the caller passes in the same working matrix every time. +function setMatrixFromBuffer(idx: number, matrix: M2x2) { + const offset = idx * MatrixLenBytes; + matrix.a.re = bufferView.getFloat32(offset + 0); + matrix.a.im = bufferView.getFloat32(offset + 4); + matrix.b.re = bufferView.getFloat32(offset + 8); + matrix.b.im = bufferView.getFloat32(offset + 12); + matrix.c.re = bufferView.getFloat32(offset + 16); + matrix.c.im = bufferView.getFloat32(offset + 20); + matrix.d.re = bufferView.getFloat32(offset + 24); + matrix.d.im = bufferView.getFloat32(offset + 28); +} + +// This turns an array of gates into an array of gates, expanding any buffer indices in the array +// into the gate sequence. The ability to pass in a buffer index is an optimization to not have to +// allocate the list of gates as a string array on every iteration if it may not be needed. +function gatesList(gates: Array): string[] { + return gates + .map((entry) => { + if (typeof entry === "number") { + return indexToOpSequence(entry); + } else { + return entry; + } + }) + .flat(); +} + +function checkMatrix(matrix: M2x2, gates: Array) { + // Here is where we check if the resulting matrix is a phase gate. + // Basically, a phase gate is one where the off-diagonal elements are zero, and the diagonal + // elements are 1 in magnitude. This means the 0 & 1 probabilities are not affected by the gate. + // The 'relative phase' of the matrix is the difference in phase between the two diagonal elements. + // The global phase is irrelevant if just doing a single gate operation. + + // All matrices come in with a trailing T or t, but that's of no interest as without that gate it's + // already a phase operation, but with less gates. So we skip testing the matrix as-is, and only + // with additional trailing gates. + + // Test with an additional Hadamard on the end + const plusHEnd = Hadamard.mul(matrix); + if (plusHEnd.isDiagonal(epsilon)) { + onPhaseFound(plusHEnd.phase(), gatesList([...gates, "H"]), plusHEnd); + } + + // It may well be that applying an X turns it into a valid Rz. So we check that too. + // Note that due to the matrix math, Y will only find a hit if X did, so no point in checking Y. + // (And obviously Z is already just a phase shift, so no need to check that either) + const plusXEnd = PauliX.mul(matrix); + if (plusXEnd.isDiagonal(epsilon)) { + onPhaseFound(plusXEnd.phase(), gatesList([...gates, "X"]), plusXEnd); + } + + // Both together (H & X) is worth a check. In testing this found some shorter sequences. + const plusHXEnd = PauliX.mul(plusHEnd); + if (plusHXEnd.isDiagonal(epsilon)) { + onPhaseFound(plusHXEnd.phase(), gatesList([...gates, "H", "X"]), plusHXEnd); + } +} + +function fillBuffer(): boolean { + // Fill the buffer up with pre-calculated matrices, testing each one for phase points as we go. + for (let i = 0; i < EntryCount; i++) { + if (phaseCountFound === phaseCount) return true; + if (i % 1000000 === 0) + console.log( + `Processing entry ${i}. Intervals found: ${phaseCountFound}. Current gate length: ${opCountForIndex(i) * 2}`, + ); + const gates = indexToOpSequence(i); + const matrix = gates.reduce((acc, gate) => { + if (gate === "A") { + return Aseq.mul(acc); + } else { + return Bseq.mul(acc); + } + }, Ident.mul(1)); + writeMatrixToBuffer(i, matrix); + checkMatrix(matrix, gates); + } + return false; +} + +// Put a no-op in the buffer for Rz(0) +onPhaseFound(0, [], Ident.mul(1)); + +if (!fillBuffer()) { + // Just filling the buffer didn't find all the intervals, so we need to start running further + // permutations of the pre-calculated matrices to find the remaining intervals. + + // No point having the first matrix be less than 24 gates, so the inner-loop will just run + // over all permutations of the 24-gate matrices. + const startFullGatesIndex = startIndexForOpCount(24); + const endFullGatesIndex = startIndexForOpCount(25) - 1; + + // The working matrices will be reused for each multiplication, so we'll just create them once. + const fullMatrix = Ident.mul(1); + const tinyMatrix = Ident.mul(1); + + // Running counter starts where the pre-calculated list finished + let i = EntryCount; + + // The nested loop will run over all the 24-gate matrices (inner loop), and multiply them with the + // pre-calculated matrices starting from the shortest (outer loop) + outer: for (let tinyIdx = 0; tinyIdx < startFullGatesIndex; tinyIdx++) { + setMatrixFromBuffer(tinyIdx, tinyMatrix); + for ( + let fullIdx = startFullGatesIndex; + fullIdx <= endFullGatesIndex; + fullIdx++ + ) { + if (i % 1000000 === 0) { + console.log( + `Processing entry ${i}. Intervals found: ${phaseCountFound}. Current gate length: ${(24 + opCountForIndex(tinyIdx)) * 2}`, + ); + } + ++i; + setMatrixFromBuffer(fullIdx, fullMatrix); + const matrix = tinyMatrix.mul(fullMatrix); + checkMatrix(matrix, [fullIdx, tinyIdx]); + if (phaseCountFound === phaseCount) break outer; + } + } +} + +// Write a file with the details of each found rotation for manual inspection if needed +const result = phaseEntries.map((entry) => + entry + ? { + phase: entry.phase, + gates: entry.sequence, + matrix: entry.matrix.toShortString(), + offset: entry.matrix.b.mag(), + } + : null, +); +writeFileSync("./rz-details.json", JSON.stringify(result, null, 2), "utf8"); + +// Create the array with the index being the phase points, and the value being the gate sequence +const phaseGates: string[] = new Array(points).fill("****"); + +// Here we fill in the other 7/8 of the points by adding T, S, ST, Z, ZT, S*, and T* to the 1/8 we found. +phaseEntries.forEach((entry) => { + const phaseIdx = Math.round((entry.phase * points) / (2 * Math.PI)); + phaseGates[phaseIdx] = entry.sequence; + + const Tidx = (phaseIdx + phaseCount) % points; + phaseGates[Tidx] = entry.sequence + "T"; + + const Sidx = (phaseIdx + phaseCount * 2) % points; + phaseGates[Sidx] = entry.sequence + "S"; + + const STidx = (phaseIdx + phaseCount * 3) % points; + phaseGates[STidx] = entry.sequence + "ST"; + + const Zidx = (phaseIdx + phaseCount * 4) % points; + phaseGates[Zidx] = entry.sequence + "Z"; + + const ZTidx = (phaseIdx + phaseCount * 5) % points; + phaseGates[ZTidx] = entry.sequence + "ZT"; + + const sidx = (phaseIdx + phaseCount * 6) % points; + phaseGates[sidx] = entry.sequence + "s"; + + const tidx = (phaseIdx + phaseCount * 7) % points; + phaseGates[tidx] = entry.sequence + "t"; +}); +writeFileSync("./rz-array.json", JSON.stringify(phaseGates, null, 1), "utf8"); + +console.log("DONE"); diff --git a/source/npm/qsharp/tools/tsconfig.json b/source/npm/qsharp/tools/tsconfig.json new file mode 100644 index 0000000000..d2eac909b8 --- /dev/null +++ b/source/npm/qsharp/tools/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "module": "node16", + "moduleResolution": "node16", + "target": "ES2022", + "lib": ["DOM", "ES2022"], + "outDir": "../dist/tools", + "rootDir": "..", + "declaration": false, + "strict": true, + "isolatedModules": true, + "esModuleInterop": true, + "skipLibCheck": true, + "types": ["node"] + }, + "include": ["./*.ts", "../ux/cplx.ts"] +} diff --git a/source/npm/qsharp/ux/bloch/bloch.tsx b/source/npm/qsharp/ux/bloch/bloch.tsx new file mode 100644 index 0000000000..c33290d645 --- /dev/null +++ b/source/npm/qsharp/ux/bloch/bloch.tsx @@ -0,0 +1,1361 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/* The math for converting basis coefficients (a, b) to a Bloch-sphere + point is: + theta = 2 * acos(magnitude(a)) + phi = arg(b) - arg(a), normalized to [0, 2 * PI) +*/ + +import { useEffect, useMemo, useRef, useState } from "preact/hooks"; +import { ComponentChildren } from "preact"; + +import { Vector3 } from "three"; + +import { Rotations, Ket0, Vec2 } from "../cplx.js"; +import { Markdown } from "../renderers.js"; +import { detectThemeChange, ensureTheme } from "../themeObserver.js"; +import { + gateInfo, + MAX_GATE_SEQUENCE_LENGTH, + sanitizeGateSequence, + VALID_GATE_CODES, +} from "./blochGates.js"; +import { BlochRenderer, DEFAULT_ROTATION_TIME_MS } from "./blochRenderer.js"; + +import rzOps from "../../rz-array.json"; + +// Markdown for the initial |0> state shown as the first trace row. +const INITIAL_KET_MARKDOWN = + "$$ | \\psi \\rangle_0 = \\begin{bmatrix} 1 \\\\ 0 \\end{bmatrix} $$"; + +export interface BlochSphereProps { + /** Gate codes (X Y Z H S s T t) to replay on mount. Sanitized and + * length-capped, so it's safe to pass straight from an untrusted URL. */ + initialGates?: string; + /** Called with the full gate sequence whenever it changes, so parents + * can keep a URL or other external state in sync. */ + onGatesChanged?: (gates: string) => void; + /** Host-supplied control rendered after the gate-program input in the + * editor row (the playground uses it for its "share link" button). */ + actionSlot?: ComponentChildren; +} + +export function BlochSphere(props: BlochSphereProps = {}) { + const canvasRef = useRef(null); + // We observe this wrapper (not the canvas) for size changes, since the + // canvas is stretched to fill it by CSS and three.js overwrites its size. + const stageRef = useRef(null); + const renderer = useRef(null); + // Scrollable trace container; kept as a ref so we can scroll the active + // row into view without ever scrolling the page. + const traceScrollRef = useRef(null); + + // The interaction model is a time-travel trace: + // * `gates` is the canonical, ordered list of applied gate codes. It is + // the only durable state; everything else is derived from it. + // * `cursor` is the viewing position in [0, gates.length]. Values + // between 0 and the end put the widget in *inspect mode*: the sphere + // shows that intermediate state without truncating the sequence. + // * `past` / `future` are undo/redo history as whole-sequence snapshots + // (one per user action), so undo reverts an entire action at once. + // + // Applying a new gate while inspecting commits the truncation (later rows + // are discarded), mirroring "navigate back, then act" in browsers. + const [gates, setGates] = useState([]); + const [cursor, setCursor] = useState(0); + const [past, setPast] = useState([]); + const [future, setFuture] = useState([]); + const [rzAngle, setRzAngle] = useState(0); + // While the user is typing in the Rz readout, this holds the in-progress + // text; null means the field mirrors the live (snapped) angle instead. + const [rzInputDraft, setRzInputDraft] = useState(null); + + // Whether the gate controls are collapsed to a compact read-only view, + // for users who just want to scrub the trace without the editing chrome. + const [controlsCollapsed, setControlsCollapsed] = useState(false); + + // Playback state. Mirrored as a ref because animation-completion + // callbacks capture state at call time and would otherwise read it stale. + // `animatingToIndexRef` is the index the in-flight animation heads toward, + // so Pause can snap there cleanly; null when nothing is animating. + const [isPlaying, setIsPlaying] = useState(false); + const isPlayingRef = useRef(false); + const animatingToIndexRef = useRef(null); + + // Playback speed multiplier (0.25x..4x). Pushed straight into + // `renderer.current.rotationTimeMs` so dragging mid-Play takes effect + // immediately (the rAF loop re-reads it every frame). + const [speed, setSpeed] = useState(1); + + function speedChange(e: Event) { + const slider = e.target as HTMLInputElement; + const next = parseFloat(slider.value); + setSpeed(next); + if (renderer.current) { + renderer.current.rotationTimeMs = DEFAULT_ROTATION_TIME_MS / next; + } + } + + // Live-text editing of the gate sequence. `draftText === null` means the + // textbox mirrors the committed `gates`. While the user is typing, + // `draftText` holds their input and is shown immediately; the expensive + // trace/sphere update is deferred until they pause (debounced). Input is + // sanitized per keystroke, so the textbox only ever holds valid codes. + const GATE_TEXT_DEBOUNCE_MS = 150; + const [draftText, setDraftText] = useState(null); + const displayValue = draftText ?? gates.join(""); + // Pending-commit timer, the text awaiting commit, and a snapshot of + // `gates` from the start of an editing burst (so the burst is one undo). + const draftTimerRef = useRef(null); + const draftPendingRef = useRef(null); + const draftBaseRef = useRef([]); + + // Measured natural width (px) of the widest trace row, fed back as an + // explicit column width so the wide equations don't clip or scroll. + const [traceContentWidth, setTraceContentWidth] = useState( + null, + ); + + // Convert gate codes to the {axis, angle} steps `snapTo` expects, keeping + // the renderer ignorant of gate codes. + function gatesToSteps(codes: string[]) { + return codes.map((c) => ({ + axis: gateInfo[c].rotateAxis, + angle: gateInfo[c].rotateAngle, + })); + } + + useEffect(() => { + if (!canvasRef.current) return; + const initialIsDark = ensureTheme() ?? false; + const r = new BlochRenderer(canvasRef.current, initialIsDark); + renderer.current = r; + // Replay any URL-supplied gates. We seed `gates` directly (rather than + // the regular applyGate path, which hits stale-closure bugs in a tight + // setState loop) and open on the latest step, so a linked-to program + // shows its final state and the user can add gates without first + // overwriting it. They can still Play/step back through the trace. + if (props.initialGates) { + const { gates: cleaned, modified } = sanitizeGateSequence( + props.initialGates, + ); + if (modified) { + console.warn( + `BlochSphere: ignored unknown gates or excess length in initialGates ` + + `(input length ${props.initialGates.length}, applied ${cleaned.length}). ` + + `Valid gate codes are: ${VALID_GATE_CODES}.`, + ); + } + if (cleaned) { + const arr = cleaned.split(""); + setGates(arr); + // Snap the sphere to the end of the sequence and park the cursor + // there, matching the latest trace step. + r.snapTo(gatesToSteps(arr)); + setCursor(arr.length); + props.onGatesChanged?.(cleaned); + } + } + // Live theme switches (e.g. VS Code light/dark toggled while open). + const themeCleanup = detectThemeChange(document.body, (isDark) => { + r.setTheme(isDark); + }); + // Keep the WebGL buffer in sync with the stage's on-screen size, so the + // widget fills whatever host it sits in and stays sharp on high-DPI. + let resizeObserver: ResizeObserver | undefined; + const stage = stageRef.current; + if (stage) { + r.resize(stage.clientWidth, stage.clientHeight); + resizeObserver = new ResizeObserver((entries) => { + const rect = entries[0]?.contentRect; + if (rect) r.resize(rect.width, rect.height); + }); + resizeObserver.observe(stage); + } + return () => { + resizeObserver?.disconnect(); + themeCleanup(); + r.dispose(); + renderer.current = null; + }; + }, []); + + // Derived: per-step trace entries (LaTeX strings) for the whole + // `gates` sequence, walking the matrix product forward from |0\u27e9. + // Computed in one pass instead of being mirrored in state, so the + // trace rows can never disagree with the underlying gate list. + const traceEntries = useMemo(() => { + let prior: Vec2 = Ket0; + return gates.map((code, i) => { + const info = gateInfo[code]; + const next = info.matrix.mulVec2(prior); + const latex = `$$ ${info.display} | \\psi \\rangle_{${i}} = + ${info.latex} + \\cdot ${prior.toLaTeX()} + = ${next.toLaTeX()} + $$`; + prior = next; + return latex; + }); + }, [gates]); + + // Progressive trace rendering. Each row runs a synchronous KaTeX + // conversion on mount, so committing a large batch at once would block + // the main thread long enough to stall the animation. Cap how many rows + // mount per render and fill the rest in during idle time. + const PROGRESSIVE_CHUNK = 6; + const prevTraceRef = useRef([]); + const renderLimitRef = useRef(0); + // Set by snap-only navigation (undo/redo) to force the whole trace to + // mount this render instead of ramping. Those paths stop the animation + // first, so there's nothing for the ramp to protect -- and ramping would + // otherwise leave the active row (and its highlight/anchor) unmounted + // until requestIdleCallback happens to fire. + const fullMountRef = useRef(false); + const [, setRampTick] = useState(0); + if (traceEntries !== prevTraceRef.current) { + const prev = prevTraceRef.current; + const total = traceEntries.length; + // Unchanged leading rows are memoized by , so they're free. + let shared = 0; + const overlap = Math.min(prev.length, total); + while (shared < overlap && prev[shared] === traceEntries[shared]) shared++; + // Small changes (or a forced full mount) render everything now; a large + // batch mounts only its unchanged prefix and lets the ramp add the rest. + renderLimitRef.current = + fullMountRef.current || total - shared <= PROGRESSIVE_CHUNK + ? total + : shared; + prevTraceRef.current = traceEntries; + fullMountRef.current = false; + } + const renderLimit = renderLimitRef.current; + + // Grow the render limit a chunk at a time during idle periods, yielding + // to the animation loop between chunks. + useEffect(() => { + const total = traceEntries.length; + if (renderLimit >= total) return; + const w = window as Window & { + requestIdleCallback?: (cb: () => void) => number; + cancelIdleCallback?: (id: number) => void; + }; + const schedule = w.requestIdleCallback + ? w.requestIdleCallback.bind(w) + : (cb: () => void) => w.setTimeout(cb, 16); + const unschedule = w.cancelIdleCallback + ? w.cancelIdleCallback.bind(w) + : (id: number) => w.clearTimeout(id); + const id = schedule(() => { + renderLimitRef.current = Math.min( + total, + renderLimitRef.current + PROGRESSIVE_CHUNK, + ); + setRampTick((n) => n + 1); + }); + return () => unschedule(id); + }, [renderLimit, traceEntries]); + + // Measure the widest trace row and feed it back as an explicit column + // width (--qs-trace-width) so the wide equations don't clip or scroll. + // The rows are absolutely positioned (so they can't stretch the grid) + // and `white-space: nowrap`, so each row's scrollWidth is its intrinsic + // width and independent of the pane width -- a stable fixed point. We + // add the scrollbar gutter, round up, and only update on real change. + const PANE_MIN_WIDTH = 480; + useEffect(() => { + const list = traceScrollRef.current; + if (!list) return; + const measure = () => { + let widestRow = 0; + for (const row of Array.from(list.children)) { + widestRow = Math.max(widestRow, (row as HTMLElement).scrollWidth); + } + const scrollbar = list.offsetWidth - list.clientWidth; + // +2 for the pane's 1px left/right border. + const next = Math.max( + PANE_MIN_WIDTH, + Math.ceil(widestRow + scrollbar + 2), + ); + setTraceContentWidth((prev) => + prev !== null && Math.abs(prev - next) <= 1 ? prev : next, + ); + }; + measure(); + // Re-measure when fonts finish loading or the host font size changes. + const ro = new ResizeObserver(measure); + ro.observe(list); + for (const row of Array.from(list.children)) ro.observe(row); + return () => ro.disconnect(); + }, [traceEntries, renderLimit]); + + // Clear any pending gate-text debounce timer on unmount so it can't + // fire a state update after the component is gone. + useEffect(() => { + return () => { + if (draftTimerRef.current !== null) clearTimeout(draftTimerRef.current); + }; + }, []); + + // Keep the active trace row in view as `cursor` advances. We drive + // `container.scrollTop` directly rather than `scrollIntoView`, which + // would scroll the whole page once the pane bottoms out. The sticky + // "latest" row overlaps the bottom of the band, so we subtract its + // height and center the active row in the remaining visible band. + useEffect(() => { + const container = traceScrollRef.current; + if (!container) return; + const active = container.querySelector( + ".qs-bloch-trace-item-current", + ); + if (!active) return; + // The latest row is sticky-pinned to the bottom, so it's always + // visible -- skip scrolling when it's the active row, which otherwise + // causes a small jump when the user clicks it. + const sticky = container.querySelector( + ".qs-bloch-trace-item-latest", + ); + if (sticky === active) return; + const stickyOverlap = sticky ? sticky.offsetHeight : 0; + const visibleHeight = container.clientHeight - stickyOverlap; + const cTop = container.scrollTop; + const cBottom = cTop + visibleHeight; + const aTop = active.offsetTop; + const aBottom = aTop + active.offsetHeight; + if (aTop < cTop || aBottom > cBottom) { + // Center the active row, clamped to the scrollable range. + const desired = aTop - (visibleHeight - active.offsetHeight) / 2; + const maxScroll = container.scrollHeight - container.clientHeight; + const target = Math.max(0, Math.min(maxScroll, desired)); + container.scrollTo({ top: target, behavior: "smooth" }); + } + }, [cursor, gates]); + + // Spherical coordinates (theta, phi) of the qubit state after the first + // `cursor` gates, re-walked through a throwaway `Rotations` so the + // overlay can't drift from the renderer. Three.js axes differ from the + // drawn Bloch axes: Bloch x = three.js z, Bloch y = three.js x, Bloch + // z = three.js y; the state starts along three.js +Y (the |0> pole). + const blochAngles = useMemo(() => { + const rot = new Rotations(); + for (let i = 0; i < cursor; i++) { + const info = gateInfo[gates[i]]; + switch (info.rotateAxis) { + case "X": + rot.rotateX(info.rotateAngle); + break; + case "Y": + rot.rotateY(info.rotateAngle); + break; + case "Z": + rot.rotateZ(info.rotateAngle); + break; + case "H": + rot.rotateH(info.rotateAngle); + break; + } + } + const tip = new Vector3(0, 1, 0).applyQuaternion(rot.currPosition); + const blochZ = Math.max(-1, Math.min(1, tip.y)); + const theta = Math.acos(blochZ); + // phi is undefined at the poles; flag it so the overlay can hide it. + const polar = Math.abs(blochZ) > 0.999999; + const phi = polar ? 0 : Math.atan2(tip.x, tip.z); + return { theta, phi, polar }; + }, [gates, cursor]); + + // State-vector ket at the cursor, walking the same matrix product as + // the trace but stopping at the cursor. Shown in the stage's corner. + const currentStateLatex = useMemo(() => { + let state: Vec2 = Ket0; + for (let i = 0; i < cursor; i++) { + state = gateInfo[gates[i]].matrix.mulVec2(state); + } + return `$$ | \\psi \\rangle = ${state.toLaTeX()} $$`; + }, [gates, cursor]); + + // "Inspect mode" means the cursor is deliberately parked on an earlier + // step (not a forward tail animation, which also has cursor < + // gates.length -- hence !isPlaying). It gates editing, but NOT + // undo/redo, which are always available when there's history. + const inInspectMode = !isPlaying && cursor < gates.length; + const canUndo = past.length > 0; + const canRedo = future.length > 0; + // Playback affordances, all derived from cursor/gates/isPlaying so the + // media buttons can't disagree with what the sphere is doing. + const atStart = cursor === 0; + const atEnd = cursor >= gates.length; + const canStepBack = !atStart; + const canStepForward = !atEnd; + const canPlay = gates.length > 0; + + /** + * Stop any in-flight playback and land cleanly on a trace step. Called + * by Pause, and as a guard before every edit/seek so the user can't + * edit mid-rotation. No-op when already stopped. When called as a Pause + * (snapToTarget=true) it snaps forward to the in-flight gate's + * destination; guards pass false since they snap elsewhere next. + */ + function stopPlayback(snapToTarget = true) { + if (!isPlayingRef.current) return; + isPlayingRef.current = false; + setIsPlaying(false); + const targetIdx = animatingToIndexRef.current; + animatingToIndexRef.current = null; + if (snapToTarget && targetIdx !== null && renderer.current) { + renderer.current.snapTo(gatesToSteps(gates.slice(0, targetIdx))); + setCursor(targetIdx); + } + } + + /** + * Animate one gate, then advance the cursor and chain to the next if + * play is still active. The recursive chain captures `pos` per gate. + */ + function playFromIndex(pos: number) { + if (!renderer.current) return; + const code = gates[pos]; + const info = gateInfo[code]; + if (!info) { + // Defensive: inputs are sanitized, but bail cleanly if one slips by. + stopPlayback(false); + return; + } + animatingToIndexRef.current = pos + 1; + renderer.current.animateStep(info.rotateAxis, info.rotateAngle, () => { + // If we were paused mid-gate, Pause already advanced the cursor and + // cancelled the rAF; bail rather than chaining. + animatingToIndexRef.current = null; + if (!isPlayingRef.current) return; + const next = pos + 1; + setCursor(next); + if (next < gates.length) { + playFromIndex(next); + } else { + isPlayingRef.current = false; + setIsPlaying(false); + } + }); + } + + /** + * Play from the cursor to the end. If already at the end, treat the + * click as Replay: rewind to the start and play from there. + */ + function play() { + if (isPlayingRef.current || gates.length === 0 || !renderer.current) { + return; + } + let startIdx = cursor; + if (cursor >= gates.length) { + // Replay: rewind to the start, then play. + renderer.current.snapTo([]); + setCursor(0); + startIdx = 0; + } + isPlayingRef.current = true; + setIsPlaying(true); + playFromIndex(startIdx); + } + + function pause() { + stopPlayback(true); + } + + function stepBack() { + if (cursor === 0 || !renderer.current) return; + stopPlayback(false); + const target = cursor - 1; + const r = renderer.current; + // Align the renderer's pose with `cursor` before animating, in case a + // just-cancelled play left it a gate ahead. + r.snapTo(gatesToSteps(gates.slice(0, cursor))); + // Animate the inverse of the last gate (same axis, negated angle) so + // the qubit retraces its arc backward. queueGate lays down trail dots + // along the reverse path; they overlap the existing trail, and the + // onComplete snapTo wipes and rebuilds the trail for [0..target-1]. + const info = gateInfo[gates[cursor - 1]]; + r.animateStep(info.rotateAxis, -info.rotateAngle, () => { + r.snapTo(gatesToSteps(gates.slice(0, target))); + setCursor(target); + }); + } + + function stepForward() { + if (cursor >= gates.length || !renderer.current) return; + stopPlayback(false); + const target = cursor + 1; + const r = renderer.current; + // Same guard as stepBack: align the renderer with `cursor` first. + r.snapTo(gatesToSteps(gates.slice(0, cursor))); + const info = gateInfo[gates[cursor]]; + r.animateStep(info.rotateAxis, info.rotateAngle, () => { + setCursor(target); + }); + } + + function jumpToStart() { + stopPlayback(false); + navigateTo(0); + } + + function jumpToEnd() { + stopPlayback(false); + navigateTo(gates.length); + } + + /** + * Snapshot the sequence before an action so Undo can return to it, and + * clear the redo stack. Call once at the start of every gate-changing + * action. + */ + function pushHistory(prev: string[]) { + setPast((p) => [...p, prev]); + setFuture([]); + } + + /** + * Apply one new gate. If inspecting an earlier step, the future part of + * the sequence is truncated (browser back-then-navigate semantics). + */ + function applyGate(code: string) { + const info = gateInfo[code]; + if (!info || !renderer.current) return; + // Stop playback first; snapToTarget=false since we snap or animate next. + stopPlayback(false); + + // Drop any pending text edit so its debounced commit can't overwrite this. + cancelDraft(); + + // Record the pre-action sequence so Undo reverts this whole action + // (including any inspect-mode truncation) in a single step. + pushHistory(gates); + + // Truncate future steps if the user is mid-inspect, then snap the + // renderer there silently before kicking off the animated rotation + // for the newly-applied gate. + let base = gates; + if (cursor < gates.length) { + base = gates.slice(0, cursor); + renderer.current.snapTo(gatesToSteps(base)); + } + renderer.current.animateStep(info.rotateAxis, info.rotateAngle); + const next = [...base, code]; + setGates(next); + setCursor(next.length); + props.onGatesChanged?.(next.join("")); + } + + /** + * Move the cursor within the existing sequence without modifying it + * (trace-row clicks, jump buttons). Snaps instantly since the user is + * inspecting, not acting. + */ + function navigateTo(pos: number) { + if (!renderer.current) return; + if (pos < 0 || pos > gates.length) return; + // The seek implicitly pauses; snapToTarget=false since we snap below. + stopPlayback(false); + renderer.current.snapTo(gatesToSteps(gates.slice(0, pos))); + setCursor(pos); + } + + /** + * Undo: restore the previous whole-sequence snapshot. One snapshot per + * action, so this reverts an entire action at once (e.g. a whole Rz + * decomposition). Always available when there's prior history. + */ + function undo() { + if (!canUndo || !renderer.current) return; + stopPlayback(false); + cancelDraft(); + const prev = past[past.length - 1]; + setPast(past.slice(0, -1)); + setFuture([gates, ...future]); + renderer.current.snapTo(gatesToSteps(prev)); + // Mount the whole restored trace now so the active row appears at once. + fullMountRef.current = true; + setGates(prev); + setCursor(prev.length); + props.onGatesChanged?.(prev.join("")); + } + + /** + * Redo: restore the snapshot most recently undone away. Symmetric with + * undo; always available when there's a state to redo. + */ + function redo() { + if (!canRedo || !renderer.current) return; + stopPlayback(false); + cancelDraft(); + const next = future[0]; + setFuture(future.slice(1)); + setPast([...past, gates]); + renderer.current.snapTo(gatesToSteps(next)); + // Mount the whole restored trace now so the active row appears at once. + fullMountRef.current = true; + setGates(next); + setCursor(next.length); + props.onGatesChanged?.(next.join("")); + } + + function clear() { + stopPlayback(false); + // Drop any pending text edit so it can't resurrect the old sequence. + cancelDraft(); + // Record the cleared-from sequence so an accidental Clear can be undone. + pushHistory(gates); + setGates([]); + setCursor(0); + // Return the Rz slider to zero so it reflects the cleared state. + setRzAngle(0); + renderer.current?.reset(); + props.onGatesChanged?.(""); + } + + // ---- Live-text gate editing ------------------------------------------- + + /** + * Cancel any pending debounced commit and drop the draft so the textbox + * mirrors `gates` again. Called by the non-text actions so a stale timer + * can't clobber the change they just made. + */ + function cancelDraft() { + if (draftTimerRef.current !== null) { + clearTimeout(draftTimerRef.current); + draftTimerRef.current = null; + } + draftPendingRef.current = null; + if (draftText !== null) setDraftText(null); + } + + /** + * Handle a keystroke in the gate textbox: sanitize immediately, show the + * result right away, and debounce the expensive sphere/trace update. + */ + function gateTextInput(e: Event) { + const value = (e.target as HTMLInputElement).value; + const clean = sanitizeGateSequence(value).gates; + // Typing interrupts any in-flight animation; the pending commit snaps + // to the right place, so we snap nowhere here. + if (isPlayingRef.current) stopPlayback(false); + // First keystroke of a burst: snapshot the pre-edit sequence so the + // whole burst undoes as one step. + if (draftText === null) draftBaseRef.current = gates; + setDraftText(clean); + draftPendingRef.current = clean; + if (draftTimerRef.current !== null) clearTimeout(draftTimerRef.current); + draftTimerRef.current = window.setTimeout( + commitDraftText, + GATE_TEXT_DEBOUNCE_MS, + ); + } + + /** + * Snap to `arr[0..fromIndex]` then animate the remaining gates one at a + * time. Shared by the actions that append a run and want the tail to + * animate in (live-text commits, the Rz "Add to sequence" button). + * Reads from `arr` because the caller's setGates hasn't flushed yet. + */ + function animateTailFrom(arr: string[], fromIndex: number) { + if (!renderer.current) return; + renderer.current.snapTo(gatesToSteps(arr.slice(0, fromIndex))); + if (fromIndex >= arr.length) { + setCursor(arr.length); + return; + } + setCursor(fromIndex); + isPlayingRef.current = true; + setIsPlaying(true); + const chain = (pos: number) => { + if (!renderer.current) return; + const info = gateInfo[arr[pos]]; + if (!info) { + isPlayingRef.current = false; + setIsPlaying(false); + return; + } + animatingToIndexRef.current = pos + 1; + renderer.current.animateStep(info.rotateAxis, info.rotateAngle, () => { + animatingToIndexRef.current = null; + if (!isPlayingRef.current) return; + const next = pos + 1; + setCursor(next); + if (next < arr.length) { + chain(next); + } else { + isPlayingRef.current = false; + setIsPlaying(false); + } + }); + }; + chain(fromIndex); + } + + /** + * Commit the pending draft text. Diffs against the sequence editing + * started from: snap to the shared prefix, then animate the divergent + * tail, so appending "H" to "XYZ" animates just the H. Recorded as one + * undo step. + */ + function commitDraftText() { + draftTimerRef.current = null; + const text = draftPendingRef.current; + draftPendingRef.current = null; + if (text === null || !renderer.current) return; + const arr = text.split(""); + const prev = draftBaseRef.current; + // Nothing changed this burst (e.g. pasting identical text): drop the + // draft without a history step, else undo gets a no-op entry. + if (prev.join("") === text) { + if (draftText !== null) setDraftText(null); + return; + } + stopPlayback(false); + // Record the pre-burst sequence as a single undoable step. + setPast((p) => [...p, prev]); + setFuture([]); + setGates(arr); + setDraftText(null); + props.onGatesChanged?.(text); + + // Shared leading run between old and new; snap to it, animate the rest. + const maxPrefix = Math.min(prev.length, arr.length); + let prefix = 0; + while (prefix < maxPrefix && prev[prefix] === arr[prefix]) prefix++; + animateTailFrom(arr, prefix); + } + + // The Rz angle is chosen with a circular dial (JSX below). Angles are + // snapped to the lookup-table resolution (1/200 rad per step, indexed + // by angle*200) so the preview matches what gets committed. + const dialRef = useRef(null); + // Pending requestAnimationFrame id while dragging, to coalesce moves. + const dialFrameRef = useRef(null); + const RZ_STEP = 1 / 200; + const RZ_STEPS = rzOps.length; + + // Snap an angle (radians) onto the lookup-table grid and wrap into + // [0, 2*PI), so dial, readout, and decomposition can't disagree. + function snapAngle(a: number): number { + let idx = Math.round(a * 200) % RZ_STEPS; + if (idx < 0) idx += RZ_STEPS; + return idx * RZ_STEP; + } + + // Pointer position to angle from the dial center. 0 rad is 3 o'clock, + // increasing counterclockwise; SVG y points down, so negate the y delta. + function angleFromPointer(clientX: number, clientY: number): number { + const svg = dialRef.current; + if (!svg) return rzAngle; + const rect = svg.getBoundingClientRect(); + const cx = rect.left + rect.width / 2; + const cy = rect.top + rect.height / 2; + let a = Math.atan2(-(clientY - cy), clientX - cx); + if (a < 0) a += Math.PI * 2; + return snapAngle(a); + } + + function dialPointerDown(e: PointerEvent) { + if (isPlaying) return; + const svg = e.currentTarget as SVGSVGElement; + svg.setPointerCapture(e.pointerId); + setRzAngle(angleFromPointer(e.clientX, e.clientY)); + } + + function dialPointerMove(e: PointerEvent) { + const svg = e.currentTarget as SVGSVGElement; + if (!svg.hasPointerCapture(e.pointerId)) return; + // Coalesce moves to one state update per frame; pointer events can + // outpace the refresh rate and each setRzAngle re-renders. + const next = angleFromPointer(e.clientX, e.clientY); + if (dialFrameRef.current !== null) return; + dialFrameRef.current = requestAnimationFrame(() => { + dialFrameRef.current = null; + setRzAngle(next); + }); + } + + function dialPointerUp(e: PointerEvent) { + const svg = e.currentTarget as SVGSVGElement; + if (svg.hasPointerCapture(e.pointerId)) + svg.releasePointerCapture(e.pointerId); + // Flush any queued frame so the final position isn't dropped. + if (dialFrameRef.current !== null) { + cancelAnimationFrame(dialFrameRef.current); + dialFrameRef.current = null; + } + setRzAngle(angleFromPointer(e.clientX, e.clientY)); + } + + // Keyboard support for the dial (focusable, role="slider"). Arrows nudge + // one step, PageUp/Down by ten, Home/End to 0 / just under a full turn. + function dialKeyDown(e: KeyboardEvent) { + if (isPlaying) return; + let next: number; + switch (e.key) { + case "ArrowRight": + case "ArrowUp": + next = rzAngle + RZ_STEP; + break; + case "ArrowLeft": + case "ArrowDown": + next = rzAngle - RZ_STEP; + break; + case "PageUp": + next = rzAngle + RZ_STEP * 10; + break; + case "PageDown": + next = rzAngle - RZ_STEP * 10; + break; + case "Home": + next = 0; + break; + case "End": + next = (RZ_STEPS - 1) * RZ_STEP; + break; + default: + return; + } + e.preventDefault(); + setRzAngle(snapAngle(next)); + } + + // The Rz readout doubles as a text field: users can type an angle in + // radians and the dial + decomposition snap to the nearest grid value + // the lookup table can produce. Parse, snap, and drop the draft so the + // field reverts to showing the live (snapped) angle. + function commitRzInput() { + if (rzInputDraft === null) return; + const parsed = Number.parseFloat(rzInputDraft); + if (Number.isFinite(parsed)) setRzAngle(snapAngle(parsed)); + setRzInputDraft(null); + } + + function rzInputKeyDown(e: KeyboardEvent) { + if (e.key === "Enter") { + e.preventDefault(); + commitRzInput(); + (e.currentTarget as HTMLInputElement).blur(); + } else if (e.key === "Escape") { + e.preventDefault(); + // Abandon the edit and restore the live angle. + setRzInputDraft(null); + (e.currentTarget as HTMLInputElement).blur(); + } + } + + // Map the current Rz angle to its precomputed Clifford+T decomposition + // (empty string at angle 0 = identity). + const rzAngleIdx = Math.round(rzAngle * 200) % rzOps.length; + const rzDecomposition = rzOps[rzAngleIdx] ?? ""; + + // Append the current Rz decomposition like a gate button does: truncate + // any inspected-future steps, clear redo, and animate the new gates in. + function applyRzDecomposition() { + if (!renderer.current || rzDecomposition.length === 0) return; + stopPlayback(false); + cancelDraft(); + // The whole decomposition is appended as one undoable action. + pushHistory(gates); + // Branch from the inspected step if inspecting; otherwise append. + const base = cursor < gates.length ? gates.slice(0, cursor) : gates; + const next = [...base, ...rzDecomposition.split("")]; + setGates(next); + // Leave the dial angle as-is so the user can add the rotation again. + props.onGatesChanged?.(next.join("")); + animateTailFrom(next, base.length); + } + + // Memoized trace rows. Keying on the values they depend on (entries + + // cursor) lets preact reuse the vnodes when only the Rz angle changed, + // keeping the dial drag cheap as the sequence grows. + const traceRows = useMemo(() => { + return traceEntries.slice(0, renderLimit).map((str, i) => { + const stepIndex = i + 1; + const classes = ["qs-bloch-trace-item"]; + if (stepIndex === cursor) classes.push("qs-bloch-trace-item-current"); + if (stepIndex > cursor) classes.push("qs-bloch-trace-item-future"); + // Pin the last row so the latest step stays visible while scrolling + // (see `.qs-bloch-trace-item-latest` in the CSS). + if (i === traceEntries.length - 1) + classes.push("qs-bloch-trace-item-latest"); + return ( +
navigateTo(stepIndex)} + > + +
+ ); + }); + }, [traceEntries, cursor, renderLimit]); + + return ( +
) + : undefined + } + > +
+
+ + + + {controlsCollapsed && ( +
+ + +
+ )} +
+ {!controlsCollapsed && ( +
+
+ +
+
+
+ {(() => { + // Knob sits on the track at the current angle. 0 rad is at + // 3 o'clock, increasing counterclockwise; SVG y points down + // so the vertical term is negated. + const trackR = 46; + const knobX = 60 + trackR * Math.cos(rzAngle); + const knobY = 60 - trackR * Math.sin(rzAngle); + return ( + + + {/* Tick marks at 0, π/2, π, 3π/2 for orientation. */} + {[0, Math.PI / 2, Math.PI, (3 * Math.PI) / 2].map((a) => ( + + ))} + + + + + ); + })()} +
+ + {"Rz("} + { + setRzInputDraft(rzAngle.toFixed(3)); + (e.currentTarget as HTMLInputElement).select(); + }} + onInput={(e) => + setRzInputDraft( + (e.currentTarget as HTMLInputElement).value, + ) + } + onKeyDown={rzInputKeyDown} + onBlur={commitRzInput} + /> + {" rad)"} + + +
+ + Decomposition: + + + {rzDecomposition.length > 0 + ? rzDecomposition + : "identity (no gates)"} + +
+
+
+
+
+ {/* Gate palette: single-qubit gates, as one segmented control. */} +
+ {( + [ + ["X", "X"], + ["Y", "Y"], + ["Z", "Z"], + ["H", "H"], + ["S", "S"], + ["s", "S†"], + ["T", "T"], + ["t", "T†"], + ] as const + ).map(([code, label]) => ( + + ))} +
+ + {/* Edit history: undo/redo, as a second segmented control. */} +
+ + +
+ +
+ +
+
+
+
+ + {props.actionSlot} +
+ {/* + Gate-count breakdown plus a T-count callout. T-count (T and T† + gates) is the key cost metric for fault-tolerant implementations, + so surfacing it live is useful after the Rz slider expands a + rotation into many gates. + */} + +
+
+ )} +
+
+
+
+ Trace + {gates.length > 0 && ( + + Step {cursor} / {gates.length} + + )} +
+ {/* + Media transport controls: jump-to-start, step-back, + play/pause/replay, step-forward, jump-to-end. Step/jump are + seek-only; the centre button is the only animated path. + */} +
+ + + {isPlaying ? ( + + ) : ( + + )} + + +
+ {/* + Speed slider. The value is the speed multiplier (higher = + faster); the renderer translates it back to milliseconds. + */} +
+ + + {speed.toFixed(2)}× +
+
+
navigateTo(0)} + > + +
+ {traceRows} +
+
+
+
+ ); +} diff --git a/source/npm/qsharp/ux/bloch/blochGates.ts b/source/npm/qsharp/ux/bloch/blochGates.ts new file mode 100644 index 0000000000..7cf88b140f --- /dev/null +++ b/source/npm/qsharp/ux/bloch/blochGates.ts @@ -0,0 +1,141 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/* + * Pure gate-code metadata and validation for the Bloch-sphere widget. + * + * Kept separate from bloch.tsx so it can be unit-tested under plain Node + * without pulling in three.js, preact, or the JSON data tables. + */ + +import { + PauliX, + PauliY, + PauliZ, + SGate, + TGate, + Hadamard, +} from "../quantum-math.js"; + +/** Rotation primitives the renderer exposes (distinct from the x/y/z axis + * labels in the visualization). */ +export type RotationAxis = "X" | "Y" | "Z" | "H"; + +/** + * Per-gate metadata, keyed by single-character gate code, shared by the + * visualization layer (to animate/snap) and the math layer (to display + * the LaTeX equation and update the state vector). + */ +export const gateInfo: Record< + string, + { + /** Display name for the LaTeX equation header (e.g. "X", "S\u2020"). */ + display: string; + /** The 2x2 matrix in the computational basis. */ + matrix: typeof PauliX; + /** Pre-rendered LaTeX for the matrix used in the trace pane. */ + latex: string; + /** Which renderer rotation primitive to invoke. */ + rotateAxis: RotationAxis; + /** Angle in radians (sign matters for adjoint variants). */ + rotateAngle: number; + } +> = { + X: { + display: "X", + matrix: PauliX, + latex: "\\begin{bmatrix} 0 & 1 \\\\ 1 & 0 \\end{bmatrix}", + rotateAxis: "X", + rotateAngle: Math.PI, + }, + Y: { + display: "Y", + matrix: PauliY, + latex: "\\begin{bmatrix} 0 & -i \\\\ i & 0 \\end{bmatrix}", + rotateAxis: "Y", + rotateAngle: Math.PI, + }, + Z: { + display: "Z", + matrix: PauliZ, + latex: "\\begin{bmatrix} 1 & 0 \\\\ 0 & -1 \\end{bmatrix}", + rotateAxis: "Z", + rotateAngle: Math.PI, + }, + S: { + display: "S", + matrix: SGate, + latex: + "\\begin{bmatrix} 1 & 0 \\\\ 0 & e^{i {\\pi \\over 2}} \\end{bmatrix}", + rotateAxis: "Z", + rotateAngle: Math.PI / 2, + }, + s: { + display: "S\u2020", + matrix: SGate.adjoint(), + latex: + "\\begin{bmatrix} 1 & 0 \\\\ 0 & e^{-i {\\pi \\over 2}} \\end{bmatrix}", + rotateAxis: "Z", + rotateAngle: -Math.PI / 2, + }, + T: { + display: "T", + matrix: TGate, + latex: + "\\begin{bmatrix} 1 & 0 \\\\ 0 & e^{i {\\pi \\over 4}} \\end{bmatrix}", + rotateAxis: "Z", + rotateAngle: Math.PI / 4, + }, + t: { + display: "T\u2020", + matrix: TGate.adjoint(), + latex: + "\\begin{bmatrix} 1 & 0 \\\\ 0 & e^{-i {\\pi \\over 4}} \\end{bmatrix}", + rotateAxis: "Z", + rotateAngle: -Math.PI / 4, + }, + H: { + display: "H", + matrix: Hadamard, + latex: + "{1 \\over \\sqrt{2}} \\begin{bmatrix} 1 & 1 \\\\ 1 & -1 \\end{bmatrix}", + rotateAxis: "H", + rotateAngle: Math.PI, + }, +}; + +/** + * The set of single-character gate codes the widget understands. Each + * character here must correspond to a `case` arm in `BlochSphere.rotate`. + */ +/** The single-character gate codes the widget understands. */ +export const VALID_GATE_CODES = "XYZHSsTt"; + +/** + * Cap on gates accepted from a single untrusted input (URL parameter, + * paste, etc.). Bounds the abuse case (a hostile link with thousands of + * gates flooding the animation queue), not the intended UX limit. + */ +export const MAX_GATE_SEQUENCE_LENGTH = 256; + +const validGateSet = new Set(VALID_GATE_CODES); + +/** + * Filter a string down to `VALID_GATE_CODES` and cap its length. Returns + * the cleaned string and whether anything was dropped. + */ +export function sanitizeGateSequence(input: string | undefined | null): { + gates: string; + modified: boolean; +} { + if (!input) return { gates: "", modified: false }; + let filtered = ""; + for (const ch of input) { + if (validGateSet.has(ch)) filtered += ch; + } + const capped = filtered.slice(0, MAX_GATE_SEQUENCE_LENGTH); + return { + gates: capped, + modified: capped.length !== input.length, + }; +} diff --git a/source/npm/qsharp/ux/bloch/blochRenderer.ts b/source/npm/qsharp/ux/bloch/blochRenderer.ts new file mode 100644 index 0000000000..5480fddc03 --- /dev/null +++ b/source/npm/qsharp/ux/bloch/blochRenderer.ts @@ -0,0 +1,713 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +// The three.js rendering layer for the Bloch sphere widget. Owns the +// WebGL scene, the animated/snap rotation logic, and the trail/axis +// visuals. Kept separate from `bloch.tsx` (the preact component) so the +// rendering code can be reasoned about without the UI state machine, and +// vice versa. + +import { + BoxGeometry, + BufferGeometry, + CanvasTexture, + ConeGeometry, + CylinderGeometry, + DirectionalLight, + Group, + Line, + LineBasicMaterial, + Mesh, + MeshBasicMaterial, + MeshLambertMaterial, + PerspectiveCamera, + Scene, + SphereGeometry, + Sprite, + SpriteMaterial, + Vector3, + WebGLRenderer, +} from "three"; + +import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js"; + +import { AppliedGate, Rotations } from "../cplx.js"; +import { RotationAxis } from "./blochGates.js"; + +// Two color palettes for the directly-WebGL-drawn parts of the scene +// (sphere material, label sprites), picked to stay legible on light/dark +// backgrounds. CSS-styled parts use the shared QDK theme tokens instead. +const lightThemeColors = { + sphereColor: 0x404080, + sphereBrightness: 2, + sphereOpacity: 0.5, + directionalLightBrightness: 0.25, + markerColor: 0xc00000, + sphereLinesOpacity: 0.2, + labelCanvasColor: "#606080", +}; + +const darkThemeColors = { + sphereColor: 0x8080c0, + sphereBrightness: 1.6, + sphereOpacity: 0.55, + directionalLightBrightness: 0.35, + markerColor: 0xff5050, + sphereLinesOpacity: 0.35, + labelCanvasColor: "#d0d0e0", +}; + +function colorsFor(isDark: boolean) { + return isDark ? darkThemeColors : lightThemeColors; +} + +// See https://gizma.com/easing/#easeInOutSine +function easeInOutSine(x: number) { + return -(Math.cos(Math.PI * x) - 1) / 2; +} + +function easeOutSine(x: number) { + return Math.sin((x * Math.PI) / 2); +} + +function hslToRgb(h: number, s: number, l: number) { + let r, g, b; + + if (s === 0) { + r = g = b = l; // achromatic + } else { + const q = l < 0.5 ? l * (1 + s) : l + s - l * s; + const p = 2 * l - q; + r = hueToRgb(p, q, h + 1 / 3); + g = hueToRgb(p, q, h); + b = hueToRgb(p, q, h - 1 / 3); + } + return ( + (Math.min(r * 255, 255) << 16) | + (Math.min(g * 255, 255) << 8) | + Math.min(b * 255, 255) + ); +} + +function hueToRgb(p: number, q: number, t: number) { + if (t < 0) t += 1; + if (t > 1) t -= 1; + if (t < 1 / 6) return p + (q - p) * 6 * t; + if (t < 1 / 2) return q; + if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6; + return p; +} + +function makeLabelSprite(text: string, fillStyle: string): Sprite { + // Render the label into an offscreen canvas used as a sprite texture. + // Sprites always face the camera, so labels stay legible while orbiting. + const size = 128; + const canvas = document.createElement("canvas"); + canvas.width = size; + canvas.height = size; + const ctx = canvas.getContext("2d")!; + ctx.font = "bold 96px sans-serif"; + ctx.textAlign = "center"; + ctx.textBaseline = "middle"; + ctx.fillStyle = fillStyle; + ctx.fillText(text, size / 2, size / 2); + + const texture = new CanvasTexture(canvas); + // depthWrite off: the mostly-transparent quad would otherwise punch a + // box-shaped hole in the grid circles behind it. + const material = new SpriteMaterial({ + map: texture, + transparent: true, + depthWrite: false, + }); + const sprite = new Sprite(material); + sprite.scale.set(1.2, 1.2, 1); + return sprite; +} + +function createLabels(isDark: boolean): Sprite[] { + const fill = colorsFor(isDark).labelCanvasColor; + + const xLabel = makeLabelSprite("x", fill); + xLabel.position.set(0, 0, 6.4); + + const yLabel = makeLabelSprite("y", fill); + yLabel.position.set(6.4, 0, 0); + + const zLabel = makeLabelSprite("z", fill); + zLabel.position.set(0, 6.4, 0); + + return [xLabel, yLabel, zLabel]; +} + +// Default duration of a single gate animation (ms). The speed slider +// overwrites `BlochRenderer.rotationTimeMs` directly; the rAF loop +// re-reads it every frame so changes take effect mid-animation. The +// slider's 0.25x..4x range covers ~1.3s down to ~83ms per gate. +export const DEFAULT_ROTATION_TIME_MS = 333; + +export class BlochRenderer { + scene: Scene; + camera: PerspectiveCamera; + renderer: WebGLRenderer; + controls: OrbitControls; + qubit: Group; + trail: Group; + rotationAxis: Group; + animationCallbackId = 0; + // Public so the speed slider can mutate it directly; no derived state. + rotationTimeMs = DEFAULT_ROTATION_TIME_MS; + // Animation queue. Each entry's optional `onComplete` fires when that + // gate's animation ends; the play loop uses it to chain to the next gate. + gateQueue: { gate: AppliedGate; onComplete?: () => void }[] = []; + rotations: Rotations; + // Stored so setTheme() can recolor materials and swap label sprites. + sphereMaterial: MeshLambertMaterial; + sphereLineMaterial: LineBasicMaterial; + markerMaterial: MeshBasicMaterial; + directionalLight: DirectionalLight; + labelSprites: Sprite[] = []; + isDark: boolean; + // Shared GPU resources for trail dots. Without these, every replayed gate + // and animation frame allocated a fresh geometry + material per path + // point, which froze the UI on trace-row clicks for long sequences. + private trailDotGeometry!: SphereGeometry; + // Pre-built fade-color palette; dot age maps to an index via + // `getTrailDotMaterial`, replacing per-dot material allocation. + private trailDotMaterials!: MeshBasicMaterial[]; + + constructor(canvas: HTMLCanvasElement, isDark: boolean) { + this.rotations = new Rotations(64); + this.isDark = isDark; + + // Build the shared trail-dot resources up front so snapTo/queueGate + // hot paths just link objects rather than allocate. + this.trailDotGeometry = new SphereGeometry(0.05, 16, 16); + const TRAIL_PALETTE_SIZE = 32; + this.trailDotMaterials = []; + for (let i = 0; i < TRAIL_PALETTE_SIZE; i++) { + const sat = i / (TRAIL_PALETTE_SIZE - 1); + this.trailDotMaterials.push( + new MeshBasicMaterial({ color: hslToRgb(0.6, sat, 0.5) }), + ); + } + const palette = colorsFor(isDark); + + const renderer = new WebGLRenderer({ + canvas, + antialias: true, + alpha: true, + }); + + const scene = new Scene(); + const camera = new PerspectiveCamera( + 30, // fov + 1, // aspect + 0.1, // near + 1000, // far + ); + + // In WebGL, Z is towards the camera (viewer looking towards -Z), Y is up, X is right + // Position slightly towards the X and Y axis to give a 'canonical' view + camera.position.x = 4; + camera.position.y = 4; + camera.position.z = 27; + camera.lookAt(0, 0, 0); + + const light = new DirectionalLight( + 0xffffff, + palette.directionalLightBrightness, + ); + light.position.set(-1, 2, 4); + scene.add(light); + this.directionalLight = light; + + // Note that the orbit controls move the camera, they don't rotate the + // scene, so the X, Y, and Z axis for the Bloch sphere remain fixed. + const controls = new OrbitControls(camera, renderer.domElement); + + // Create a group to hold the qubit + const qubit = new Group(); + + // The sphere and its grid lines stay fixed: a gate rotates the qubit's + // *state*, not the reference frame. Only the position marker lives in + // the rotating `qubit` group. + const sphereFrame = new Group(); + + // Add the main sphere. + const sphereGeometry = new SphereGeometry(5, 96, 64); + const material = new MeshLambertMaterial({ + emissive: palette.sphereColor, + emissiveIntensity: palette.sphereBrightness, + transparent: true, + opacity: palette.sphereOpacity, + }); + this.sphereMaterial = material; + const sphere = new Mesh(sphereGeometry, material); + // Draw the sphere (renderOrder 0) before the grid lines (1). Both are + // transparent, so without an explicit order three.js sorts by centroid + // and the sphere sometimes paints over the near-side lines. + sphere.renderOrder = 0; + sphereFrame.add(sphere); + + // The spin-direction marker is the only part of the qubit group that + // moves with a gate; it tracks the state vector across the sphere. + const coneGeometry = new ConeGeometry(0.2, 0.75, 32); + const coneMat = new MeshBasicMaterial({ color: palette.markerColor }); + this.markerMaterial = coneMat; + const marker = new Mesh(coneGeometry, coneMat); + marker.position.set(0, 5.125, 0.4); + marker.rotateX(Math.PI / 2); + qubit.add(marker); + + // Draw smooth latitude/longitude grid lines on the sphere. Each circle + // is a single high-segment line loop, which reads as a clean great-circle. + const gridRadius = 5.1; + const circleSegments = 128; + const lineMaterial = new LineBasicMaterial({ + // Test depth so far-side circles stay occluded, but don't write it + // (lines render after the sphere and shouldn't depth-fight). + depthTest: true, + depthWrite: false, + transparent: true, + opacity: palette.sphereLinesOpacity, + }); + this.sphereLineMaterial = lineMaterial; + const sphereLines = new Group(); + + const addCircle = (pointAt: (angle: number) => Vector3) => { + const points: Vector3[] = []; + for (let i = 0; i <= circleSegments; i++) { + points.push(pointAt((i / circleSegments) * Math.PI * 2)); + } + const geometry = new BufferGeometry().setFromPoints(points); + const line = new Line(geometry, lineMaterial); + // After the sphere so it never paints over the lines. + line.renderOrder = 1; + sphereLines.add(line); + }; + + // Latitude circles, skipping the degenerate pole rings. + const latitudeCount = 18; + for (let i = 1; i < latitudeCount; i++) { + const theta = (i / latitudeCount) * Math.PI; + const y = gridRadius * Math.cos(theta); + const r = gridRadius * Math.sin(theta); + addCircle( + (angle) => new Vector3(r * Math.cos(angle), y, r * Math.sin(angle)), + ); + } + + // Longitude circles: great circles through both poles. Each + // half-meridian repeats on the far side, so half a turn covers all. + const longitudeCount = 18; + for (let i = 0; i < longitudeCount; i++) { + const phi = (i / longitudeCount) * Math.PI; + const cosPhi = Math.cos(phi); + const sinPhi = Math.sin(phi); + addCircle( + (angle) => + new Vector3( + gridRadius * Math.sin(angle) * cosPhi, + gridRadius * Math.cos(angle), + gridRadius * Math.sin(angle) * sinPhi, + ), + ); + } + + sphereFrame.add(sphereLines); + scene.add(sphereFrame); + scene.add(qubit); + + // Create a group to hold the trailing points + const trail = new Group(); + scene.add(trail); + + // Add the axes + const axisMaterial = new MeshBasicMaterial({ color: 0xe0d0c0 }); + const zAxis = new CylinderGeometry(0.075, 0.075, 12, 32, 8); + const zAxisMesh = new Mesh(zAxis, axisMaterial); + scene.add(zAxisMesh); + + const zPointer = new ConeGeometry(0.2, 0.8, 16); + const zPointerMesh = new Mesh(zPointer, axisMaterial); + zPointerMesh.position.set(0, 6, 0); + scene.add(zPointerMesh); + + const yAxisMesh = new Mesh(zAxis, axisMaterial); + yAxisMesh.rotateZ(Math.PI / 2); + scene.add(yAxisMesh); + const yPointerMesh = new Mesh(zPointer, axisMaterial); + yPointerMesh.position.set(6, 0, 0); + yPointerMesh.rotateZ(-Math.PI / 2); + scene.add(yPointerMesh); + + const xAxisMesh = new Mesh(zAxis, axisMaterial); + xAxisMesh.rotateX(Math.PI / 2); + scene.add(xAxisMesh); + const xPointerMesh = new Mesh(zPointer, axisMaterial); + xPointerMesh.position.set(0, 0, 6); + xPointerMesh.rotateX(Math.PI / 2); + scene.add(xPointerMesh); + + const rotationAxis = new Group(); + const rotationAxisMaterial = new MeshLambertMaterial({ + emissive: 0x808080, + emissiveIntensity: 1.5, + transparent: true, + opacity: 0.75, + }); + const axisBox = new BoxGeometry(0.33, 0.33, 12.5); + const axisBoxMesh = new Mesh(axisBox, rotationAxisMaterial); + rotationAxis.add(axisBoxMesh); + + const fins = [ + [2, 0.25, 0.25, 0, 0, 5.75], + [0.25, 2, 0.25, 0, 0, 5.75], + [2, 0.25, 0.25, 0, 0, -5.75], + [0.25, 0.25, 2, 0, 0, -5.75], + ]; + + fins.forEach((fin) => { + const finBox = new BoxGeometry(fin[0], fin[1], fin[2]); + const finBoxMesh = new Mesh(finBox, rotationAxisMaterial); + finBoxMesh.position.set(fin[3], fin[4], fin[5]); + rotationAxis.add(finBoxMesh); + }); + + this.rotationAxis = rotationAxis; + + // See https://threejs.org/manual/#en/rendering-on-demand + controls.addEventListener("change", () => + requestAnimationFrame(() => this.render()), + ); + + this.renderer = renderer; + this.scene = scene; + this.camera = camera; + this.controls = controls; + this.qubit = qubit; + this.trail = trail; + + // Labels are synchronous now, so just create them and render once. + this.labelSprites = createLabels(isDark); + this.labelSprites.forEach((s) => scene.add(s)); + this.render(); + } + + queueGate(gate: AppliedGate, onComplete?: () => void) { + this.gateQueue.push({ gate, onComplete }); + if (this.animationCallbackId) return; // Queue is already running + + // Close over these values for the running queue + let currentEntry: + | { gate: AppliedGate; onComplete?: () => void } + | undefined; + let startTime = 0; + + const processQueue = () => { + if (!currentEntry) { + currentEntry = this.gateQueue.shift(); + if (!currentEntry) { + // Queue was empty. Done + this.animationCallbackId = 0; + return; + } else { + const axisInLocal = this.qubit.worldToLocal(currentEntry.gate.axis); + this.rotationAxis.lookAt(axisInLocal); + this.qubit.add(this.rotationAxis); + startTime = performance.now(); + } + } + + // Calculate the percent of rotation time elapsed from start to now + const x = (performance.now() - startTime) / this.rotationTimeMs; + + // Ease the rotation + const t = x < 1 ? easeInOutSine(x) : 1; + + // Rotate the qubit to the correct position + const currentRotation = this.rotations.getRotationAtPercent( + currentEntry.gate, + t, + ); + + currentRotation.path.forEach((val) => { + // Draw any that don't already have a point + if (val.ref) return; + // Shared geometry + placeholder material; the fade pass assigns the + // correct material this frame. + const trackBall = new Mesh( + this.trailDotGeometry, + this.trailDotMaterials[0], + ); + trackBall.position.set(0, 5, 0); + + // Convert to world space + trackBall.position.applyQuaternion(val.pos); + + // Save along with the interpolation point + this.trail.add(trackBall); + val.ref = trackBall; + }); + + // Set qubit position to slerped values + this.qubit.quaternion.copy(currentRotation.pos); + + // Fade out the trail using shared palette materials. + this.trail.children.forEach((child, idx, arr) => { + const ball = child as Mesh; + const sat = easeOutSine((idx + 1) / arr.length); + ball.material = this.getTrailDotMaterial(sat); + ball.scale.setScalar(sat + 0.5); + }); + + this.render(); + + // Gate done: fire the completion callback (which may queue another + // gate -- queueGate sees the live animationCallbackId and appends). + if (t >= 1) { + const finishedCb = currentEntry.onComplete; + currentEntry = undefined; + this.qubit.remove(this.rotationAxis); + this.render(); + finishedCb?.(); + } + + this.animationCallbackId = requestAnimationFrame(processQueue); + }; + + // Kick off processing + processQueue(); + } + + /** + * Animate a single gate by axis + angle, optionally invoking + * `onComplete` when it finishes. The seam the component's play loop uses + * to chain gates without knowing about `AppliedGate` / `Rotations`. + */ + animateStep(axis: RotationAxis, angle: number, onComplete?: () => void) { + let applied: AppliedGate; + switch (axis) { + case "X": + applied = this.rotations.rotateX(angle); + break; + case "Y": + applied = this.rotations.rotateY(angle); + break; + case "Z": + applied = this.rotations.rotateZ(angle); + break; + case "H": + applied = this.rotations.rotateH(angle); + break; + } + this.queueGate(applied, onComplete); + } + + rotateX(angle: number) { + this.queueGate(this.rotations.rotateX(angle)); + } + + rotateY(angle: number) { + this.queueGate(this.rotations.rotateY(angle)); + } + + rotateZ(angle: number) { + this.queueGate(this.rotations.rotateZ(angle)); + } + + rotateH(angle: number) { + this.queueGate(this.rotations.rotateH(angle)); + } + + reset() { + // Cancel any in-flight animation and drain the queue so its render + // callback can't write the in-progress quaternion back over the reset + // (otherwise clearing mid-playback leaves the state indicator stranded + // wherever the last frame landed). + if (this.animationCallbackId) { + cancelAnimationFrame(this.animationCallbackId); + this.animationCallbackId = 0; + } + this.gateQueue.length = 0; + // Detach the rotation-axis indicator in case we're cancelling mid-flight. + this.qubit.remove(this.rotationAxis); + this.controls.reset(); + this.rotations.reset(); + this.trail.clear(); + this.scene.position.set(0, 0, 0); + this.qubit.quaternion.identity(); + this.qubit.rotation.set(0, 0, 0); + this.camera.position.set(4, 4, 27); + this.camera.lookAt(0, 0, 0); + this.render(); + } + + /** + * Apply a sequence of rotations instantly with no animation, rebuilding + * the dotted trail from the same interpolation points the animated path + * uses. Used by trace inspection and undo/redo. + */ + snapTo(steps: { axis: RotationAxis; angle: number }[]) { + // Cancel any in-flight animation so its render callback doesn't write + // the in-progress quaternion back over our snap. + if (this.animationCallbackId) { + cancelAnimationFrame(this.animationCallbackId); + this.animationCallbackId = 0; + } + this.gateQueue.length = 0; + this.trail.clear(); + // Detach the rotation-axis indicator in case we're cancelling mid-flight. + this.qubit.remove(this.rotationAxis); + + // Reset the rotation model, then apply each step, keeping each + // AppliedGate so we can rebuild the trail from its interpolation path. + this.rotations.reset(); + this.qubit.quaternion.identity(); + for (const { axis, angle } of steps) { + let applied; + switch (axis) { + case "X": + applied = this.rotations.rotateX(angle); + break; + case "Y": + applied = this.rotations.rotateY(angle); + break; + case "Z": + applied = this.rotations.rotateZ(angle); + break; + case "H": + applied = this.rotations.rotateH(angle); + break; + } + // Same trackball construction as queueGate, but defer color/scale to + // one fade pass after the loop. These dots are throwaway visuals + // owned by the snap, so we don't set val.ref. + for (const val of applied.path) { + const trackBall = new Mesh( + this.trailDotGeometry, + this.trailDotMaterials[0], + ); + trackBall.position.set(0, 5, 0); + trackBall.position.applyQuaternion(val.pos); + this.trail.add(trackBall); + } + } + // Same age-based fade as the animation loop, so a rebuilt trail looks + // identical to one drawn step by step. + this.trail.children.forEach((child, idx, arr) => { + const ball = child as Mesh; + const sat = easeOutSine((idx + 1) / arr.length); + ball.material = this.getTrailDotMaterial(sat); + ball.scale.setScalar(sat + 0.5); + }); + this.qubit.quaternion.copy(this.rotations.currPosition); + this.render(); + } + + /** + * Map an age-fade saturation in [0, 1] to a pre-built palette material, + * avoiding per-dot material allocation. Bucketing into 32 entries is + * visually imperceptible. + */ + private getTrailDotMaterial(sat: number): MeshBasicMaterial { + const n = this.trailDotMaterials.length; + const idx = Math.min(n - 1, Math.max(0, Math.floor(sat * n))); + return this.trailDotMaterials[idx]; + } + + render() { + this.controls.update(); + this.renderer.render(this.scene, this.camera); + } + + // Resize the WebGL buffer to the container's on-screen size. The `false` + // arg leaves the canvas CSS size alone so it keeps filling its flex cell + // while render resolution tracks actual pixels; aspect is updated to + // keep the sphere round. + resize(width: number, height: number) { + const w = Math.max(1, Math.floor(width)); + const h = Math.max(1, Math.floor(height)); + this.renderer.setPixelRatio(window.devicePixelRatio || 1); + this.renderer.setSize(w, h, false); + this.camera.aspect = w / h; + this.camera.updateProjectionMatrix(); + this.render(); + } + + setTheme(isDark: boolean) { + if (this.isDark === isDark) return; + this.isDark = isDark; + const palette = colorsFor(isDark); + + this.sphereMaterial.emissive.setHex(palette.sphereColor); + this.sphereMaterial.emissiveIntensity = palette.sphereBrightness; + this.sphereMaterial.opacity = palette.sphereOpacity; + this.sphereMaterial.needsUpdate = true; + + this.markerMaterial.color.setHex(palette.markerColor); + this.markerMaterial.needsUpdate = true; + + this.sphereLineMaterial.opacity = palette.sphereLinesOpacity; + this.sphereLineMaterial.needsUpdate = true; + + this.directionalLight.intensity = palette.directionalLightBrightness; + + // Sprite textures are baked at their generation colors, so recreate them. + this.labelSprites.forEach((sprite) => { + this.scene.remove(sprite); + sprite.material.map?.dispose(); + sprite.material.dispose(); + }); + this.labelSprites = createLabels(isDark); + this.labelSprites.forEach((s) => this.scene.add(s)); + + this.render(); + } + + dispose() { + // Stop any in-flight frame so it doesn't render into a dead context. + if (this.animationCallbackId) { + cancelAnimationFrame(this.animationCallbackId); + this.animationCallbackId = 0; + } + this.controls.dispose(); + // three.js doesn't free GPU resources automatically; walk the scene and + // dispose each Mesh's geometry/material/textures, or remounts leak GPU + // memory and WebGL contexts. Trail dots share resources, disposed once + // below, so skip them here. + const sharedGeo = this.trailDotGeometry; + const sharedMats = new Set(this.trailDotMaterials); + this.scene.traverse((obj) => { + const mesh = obj as Mesh; + if (mesh.geometry && mesh.geometry !== sharedGeo) { + mesh.geometry.dispose(); + } + const mat = mesh.material as + | { map?: { dispose: () => void }; dispose?: () => void } + | { map?: { dispose: () => void }; dispose?: () => void }[] + | undefined; + if (Array.isArray(mat)) { + mat.forEach((m) => { + if (sharedMats.has(m as MeshBasicMaterial)) return; + m.map?.dispose(); + m.dispose?.(); + }); + } else if (mat && !sharedMats.has(mat as MeshBasicMaterial)) { + mat.map?.dispose(); + mat.dispose?.(); + } + }); + // Dispose the shared trail-dot resources exactly once. + sharedGeo.dispose(); + this.trailDotMaterials.forEach((m) => m.dispose()); + this.trailDotMaterials = []; + this.labelSprites.forEach((sprite) => { + sprite.material.map?.dispose(); + sprite.material.dispose(); + }); + this.labelSprites = []; + this.renderer.dispose(); + } +} diff --git a/source/npm/qsharp/ux/circuit-vis/state-viz/worker/stateCompute.ts b/source/npm/qsharp/ux/circuit-vis/state-viz/worker/stateCompute.ts index f148b578b7..80ce087e08 100644 --- a/source/npm/qsharp/ux/circuit-vis/state-viz/worker/stateCompute.ts +++ b/source/npm/qsharp/ux/circuit-vis/state-viz/worker/stateCompute.ts @@ -5,9 +5,30 @@ // Implements a small statevector simulator that evaluates the circuit model and // produces an amplitude map. Intentionally avoids DOM/visualization concerns so // it can run on the main thread or in a Web Worker. +// +// The complex-number, 2x2 matrix, and gate-matrix definitions are shared with +// the Bloch sphere widget via `../../../quantum-math.js`. That module is +// deliberately three.js-free so it can be bundled into this worker without +// pulling in three.js's ~600 KB. Do NOT switch this import to `cplx.js` -- +// that file additionally re-exports the quaternion-driven Rotations engine and +// would drag three into the worker. import type { ComponentGrid, Operation, Qubit } from "../../circuit.js"; import { evaluateAngleExpression } from "../../angleExpression.js"; +import { + Cplx, + M2x2, + PauliX, + PauliY, + PauliZ, + Hadamard, + SGate, + TGate, + SXGate, + rotationX, + rotationY, + rotationZ, +} from "../../../quantum-math.js"; // This holds the complex amplitudes of the different basis states. export type AmpMap = Record; @@ -19,107 +40,6 @@ export class UnsupportedStateComputeError extends Error { } } -// Small complex helpers -class Complex { - constructor( - public re: number, - public im: number, - ) {} - static add(a: Complex, b: Complex) { - return new Complex(a.re + b.re, a.im + b.im); - } - static mul(a: Complex, b: Complex) { - return new Complex(a.re * b.re - a.im * b.im, a.re * b.im + a.im * b.re); - } - static conj(a: Complex) { - return new Complex(a.re, -a.im); - } -} - -function adjointMat2(mat: Complex[]): Complex[] { - // 2x2 matrix stored as [m00, m01, m10, m11]. - // Adjoint is conjugate transpose: [[conj(m00), conj(m10)], [conj(m01), conj(m11)]]. - return [ - Complex.conj(mat[0]), - Complex.conj(mat[2]), - Complex.conj(mat[1]), - Complex.conj(mat[3]), - ]; -} - -// Matrices for single-qubit gates -const GATE = { - X: [ - new Complex(0, 0), - new Complex(1, 0), - new Complex(1, 0), - new Complex(0, 0), - ], - Y: [ - new Complex(0, 0), - new Complex(0, -1), - new Complex(0, 1), - new Complex(0, 0), - ], - Z: [ - new Complex(1, 0), - new Complex(0, 0), - new Complex(0, 0), - new Complex(-1, 0), - ], - H: [ - new Complex(Math.SQRT1_2, 0), - new Complex(Math.SQRT1_2, 0), - new Complex(Math.SQRT1_2, 0), - new Complex(-Math.SQRT1_2, 0), - ], - S: [ - new Complex(1, 0), - new Complex(0, 0), - new Complex(0, 0), - new Complex(0, 1), - ], // [[1,0],[0,i]] - T: [ - new Complex(1, 0), - new Complex(0, 0), - new Complex(0, 0), - new Complex(Math.SQRT1_2, Math.SQRT1_2), - ], - SX: [ - // sqrt(X) - new Complex(0.5, 0.5), - new Complex(0.5, -0.5), - new Complex(0.5, -0.5), - new Complex(0.5, 0.5), - ], -}; - -function rotationX(theta: number) { - const c = Math.cos(theta / 2); - const s = Math.sin(theta / 2); - return [ - new Complex(c, 0), - new Complex(0, -s), - new Complex(0, -s), - new Complex(c, 0), - ]; -} -function rotationY(theta: number) { - const c = Math.cos(theta / 2); - const s = Math.sin(theta / 2); - return [ - new Complex(c, 0), - new Complex(-s, 0), - new Complex(s, 0), - new Complex(c, 0), - ]; -} -function rotationZ(theta: number) { - const eNeg = new Complex(Math.cos(-theta / 2), Math.sin(-theta / 2)); - const ePos = new Complex(Math.cos(theta / 2), Math.sin(theta / 2)); - return [eNeg, new Complex(0, 0), new Complex(0, 0), ePos]; -} - function parseTheta(op: Operation): number | undefined { const arg = op.args?.[0]; if (!arg) return undefined; @@ -128,13 +48,19 @@ function parseTheta(op: Operation): number | undefined { } function applySingleQubit( - state: Complex[], + state: Cplx[], target: number, - mat: Complex[], + mat: M2x2, controls: number[] = [], ): void { const N = state.length; const mask = 1 << target; + // Hoist the 4 matrix entries to locals so the hot inner loop is pure + // multiply/add on already-resolved Cplx instances. + const m00 = mat.a; + const m01 = mat.b; + const m10 = mat.c; + const m11 = mat.d; for (let i = 0; i < N; i += 2 * mask) { for (let j = 0; j < mask; j++) { const i0 = i + j; @@ -143,10 +69,8 @@ function applySingleQubit( if (!okControls) continue; const a0 = state[i0]; const a1 = state[i1]; - const n0 = Complex.add(Complex.mul(mat[0], a0), Complex.mul(mat[1], a1)); - const n1 = Complex.add(Complex.mul(mat[2], a0), Complex.mul(mat[3], a1)); - state[i0] = n0; - state[i1] = n1; + state[i0] = m00.mul(a0).add(m01.mul(a1)); + state[i1] = m10.mul(a0).add(m11.mul(a1)); } } } @@ -158,9 +82,9 @@ export function computeAmpMapForCircuit( const n = qubits.length; if (n === 0) return {}; const dim = 1 << n; - const state: Complex[] = new Array(dim); - for (let i = 0; i < dim; i++) state[i] = new Complex(0, 0); - state[0] = new Complex(1, 0); + const state: Cplx[] = new Array(dim); + for (let i = 0; i < dim; i++) state[i] = Cplx.zero; + state[0] = Cplx.one; for (const col of componentGrid) { for (const op of col.components) { @@ -174,28 +98,28 @@ export function computeAmpMapForCircuit( continue; } const t = targetQubits[0]; - let mat: Complex[] | undefined; + let mat: M2x2 | undefined; switch (op.gate) { case "X": - mat = GATE.X; + mat = PauliX; break; case "Y": - mat = GATE.Y; + mat = PauliY; break; case "Z": - mat = GATE.Z; + mat = PauliZ; break; case "H": - mat = GATE.H; + mat = Hadamard; break; case "S": - mat = GATE.S; + mat = SGate; break; case "T": - mat = GATE.T; + mat = TGate; break; case "SX": - mat = GATE.SX; + mat = SXGate; break; case "Rx": { const th = parseTheta(op); @@ -216,7 +140,7 @@ export function computeAmpMapForCircuit( break; } if (mat) { - mat = isAdjoint ? adjointMat2(mat) : mat; + mat = isAdjoint ? mat.adjoint() : mat; applySingleQubit(state, t, mat, controls); } break; diff --git a/source/npm/qsharp/ux/cplx.ts b/source/npm/qsharp/ux/cplx.ts new file mode 100644 index 0000000000..ef54db977d --- /dev/null +++ b/source/npm/qsharp/ux/cplx.ts @@ -0,0 +1,144 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +// Three.js-aware extension of `./quantum-math.js`. The complex-number, +// 2-vector, 2x2-matrix, and gate-matrix primitives live in +// `quantum-math.ts` (worker-safe, no `three` import); this file adds the +// quaternion-driven `Rotations` engine that powers the Bloch sphere +// animation. We re-export everything from `quantum-math` so existing +// consumers (notably `bloch.tsx` and `tools/rz-synthesis.ts`) keep +// working without changing their import paths. + +import { Quaternion, Vector3 } from "three"; +import { compare, numToStr } from "./quantum-math.js"; + +export * from "./quantum-math.js"; + +// Holds a set of rotations for a qubit, and the points in that rotation +export type AppliedGate = { + name: string; + axis: Vector3; + angle: number; + path: { pos: Quaternion; ref?: any }[]; + endPos: Quaternion; +}; + +export type PathEntry = { pos: Quaternion; ref?: any }; + +export class Rotations { + gates: AppliedGate[] = []; + currPosition = new Quaternion(); + + constructor( + public pointsPerRotation = 32, // Assuming a common gate rotation of pi radians + public timePerGateMs = 500, + ) {} + + reset() { + this.gates = []; + this.currPosition = new Quaternion(); + } + + getPathLength(axis: Vector3, rotationAngle: number): number { + /* + To calculate the distance a point travels around a unit sphere as a rotation is applied. + - Calculate the angle (theta) between the axis of rotation and the point + - Get the radius for the circle around the (unit) sphere at theta + - Calculate the distance traveled as the rotation angle * radius + */ + + const pointStart = new Vector3(0, 1, 0); + const pointCurrent = pointStart.applyQuaternion(this.currPosition); + const pointToAxisAngle = pointCurrent.angleTo(axis); + const arcRadius = Math.sin(pointToAxisAngle); + const pathTraveled = arcRadius * rotationAngle; + return Math.abs(pathTraveled); + } + + applyGate(name: string, axis: Vector3, angle: number): AppliedGate { + // Get the target position by applying the rotation to the current position + const endPos = new Quaternion() + .setFromAxisAngle(axis, angle) + .multiply(this.currPosition); + + const pathDistance = this.getPathLength(axis, angle); + const pointCount = Math.floor( + (pathDistance * this.pointsPerRotation) / Math.PI, + ); + + // Generate a set of points between the current and target position + const path: PathEntry[] = []; + for (let i = 0; i < pointCount; i++) { + const t = i / pointCount; + path.push({ pos: this.currPosition.clone().slerp(endPos, t) }); + } + const gate = { name, path, endPos, axis, angle }; + this.gates.push(gate); + + // Update the current position to the final target + this.currPosition = endPos; + return gate; + } + + rotateX(angle?: number): AppliedGate { + const name = angle === undefined ? "X" : `X(${numToStr(angle)})`; + if (angle === undefined) angle = Math.PI; + // The Bloch sphere X axis is the Z axis in WebGL + return this.applyGate(name, new Vector3(0, 0, 1), angle); + } + rotateY(angle?: number): AppliedGate { + const name = angle === undefined ? "Y" : `Y(${numToStr(angle)})`; + if (angle === undefined) angle = Math.PI; + // The Bloch sphere Y axis is the X axis in WebGL + return this.applyGate(name, new Vector3(1, 0, 0), angle); + } + + rotateZ(angle?: number): AppliedGate { + const name = + angle === undefined + ? "Z" + : compare(angle, Math.PI / 2) + ? "S" + : compare(angle, Math.PI / 4) + ? "T" + : `Z(${numToStr(angle)})`; + if (angle === undefined) angle = Math.PI; + // The Bloch sphere Z axis is the Y axis in WebGL + return this.applyGate(name, new Vector3(0, 1, 0), angle); + } + + rotateH(angle?: number): AppliedGate { + const name = angle === undefined ? "H" : `H(${numToStr(angle)})`; + if (angle === undefined) angle = Math.PI; + // Bloch sphere X & Z axes are the Y and Z axes in WebGL + const hAxis = new Vector3(0, 1, 1).normalize(); + return this.applyGate(name, hAxis, angle); + } + + getRotationAtPercent( + gate: AppliedGate, + percent: number, + ): { + pos: Quaternion; + path: PathEntry[]; + } { + if (percent < 0 || percent > 1) throw Error("Invalid percent"); + + // If there is no path, it didn't move. Start and end are the same + if (!gate.path.length) return { pos: gate.endPos.clone(), path: [] }; + + // Get the path up until this percent. Note that the first element is at + // 0%, and the 100% has no entry. For example, if the path has 4 entries + // these are at 0, 0.25, 0.5, and 0.75 of the rotation path. + + const stepSize = 1 / gate.path.length; + const steps = Math.floor(percent / stepSize); + + // As the first point is at 0%, add one (unless at 100%) + const path = gate.path.slice(0, Math.min(steps + 1, gate.path.length)); + return { + pos: gate.path[0].pos.clone().slerp(gate.endPos, percent), + path, + }; + } +} diff --git a/source/npm/qsharp/ux/index.ts b/source/npm/qsharp/ux/index.ts index dfdb3b89c2..709b29bb9f 100644 --- a/source/npm/qsharp/ux/index.ts +++ b/source/npm/qsharp/ux/index.ts @@ -20,6 +20,7 @@ export { SpaceChart } from "./spaceChart.js"; export { ScatterChart } from "./scatterChart.js"; export { EstimatesOverview } from "./estimatesOverview.js"; export { EstimatesPanel } from "./estimatesPanel.js"; +export { BlochSphere } from "./bloch/bloch.js"; export { Circuit, CircuitPanel } from "./circuit.js"; export { setRenderer, Markdown } from "./renderers.js"; export { Atoms, type ZoneLayout, type TraceData } from "./atoms/index.js"; diff --git a/source/npm/qsharp/ux/qsharp-ux.css b/source/npm/qsharp/ux/qsharp-ux.css index 8ae3ceca6a..1ec324b728 100644 --- a/source/npm/qsharp/ux/qsharp-ux.css +++ b/source/npm/qsharp/ux/qsharp-ux.css @@ -535,6 +535,875 @@ modern-normalize (see https://mattbrictson.com/blog/css-normalize-and-reset for color: red; } +.qs-gate-buttons button { + margin-top: 8px; + width: 50px; + height: 25px; +} + +/* The gate-button toolbar is a row of segmented control groups: the gate + palette (X..T†), the undo/redo pair, and reset. Each group is a single + continuous "toolbelt" bar -- one rounded, bordered surface -- and the + individual gates are transparent segments inside it divided by thin + internal rules, so a group reads as one cohesive control rather than a + row of separate buttons. */ +.qs-gate-buttons { + display: flex; + /* The palette, undo/redo, and clear groups must stay together on a + single line -- they read as one toolbar. The control panel is sized + to fit this row, so it must never wrap. */ + flex-wrap: nowrap; + align-items: center; + gap: 8px; +} +.qs-bloch-gate-group { + display: inline-flex; + /* The bar surface: the border, rounding, and background live on the + group, not on its buttons. `overflow: hidden` clips the segments' + hover fill to the rounded outer corners. */ + border: 1px solid var(--qdk-widget-outline); + border-radius: 5px; + background: var(--qdk-menu-fill); + overflow: hidden; +} +/* Buttons become flat, borderless segments of the bar. We override the + shared themed-button rules (which give each button its own fill, + border, and rounding) so only the group surface shows through. A thin + left rule on every segment except the first draws the internal + dividers between gates. */ +.qs-gate-buttons .qs-bloch-gate-group button { + margin: 0; + height: 28px; + background: transparent; + border: none; + border-radius: 0; + /* Divider between segments. We mix the foreground into the fill rather + than using --qdk-widget-outline: in the dark theme the outline token + (#444) is identical to --qdk-menu-fill, so an outline-coloured rule + would be invisible against the bar. A translucent foreground line + reads clearly on both the light and dark button fills. */ + border-left: 1px solid + color-mix(in srgb, var(--qdk-host-foreground) 35%, transparent); +} +.qs-gate-buttons .qs-bloch-gate-group button:first-child { + border-left: none; +} +.qs-gate-buttons .qs-bloch-gate-group button:hover:not(:disabled) { + background: var(--qdk-menu-fill-hover); +} +/* Keep the focus ring inside the bar so it isn't clipped by the group's + `overflow: hidden`, and lift it above neighbouring dividers. */ +.qs-gate-buttons .qs-bloch-gate-group button:focus-visible { + outline: 2px solid var(--qdk-focus-border, var(--qdk-atom-fill)); + outline-offset: -2px; + position: relative; + z-index: 1; +} +/* The gate palette segments share a fixed footprint so the set reads as + an even keypad. */ +.qs-gate-buttons .qs-bloch-gate-group-palette button { + width: 38px; +} + +/* ---- Bloch widget: themed form controls ---- + Browser-default