web: working auth, bare profile

This commit is contained in:
Mark Joshwel 2025-02-13 20:58:12 +08:00
parent 702255897e
commit 86a9f91b0e
11 changed files with 1125 additions and 2586 deletions

View file

@ -1,11 +1,11 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title> <title>Document</title>
</head> </head>
<body> <body>
404 404
</body> </body>
</html> </html>

View file

@ -1,61 +0,0 @@
<div class="uk-card">
<div class="uk-card-header space-y-2">
<h3 class="uk-h3">Create an account</h3>
<p class="text-muted-foreground">
Enter your email below to create your account
</p>
</div>
<div class="uk-card-body space-y-4">
<div class="grid grid-cols-2 gap-6">
<button class="uk-btn uk-btn-default">
<svg viewBox="0 0 438.549 438.549" class="mr-2 h-4 w-4">
<path
fill="currentColor"
d="M409.132 114.573c-19.608-33.596-46.205-60.194-79.798-79.8-33.598-19.607-70.277-29.408-110.063-29.408-39.781 0-76.472 9.804-110.063 29.408-33.596 19.605-60.192 46.204-79.8 79.8C9.803 148.168 0 184.854 0 224.63c0 47.78 13.94 90.745 41.827 128.906 27.884 38.164 63.906 64.572 108.063 79.227 5.14.954 8.945.283 11.419-1.996 2.475-2.282 3.711-5.14 3.711-8.562 0-.571-.049-5.708-.144-15.417a2549.81 2549.81 0 01-.144-25.406l-6.567 1.136c-4.187.767-9.469 1.092-15.846 1-6.374-.089-12.991-.757-19.842-1.999-6.854-1.231-13.229-4.086-19.13-8.559-5.898-4.473-10.085-10.328-12.56-17.556l-2.855-6.57c-1.903-4.374-4.899-9.233-8.992-14.559-4.093-5.331-8.232-8.945-12.419-10.848l-1.999-1.431c-1.332-.951-2.568-2.098-3.711-3.429-1.142-1.331-1.997-2.663-2.568-3.997-.572-1.335-.098-2.43 1.427-3.289 1.525-.859 4.281-1.276 8.28-1.276l5.708.853c3.807.763 8.516 3.042 14.133 6.851 5.614 3.806 10.229 8.754 13.846 14.842 4.38 7.806 9.657 13.754 15.846 17.847 6.184 4.093 12.419 6.136 18.699 6.136 6.28 0 11.704-.476 16.274-1.423 4.565-.952 8.848-2.383 12.847-4.285 1.713-12.758 6.377-22.559 13.988-29.41-10.848-1.14-20.601-2.857-29.264-5.14-8.658-2.286-17.605-5.996-26.835-11.14-9.235-5.137-16.896-11.516-22.985-19.126-6.09-7.614-11.088-17.61-14.987-29.979-3.901-12.374-5.852-26.648-5.852-42.826 0-23.035 7.52-42.637 22.557-58.817-7.044-17.318-6.379-36.732 1.997-58.24 5.52-1.715 13.706-.428 24.554 3.853 10.85 4.283 18.794 7.952 23.84 10.994 5.046 3.041 9.089 5.618 12.135 7.708 17.705-4.947 35.976-7.421 54.818-7.421s37.117 2.474 54.823 7.421l10.849-6.849c7.419-4.57 16.18-8.758 26.262-12.565 10.088-3.805 17.802-4.853 23.134-3.138 8.562 21.509 9.325 40.922 2.279 58.24 15.036 16.18 22.559 35.787 22.559 58.817 0 16.178-1.958 30.497-5.853 42.966-3.9 12.471-8.941 22.457-15.125 29.979-6.191 7.521-13.901 13.85-23.131 18.986-9.232 5.14-18.182 8.85-26.84 11.136-8.662 2.286-18.415 4.004-29.263 5.146 9.894 8.562 14.842 22.077 14.842 40.539v60.237c0 3.422 1.19 6.279 3.572 8.562 2.379 2.279 6.136 2.95 11.276 1.995 44.163-14.653 80.185-41.062 108.068-79.226 27.88-38.161 41.825-81.126 41.825-128.906-.01-39.771-9.818-76.454-29.414-110.049z"
></path>
</svg>
Github
</button>
<button class="uk-btn uk-btn-default">
<svg role="img" viewBox="0 0 24 24" class="mr-2 h-4 w-4">
<path
fill="currentColor"
d="M12.48 10.92v3.28h7.84c-.24 1.84-.853 3.187-1.787 4.133-1.147 1.147-2.933 2.4-6.053 2.4-4.827 0-8.6-3.893-8.6-8.72s3.773-8.72 8.6-8.72c2.6 0 4.507 1.027 5.907 2.347l2.307-2.307C18.747 1.44 16.133 0 12.48 0 5.867 0 .307 5.387.307 12s5.56 12 12.173 12c3.573 0 6.267-1.173 8.373-3.36 2.16-2.16 2.84-5.213 2.84-7.667 0-.76-.053-1.467-.173-2.053H12.48z"
></path>
</svg>
Google
</button>
</div>
<div class="relative">
<div class="absolute inset-0 flex items-center">
<span class="w-full border-t border-border"></span>
</div>
<div class="relative flex justify-center text-xs uppercase">
<span class="bg-background px-2 text-muted-foreground"
>Or continue with</span
>
</div>
</div>
<div class="space-y-2">
<label class="uk-form-label" for="email">Email</label>
<input
class="uk-input"
id="email"
type="text"
placeholder="m@example.com"
/>
</div>
<div class="space-y-2">
<label class="uk-form-label" for="password">Password</label>
<input
class="uk-input"
id="password"
type="password"
placeholder="Password"
/>
</div>
</div>
<div class="uk-card-footer">
<button class="uk-btn uk-btn-primary w-full">Create account</button>
</div>
</div>

File diff suppressed because it is too large Load diff

View file

