diff --git a/.prettierignore b/.prettierignore index 3084333940e..290784db84e 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 a047cd7db12..a0f9d83e3af 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.28.1", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.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", @@ -3648,6 +3693,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", @@ -4758,6 +4810,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", @@ -6187,6 +6246,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 4ce70f1d0c1..7a066e593aa 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 50fcbbe4d4d..46ba3ee1dc7 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 00000000000..b5a7eddfcc5 --- /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 00000000000..226f5ff968d --- /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 00000000000..1be31631ef3 --- /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 00000000000..f3bf7fe2081 --- /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 00000000000..d2eac909b8a --- /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.css b/source/npm/qsharp/ux/bloch/bloch.css new file mode 100644 index 00000000000..a48a8e6e432 --- /dev/null +++ b/source/npm/qsharp/ux/bloch/bloch.css @@ -0,0 +1,875 @@ +/* Copyright (c) Microsoft Corporation. + Licensed under the MIT License. */ + +/* Styles for the Bloch sphere widget (see bloch.tsx). Bundled together + with qsharp-ux.css, so the shared --qdk-* theme tokens (defined in + qdk-theme.css) are available here without a separate @import. */ + +.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 + + + )} + + {!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 00000000000..7cf88b140fa --- /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 00000000000..5480fddc037 --- /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 f148b578b7a..80ce087e08e 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 00000000000..ef54db977d1 --- /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 dfdb3b89c22..709b29bb9f4 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/quantum-math.ts b/source/npm/qsharp/ux/quantum-math.ts new file mode 100644 index 00000000000..0ada3e40881 --- /dev/null +++ b/source/npm/qsharp/ux/quantum-math.ts @@ -0,0 +1,534 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +// Basic classes for complex numbers, 2-vectors, and 2x2 matrices, plus the +// canonical single-qubit gate constants and computational-basis kets. +// +// IMPORTANT: this module must remain free of `three`, DOM, and any other +// browser-only or heavyweight imports. It is consumed by the state-viz +// state-compute worker (which is bundled into a Web Worker chunk) and by +// the Bloch sphere widget; pulling `three` in here would silently bloat +// the worker bundle by ~600 KB. Three.js-dependent code (Rotations, +// AppliedGate, PathEntry) lives in `./cplx.ts`, which re-exports +// everything below for back-compat. + +const epsilon = 0.000001; // Tolerance when comparing numbers +export function compare(a: number, b: number, eps = epsilon): boolean { + return Math.abs(a - b) < eps; +} + +const fmt = new Intl.NumberFormat("en-US", { maximumFractionDigits: 4 }); +export const numToStr = (n: number) => fmt.format(n); + +// Some common numbers after various gates to display in LaTeX +// - 1 / sqrt(2) = 0.7071067811865476 = sqrt(2) / 2 +// - 1 / (2 * sqrt(2)) = 0.3535533905932738 = sqrt(2) / 4 +// - (1 + sqrt(2)) / (2 * sqrt(2)) = 0.8535533905932737 = cos^2(pi / 8) +// - (-1 + sqrt(2)) / (2 * sqrt(2)) = 0.14644660940672624 = sin^2(pi / 8) +function numToLaTeX(n: number, forceSign = false): string { + let result = ""; + if (n < 0) { + result += "- {"; + } else if (forceSign) { + result += "+ {"; + } else { + result += "{"; + } + + n = Math.abs(n); + if (compare(n, 0)) { + result += "0"; + } else if (compare(n, 1)) { + result += "1"; + } else if (compare(n, 0.5)) { + result += "1 \\over 2"; + } else if (compare(n, 0.25)) { + result += "1 \\over 4"; + } else if (compare(n, 0.75)) { + result += "3 \\over 4"; + } else if (compare(n, Math.SQRT1_2)) { + // result += "\\sqrt{2} \\over 2"; + result += "1 \\over \\sqrt{2}"; + } else if (compare(n, 0.1464466094)) { + result += "2 - \\sqrt{2} \\over 4"; + // result += "{-1 + \\sqrt{2}} \\over 2 \\sqrt{2}"; + // result += "\\sin^2{\\pi \\over 8}"; + } else if (compare(n, 0.3535533905)) { + // result += "1 \\over {2 \\sqrt{2}}"; + result += "\\sqrt{2} \\over 4"; + } else if (compare(n, 0.8535533905)) { + result += "{2 + \\sqrt{2}} \\over 4"; + // result += "{1 + \\sqrt{2}} \\over {2 \\sqrt{2}}"; + // result += "\\cos^2{\\pi \\over 8}"; + } else if (compare(n, 0.8660254037844386)) { + result += "\\sqrt{3} \\over 2"; + } else { + result += numToStr(n); + } + + return result + "}"; +} + +export class Cplx { + constructor( + public re: number, + public im: number, + ) {} + + static zero = new Cplx(0, 0); + static one = new Cplx(1, 0); + static i = new Cplx(0, 1); + static negOne = new Cplx(-1, 0); + static negI = new Cplx(0, -1); + static e_to_i_pi_over_2 = new Cplx(0, 1); + static e_to_i_pi_over_4 = new Cplx(Math.SQRT1_2, Math.SQRT1_2); + + add(c: Cplx): Cplx { + return new Cplx(this.re + c.re, this.im + c.im); + } + + sub(c: Cplx): Cplx { + return new Cplx(this.re - c.re, this.im - c.im); + } + + mul(c: Cplx | number): Cplx { + if (typeof c === "number") { + return new Cplx(this.re * c, this.im * c); + } else { + // FOIL: (a + bi)(c + di) = ac + adi + bci + bdi^2 + return new Cplx( + this.re * c.re - this.im * c.im, + this.re * c.im + this.im * c.re, + ); + } + } + + mag(): number { + return Math.sqrt(this.re ** 2 + this.im ** 2); + } + + isUnit(): boolean { + return compare(this.mag(), 1.0); + } + + norm(): Cplx { + if (this.isUnit()) { + return new Cplx(this.re, this.im); + } else { + return this.mul(1 / this.mag()); + } + } + + conj(): Cplx { + return new Cplx(this.re, -this.im); + } + + compare(c: Cplx, eps = epsilon): boolean { + return compare(this.re, c.re, eps) && compare(this.im, c.im, eps); + } + + toPolar() { + const magnitude = Math.sqrt(this.re * this.re + this.im * this.im); + const phase = Math.atan2(this.im, this.re); + return { magnitude, phase }; + } + + static fromPolar(magnitude: number, phase: number) { + const result = new Cplx(Math.cos(phase), Math.sin(phase)).mul(magnitude); + return result; + } + + static parse(input: string): Cplx | null { + // Valid formats: "0", "1", "i", "-i", "-1.2+3i", "-2i", etc. + + // Removal all whitespace + input = input.replace(/\s/g, ""); + + // Handle special and common cases + switch (input) { + case "0": + return new Cplx(0, 0); + case "1": + return new Cplx(1, 0); + case "i": + return new Cplx(0, 1); + case "-1": + return new Cplx(-1, 0); + case "-i": + return new Cplx(0, -1); + default: + break; + } + + // Regular expressions to parse a complex number + // - Optional leading '+' or '-' sign + // - Numeric value for real part (optional if imaginary part is present) + // - Optional numeric imaginary part with leading [+-] and trailing 'i' + // - If real part is not present, leading '+' on imaginary part is optional + // - Numeric parts are an integer followed by an optional decimal part + // - If decimal part is present, it must contain at least one digit + // - Scientific notation is not supported + + // To ease parsing, look for the real and imaginary parts separately + const rePart = /^[+-]?(\d+)(\.\d+)?(?=$|[+-])/; + const imPart = /(^|[+-])(\d+)(\.\d+)?(?=i$)/; + + const reMatch = input.match(rePart); + const imMatch = input.match(imPart); + if (!reMatch && !imMatch) { + return null; + } + + const reVal = parseFloat(reMatch?.[0] ?? "0"); + const imVal = parseFloat(imMatch?.[0] ?? "0"); + return new Cplx(reVal, imVal); + } + + toString() { + const reTo4 = numToStr(this.re); + const imTo4 = compare(this.im, 1) + ? "" + : compare(this.im, -1) + ? "-" + : numToStr(this.im); + + if (compare(this.im, 0)) { + return reTo4; + } else if (compare(this.re, 0)) { + return `${imTo4}${"i"}`; + } else { + return `${reTo4}${this.im > 0 ? "+" : ""}${imTo4}i`; + } + } + + toLaTeX() { + if (this.compare(Cplx.zero)) { + return "{0}"; + } else if (this.compare(Cplx.one)) { + return "{1}"; + } else if (this.compare(Cplx.i)) { + return "{i}"; + } else if (this.compare(Cplx.negOne)) { + return "{-1}"; + } else if (this.compare(Cplx.negI)) { + return "{-i}"; + } else if (this.compare(Cplx.e_to_i_pi_over_2)) { + return "{e^{i {\\pi \\over 2}}}"; + } else if (this.compare(Cplx.e_to_i_pi_over_4)) { + return "{e^{i {\\pi \\over 4}}}"; + } else if (compare(this.re, 0)) { + return numToLaTeX(this.im) + "i"; + } else if (compare(this.im, 0)) { + return numToLaTeX(this.re); + } else { + return `${numToLaTeX(this.re)} ${numToLaTeX(this.im, true)}i`; + } + } +} + +// Convenience constructor accepting a number, an existing Cplx, or a textbook- +// style string like "1+2i" / "-i" / "3.5". String parsing delegates to +// `Cplx.parse`; it's deliberately lenient so the matrix/vector factories below +// can also accept string inputs split on commas. +export function cplx(x: number | string | Cplx): Cplx { + if (typeof x === "number") { + return new Cplx(x, 0); + } else if (typeof x === "string") { + const result = Cplx.parse(x); + if (result) { + return result; + } else { + throw Error("Invalid cplx string"); + } + } else if (x instanceof Cplx) { + return new Cplx(x.re, x.im); + } else { + throw Error("Invalid cplx parameter"); + } +} + +export class Vec2 { + constructor( + public x: Cplx, + public y: Cplx, + ) {} + add(v: Vec2): Vec2 { + return new Vec2(this.x.add(v.x), this.y.add(v.y)); + } + + sub(v: Vec2): Vec2 { + return new Vec2(this.x.sub(v.x), this.y.sub(v.y)); + } + + mul(v: number): Vec2 { + return new Vec2(this.x.mul(v), this.y.mul(v)); + } + + innerProduct(v: Vec2): Cplx { + return this.x.mul(v.x).add(this.y.mul(v.y)); + } + + outerProduct(v: Vec2): M2x2 { + return new M2x2( + this.x.mul(v.x), + this.x.mul(v.y), + this.y.mul(v.x), + this.y.mul(v.y), + ); + } + + remove0Phase(): Vec2 { + const p0 = this.x.toPolar(); + const p1 = this.y.toPolar(); + + return new Vec2( + Cplx.fromPolar(p0.magnitude, 0), + Cplx.fromPolar(p1.magnitude, p1.phase - p0.phase), + ); + } + + compare(v: Vec2): boolean { + return this.x.compare(v.x) && this.y.compare(v.y); + } + + toLaTeX() { + return `\\begin{bmatrix} ${this.x.toLaTeX()} \\\\ ${this.y.toLaTeX()} \\end{bmatrix}`; + } + + toString() { + return `[${this.x},${this.y}]`; + } +} + +// Convenience constructor for `Vec2` accepting either an existing Vec2, an +// array of two numeric/Cplx entries, or a comma-separated textbook string like +// `"1,i"`. The string form is mostly useful in tests and ad-hoc declarations +// where matching textbook notation matters more than micro-optimizing module +// init. +export function vec2(input: Vec2 | string | (number | Cplx)[]): Vec2 { + if (input instanceof Vec2) { + return new Vec2(input.x, input.y); + } else if (Array.isArray(input) && input.length === 2) { + return new Vec2(cplx(input[0]), cplx(input[1])); + } else if (typeof input === "string") { + const parts = input.split(","); + if (parts.length === 2) { + return new Vec2(cplx(parts[0]), cplx(parts[1])); + } + } + throw Error("Invalid input parameter to vec2"); +} + +// A 2x2 matrix of complex numbers +export class M2x2 { + constructor( + public a: Cplx, + public b: Cplx, + public c: Cplx, + public d: Cplx, + ) {} + + add(m: M2x2): M2x2 { + return new M2x2( + this.a.add(m.a), + this.b.add(m.b), + this.c.add(m.c), + this.d.add(m.d), + ); + } + + sub(m: M2x2): M2x2 { + return new M2x2( + this.a.sub(m.a), + this.b.sub(m.b), + this.c.sub(m.c), + this.d.sub(m.d), + ); + } + + mul(m: M2x2 | Cplx | number): M2x2 { + if (typeof m === "number") m = cplx(m); + if (m instanceof Cplx) { + return new M2x2( + this.a.mul(m), + this.b.mul(m), + this.c.mul(m), + this.d.mul(m), + ); + } else { + return new M2x2( + this.a.mul(m.a).add(this.b.mul(m.c)), + this.a.mul(m.b).add(this.b.mul(m.d)), + this.c.mul(m.a).add(this.d.mul(m.c)), + this.c.mul(m.b).add(this.d.mul(m.d)), + ); + } + } + + mulVec2(v: Vec2): Vec2 { + return new Vec2( + this.a.mul(v.x).add(this.b.mul(v.y)), + this.c.mul(v.x).add(this.d.mul(v.y)), + ); + } + + compare(m: M2x2): boolean { + return ( + this.a.compare(m.a) && + this.b.compare(m.b) && + this.c.compare(m.c) && + this.d.compare(m.d) + ); + } + + det(): Cplx { + return this.a.mul(this.d).sub(this.b.mul(this.c)); + } + + transpose(): M2x2 { + return new M2x2(this.a, this.c, this.b, this.d); + } + + adjoint(): M2x2 { + return new M2x2(this.a.conj(), this.c.conj(), this.b.conj(), this.d.conj()); + } + + isDiagonal(eps = epsilon): boolean { + return this.b.compare(Cplx.zero, eps) && this.c.compare(Cplx.zero, eps); + } + + phase(): number { + const pa = this.a.toPolar(); + const pd = this.d.toPolar(); + let phase = pd.phase - pa.phase; + if (phase < 0) phase += Math.PI * 2; + return phase; + } + + toString() { + return `[ + ${this.a.toString()}, ${this.b.toString()} + ${this.c.toString()}, ${this.d.toString()} +]`; + } + + toShortString() { + return `[[${this.a.toString()},${this.b.toString()}],[${this.c.toString()},${this.d.toString()}]]`; + } +} + +// Convenience constructor for `M2x2` accepting either an existing M2x2, an +// array of four numeric/Cplx entries in row-major order, or a comma-separated +// textbook string like `"0, 1, 1, 0"`. Same rationale as `vec2(string)`: kept +// for tests and ad-hoc one-offs where matching the matrix's visual layout +// matters more than module-init speed. +export function m2x2(v: M2x2 | (number | Cplx)[] | string): M2x2 { + if (v instanceof M2x2) { + return new M2x2(v.a, v.b, v.c, v.d); + } else if (Array.isArray(v) && v.length === 4) { + return new M2x2(cplx(v[0]), cplx(v[1]), cplx(v[2]), cplx(v[3])); + } else if (typeof v === "string") { + const parts = v.split(","); + if (parts.length === 4) { + return new M2x2( + cplx(parts[0]), + cplx(parts[1]), + cplx(parts[2]), + cplx(parts[3]), + ); + } + } + throw Error("Invalid input paramter to m2x2"); +} + +// I = [[1, 0], [0, 1]] +export const Ident = new M2x2(Cplx.one, Cplx.zero, Cplx.zero, Cplx.one); + +// X = [[0, 1], [1, 0]] +export const PauliX = new M2x2(Cplx.zero, Cplx.one, Cplx.one, Cplx.zero); + +// Y = [[0, -i], [i, 0]] +export const PauliY = new M2x2(Cplx.zero, Cplx.negI, Cplx.i, Cplx.zero); + +// Z = [[1, 0], [0, -1]] +export const PauliZ = new M2x2(Cplx.one, Cplx.zero, Cplx.zero, Cplx.negOne); + +// H = 1/sqrt(2) * [[1, 1], [1, -1]] +export const Hadamard = new M2x2( + new Cplx(Math.SQRT1_2, 0), + new Cplx(Math.SQRT1_2, 0), + new Cplx(Math.SQRT1_2, 0), + new Cplx(-Math.SQRT1_2, 0), +); + +// S = [[1, 0], [0, i]] +export const SGate = new M2x2(Cplx.one, Cplx.zero, Cplx.zero, Cplx.i); + +// T = [[1, 0], [0, e^{i pi/4}]] +export const TGate = new M2x2( + Cplx.one, + Cplx.zero, + Cplx.zero, + Cplx.e_to_i_pi_over_4, +); + +// Square root of X (sometimes written V). Half-rotation around the Bloch X +// axis: (1+i)/2 on the diagonal, (1-i)/2 off-diagonal. +// SX = 1/2 * [[1+i, 1-i], [1-i, 1+i]] +export const SXGate = new M2x2( + new Cplx(0.5, 0.5), + new Cplx(0.5, -0.5), + new Cplx(0.5, -0.5), + new Cplx(0.5, 0.5), +); + +// Single-qubit rotation gates parameterized by angle theta. +// Rx(θ) = [[cos(θ/2), -i sin(θ/2)], [-i sin(θ/2), cos(θ/2)]] +export function rotationX(theta: number): M2x2 { + const c = Math.cos(theta / 2); + const s = Math.sin(theta / 2); + return new M2x2( + new Cplx(c, 0), + new Cplx(0, -s), + new Cplx(0, -s), + new Cplx(c, 0), + ); +} + +// Ry(θ) = [[cos(θ/2), -sin(θ/2)], [sin(θ/2), cos(θ/2)]] +export function rotationY(theta: number): M2x2 { + const c = Math.cos(theta / 2); + const s = Math.sin(theta / 2); + return new M2x2( + new Cplx(c, 0), + new Cplx(-s, 0), + new Cplx(s, 0), + new Cplx(c, 0), + ); +} + +// Rz(θ) = [[e^{-iθ/2}, 0], [0, e^{iθ/2}]] +export function rotationZ(theta: number): M2x2 { + const eNeg = new Cplx(Math.cos(-theta / 2), Math.sin(-theta / 2)); + const ePos = new Cplx(Math.cos(theta / 2), Math.sin(theta / 2)); + return new M2x2(eNeg, Cplx.zero, Cplx.zero, ePos); +} + +// --- Computational-basis kets --- +// |0> = [1, 0], |1> = [0, 1] +export const Ket0 = new Vec2(Cplx.one, Cplx.zero); +export const Ket1 = new Vec2(Cplx.zero, Cplx.one); + +// |+> = 1/sqrt(2) * [1, 1] +// |-> = 1/sqrt(2) * [1, -1] +// |+i> = 1/sqrt(2) * [1, i] +// |-i> = 1/sqrt(2) * [1, -i] +const inv_sqrt_2 = new Cplx(Math.SQRT1_2, 0); +const neg_inv_sqrt_2 = new Cplx(-Math.SQRT1_2, 0); +const i_inv_sqrt_2 = new Cplx(0, Math.SQRT1_2); +const neg_i_inv_sqrt_2 = new Cplx(0, -Math.SQRT1_2); + +export const KetPlus = new Vec2(inv_sqrt_2, inv_sqrt_2); +export const KetMinus = new Vec2(inv_sqrt_2, neg_inv_sqrt_2); +export const KetPlusI = new Vec2(inv_sqrt_2, i_inv_sqrt_2); +export const KetMinusI = new Vec2(inv_sqrt_2, neg_i_inv_sqrt_2); diff --git a/source/npm/qsharp/ux/renderers.tsx b/source/npm/qsharp/ux/renderers.tsx index eb436cdcab8..a25144541f8 100644 --- a/source/npm/qsharp/ux/renderers.tsx +++ b/source/npm/qsharp/ux/renderers.tsx @@ -2,6 +2,7 @@ // Licensed under the MIT License. import { createElement } from "preact"; +import { useMemo } from "preact/hooks"; // Default renderer to be replaced before components are first used. // Expectation is that this will convert markdown and/or LaTeX to HTML. @@ -21,10 +22,17 @@ export function Markdown(props: { tagName?: string; }) { const tag = props.tagName || "div"; + // Cache the rendered HTML keyed on the markdown input. The renderer + // runs markdown + KaTeX conversion, which is expensive; without this + // memo every parent re-render (e.g. dragging an unrelated slider/dial) + // would re-run the conversion for every Markdown instance on screen. + // Returning a stable __html string also lets preact skip re-setting + // innerHTML when the markdown hasn't changed. + const html = useMemo(() => theRenderer(props.markdown), [props.markdown]); const nodeProps = { className: props.className, dangerouslySetInnerHTML: { - __html: theRenderer(props.markdown), + __html: html, }, }; diff --git a/source/npm/qsharp/ux/themeObserver.ts b/source/npm/qsharp/ux/themeObserver.ts index 14022bccaca..39e290bf64d 100644 --- a/source/npm/qsharp/ux/themeObserver.ts +++ b/source/npm/qsharp/ux/themeObserver.ts @@ -67,8 +67,14 @@ export function ensureTheme(): boolean | undefined { * * @param el The element to observe for theme attribute changes (usually document.body) * @param callback The callback to invoke when the theme changes + * @returns A disposer that stops the underlying MutationObserver. Long-lived + * pages can ignore this; components that mount/unmount (e.g. webview + * subviews) should call it on cleanup so observers don't accumulate. */ -export function detectThemeChange(el: Element, callback: ThemeChangeCallback) { +export function detectThemeChange( + el: Element, + callback: ThemeChangeCallback, +): () => void { const observer = new MutationObserver((mutations: MutationRecord[]) => { let isDark = false; // Default to light @@ -96,6 +102,8 @@ export function detectThemeChange(el: Element, callback: ThemeChangeCallback) { commonThemeAttribute, ], }); + + return () => observer.disconnect(); } /** diff --git a/source/npm/qsharp/ux/tsconfig.json b/source/npm/qsharp/ux/tsconfig.json index 267fe9d4d65..1010adb5601 100644 --- a/source/npm/qsharp/ux/tsconfig.json +++ b/source/npm/qsharp/ux/tsconfig.json @@ -14,6 +14,7 @@ "isolatedModules": true, "esModuleInterop": true, "skipLibCheck": true, + "resolveJsonModule": true, "types": [] } } diff --git a/source/playground/src/main.css b/source/playground/src/main.css index 9cba2c29627..bf2377d8788 100644 --- a/source/playground/src/main.css +++ b/source/playground/src/main.css @@ -106,6 +106,18 @@ pre:has(code) { margin-top: 32px; } +/* The Bloch sphere view occupies the whole content area (both the editor + and results columns) rather than the single editor column it would + otherwise auto-place into, so the sphere can stretch horizontally and + the history pane can sit at the right edge of the viewport. */ +.bloch-view { + grid-column: 2 / 4; + grid-row: 2; + min-width: 0; + min-height: 0; + padding: 12px; +} + .file-name { border: 1px solid var(--border-color); border-bottom: 0px; diff --git a/source/playground/src/main.tsx b/source/playground/src/main.tsx index e5ddc9b9ab9..804fa55c5ee 100644 --- a/source/playground/src/main.tsx +++ b/source/playground/src/main.tsx @@ -31,7 +31,7 @@ import { Nav } from "./nav.js"; import { Editor } from "./editor.js"; import { registerOpenQasmLanguage } from "./openqasm-language.js"; import { OutputTabs } from "./tabs.js"; -import { useEffect, useState } from "preact/hooks"; +import { useEffect, useRef, useState } from "preact/hooks"; import { Kata as Katas } from "./kata.js"; import { DocumentationDisplay, @@ -49,7 +49,7 @@ import { // Set up the Markdown renderer with KaTeX support import mk from "@vscode/markdown-it-katex"; import markdownIt from "markdown-it"; -import { setRenderer } from "qsharp-lang/ux"; +import { setRenderer, BlochSphere } from "qsharp-lang/ux"; const md = markdownIt("commonmark"); md.use((mk as any).default, { @@ -107,8 +107,22 @@ function App(props: { }); const [currentNavItem, setCurrentNavItem] = useState( - props.linkedCode ? "linked" : "sample-Minimal", + props.linkedCode + ? "linked" + : new URLSearchParams(window.location.search).get("view") === "bloch" + ? "bloch" + : "sample-Minimal", ); + // Holds the latest applied-gate sequence reported by . We use + // a ref rather than state so we don't re-render the world on every gate + // press; the value is only read when the user clicks the share button. + const blochGatesRef = useRef( + new URLSearchParams(window.location.search).get("gates") ?? "", + ); + // The initial gate string we hand to on first mount, captured + // once so React/Preact's strict reconciliation rules don't try to replay + // gates after the user has already interacted with the sphere. + const [initialBlochGates] = useState(() => blochGatesRef.current); const [shotError, setShotError] = useState( undefined, ); @@ -170,16 +184,81 @@ function App(props: { function onNavItemSelected(name: string) { // If there was a ?code link on the URL before, clear it out const newURL = new URL(window.location.href); + let urlChanged = false; if (newURL.searchParams.get("code")) { newURL.searchParams.delete("code"); newURL.searchParams.delete("profile"); newURL.searchParams.delete("lang"); window.history.pushState({}, "", newURL.toString()); props.linkedCode = undefined; + urlChanged = true; + } + // Keep ?view=bloch in sync with the selected nav item. We also drop + // ?gates when navigating away from Bloch since it's only meaningful + // there, and reset the cached gate string so a subsequent return to + // Bloch starts from |0⟩ rather than replaying old gates. + if (name === "bloch") { + if (newURL.searchParams.get("view") !== "bloch") { + newURL.searchParams.set("view", "bloch"); + urlChanged = true; + } + } else { + if (newURL.searchParams.get("view")) { + newURL.searchParams.delete("view"); + urlChanged = true; + } + if (newURL.searchParams.get("gates")) { + newURL.searchParams.delete("gates"); + urlChanged = true; + } + blochGatesRef.current = ""; + } + if (urlChanged) { + window.history.pushState({}, "", newURL.toString()); } setCurrentNavItem(name); } + function onShareBlochLink(ev: MouseEvent) { + // Build a URL that captures the current sphere state so the recipient + // sees the same view. The applied-gate sequence is the canonical + // representation of state; reports it via onGatesChanged. + const popup = document.getElementById("popup") as HTMLDivElement; + function showPopup(text: string) { + popup.style.display = "block"; + popup.innerText = text; + popup.style.left = `${ev.clientX - 120}px`; + popup.style.top = `${ev.clientY + 20}px`; + setTimeout(() => { + popup.style.display = "none"; + }, 2000); + } + + const newURL = new URL(window.location.href); + newURL.searchParams.set("view", "bloch"); + const gates = blochGatesRef.current; + if (gates) { + newURL.searchParams.set("gates", gates); + } else { + newURL.searchParams.delete("gates"); + } + const url = newURL.toString(); + // Update the address bar so the user can also grab the link manually + // if the clipboard write is blocked by the embedding context. + window.history.pushState({}, "", url); + // navigator.clipboard.writeText returns a Promise that can reject in + // iframed/embedded browser contexts (e.g. VS Code's Simple Browser) + // when the clipboard-write permission is not delegated. We need to + // await the result before reporting success. + navigator.clipboard.writeText(url).then( + () => showPopup("Link was copied to the clipboard"), + (err) => { + console.warn("Clipboard write failed:", err); + showPopup("Unable to copy. Link: " + url); + }, + ); + } + return ( <> @@ -234,6 +313,34 @@ function App(props: { onRestartCompiler={onRestartCompiler} languageService={languageService} > + ) : currentNavItem === "bloch" ? ( +
+ { + blochGatesRef.current = gates; + }} + actionSlot={ + + Get a link to the Bloch sphere view + + + } + /> +
) : ( - {props.samples.map((name) => (
))} - + +
onSelected("bloch")} + > + Bloch sphere +
+ {props.openqasmSamples.map((name) => (
+ +// Dedicated entry point for the Bloch sphere panel. Keeping this separate from +// the shared webview.tsx bundle means three.js only lands in this chunk instead +// of bloating the webview.js used by every other panel. + +const vscodeApi = acquireVsCodeApi(); + +import { render } from "preact"; +import { + BlochSphere, + setRenderer, + detectThemeChange, + updateStyleSheetTheme, +} from "qsharp-lang/ux"; +import "./webview.css"; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore - there are no types for this +import mk from "@vscode/markdown-it-katex"; +import markdownIt from "markdown-it"; +const md = markdownIt("commonmark"); +md.use(mk, { + enableMathBlockInHtml: true, + enableMathInlineInHtml: true, +}); +setRenderer((input: string) => md.render(input)); + +window.addEventListener("load", main); + +function main() { + render(, document.body); + detectThemeChange(document.body, (isDark: boolean) => { + updateStyleSheetTheme( + isDark, + "github-markdown", + /(light\.css)|(dark\.css)/, + "light.css", + "dark.css", + ); + }); + vscodeApi.postMessage({ command: "ready" }); +} diff --git a/source/vscode/src/webview/tsconfig.json b/source/vscode/src/webview/tsconfig.json index 818fc9ad164..b38e422d8eb 100644 --- a/source/vscode/src/webview/tsconfig.json +++ b/source/vscode/src/webview/tsconfig.json @@ -4,6 +4,7 @@ "target": "ES2022", "noEmit": true, "allowImportingTsExtensions": true, + "resolveJsonModule": true, "lib": ["DOM", "ES2022"], "rootDir": ".", "strict": true /* enable all strict type-checking options */, diff --git a/source/vscode/src/webviewPanel.ts b/source/vscode/src/webviewPanel.ts index e7f4c199378..20a9c116293 100644 --- a/source/vscode/src/webviewPanel.ts +++ b/source/vscode/src/webviewPanel.ts @@ -54,6 +54,13 @@ export function registerWebViewCommands(context: ExtensionContext) { }), ); + context.subscriptions.push( + commands.registerCommand(`${qsharpExtensionId}.showBloch`, async () => { + const message = { command: "bloch" }; + sendMessageToPanel({ panelType: "bloch" }, true, message); + }), + ); + const handleShowHistogram = async (resource?: vscode.Uri, expr?: string) => { clearCommandDiagnostics(); @@ -204,6 +211,7 @@ type PanelType = | "estimates" | "help" | "circuit" + | "bloch" | "documentation"; const panels: Record = { @@ -211,6 +219,7 @@ const panels: Record = { estimates: {}, circuit: {}, help: {}, + bloch: {}, documentation: {}, }; @@ -219,6 +228,7 @@ const panelTypeToTitle: Record = { estimates: "QDK Estimates", circuit: "QDK Circuit", help: "Q# Help", + bloch: "Bloch Sphere", documentation: "Q# Documentation", }; @@ -256,7 +266,10 @@ function createPanel( QSharpWebViewType, title, { - viewColumn: ViewColumn.Three, + // The Bloch sphere is a standalone interactive view, so open it in + // the active (main) editor column rather than beside the source. + // Other panels (help, circuit, histogram, etc.) open to the side. + viewColumn: type == "bloch" ? ViewColumn.Active : ViewColumn.Three, preserveFocus: true, }, { @@ -293,7 +306,10 @@ export function sendMessageToPanel( message: any, ) { const panelRecord = getOrCreatePanel(panel.panelType, panel.id); - if (reveal) panelRecord.panel.reveal(ViewColumn.Beside); + if (reveal) + panelRecord.panel.reveal( + panel.panelType == "bloch" ? ViewColumn.Active : ViewColumn.Beside, + ); if (message) panelRecord.panel.sendMessage(message); } @@ -333,8 +349,9 @@ export class QSharpWebViewPanel { const katexCss = getUri(["out", "katex", "katex.min.css"]); const githubCss = getUri(["out", "katex", "github-markdown-dark.css"]); - const webviewCss = getUri(["out", "webview", "webview.css"]); - const webviewJs = getUri(["out", "webview", "webview.js"]); + const bundleName = this.type == "bloch" ? "bloch" : "webview"; + const webviewCss = getUri(["out", "webview", `${bundleName}.css`]); + const webviewJs = getUri(["out", "webview", `${bundleName}.js`]); const resourcesUri = getUri(["resources"]); return /*html*/ ` @@ -409,6 +426,7 @@ export class QSharpViewViewPanelSerializer implements WebviewPanelSerializer { panelType !== "histogram" && panelType !== "circuit" && panelType !== "help" && + panelType !== "bloch" && panelType != "documentation" ) { // If it was loading when closed, that's fine