@ -1,142 +0,0 @@
<body
class="bg-background font-geist-sans text-sm text-foreground"
data-sveltekit-preload-data="hover"
>
<div style="display: contents">
<!--[--><!--[--><!----><!---->
<div class="hidden h-screen grid-cols-2 xl:grid">
<div
class="col-span-1 hidden flex-col justify-between bg-zinc-900 p-8 text-white lg:flex"
>
<div class="flex items-center text-lg font-medium">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="mr-2 h-6 w-6"
>
<path
d="M15 6v12a3 3 0 1 0 3-3H6a3 3 0 1 0 3 3V6a3 3 0 1 0-3 3h12a3 3 0 1 0-3-3"
></path>
</svg>
Acme Inc
</div>
<blockquote class="space-y-2">
<p class="text-lg">
"This library has saved me countless hours of work and helped me
deliver stunning designs to my clients faster than ever before."
</p>
<footer class="text-sm">Sofia Davis</footer>
</blockquote>
</div>
<div class="col-span-2 flex flex-col p-8 lg:col-span-1">
<div class="flex flex-none justify-end">
<button class="uk-btn uk-btn-ghost">Login</button>
</div>
<div class="flex flex-1 items-center justify-center">
<div class="w-80 space-y-6">
<div class="flex flex-col space-y-2 text-center">
<h1 class="uk-h3">Create an account</h1>
<p class="text-sm text-muted-foreground">
Enter your email below to create your account
</p>
</div>
<div class="space-y-2">
<input
class="uk-input"
placeholder="name@example.com"
type="text"
/>
<button class="uk-btn uk-btn-primary w-full">
<!--[!--><!--]-->
Sign in with Email
</button>
</div>
<div class="relative">
<div class="absolute inset-0 flex items-center">
<span class="w-full border-t border-border"></span>
</div>
<div class="relative flex justify-center text-xs uppercase">
<span class="bg-background px-2 text-muted-foreground"
>Or continue with</span
>
</div>
</div>
<button class="uk-btn uk-btn-default w-full">
<svg viewBox="0 0 438.549 438.549" class="mr-2 h-4 w-4">
<path
fill="currentColor"
d="M409.132 114.573c-19.608-33.596-46.205-60.194-79.798-79.8-33.598-19.607-70.277-29.408-110.063-29.408-39.781 0-76.472 9.804-110.063 29.408-33.596 19.605-60.192 46.204-79.8 79.8C9.803 148.168 0 184.854 0 224.63c0 47.78 13.94 90.745 41.827 128.906 27.884 38.164 63.906 64.572 108.063 79.227 5.14.954 8.945.283 11.419-1.996 2.475-2.282 3.711-5.14 3.711-8.562 0-.571-.049-5.708-.144-15.417a2549.81 2549.81 0 01-.144-25.406l-6.567 1.136c-4.187.767-9.469 1.092-15.846 1-6.374-.089-12.991-.757-19.842-1.999-6.854-1.231-13.229-4.086-19.13-8.559-5.898-4.473-10.085-10.328-12.56-17.556l-2.855-6.57c-1.903-4.374-4.899-9.233-8.992-14.559-4.093-5.331-8.232-8.945-12.419-10.848l-1.999-1.431c-1.332-.951-2.568-2.098-3.711-3.429-1.142-1.331-1.997-2.663-2.568-3.997-.572-1.335-.098-2.43 1.427-3.289 1.525-.859 4.281-1.276 8.28-1.276l5.708.853c3.807.763 8.516 3.042 14.133 6.851 5.614 3.806 10.229 8.754 13.846 14.842 4.38 7.806 9.657 13.754 15.846 17.847 6.184 4.093 12.419 6.136 18.699 6.136 6.28 0 11.704-.476 16.274-1.423 4.565-.952 8.848-2.383 12.847-4.285 1.713-12.758 6.377-22.559 13.988-29.41-10.848-1.14-20.601-2.857-29.264-5.14-8.658-2.286-17.605-5.996-26.835-11.14-9.235-5.137-16.896-11.516-22.985-19.126-6.09-7.614-11.088-17.61-14.987-29.979-3.901-12.374-5.852-26.648-5.852-42.826 0-23.035 7.52-42.637 22.557-58.817-7.044-17.318-6.379-36.732 1.997-58.24 5.52-1.715 13.706-.428 24.554 3.853 10.85 4.283 18.794 7.952 23.84 10.994 5.046 3.041 9.089 5.618 12.135 7.708 17.705-4.947 35.976-7.421 54.818-7.421s37.117 2.474 54.823 7.421l10.849-6.849c7.419-4.57 16.18-8.758 26.262-12.565 10.088-3.805 17.802-4.853 23.134-3.138 8.562 21.509 9.325 40.922 2.279 58.24 15.036 16.18 22.559 35.787 22.559 58.817 0 16.178-1.958 30.497-5.853 42.966-3.9 12.471-8.941 22.457-15.125 29.979-6.191 7.521-13.901 13.85-23.131 18.986-9.232 5.14-18.182 8.85-26.84 11.136-8.662 2.286-18.415 4.004-29.263 5.146 9.894 8.562 14.842 22.077 14.842 40.539v60.237c0 3.422 1.19 6.279 3.572 8.562 2.379 2.279 6.136 2.95 11.276 1.995 44.163-14.653 80.185-41.062 108.068-79.226 27.88-38.161 41.825-81.126 41.825-128.906-.01-39.771-9.818-76.454-29.414-110.049z"
></path>
</svg>
Github
</button>
<p class="px-8 text-center text-sm text-muted-foreground">
By clicking continue, you agree to our
<a
class="underline underline-offset-4 hover:text-primary"
href="#"
>Terms of Service</a
>
and
<a
class="underline underline-offset-4 hover:text-primary"
href="#"
>Privacy Policy</a
>.
</p>
</div>
</div>
</div>
</div>
<!----><!----><!----><!--]-->
<!--[!-->
<div
id="svelte-announcer"
aria-live="assertive"
aria-atomic="true"
style="
position: absolute;
left: 0;
top: 0;
clip: rect(0 0 0 0);
clip-path: inset(50%);
overflow: hidden;
white-space: nowrap;
width: 1px;
height: 1px;
"
>
<!---->
</div>
<!--]--><!--]-->
<script>
{
__sveltekit_ceme51 = {
base: new URL("..", location).pathname.slice(0, -1),
};
const element = document.currentScript.parentElement;
const data = [null, null];
Promise.all([
import("../_app/immutable/entry/start.Vst7ySbz.js"),
import("../_app/immutable/entry/app.D3_5gIyu.js"),
]).then(([kit, app]) => {
kit.start(app, element, {
node_ids: [0, 3],
data,
form: null,
error: null,
});
});
}
</script>
</div>
</body>

View file

@ -110,10 +110,10 @@
<div class="flex flex-col !space-y-2 text-center"> <div class="flex flex-col !space-y-2 text-center">
<h1 class="uk-h3">Authenticate with Us</h1> <h1 class="uk-h3">Authenticate with Us</h1>
<p class="text-sm text-muted-foreground"> <p class="text-sm text-muted-foreground">
Log in with a magic link. No account yet? We'll make one! Log in with a social sign on. No account yet? It'll make one!
</p> </p>
</div> </div>
<div class="!space-y-2"> <!-- <div class="!space-y-2">
<input id="auth-field-email" class="uk-input" placeholder="name@example.com" type="text" /> <input id="auth-field-email" class="uk-input" placeholder="name@example.com" type="text" />
<a <a
id="auth-button-magic" id="auth-button-magic"
@ -133,8 +133,11 @@
>Or continue with</span >Or continue with</span
> >
</div> </div>
</div> </div> -->
<button id="auth-button-sso-google" class="uk-btn uk-btn-default w-full"> <button
id="auth-button-sso-google"
class="uk-btn uk-btn-primary w-full"
>
<svg role="img" viewBox="0 0 24 24" class="mr-2 h-4 w-4"> <svg role="img" viewBox="0 0 24 24" class="mr-2 h-4 w-4">
<path <path
fill="currentColor" fill="currentColor"

View file

@ -33,53 +33,53 @@ const actionCodeSettings = {
// h2..... id="auth-modal-result-header" // h2..... id="auth-modal-result-header"
// p...... id="auth-modal-result-body" // p...... id="auth-modal-result-body"
// handle magic link auth // // handle magic link auth
const buttonSendLink = document.getElementById("auth-button-magic"); // const buttonSendLink = document.getElementById("auth-button-magic");
buttonSendLink.addEventListener("click", async (event) => { // buttonSendLink.addEventListener("click", async (event) => {
console.log("ebcd-auth: clicked magic"); // console.log("ebcd-auth: clicked magic");
const modalResultHeader = document.getElementById("auth-modal-result-header"); // const modalResultHeader = document.getElementById("auth-modal-result-header");
const modalResultBody = document.getElementById("auth-modal-result-body"); // const modalResultBody = document.getElementById("auth-modal-result-body");
const fieldEmail = document.getElementById("auth-field-email"); // const fieldEmail = document.getElementById("auth-field-email");
// try get email from fieldEmail.value // // try get email from fieldEmail.value
const email = fieldEmail ? fieldEmail.value.trim() : null; // const email = fieldEmail ? fieldEmail.value.trim() : null;
// if email is blank // // if email is blank
if (!email) { // if (!email) {
modalResultHeader.innerText = "Error!"; // modalResultHeader.innerText = "Error!";
modalResultBody.innerText = "Please enter an email address."; // modalResultBody.innerText = "Please enter an email address.";
return; // return;
} // }
// if email is not valid // // if email is not valid
if (!email.includes("@")) { // if (!email.includes("@")) {
modalResultHeader.innerText = "Error!"; // modalResultHeader.innerText = "Error!";
modalResultBody.innerText = "Please enter a valid email address."; // modalResultBody.innerText = "Please enter a valid email address.";
return; // return;
} // }
console.log("ebcd-auth/auth-button-magic: sent!"); // console.log("ebcd-auth/auth-button-magic: sent!");
authWithMagicLink(auth, email, actionCodeSettings) // authWithMagicLink(auth, email, actionCodeSettings)
.then(() => { // .then(() => {
console.log("ebcd-auth/auth-button-magic: success!"); // console.log("ebcd-auth/auth-button-magic: success!");
// The link was successfully sent. Inform the user. // // The link was successfully sent. Inform the user.
modalResultHeader.innerText = "You've Got Mail!"; // modalResultHeader.innerText = "You've Got Mail!";
modalResultBody.innerText = `We've sent you an email to ${email} with a magical link to authenticate with us. If you're a new user, you'll make an account. If you're an existing user, you'll be logged in. Check your inbox!`; // modalResultBody.innerText = `We've sent you an email to ${email} with a magical link to authenticate with us. If you're a new user, you'll make an account. If you're an existing user, you'll be logged in. Check your inbox!`;
// Save the email locally so you don't need to ask the user for it again // // Save the email locally so you don't need to ask the user for it again
// if they open the link on the same device. // // if they open the link on the same device.
window.localStorage.setItem("emailForSignIn", email); // window.localStorage.setItem("emailForSignIn", email);
}) // })
.catch((error) => { // .catch((error) => {
console.log( // console.log(
"ebcd-auth/auth-button-magic: error...", // "ebcd-auth/auth-button-magic: error...",
error.code, // error.code,
error.message // error.message
); // );
modalResultHeader.innerText = "Error!"; // modalResultHeader.innerText = "Error!";
modalResultBody.innerHTML = `We've encountered an error. Tell the booth runner about this!<br>${error.message}`; // modalResultBody.innerHTML = `We've encountered an error. Tell the booth runner about this!<br>${error.message}`;
}); // });
}); // });
// handle sso auth // handle sso auth
// <button id="button-sso-google"> // <button id="button-sso-google">

View file

@ -3,9 +3,7 @@ import "https://unpkg.com/franken-ui@2.0.0-internal.42/dist/js/icon.iife.js";
const htmlElement = document.documentElement; const htmlElement = document.documentElement;
const __FRANKEN__ = JSON.parse( const __FRANKEN__ = JSON.parse(localStorage.getItem("__FRANKEN__") || "{}");
localStorage.getItem("__FRANKEN__") || "{}"
);
if ( if (
__FRANKEN__.mode === "dark" || __FRANKEN__.mode === "dark" ||

View file

@ -0,0 +1,18 @@
import { auth } from "./ebcd-common-firebase.js";
console.log("ebcd-profile loaded <3");
// check url params
const urlParams = new URLSearchParams(window.location.search);
// if logOut=true, sign out
if (urlParams.get("logOut") === "true") {
auth
.signOut()
.then(() => {
window.location = "/";
})
.catch((error) => {
console.error("ebcd-profile: error signing out", error);
});
}

View file

@ -51,7 +51,10 @@ export var qrcodegen;
// This determines the size of this barcode. // This determines the size of this barcode.
version, version,
// The error correction level used in this QR Code. // The error correction level used in this QR Code.
errorCorrectionLevel, dataCodewords, msk) { errorCorrectionLevel,
dataCodewords,
msk
) {
this.version = version; this.version = version;
this.errorCorrectionLevel = errorCorrectionLevel; this.errorCorrectionLevel = errorCorrectionLevel;
// The modules of this QR Code (false = light, true = dark). // The modules of this QR Code (false = light, true = dark).
@ -62,13 +65,11 @@ export var qrcodegen;
// Check scalar arguments // Check scalar arguments
if (version < QrCode.MIN_VERSION || version > QrCode.MAX_VERSION) if (version < QrCode.MIN_VERSION || version > QrCode.MAX_VERSION)
throw new RangeError("Version value out of range"); throw new RangeError("Version value out of range");
if (msk < -1 || msk > 7) if (msk < -1 || msk > 7) throw new RangeError("Mask value out of range");
throw new RangeError("Mask value out of range");
this.size = version * 4 + 17; this.size = version * 4 + 17;
// Initialize both grids to be size*size arrays of Boolean false // Initialize both grids to be size*size arrays of Boolean false
let row = []; let row = [];
for (let i = 0; i < this.size; i++) for (let i = 0; i < this.size; i++) row.push(false);
row.push(false);
for (let i = 0; i < this.size; i++) { for (let i = 0; i < this.size; i++) {
this.modules.push(row.slice()); // Initially all light this.modules.push(row.slice()); // Initially all light
this.isFunction.push(row.slice()); this.isFunction.push(row.slice());
@ -78,7 +79,8 @@ export var qrcodegen;
const allCodewords = this.addEccAndInterleave(dataCodewords); const allCodewords = this.addEccAndInterleave(dataCodewords);
this.drawCodewords(allCodewords); this.drawCodewords(allCodewords);
// Do masking // Do masking
if (msk == -1) { // Automatically choose best mask if (msk == -1) {
// Automatically choose best mask
let minPenalty = 1000000000; let minPenalty = 1000000000;
for (let i = 0; i < 8; i++) { for (let i = 0; i < 8; i++) {
this.applyMask(i); this.applyMask(i);
@ -125,26 +127,49 @@ export var qrcodegen;
// This function allows the user to create a custom sequence of segments that switches // This function allows the user to create a custom sequence of segments that switches
// between modes (such as alphanumeric and byte) to encode text in less space. // between modes (such as alphanumeric and byte) to encode text in less space.
// This is a mid-level API; the high-level API is encodeText() and encodeBinary(). // This is a mid-level API; the high-level API is encodeText() and encodeBinary().
static encodeSegments(segs, ecl, minVersion = 1, maxVersion = 40, mask = -1, boostEcl = true) { static encodeSegments(
if (!(QrCode.MIN_VERSION <= minVersion && minVersion <= maxVersion && maxVersion <= QrCode.MAX_VERSION) segs,
|| mask < -1 || mask > 7) ecl,
minVersion = 1,
maxVersion = 40,
mask = -1,
boostEcl = true
) {
if (
!(
QrCode.MIN_VERSION <= minVersion &&
minVersion <= maxVersion &&
maxVersion <= QrCode.MAX_VERSION
) ||
mask < -1 ||
mask > 7
)
throw new RangeError("Invalid value"); throw new RangeError("Invalid value");
// Find the minimal version number to use // Find the minimal version number to use
let version; let version;
let dataUsedBits; let dataUsedBits;
for (version = minVersion;; version++) { for (version = minVersion; ; version++) {
const dataCapacityBits = QrCode.getNumDataCodewords(version, ecl) * 8; // Number of data bits available const dataCapacityBits = QrCode.getNumDataCodewords(version, ecl) * 8; // Number of data bits available
const usedBits = QrSegment.getTotalBits(segs, version); const usedBits = QrSegment.getTotalBits(segs, version);
if (usedBits <= dataCapacityBits) { if (usedBits <= dataCapacityBits) {
dataUsedBits = usedBits; dataUsedBits = usedBits;
break; // This version number is found to be suitable break; // This version number is found to be suitable
} }
if (version >= maxVersion) // All versions in the range could not fit the given data if (version >= maxVersion)
// All versions in the range could not fit the given data
throw new RangeError("Data too long"); throw new RangeError("Data too long");
} }
// Increase the error correction level while the data still fits in the current version number // Increase the error correction level while the data still fits in the current version number
for (const newEcl of [QrCode.Ecc.MEDIUM, QrCode.Ecc.QUARTILE, QrCode.Ecc.HIGH]) { // From low to high for (const newEcl of [
if (boostEcl && dataUsedBits <= QrCode.getNumDataCodewords(version, newEcl) * 8) QrCode.Ecc.MEDIUM,
QrCode.Ecc.QUARTILE,
QrCode.Ecc.HIGH,
]) {
// From low to high
if (
boostEcl &&
dataUsedBits <= QrCode.getNumDataCodewords(version, newEcl) * 8
)
ecl = newEcl; ecl = newEcl;
} }
// Concatenate all segments to create the data bit string // Concatenate all segments to create the data bit string
@ -152,24 +177,26 @@ export var qrcodegen;
for (const seg of segs) { for (const seg of segs) {
appendBits(seg.mode.modeBits, 4, bb); appendBits(seg.mode.modeBits, 4, bb);
appendBits(seg.numChars, seg.mode.numCharCountBits(version), bb); appendBits(seg.numChars, seg.mode.numCharCountBits(version), bb);
for (const b of seg.getData()) for (const b of seg.getData()) bb.push(b);
bb.push(b);
} }
assert(bb.length == dataUsedBits); assert(bb.length == dataUsedBits);
// Add terminator and pad up to a byte if applicable // Add terminator and pad up to a byte if applicable
const dataCapacityBits = QrCode.getNumDataCodewords(version, ecl) * 8; const dataCapacityBits = QrCode.getNumDataCodewords(version, ecl) * 8;
assert(bb.length <= dataCapacityBits); assert(bb.length <= dataCapacityBits);
appendBits(0, Math.min(4, dataCapacityBits - bb.length), bb); appendBits(0, Math.min(4, dataCapacityBits - bb.length), bb);
appendBits(0, (8 - bb.length % 8) % 8, bb); appendBits(0, (8 - (bb.length % 8)) % 8, bb);
assert(bb.length % 8 == 0); assert(bb.length % 8 == 0);
// Pad with alternating bytes until data capacity is reached // Pad with alternating bytes until data capacity is reached
for (let padByte = 0xEC; bb.length < dataCapacityBits; padByte ^= 0xEC ^ 0x11) for (
let padByte = 0xec;
bb.length < dataCapacityBits;
padByte ^= 0xec ^ 0x11
)
appendBits(padByte, 8, bb); appendBits(padByte, 8, bb);
// Pack bits into bytes in big endian // Pack bits into bytes in big endian
let dataCodewords = []; let dataCodewords = [];
while (dataCodewords.length * 8 < bb.length) while (dataCodewords.length * 8 < bb.length) dataCodewords.push(0);
dataCodewords.push(0); bb.forEach((b, i) => (dataCodewords[i >>> 3] |= b << (7 - (i & 7))));
bb.forEach((b, i) => dataCodewords[i >>> 3] |= b << (7 - (i & 7)));
// Create the QR Code object // Create the QR Code object
return new QrCode(version, ecl, dataCodewords, mask); return new QrCode(version, ecl, dataCodewords, mask);
} }
@ -178,7 +205,9 @@ export var qrcodegen;
// for light or true for dark. The top left corner has the coordinates (x=0, y=0). // for light or true for dark. The top left corner has the coordinates (x=0, y=0).
// If the given coordinates are out of bounds, then false (light) is returned. // If the given coordinates are out of bounds, then false (light) is returned.
getModule(x, y) { getModule(x, y) {
return 0 <= x && x < this.size && 0 <= y && y < this.size && this.modules[y][x]; return (
0 <= x && x < this.size && 0 <= y && y < this.size && this.modules[y][x]
);
} }
/*-- Private helper methods for constructor: Drawing function modules --*/ /*-- Private helper methods for constructor: Drawing function modules --*/
// Reads this object's version field, and draws and marks all function modules. // Reads this object's version field, and draws and marks all function modules.
@ -198,7 +227,13 @@ export var qrcodegen;
for (let i = 0; i < numAlign; i++) { for (let i = 0; i < numAlign; i++) {
for (let j = 0; j < numAlign; j++) { for (let j = 0; j < numAlign; j++) {
// Don't draw on the three finder corners // Don't draw on the three finder corners
if (!(i == 0 && j == 0 || i == 0 && j == numAlign - 1 || i == numAlign - 1 && j == 0)) if (
!(
(i == 0 && j == 0) ||
(i == 0 && j == numAlign - 1) ||
(i == numAlign - 1 && j == 0)
)
)
this.drawAlignmentPattern(alignPatPos[i], alignPatPos[j]); this.drawAlignmentPattern(alignPatPos[i], alignPatPos[j]);
} }
} }
@ -210,11 +245,10 @@ export var qrcodegen;
// based on the given mask and this object's error correction level field. // based on the given mask and this object's error correction level field.
drawFormatBits(mask) { drawFormatBits(mask) {
// Calculate error correction code and pack bits // Calculate error correction code and pack bits
const data = this.errorCorrectionLevel.formatBits << 3 | mask; // errCorrLvl is uint2, mask is uint3 const data = (this.errorCorrectionLevel.formatBits << 3) | mask; // errCorrLvl is uint2, mask is uint3
let rem = data; let rem = data;
for (let i = 0; i < 10; i++) for (let i = 0; i < 10; i++) rem = (rem << 1) ^ ((rem >>> 9) * 0x537);
rem = (rem << 1) ^ ((rem >>> 9) * 0x537); const bits = ((data << 10) | rem) ^ 0x5412; // uint15
const bits = (data << 10 | rem) ^ 0x5412; // uint15
assert(bits >>> 15 == 0); assert(bits >>> 15 == 0);
// Draw first copy // Draw first copy
for (let i = 0; i <= 5; i++) for (let i = 0; i <= 5; i++)
@ -234,18 +268,16 @@ export var qrcodegen;
// Draws two copies of the version bits (with its own error correction code), // Draws two copies of the version bits (with its own error correction code),
// based on this object's version field, iff 7 <= version <= 40. // based on this object's version field, iff 7 <= version <= 40.
drawVersion() { drawVersion() {
if (this.version < 7) if (this.version < 7) return;
return;
// Calculate error correction code and pack bits // Calculate error correction code and pack bits
let rem = this.version; // version is uint6, in the range [7, 40] let rem = this.version; // version is uint6, in the range [7, 40]
for (let i = 0; i < 12; i++) for (let i = 0; i < 12; i++) rem = (rem << 1) ^ ((rem >>> 11) * 0x1f25);
rem = (rem << 1) ^ ((rem >>> 11) * 0x1F25); const bits = (this.version << 12) | rem; // uint18
const bits = this.version << 12 | rem; // uint18
assert(bits >>> 18 == 0); assert(bits >>> 18 == 0);
// Draw two copies // Draw two copies
for (let i = 0; i < 18; i++) { for (let i = 0; i < 18; i++) {
const color = getBit(bits, i); const color = getBit(bits, i);
const a = this.size - 11 + i % 3; const a = this.size - 11 + (i % 3);
const b = Math.floor(i / 3); const b = Math.floor(i / 3);
this.setFunctionModule(a, b, color); this.setFunctionModule(a, b, color);
this.setFunctionModule(b, a, color); this.setFunctionModule(b, a, color);
@ -269,7 +301,11 @@ export var qrcodegen;
drawAlignmentPattern(x, y) { drawAlignmentPattern(x, y) {
for (let dy = -2; dy <= 2; dy++) { for (let dy = -2; dy <= 2; dy++) {
for (let dx = -2; dx <= 2; dx++) for (let dx = -2; dx <= 2; dx++)
this.setFunctionModule(x + dx, y + dy, Math.max(Math.abs(dx), Math.abs(dy)) != 1); this.setFunctionModule(
x + dx,
y + dy,
Math.max(Math.abs(dx), Math.abs(dy)) != 1
);
} }
} }
// Sets the color of a module and marks it as a function module. // Sets the color of a module and marks it as a function module.
@ -290,17 +326,19 @@ export var qrcodegen;
const numBlocks = QrCode.NUM_ERROR_CORRECTION_BLOCKS[ecl.ordinal][ver]; const numBlocks = QrCode.NUM_ERROR_CORRECTION_BLOCKS[ecl.ordinal][ver];
const blockEccLen = QrCode.ECC_CODEWORDS_PER_BLOCK[ecl.ordinal][ver]; const blockEccLen = QrCode.ECC_CODEWORDS_PER_BLOCK[ecl.ordinal][ver];
const rawCodewords = Math.floor(QrCode.getNumRawDataModules(ver) / 8); const rawCodewords = Math.floor(QrCode.getNumRawDataModules(ver) / 8);
const numShortBlocks = numBlocks - rawCodewords % numBlocks; const numShortBlocks = numBlocks - (rawCodewords % numBlocks);
const shortBlockLen = Math.floor(rawCodewords / numBlocks); const shortBlockLen = Math.floor(rawCodewords / numBlocks);
// Split data into blocks and append ECC to each block // Split data into blocks and append ECC to each block
let blocks = []; let blocks = [];
const rsDiv = QrCode.reedSolomonComputeDivisor(blockEccLen); const rsDiv = QrCode.reedSolomonComputeDivisor(blockEccLen);
for (let i = 0, k = 0; i < numBlocks; i++) { for (let i = 0, k = 0; i < numBlocks; i++) {
let dat = data.slice(k, k + shortBlockLen - blockEccLen + (i < numShortBlocks ? 0 : 1)); let dat = data.slice(
k,
k + shortBlockLen - blockEccLen + (i < numShortBlocks ? 0 : 1)
);
k += dat.length; k += dat.length;
const ecc = QrCode.reedSolomonComputeRemainder(dat, rsDiv); const ecc = QrCode.reedSolomonComputeRemainder(dat, rsDiv);
if (i < numShortBlocks) if (i < numShortBlocks) dat.push(0);
dat.push(0);
blocks.push(dat.concat(ecc)); blocks.push(dat.concat(ecc));
} }
// Interleave (not concatenate) the bytes from every block into a single sequence // Interleave (not concatenate) the bytes from every block into a single sequence
@ -318,14 +356,17 @@ export var qrcodegen;
// Draws the given sequence of 8-bit codewords (data and error correction) onto the entire // Draws the given sequence of 8-bit codewords (data and error correction) onto the entire
// data area of this QR Code. Function modules need to be marked off before this is called. // data area of this QR Code. Function modules need to be marked off before this is called.
drawCodewords(data) { drawCodewords(data) {
if (data.length != Math.floor(QrCode.getNumRawDataModules(this.version) / 8)) if (
data.length != Math.floor(QrCode.getNumRawDataModules(this.version) / 8)
)
throw new RangeError("Invalid argument"); throw new RangeError("Invalid argument");
let i = 0; // Bit index into the data let i = 0; // Bit index into the data
// Do the funny zigzag scan // Do the funny zigzag scan
for (let right = this.size - 1; right >= 1; right -= 2) { // Index of right column in each column pair for (let right = this.size - 1; right >= 1; right -= 2) {
if (right == 6) // Index of right column in each column pair
right = 5; if (right == 6) right = 5;
for (let vert = 0; vert < this.size; vert++) { // Vertical counter for (let vert = 0; vert < this.size; vert++) {
// Vertical counter
for (let j = 0; j < 2; j++) { for (let j = 0; j < 2; j++) {
const x = right - j; // Actual x coordinate const x = right - j; // Actual x coordinate
const upward = ((right + 1) & 2) == 0; const upward = ((right + 1) & 2) == 0;
@ -347,8 +388,7 @@ export var qrcodegen;
// the same mask value a second time will undo the mask. A final well-formed // the same mask value a second time will undo the mask. A final well-formed
// QR Code needs exactly one (not zero, two, etc.) mask applied. // QR Code needs exactly one (not zero, two, etc.) mask applied.
applyMask(mask) { applyMask(mask) {
if (mask < 0 || mask > 7) if (mask < 0 || mask > 7) throw new RangeError("Mask value out of range");
throw new RangeError("Mask value out of range");
for (let y = 0; y < this.size; y++) { for (let y = 0; y < this.size; y++) {
for (let x = 0; x < this.size; x++) { for (let x = 0; x < this.size; x++) {
let invert; let invert;
@ -369,15 +409,16 @@ export var qrcodegen;
invert = (Math.floor(x / 3) + Math.floor(y / 2)) % 2 == 0; invert = (Math.floor(x / 3) + Math.floor(y / 2)) % 2 == 0;
break; break;
case 5: case 5:
invert = x * y % 2 + x * y % 3 == 0; invert = ((x * y) % 2) + ((x * y) % 3) == 0;
break; break;
case 6: case 6:
invert = (x * y % 2 + x * y % 3) % 2 == 0; invert = (((x * y) % 2) + ((x * y) % 3)) % 2 == 0;
break; break;
case 7: case 7:
invert = ((x + y) % 2 + x * y % 3) % 2 == 0; invert = (((x + y) % 2) + ((x * y) % 3)) % 2 == 0;
break; break;
default: throw new Error("Unreachable"); default:
throw new Error("Unreachable");
} }
if (!this.isFunction[y][x] && invert) if (!this.isFunction[y][x] && invert)
this.modules[y][x] = !this.modules[y][x]; this.modules[y][x] = !this.modules[y][x];
@ -396,20 +437,20 @@ export var qrcodegen;
for (let x = 0; x < this.size; x++) { for (let x = 0; x < this.size; x++) {
if (this.modules[y][x] == runColor) { if (this.modules[y][x] == runColor) {
runX++; runX++;
if (runX == 5) if (runX == 5) result += QrCode.PENALTY_N1;
result += QrCode.PENALTY_N1; else if (runX > 5) result++;
else if (runX > 5) } else {
result++;
}
else {
this.finderPenaltyAddHistory(runX, runHistory); this.finderPenaltyAddHistory(runX, runHistory);
if (!runColor) if (!runColor)
result += this.finderPenaltyCountPatterns(runHistory) * QrCode.PENALTY_N3; result +=
this.finderPenaltyCountPatterns(runHistory) * QrCode.PENALTY_N3;
runColor = this.modules[y][x]; runColor = this.modules[y][x];
runX = 1; runX = 1;
} }
} }
result += this.finderPenaltyTerminateAndCount(runColor, runX, runHistory) * QrCode.PENALTY_N3; result +=
this.finderPenaltyTerminateAndCount(runColor, runX, runHistory) *
QrCode.PENALTY_N3;
} }
// Adjacent modules in column having same color, and finder-like patterns // Adjacent modules in column having same color, and finder-like patterns
for (let x = 0; x < this.size; x++) { for (let x = 0; x < this.size; x++) {
@ -419,28 +460,30 @@ export var qrcodegen;
for (let y = 0; y < this.size; y++) { for (let y = 0; y < this.size; y++) {
if (this.modules[y][x] == runColor) { if (this.modules[y][x] == runColor) {
runY++; runY++;
if (runY == 5) if (runY == 5) result += QrCode.PENALTY_N1;
result += QrCode.PENALTY_N1; else if (runY > 5) result++;
else if (runY > 5) } else {
result++;
}
else {
this.finderPenaltyAddHistory(runY, runHistory); this.finderPenaltyAddHistory(runY, runHistory);
if (!runColor) if (!runColor)
result += this.finderPenaltyCountPatterns(runHistory) * QrCode.PENALTY_N3; result +=
this.finderPenaltyCountPatterns(runHistory) * QrCode.PENALTY_N3;
runColor = this.modules[y][x]; runColor = this.modules[y][x];
runY = 1; runY = 1;
} }
} }
result += this.finderPenaltyTerminateAndCount(runColor, runY, runHistory) * QrCode.PENALTY_N3; result +=
this.finderPenaltyTerminateAndCount(runColor, runY, runHistory) *
QrCode.PENALTY_N3;
} }
// 2*2 blocks of modules having same color // 2*2 blocks of modules having same color
for (let y = 0; y < this.size - 1; y++) { for (let y = 0; y < this.size - 1; y++) {
for (let x = 0; x < this.size - 1; x++) { for (let x = 0; x < this.size - 1; x++) {
const color = this.modules[y][x]; const color = this.modules[y][x];
if (color == this.modules[y][x + 1] && if (
color == this.modules[y][x + 1] &&
color == this.modules[y + 1][x] && color == this.modules[y + 1][x] &&
color == this.modules[y + 1][x + 1]) color == this.modules[y + 1][x + 1]
)
result += QrCode.PENALTY_N2; result += QrCode.PENALTY_N2;
} }
} }
@ -461,12 +504,13 @@ export var qrcodegen;
// Each position is in the range [0,177), and are used on both the x and y axes. // Each position is in the range [0,177), and are used on both the x and y axes.
// This could be implemented as lookup table of 40 variable-length lists of integers. // This could be implemented as lookup table of 40 variable-length lists of integers.
getAlignmentPatternPositions() { getAlignmentPatternPositions() {
if (this.version == 1) if (this.version == 1) return [];
return [];
else { else {
const numAlign = Math.floor(this.version / 7) + 2; const numAlign = Math.floor(this.version / 7) + 2;
const step = (this.version == 32) ? 26 : const step =
Math.ceil((this.version * 4 + 4) / (numAlign * 2 - 2)) * 2; this.version == 32
? 26
: Math.ceil((this.version * 4 + 4) / (numAlign * 2 - 2)) * 2;
let result = [6]; let result = [6];
for (let pos = this.size - 7; result.length < numAlign; pos -= step) for (let pos = this.size - 7; result.length < numAlign; pos -= step)
result.splice(1, 0, pos); result.splice(1, 0, pos);
@ -483,8 +527,7 @@ export var qrcodegen;
if (ver >= 2) { if (ver >= 2) {
const numAlign = Math.floor(ver / 7) + 2; const numAlign = Math.floor(ver / 7) + 2;
result -= (25 * numAlign - 10) * numAlign - 55; result -= (25 * numAlign - 10) * numAlign - 55;
if (ver >= 7) if (ver >= 7) result -= 36;
result -= 36;
} }
assert(208 <= result && result <= 29648); assert(208 <= result && result <= 29648);
return result; return result;
@ -493,9 +536,11 @@ export var qrcodegen;
// QR Code of the given version number and error correction level, with remainder bits discarded. // QR Code of the given version number and error correction level, with remainder bits discarded.
// This stateless pure function could be implemented as a (40*4)-cell lookup table. // This stateless pure function could be implemented as a (40*4)-cell lookup table.
static getNumDataCodewords(ver, ecl) { static getNumDataCodewords(ver, ecl) {
return Math.floor(QrCode.getNumRawDataModules(ver) / 8) - return (
Math.floor(QrCode.getNumRawDataModules(ver) / 8) -
QrCode.ECC_CODEWORDS_PER_BLOCK[ecl.ordinal][ver] * QrCode.ECC_CODEWORDS_PER_BLOCK[ecl.ordinal][ver] *
QrCode.NUM_ERROR_CORRECTION_BLOCKS[ecl.ordinal][ver]; QrCode.NUM_ERROR_CORRECTION_BLOCKS[ecl.ordinal][ver]
);
} }
// Returns a Reed-Solomon ECC generator polynomial for the given degree. This could be // Returns a Reed-Solomon ECC generator polynomial for the given degree. This could be
// implemented as a lookup table over all possible parameter values, instead of as an algorithm. // implemented as a lookup table over all possible parameter values, instead of as an algorithm.
@ -505,8 +550,7 @@ export var qrcodegen;
// Polynomial coefficients are stored from highest to lowest power, excluding the leading term which is always 1. // Polynomial coefficients are stored from highest to lowest power, excluding the leading term which is always 1.
// For example the polynomial x^3 + 255x^2 + 8x + 93 is stored as the uint8 array [255, 8, 93]. // For example the polynomial x^3 + 255x^2 + 8x + 93 is stored as the uint8 array [255, 8, 93].
let result = []; let result = [];
for (let i = 0; i < degree - 1; i++) for (let i = 0; i < degree - 1; i++) result.push(0);
result.push(0);
result.push(1); // Start off with the monomial x^0 result.push(1); // Start off with the monomial x^0
// Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}), // Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}),
// and drop the highest monomial term which is always 1x^degree. // and drop the highest monomial term which is always 1x^degree.
@ -516,8 +560,7 @@ export var qrcodegen;
// Multiply the current product by (x - r^i) // Multiply the current product by (x - r^i)
for (let j = 0; j < result.length; j++) { for (let j = 0; j < result.length; j++) {
result[j] = QrCode.reedSolomonMultiply(result[j], root); result[j] = QrCode.reedSolomonMultiply(result[j], root);
if (j + 1 < result.length) if (j + 1 < result.length) result[j] ^= result[j + 1];
result[j] ^= result[j + 1];
} }
root = QrCode.reedSolomonMultiply(root, 0x02); root = QrCode.reedSolomonMultiply(root, 0x02);
} }
@ -525,11 +568,14 @@ export var qrcodegen;
} }
// Returns the Reed-Solomon error correction codeword for the given data and divisor polynomials. // Returns the Reed-Solomon error correction codeword for the given data and divisor polynomials.
static reedSolomonComputeRemainder(data, divisor) { static reedSolomonComputeRemainder(data, divisor) {
let result = divisor.map(_ => 0); let result = divisor.map((_) => 0);
for (const b of data) { // Polynomial division for (const b of data) {
// Polynomial division
const factor = b ^ result.shift(); const factor = b ^ result.shift();
result.push(0); result.push(0);
divisor.forEach((coef, i) => result[i] ^= QrCode.reedSolomonMultiply(coef, factor)); divisor.forEach(
(coef, i) => (result[i] ^= QrCode.reedSolomonMultiply(coef, factor))
);
} }
return result; return result;
} }
@ -541,7 +587,7 @@ export var qrcodegen;
// Russian peasant multiplication // Russian peasant multiplication
let z = 0; let z = 0;
for (let i = 7; i >= 0; i--) { for (let i = 7; i >= 0; i--) {
z = (z << 1) ^ ((z >>> 7) * 0x11D); z = (z << 1) ^ ((z >>> 7) * 0x11d);
z ^= ((y >>> i) & 1) * x; z ^= ((y >>> i) & 1) * x;
} }
assert(z >>> 8 == 0); assert(z >>> 8 == 0);
@ -552,13 +598,25 @@ export var qrcodegen;
finderPenaltyCountPatterns(runHistory) { finderPenaltyCountPatterns(runHistory) {
const n = runHistory[1]; const n = runHistory[1];
assert(n <= this.size * 3); assert(n <= this.size * 3);
const core = n > 0 && runHistory[2] == n && runHistory[3] == n * 3 && runHistory[4] == n && runHistory[5] == n; const core =
return (core && runHistory[0] >= n * 4 && runHistory[6] >= n ? 1 : 0) n > 0 &&
+ (core && runHistory[6] >= n * 4 && runHistory[0] >= n ? 1 : 0); runHistory[2] == n &&
runHistory[3] == n * 3 &&
runHistory[4] == n &&
runHistory[5] == n;
return (
(core && runHistory[0] >= n * 4 && runHistory[6] >= n ? 1 : 0) +
(core && runHistory[6] >= n * 4 && runHistory[0] >= n ? 1 : 0)
);
} }
// Must be called at the end of a line (row or column) of modules. A helper function for getPenaltyScore(). // Must be called at the end of a line (row or column) of modules. A helper function for getPenaltyScore().
finderPenaltyTerminateAndCount(currentRunColor, currentRunLength, runHistory) { finderPenaltyTerminateAndCount(
if (currentRunColor) { // Terminate dark run currentRunColor,
currentRunLength,
runHistory
) {
if (currentRunColor) {
// Terminate dark run
this.finderPenaltyAddHistory(currentRunLength, runHistory); this.finderPenaltyAddHistory(currentRunLength, runHistory);
currentRunLength = 0; currentRunLength = 0;
} }
@ -568,8 +626,7 @@ export var qrcodegen;
} }
// Pushes the given value to the front and drops the last value. A helper function for getPenaltyScore(). // Pushes the given value to the front and drops the last value. A helper function for getPenaltyScore().
finderPenaltyAddHistory(currentRunLength, runHistory) { finderPenaltyAddHistory(currentRunLength, runHistory) {
if (runHistory[0] == 0) if (runHistory[0] == 0) currentRunLength += this.size; // Add light border to initial run
currentRunLength += this.size; // Add light border to initial run
runHistory.pop(); runHistory.pop();
runHistory.unshift(currentRunLength); runHistory.unshift(currentRunLength);
} }
@ -587,18 +644,49 @@ export var qrcodegen;
QrCode.ECC_CODEWORDS_PER_BLOCK = [ QrCode.ECC_CODEWORDS_PER_BLOCK = [
// Version: (note that index 0 is for padding, and is set to an illegal value) // Version: (note that index 0 is for padding, and is set to an illegal value)
//0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level //0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level
[-1, 7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30, 28, 28, 28, 28, 30, 30, 26, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30], [
[-1, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26, 30, 22, 22, 24, 24, 28, 28, 26, 26, 26, 26, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28], -1, 7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30,
[-1, 13, 22, 18, 26, 18, 24, 18, 22, 20, 24, 28, 26, 24, 20, 30, 24, 28, 28, 26, 30, 28, 30, 30, 30, 30, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30], 28, 28, 28, 28, 30, 30, 26, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
[-1, 17, 28, 22, 16, 22, 28, 26, 26, 24, 28, 24, 28, 22, 24, 24, 30, 28, 28, 26, 28, 30, 24, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30], // High 30, 30, 30, 30,
],
[
-1, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26, 30, 22, 22, 24, 24, 28, 28,
26, 26, 26, 26, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
28, 28, 28, 28, 28,
],
[
-1, 13, 22, 18, 26, 18, 24, 18, 22, 20, 24, 28, 26, 24, 20, 30, 24, 28,
28, 26, 30, 28, 30, 30, 30, 30, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30,
30, 30, 30, 30, 30,
],
[
-1, 17, 28, 22, 16, 22, 28, 26, 26, 24, 28, 24, 28, 22, 24, 24, 30, 28,
28, 26, 28, 30, 24, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
30, 30, 30, 30, 30,
], // High
]; ];
QrCode.NUM_ERROR_CORRECTION_BLOCKS = [ QrCode.NUM_ERROR_CORRECTION_BLOCKS = [
// Version: (note that index 0 is for padding, and is set to an illegal value) // Version: (note that index 0 is for padding, and is set to an illegal value)
//0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level //0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level
[-1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25], [
[-1, 1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, 17, 17, 18, 20, 21, 23, 25, 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49], -1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9,
[-1, 1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20, 23, 23, 25, 27, 29, 34, 34, 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68], 10, 12, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25,
[-1, 1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, 25, 34, 30, 32, 35, 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81], // High ],
[
-1, 1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, 17,
17, 18, 20, 21, 23, 25, 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47,
49,
],
[
-1, 1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20,
23, 23, 25, 27, 29, 34, 34, 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62,
65, 68,
],
[
-1, 1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25,
25, 34, 30, 32, 35, 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74,
77, 81,
], // High
]; ];
qrcodegen.QrCode = QrCode; qrcodegen.QrCode = QrCode;
// Appends the given number of low-order bits of the given value // Appends the given number of low-order bits of the given value
@ -606,7 +694,11 @@ export var qrcodegen;
function appendBits(val, len, bb) { function appendBits(val, len, bb) {
if (len < 0 || len > 31 || val >>> len != 0) if (len < 0 || len > 31 || val >>> len != 0)
throw new RangeError("Value out of range"); throw new RangeError("Value out of range");
for (let i = len - 1; i >= 0; i--) // Append bit by bit for (
let i = len - 1;
i >= 0;
i-- // Append bit by bit
)
bb.push((val >>> i) & 1); bb.push((val >>> i) & 1);
} }
// Returns true iff the i'th bit of x is set to 1. // Returns true iff the i'th bit of x is set to 1.
@ -615,8 +707,7 @@ export var qrcodegen;
} }
// Throws an exception if the given condition is false. // Throws an exception if the given condition is false.
function assert(cond) { function assert(cond) {
if (!cond) if (!cond) throw new Error("Assertion error");
throw new Error("Assertion error");
} }
/*---- Data segment class ----*/ /*---- Data segment class ----*/
/* /*
@ -643,12 +734,12 @@ export var qrcodegen;
// Always zero or positive. Not the same as the data's bit length. // Always zero or positive. Not the same as the data's bit length.
numChars, numChars,
// The data bits of this segment. Accessed through getData(). // The data bits of this segment. Accessed through getData().
bitData) { bitData
) {
this.mode = mode; this.mode = mode;
this.numChars = numChars; this.numChars = numChars;
this.bitData = bitData; this.bitData = bitData;
if (numChars < 0) if (numChars < 0) throw new RangeError("Invalid argument");
throw new RangeError("Invalid argument");
this.bitData = bitData.slice(); // Make defensive copy this.bitData = bitData.slice(); // Make defensive copy
} }
/*-- Static factory functions (mid level) --*/ /*-- Static factory functions (mid level) --*/
@ -657,8 +748,7 @@ export var qrcodegen;
// can be converted to UTF-8 bytes and encoded as a byte mode segment. // can be converted to UTF-8 bytes and encoded as a byte mode segment.
static makeBytes(data) { static makeBytes(data) {
let bb = []; let bb = [];
for (const b of data) for (const b of data) appendBits(b, 8, bb);
appendBits(b, 8, bb);
return new QrSegment(QrSegment.Mode.BYTE, data.length, bb); return new QrSegment(QrSegment.Mode.BYTE, data.length, bb);
} }
// Returns a segment representing the given string of decimal digits encoded in numeric mode. // Returns a segment representing the given string of decimal digits encoded in numeric mode.
@ -666,7 +756,8 @@ export var qrcodegen;
if (!QrSegment.isNumeric(digits)) if (!QrSegment.isNumeric(digits))
throw new RangeError("String contains non-numeric characters"); throw new RangeError("String contains non-numeric characters");
let bb = []; let bb = [];
for (let i = 0; i < digits.length;) { // Consume up to 3 digits per iteration for (let i = 0; i < digits.length; ) {
// Consume up to 3 digits per iteration
const n = Math.min(digits.length - i, 3); const n = Math.min(digits.length - i, 3);
appendBits(parseInt(digits.substr(i, n), 10), n * 3 + 1, bb); appendBits(parseInt(digits.substr(i, n), 10), n * 3 + 1, bb);
i += n; i += n;
@ -678,30 +769,35 @@ export var qrcodegen;
// dollar, percent, asterisk, plus, hyphen, period, slash, colon. // dollar, percent, asterisk, plus, hyphen, period, slash, colon.
static makeAlphanumeric(text) { static makeAlphanumeric(text) {
if (!QrSegment.isAlphanumeric(text)) if (!QrSegment.isAlphanumeric(text))
throw new RangeError("String contains unencodable characters in alphanumeric mode"); throw new RangeError(
"String contains unencodable characters in alphanumeric mode"
);
let bb = []; let bb = [];
let i; let i;
for (i = 0; i + 2 <= text.length; i += 2) { // Process groups of 2 for (i = 0; i + 2 <= text.length; i += 2) {
// Process groups of 2
let temp = QrSegment.ALPHANUMERIC_CHARSET.indexOf(text.charAt(i)) * 45; let temp = QrSegment.ALPHANUMERIC_CHARSET.indexOf(text.charAt(i)) * 45;
temp += QrSegment.ALPHANUMERIC_CHARSET.indexOf(text.charAt(i + 1)); temp += QrSegment.ALPHANUMERIC_CHARSET.indexOf(text.charAt(i + 1));
appendBits(temp, 11, bb); appendBits(temp, 11, bb);
} }
if (i < text.length) // 1 character remaining if (i < text.length)
appendBits(QrSegment.ALPHANUMERIC_CHARSET.indexOf(text.charAt(i)), 6, bb); // 1 character remaining
appendBits(
QrSegment.ALPHANUMERIC_CHARSET.indexOf(text.charAt(i)),
6,
bb
);
return new QrSegment(QrSegment.Mode.ALPHANUMERIC, text.length, bb); return new QrSegment(QrSegment.Mode.ALPHANUMERIC, text.length, bb);
} }
// Returns a new mutable list of zero or more segments to represent the given Unicode text string. // Returns a new mutable list of zero or more segments to represent the given Unicode text string.
// The result may use various segment modes and switch modes to optimize the length of the bit stream. // The result may use various segment modes and switch modes to optimize the length of the bit stream.
static makeSegments(text) { static makeSegments(text) {
// Select the most efficient segment encoding automatically // Select the most efficient segment encoding automatically
if (text == "") if (text == "") return [];
return []; else if (QrSegment.isNumeric(text)) return [QrSegment.makeNumeric(text)];
else if (QrSegment.isNumeric(text))
return [QrSegment.makeNumeric(text)];
else if (QrSegment.isAlphanumeric(text)) else if (QrSegment.isAlphanumeric(text))
return [QrSegment.makeAlphanumeric(text)]; return [QrSegment.makeAlphanumeric(text)];
else else return [QrSegment.makeBytes(QrSegment.toUtf8ByteArray(text))];
return [QrSegment.makeBytes(QrSegment.toUtf8ByteArray(text))];
} }
// Returns a segment representing an Extended Channel Interpretation // Returns a segment representing an Extended Channel Interpretation
// (ECI) designator with the given assignment value. // (ECI) designator with the given assignment value.
@ -709,18 +805,14 @@ export var qrcodegen;
let bb = []; let bb = [];
if (assignVal < 0) if (assignVal < 0)
throw new RangeError("ECI assignment value out of range"); throw new RangeError("ECI assignment value out of range");
else if (assignVal < (1 << 7)) else if (assignVal < 1 << 7) appendBits(assignVal, 8, bb);
appendBits(assignVal, 8, bb); else if (assignVal < 1 << 14) {
else if (assignVal < (1 << 14)) {
appendBits(0b10, 2, bb); appendBits(0b10, 2, bb);
appendBits(assignVal, 14, bb); appendBits(assignVal, 14, bb);
} } else if (assignVal < 1000000) {
else if (assignVal < 1000000) {
appendBits(0b110, 3, bb); appendBits(0b110, 3, bb);
appendBits(assignVal, 21, bb); appendBits(assignVal, 21, bb);
} } else throw new RangeError("ECI assignment value out of range");
else
throw new RangeError("ECI assignment value out of range");
return new QrSegment(QrSegment.Mode.ECI, 0, bb); return new QrSegment(QrSegment.Mode.ECI, 0, bb);
} }
// Tests whether the given string can be encoded as a segment in numeric mode. // Tests whether the given string can be encoded as a segment in numeric mode.
@ -745,8 +837,7 @@ export var qrcodegen;
let result = 0; let result = 0;
for (const seg of segs) { for (const seg of segs) {
const ccbits = seg.mode.numCharCountBits(version); const ccbits = seg.mode.numCharCountBits(version);
if (seg.numChars >= (1 << ccbits)) if (seg.numChars >= 1 << ccbits) return Infinity; // The segment's length doesn't fit the field's bit width
return Infinity; // The segment's length doesn't fit the field's bit width
result += 4 + ccbits + seg.bitData.length; result += 4 + ccbits + seg.bitData.length;
} }
return result; return result;
@ -756,8 +847,7 @@ export var qrcodegen;
str = encodeURI(str); str = encodeURI(str);
let result = []; let result = [];
for (let i = 0; i < str.length; i++) { for (let i = 0; i < str.length; i++) {
if (str.charAt(i) != "%") if (str.charAt(i) != "%") result.push(str.charCodeAt(i));
result.push(str.charCodeAt(i));
else { else {
result.push(parseInt(str.substr(i + 1, 2), 16)); result.push(parseInt(str.substr(i + 1, 2), 16));
i += 2; i += 2;
@ -773,7 +863,8 @@ export var qrcodegen;
QrSegment.ALPHANUMERIC_REGEX = /^[A-Z0-9 $%*+.\/:-]*$/; QrSegment.ALPHANUMERIC_REGEX = /^[A-Z0-9 $%*+.\/:-]*$/;
// The set of all legal characters in alphanumeric mode, // The set of all legal characters in alphanumeric mode,
// where each character value maps to the index in the string. // where each character value maps to the index in the string.
QrSegment.ALPHANUMERIC_CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"; QrSegment.ALPHANUMERIC_CHARSET =
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:";
qrcodegen.QrSegment = QrSegment; qrcodegen.QrSegment = QrSegment;
})(qrcodegen || (qrcodegen = {})); })(qrcodegen || (qrcodegen = {}));
/*---- Public helper enumeration ----*/ /*---- Public helper enumeration ----*/
@ -789,7 +880,8 @@ export var qrcodegen;
// In the range 0 to 3 (unsigned 2-bit integer). // In the range 0 to 3 (unsigned 2-bit integer).
ordinal, ordinal,
// (Package-private) In the range 0 to 3 (unsigned 2-bit integer). // (Package-private) In the range 0 to 3 (unsigned 2-bit integer).
formatBits) { formatBits
) {
this.ordinal = ordinal; this.ordinal = ordinal;
this.formatBits = formatBits; this.formatBits = formatBits;
} }
@ -800,7 +892,7 @@ export var qrcodegen;
Ecc.QUARTILE = new Ecc(2, 3); // The QR Code can tolerate about 25% erroneous codewords Ecc.QUARTILE = new Ecc(2, 3); // The QR Code can tolerate about 25% erroneous codewords
Ecc.HIGH = new Ecc(3, 2); // The QR Code can tolerate about 30% erroneous codewords Ecc.HIGH = new Ecc(3, 2); // The QR Code can tolerate about 30% erroneous codewords
QrCode.Ecc = Ecc; QrCode.Ecc = Ecc;
})(QrCode = qrcodegen.QrCode || (qrcodegen.QrCode = {})); })((QrCode = qrcodegen.QrCode || (qrcodegen.QrCode = {})));
})(qrcodegen || (qrcodegen = {})); })(qrcodegen || (qrcodegen = {}));
/*---- Public helper enumeration ----*/ /*---- Public helper enumeration ----*/
(function (qrcodegen) { (function (qrcodegen) {
@ -815,7 +907,8 @@ export var qrcodegen;
// The mode indicator bits, which is a uint4 value (range 0 to 15). // The mode indicator bits, which is a uint4 value (range 0 to 15).
modeBits, modeBits,
// Number of character count bits for three different version ranges. // Number of character count bits for three different version ranges.
numBitsCharCount) { numBitsCharCount
) {
this.modeBits = modeBits; this.modeBits = modeBits;
this.numBitsCharCount = numBitsCharCount; this.numBitsCharCount = numBitsCharCount;
} }
@ -833,5 +926,5 @@ export var qrcodegen;
Mode.KANJI = new Mode(0x8, [8, 10, 12]); Mode.KANJI = new Mode(0x8, [8, 10, 12]);
Mode.ECI = new Mode(0x7, [0, 0, 0]); Mode.ECI = new Mode(0x7, [0, 0, 0]);
QrSegment.Mode = Mode; QrSegment.Mode = Mode;
})(QrSegment = qrcodegen.QrSegment || (qrcodegen.QrSegment = {})); })((QrSegment = qrcodegen.QrSegment || (qrcodegen.QrSegment = {})));
})(qrcodegen || (qrcodegen = {})); })(qrcodegen || (qrcodegen = {}));

149
Web/public/profile.html Normal file
View file

@ -0,0 +1,149 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Echoes Behind Closed Doors</title>
<!-- favicons -->
<link
rel="apple-touch-icon"
sizes="180x180"
href="/png/apple-touch-icon.png"
/>
<link rel="icon" type="image/x-icon" href="/ico/favicon.ico" />
<link
rel="icon"
type="image/png"
sizes="32x32"
href="/png/favicon-32x32.png"
/>
<link
rel="icon"
type="image/png"
sizes="16x16"
href="/png/favicon-16x16.png"
/>
<link rel="manifest" href="/site.webmanifest" />
<!-- TODO: social share -->
<!-- ui stuff -->
<!-- temporary ui bundling fix (https://github.com/oven-sh/bun/issues/17243) -->
<link
rel="stylesheet"
href="https://unpkg.com/franken-ui@2.0.0-internal.42/dist/css/core.min.css"
/>
<script src="https://unpkg.com/@tailwindcss/browser@4"></script>
<script type="module" src="/js/ebcd-common-franken-ui.js"></script>
<script type="module" src="/js/ebcd-common-navbar.js"></script>
<script type="module" src="/js/ebcd-profile.js"></script>
<style>
/* latin-ext */
@font-face {
font-family: "Geist";
font-style: normal;
font-weight: 100 900;
font-display: swap;
src: url(https://fonts.gstatic.com/s/geist/v1/gyByhwUxId8gMEwSGFWNPoTcZY7pVQ.woff2)
format("woff2");
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7,
U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F,
U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F,
U+A720-A7FF;
}
/* latin */
@font-face {
font-family: "Geist";
font-style: normal;
font-weight: 100 900;
font-display: swap;
src: url(https://fonts.gstatic.com/s/geist/v1/gyByhwUxId8gMEwcGFWNPoTcZY4.woff2)
format("woff2");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6,
U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* latin-ext */
@font-face {
font-family: "Geist Mono";
font-style: normal;
font-weight: 100 900;
font-display: swap;
src: url(https://fonts.gstatic.com/s/geistmono/v1/or3nQ6H-1_WfwkMZI_qYFrkdmhHijks9bNn0.woff2)
format("woff2");
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7,
U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F,
U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F,
U+A720-A7FF;
}
/* latin */
@font-face {
font-family: "Geist Mono";
font-style: normal;
font-weight: 100 900;
font-display: swap;
src: url(https://fonts.gstatic.com/s/geistmono/v1/or3nQ6H-1_WfwkMZI_qYFrcdmhHijks9bA.woff2)
format("woff2");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6,
U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@theme {
--font-sans: "Geist", sans-serif;
--font-mono: "'Geist Mono'", monospace;
}
:root {
font-family: Geist, sans-serif;
font-feature-settings: "liga" 1, "calt" 1; /* fix for Chrome */
}
@media (max-width: 768px) {
.uk-subnav > * > :first-child {
padding-left: 0.5rem !important;
padding-right: 0.5rem !important;
}
}
</style>
</head>
<body class="bg-background text-foreground">
<header
class="uk-position-top !uk-position-z-index p-4 flex justify-between !bg-[hsl(var(--muted))]/75 !backdrop-blur-md text-muted-foreground"
data-uk-sticky="position:top"
>
<div class="flex flex-row gap-2">
<img src="/png/logo-icon.png" alt="wirm logo" class="!h-[2.5rem]" />
<img
src="/png/logo-wordmark-blue.png"
alt="wirm wordmark"
class="!h-[2.5rem]"
/>
</div>
<nav class="flex">
<ul class="uk-subnav uk-subnav-primary">
<li class="uk-active"><a href="/">About</a></li>
<li>
<a href>
<span class="mr-2">Account</span>
<uk-icon icon="chevron-down"></uk-icon>
</a>
<div data-uk-dropdown="mode: click">
<ul class="uk-dropdown-nav uk-nav">
<li id="nav-auth-logIn">
<a href="/auth.html">Authenticate</a>
</li>
<li id="nav-auth-profile">
<a href="/profile.html">Profile</a>
</li>
<li id="nav-auth-logOut">
<a href="/profile.html?logOut=true">Log Out</a>
</li>
</ul>
</div>
</li>
<li><a href="/booth.html">Manage Booth</a></li>
</ul>
</nav>
</header>
</body>
</html>