Update pages 🚀
This commit is contained in:
commit
35ce6de561
20 changed files with 822 additions and 0 deletions
1
.domains
Normal file
1
.domains
Normal file
|
@ -0,0 +1 @@
|
|||
ok-ready-go.speedclimbing.org
|
79
index.css
Normal file
79
index.css
Normal file
|
@ -0,0 +1,79 @@
|
|||
@keyframes blinker {
|
||||
50% {
|
||||
opacity: 0.3;
|
||||
}
|
||||
}
|
||||
|
||||
.loading {
|
||||
font-size: 2em;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.timer {
|
||||
font-size: 8em;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.timer.over {
|
||||
color: #0f0;
|
||||
animation: blinker 2s ease infinite;
|
||||
}
|
||||
|
||||
.timer.sending {
|
||||
color: #ff0;
|
||||
animation: blinker 2s ease infinite;
|
||||
}
|
||||
|
||||
html {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
main {
|
||||
padding-top: 0 !important;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.timer-container-div {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.timer-div {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tap-area {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.hide-before-init {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.remote-connection-card {
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
left: 0;
|
||||
background-color: var(--background-color);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
details {
|
||||
border-bottom: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
104
index.html
Normal file
104
index.html
Normal file
|
@ -0,0 +1,104 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<script defer src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"></script>
|
||||
<script src="https://unpkg.com/mqtt/dist/mqtt.min.js"></script>
|
||||
|
||||
<script src="lib/crypto_helper.js"></script>
|
||||
<script src="js/index.js"></script>
|
||||
<script src="js/localState.js"></script>
|
||||
<script src="js/mqtt.js"></script>
|
||||
|
||||
<link rel="stylesheet" href="https://unpkg.com/@picocss/pico@latest/css/pico.min.css" />
|
||||
<link rel="stylesheet" href="index.css" />
|
||||
|
||||
<audio id="sound-0" src="sound/0.mp3" preload="auto"></audio>
|
||||
<audio id="sound-1" src="sound/1.mp3" preload="auto"></audio>
|
||||
<audio id="sound-2" src="sound/2.mp3" preload="auto"></audio>
|
||||
<audio id="sound-3" src="sound/3.mp3" preload="auto"></audio>
|
||||
<audio id="sound-4" src="sound/4.mp3" preload="auto"></audio>
|
||||
<audio id="sound-5" src="sound/5.mp3" preload="auto"></audio>
|
||||
<audio id="sound-6" src="sound/6.mp3" preload="auto"></audio>
|
||||
<audio id="sound-7" src="sound/7.mp3" preload="auto"></audio>
|
||||
<audio id="sound-8" src="sound/8.mp3" preload="auto"></audio>
|
||||
<audio id="sound-9" src="sound/9.mp3" preload="auto"></audio>
|
||||
<audio id="sound-ok-ready-go" src="sound/ok-ready-go.mp3" preload="auto"></audio>
|
||||
<audio id="sound-silence" src="sound/silence.mp3" preload="auto"></audio>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="timer-container-div hide-after-init">
|
||||
<h1 class="loading" aria-busy="true">Initializing...</h1>
|
||||
</div>
|
||||
<main class="container hide-before-init" x-data>
|
||||
<div class="timer-container-div" x-show="$store.localState._state !== 5">
|
||||
<div @click="$store.localState.next()" class="tap-area" x-show="$store.localState._state === 2"></div>
|
||||
<div @click="$store.localState.next()" class="timer-div">
|
||||
<hgroup>
|
||||
<h1>OK! .. READY! ... GO!</h1>
|
||||
<h2><span x-text="$store.localState.stateHint"></span> <b x-show="$store.mqtt.connected">(connected)</b></h2>
|
||||
</hgroup>
|
||||
|
||||
<div x-data="Timer">
|
||||
<p :class="'timer' + (over ? ($store.localState._state === 3 ? ' sending':' over'):'')"
|
||||
x-text="time + 's'"></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div x-show="$store.localState._state === 0" class="remote-connection-card">
|
||||
<div class="container">
|
||||
<details>
|
||||
<div class="container">
|
||||
<p>If you want to automatically transfer the time to a computer, follow these steps:</p>
|
||||
|
||||
<div x-show="!$store.mqtt.connected">
|
||||
<ul>
|
||||
<li>Enter a password and press tap connect</li>
|
||||
|
||||
<li>
|
||||
<form x-data="PasswordForm()" @submit.prevent="submitForm">
|
||||
<label for="passwordForm_password">Password:</label>
|
||||
<input id="passwordForm_password" type="text" x-model="formData.password"
|
||||
placeholder="Password" />
|
||||
<small>Make sure, this is exactly the same on your computer!</small>
|
||||
<button type="submit">Connect</button>
|
||||
</form>
|
||||
</li>
|
||||
<li>Download the receiver tool from <a
|
||||
href="https://itsblue.dev/dorian/ok-ready-go/releases/latest">here</a> to your computer
|
||||
</li>
|
||||
<li>Start the receiver tool on your computer</li>
|
||||
<li>Enter the same password on the receiver tool and click connect</li>
|
||||
<li>Done!</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div x-show="$store.mqtt.connected">
|
||||
<ul>
|
||||
<li>Download the receiver tool from <a
|
||||
href="https://itsblue.dev/dorian/ok-ready-go/releases/latest">here</a> to your computer
|
||||
</li>
|
||||
<li>Start the receiver tool on your computer</li>
|
||||
<li>Enter the password '<b x-text="$store.localState.password"></b>' on the receiver tool and click connect</li>
|
||||
<li>Done!</li>
|
||||
<li>
|
||||
<p>If you no longer want to send the time, tap Disconnect</p>
|
||||
<button @click="$store.localState.password = ''">Disconnect</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<summary role="button">Remote connection</summary>
|
||||
</details>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="timer-container-div" x-show="$store.localState._state === 5">
|
||||
<h1 class="loading" aria-busy="true">Connecting...</h1>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
72
js/index.js
Normal file
72
js/index.js
Normal file
|
@ -0,0 +1,72 @@
|
|||
async function sayNumber(number) {
|
||||
console.log(number);
|
||||
number = number.toString();
|
||||
number = number.replace(/[^0-9]/, "");
|
||||
for (let i = 0; i < number.length; i++) {
|
||||
await playAudio(document.getElementById(`sound-${number[i]}`));
|
||||
}
|
||||
}
|
||||
|
||||
function playAudio(audio) {
|
||||
return new Promise((res) => {
|
||||
audio.play();
|
||||
audio.onended = res;
|
||||
});
|
||||
}
|
||||
|
||||
function uuidv4() {
|
||||
return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c) =>
|
||||
(
|
||||
c ^
|
||||
(crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))
|
||||
).toString(16)
|
||||
);
|
||||
}
|
||||
|
||||
function PasswordForm() {
|
||||
return {
|
||||
formData: {
|
||||
password: "",
|
||||
},
|
||||
submitForm() {
|
||||
Alpine.store("localState").password = this.formData.password;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function Timer() {
|
||||
return {
|
||||
time: 0,
|
||||
over: false,
|
||||
init() {
|
||||
setInterval(() => {
|
||||
const startedAt = Alpine.store("localState").startedAt;
|
||||
const resultTime = Alpine.store("localState").time;
|
||||
|
||||
let time;
|
||||
if (!startedAt && !resultTime) {
|
||||
time = 0;
|
||||
this.over = false;
|
||||
} else if (resultTime) {
|
||||
time = resultTime / 1000;
|
||||
this.over = true;
|
||||
} else {
|
||||
this.over = false;
|
||||
time = (new Date().getTime() - startedAt) / 1000;
|
||||
}
|
||||
|
||||
this.time = time.toFixed(2);
|
||||
}, 10);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const event = new Event('wasm-loaded');
|
||||
wasm_bindgen('lib/crypto_helper_bg.wasm').then(() => {
|
||||
document.dispatchEvent(event);
|
||||
});
|
||||
|
||||
document.addEventListener("alpine:init", () => {
|
||||
document.getElementsByClassName("hide-after-init").item(0).outerHTML = ""
|
||||
document.getElementsByClassName("hide-before-init").item(0).classList.remove("hide-before-init")
|
||||
});
|
105
js/localState.js
Normal file
105
js/localState.js
Normal file
|
@ -0,0 +1,105 @@
|
|||
document.addEventListener("alpine:init", () => {
|
||||
Alpine.store("localState", {
|
||||
_state: 0,
|
||||
// 0: idle
|
||||
// 1: starting
|
||||
// 2: running
|
||||
// 3: sending time to mqtt
|
||||
// 4: stopped
|
||||
// 5: connecting to mqtt
|
||||
|
||||
startedAt: null,
|
||||
time: null,
|
||||
stateHint: "",
|
||||
password: null,
|
||||
|
||||
init() {
|
||||
Alpine.effect(() => {
|
||||
if (this.password == null) {
|
||||
this.password = localStorage.getItem("password");
|
||||
} else {
|
||||
localStorage.setItem("password", this.password);
|
||||
}
|
||||
|
||||
const mqtt = Alpine.store("mqtt");
|
||||
if (!mqtt) return;
|
||||
if (this.password == null || this.password == "") {
|
||||
mqtt.disconnect();
|
||||
} else {
|
||||
mqtt.connect();
|
||||
}
|
||||
});
|
||||
|
||||
Alpine.effect(() => {
|
||||
switch (this._state) {
|
||||
case 0:
|
||||
this.stateHint = "Tap here to start";
|
||||
break;
|
||||
case 1:
|
||||
this.stateHint = "Get ready...";
|
||||
break;
|
||||
case 2:
|
||||
this.stateHint = "Tap anywhere to stop";
|
||||
break;
|
||||
case 3:
|
||||
this.stateHint = "Sending time to MQTT...";
|
||||
break;
|
||||
|
||||
case 4:
|
||||
this.stateHint = "Tap here to reset";
|
||||
break;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
next() {
|
||||
playAudio(document.getElementById("sound-silence"));
|
||||
|
||||
if (this._state == 1 || this._state == 3) return;
|
||||
|
||||
this._setState((this._state + 1) % 5);
|
||||
},
|
||||
|
||||
_setState(state) {
|
||||
switch (state) {
|
||||
case 0: {
|
||||
this.startedAt = null;
|
||||
this.time = null;
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
playAudio(document.getElementById("sound-ok-ready-go")).then(() => {
|
||||
Alpine.store("localState")._setState(2);
|
||||
});
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
this.startedAt = new Date().getTime() - 200;
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
this.time =
|
||||
Math.floor(((new Date().getTime() - this.startedAt) / 1000).toFixed(2) * 1000);
|
||||
this.startedAt = null;
|
||||
sayNumber(this.time / 10);
|
||||
|
||||
if (Alpine.store("mqtt").connected) {
|
||||
Alpine.store("mqtt")
|
||||
.sendTime(this.time)
|
||||
.then(() => {
|
||||
Alpine.store("localState")._setState(4);
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
state = 4;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
this._state = state;
|
||||
},
|
||||
});
|
||||
});
|
132
js/mqtt.js
Normal file
132
js/mqtt.js
Normal file
|
@ -0,0 +1,132 @@
|
|||
let wasm_inited_resolve;
|
||||
const wasm_inited = new Promise((resolve) => {
|
||||
wasm_inited_resolve = resolve;
|
||||
});
|
||||
|
||||
document.addEventListener("wasm-loaded", () => {
|
||||
wasm_inited_resolve(wasm_bindgen);
|
||||
});
|
||||
|
||||
document.addEventListener("alpine:init", () => {
|
||||
Alpine.store("mqtt", {
|
||||
connected: false,
|
||||
_client: null,
|
||||
_topics: null,
|
||||
_c: null,
|
||||
|
||||
_pendingPromises: {},
|
||||
|
||||
sendTime(time) {
|
||||
if (!this.connected) return null;
|
||||
|
||||
const id = uuidv4();
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
this._pendingPromises[id] = [resolve, reject];
|
||||
});
|
||||
this._publish({
|
||||
id: id, // used to prevent replay attacks and to identify confirm messages
|
||||
kind: "Time", // can be "time" or "confirm"
|
||||
time: time, // only used for "time"
|
||||
});
|
||||
|
||||
return promise;
|
||||
},
|
||||
|
||||
async connect() {
|
||||
if (this.connected) return;
|
||||
|
||||
const password = Alpine.store("localState").password;
|
||||
const that = this;
|
||||
const brokerDomain = "broker.emqx.io";
|
||||
const url = `wss://${brokerDomain}:8084/mqtt`;
|
||||
|
||||
if (!password) return false;
|
||||
|
||||
const { Crypto } = await wasm_inited;
|
||||
|
||||
Alpine.store("localState")._state = 5;
|
||||
|
||||
// derive key from password
|
||||
this._c = new Crypto(password, brokerDomain);
|
||||
|
||||
console.log("Test", this._encrypt("test"));
|
||||
|
||||
this._topics = {
|
||||
time: Crypto.sha256(
|
||||
this._encrypt(`org.speedclimbing.ok-ready-go.${password}.time`)
|
||||
).toString(),
|
||||
confirmation: Crypto.sha256(
|
||||
this._encrypt(
|
||||
`org.speedclimbing.ok-ready-go.${password}.confirmation`
|
||||
)
|
||||
).toString(),
|
||||
};
|
||||
|
||||
console.log("Connecting to MQTT broker...");
|
||||
|
||||
const options = {
|
||||
// Clean session
|
||||
clean: true,
|
||||
connectTimeout: 4000,
|
||||
};
|
||||
|
||||
this._client = mqtt.connect(url, options);
|
||||
|
||||
this._client.on("connect", () => {
|
||||
Alpine.store("localState")._state = 0;
|
||||
|
||||
that._client.subscribe(that._topics.confirmation);
|
||||
this.connected = true;
|
||||
});
|
||||
|
||||
this._client.on("message", (topic, message) => {
|
||||
// message is Buffer
|
||||
message = that._decrypt(message.toString());
|
||||
const data = JSON.parse(message);
|
||||
|
||||
if (
|
||||
topic !== that._topics.confirmation ||
|
||||
data.kind !== "Confirm" ||
|
||||
Object.keys(this._pendingPromises).indexOf(data.id) === -1
|
||||
)
|
||||
return;
|
||||
|
||||
console.log("<<< ", data);
|
||||
this._pendingPromises[data.id][0]();
|
||||
});
|
||||
},
|
||||
|
||||
disconnect() {
|
||||
if (!this.connected) return;
|
||||
|
||||
this._client.end(true);
|
||||
|
||||
this._client = null;
|
||||
this.connected = false;
|
||||
this._topics = null;
|
||||
|
||||
for (const promiseId in this._pendingPromises) {
|
||||
this._pendingPromises[promiseId][1]();
|
||||
}
|
||||
|
||||
this._pendingPromises = {};
|
||||
},
|
||||
|
||||
_publish(data) {
|
||||
const encryptedData = this._encrypt(JSON.stringify(data));
|
||||
console.log(">>> ", data);
|
||||
this._client.publish(this._topics.time, encryptedData, {
|
||||
qos: 1,
|
||||
retain: false,
|
||||
});
|
||||
},
|
||||
|
||||
_encrypt(data) {
|
||||
return this._c.encrypt(data);
|
||||
},
|
||||
|
||||
_decrypt(data) {
|
||||
return this._c.decrypt(data);
|
||||
},
|
||||
});
|
||||
});
|
329
lib/crypto_helper.js
Normal file
329
lib/crypto_helper.js
Normal file
|
@ -0,0 +1,329 @@
|
|||
let wasm_bindgen;
|
||||
(function() {
|
||||
const __exports = {};
|
||||
let script_src;
|
||||
if (typeof document === 'undefined') {
|
||||
script_src = location.href;
|
||||
} else {
|
||||
script_src = new URL(document.currentScript.src, location.href).toString();
|
||||
}
|
||||
let wasm;
|
||||
|
||||
const heap = new Array(128).fill(undefined);
|
||||
|
||||
heap.push(undefined, null, true, false);
|
||||
|
||||
function getObject(idx) { return heap[idx]; }
|
||||
|
||||
let heap_next = heap.length;
|
||||
|
||||
function dropObject(idx) {
|
||||
if (idx < 132) return;
|
||||
heap[idx] = heap_next;
|
||||
heap_next = idx;
|
||||
}
|
||||
|
||||
function takeObject(idx) {
|
||||
const ret = getObject(idx);
|
||||
dropObject(idx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
const cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
|
||||
|
||||
cachedTextDecoder.decode();
|
||||
|
||||
let cachedUint8Memory0 = null;
|
||||
|
||||
function getUint8Memory0() {
|
||||
if (cachedUint8Memory0 === null || cachedUint8Memory0.byteLength === 0) {
|
||||
cachedUint8Memory0 = new Uint8Array(wasm.memory.buffer);
|
||||
}
|
||||
return cachedUint8Memory0;
|
||||
}
|
||||
|
||||
function getStringFromWasm0(ptr, len) {
|
||||
return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len));
|
||||
}
|
||||
|
||||
let WASM_VECTOR_LEN = 0;
|
||||
|
||||
const cachedTextEncoder = new TextEncoder('utf-8');
|
||||
|
||||
const encodeString = (typeof cachedTextEncoder.encodeInto === 'function'
|
||||
? function (arg, view) {
|
||||
return cachedTextEncoder.encodeInto(arg, view);
|
||||
}
|
||||
: function (arg, view) {
|
||||
const buf = cachedTextEncoder.encode(arg);
|
||||
view.set(buf);
|
||||
return {
|
||||
read: arg.length,
|
||||
written: buf.length
|
||||
};
|
||||
});
|
||||
|
||||
function passStringToWasm0(arg, malloc, realloc) {
|
||||
|
||||
if (realloc === undefined) {
|
||||
const buf = cachedTextEncoder.encode(arg);
|
||||
const ptr = malloc(buf.length);
|
||||
getUint8Memory0().subarray(ptr, ptr + buf.length).set(buf);
|
||||
WASM_VECTOR_LEN = buf.length;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
let len = arg.length;
|
||||
let ptr = malloc(len);
|
||||
|
||||
const mem = getUint8Memory0();
|
||||
|
||||
let offset = 0;
|
||||
|
||||
for (; offset < len; offset++) {
|
||||
const code = arg.charCodeAt(offset);
|
||||
if (code > 0x7F) break;
|
||||
mem[ptr + offset] = code;
|
||||
}
|
||||
|
||||
if (offset !== len) {
|
||||
if (offset !== 0) {
|
||||
arg = arg.slice(offset);
|
||||
}
|
||||
ptr = realloc(ptr, len, len = offset + arg.length * 3);
|
||||
const view = getUint8Memory0().subarray(ptr + offset, ptr + len);
|
||||
const ret = encodeString(arg, view);
|
||||
|
||||
offset += ret.written;
|
||||
}
|
||||
|
||||
WASM_VECTOR_LEN = offset;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
let cachedInt32Memory0 = null;
|
||||
|
||||
function getInt32Memory0() {
|
||||
if (cachedInt32Memory0 === null || cachedInt32Memory0.byteLength === 0) {
|
||||
cachedInt32Memory0 = new Int32Array(wasm.memory.buffer);
|
||||
}
|
||||
return cachedInt32Memory0;
|
||||
}
|
||||
/**
|
||||
*/
|
||||
__exports.greet = function() {
|
||||
wasm.greet();
|
||||
};
|
||||
|
||||
function addHeapObject(obj) {
|
||||
if (heap_next === heap.length) heap.push(heap.length + 1);
|
||||
const idx = heap_next;
|
||||
heap_next = heap[idx];
|
||||
|
||||
heap[idx] = obj;
|
||||
return idx;
|
||||
}
|
||||
/**
|
||||
*/
|
||||
class Crypto {
|
||||
|
||||
static __wrap(ptr) {
|
||||
const obj = Object.create(Crypto.prototype);
|
||||
obj.ptr = ptr;
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
__destroy_into_raw() {
|
||||
const ptr = this.ptr;
|
||||
this.ptr = 0;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
free() {
|
||||
const ptr = this.__destroy_into_raw();
|
||||
wasm.__wbg_crypto_free(ptr);
|
||||
}
|
||||
/**
|
||||
* @param {string} password
|
||||
* @param {string} salt
|
||||
*/
|
||||
constructor(password, salt) {
|
||||
const ptr0 = passStringToWasm0(password, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||
const len0 = WASM_VECTOR_LEN;
|
||||
const ptr1 = passStringToWasm0(salt, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||
const len1 = WASM_VECTOR_LEN;
|
||||
const ret = wasm.crypto_new(ptr0, len0, ptr1, len1);
|
||||
return Crypto.__wrap(ret);
|
||||
}
|
||||
/**
|
||||
* @param {string} input
|
||||
* @returns {string}
|
||||
*/
|
||||
static sha256(input) {
|
||||
try {
|
||||
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
||||
const ptr0 = passStringToWasm0(input, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||
const len0 = WASM_VECTOR_LEN;
|
||||
wasm.crypto_sha256(retptr, ptr0, len0);
|
||||
var r0 = getInt32Memory0()[retptr / 4 + 0];
|
||||
var r1 = getInt32Memory0()[retptr / 4 + 1];
|
||||
return getStringFromWasm0(r0, r1);
|
||||
} finally {
|
||||
wasm.__wbindgen_add_to_stack_pointer(16);
|
||||
wasm.__wbindgen_free(r0, r1);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param {string} plaintext
|
||||
* @returns {string}
|
||||
*/
|
||||
encrypt(plaintext) {
|
||||
try {
|
||||
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
||||
const ptr0 = passStringToWasm0(plaintext, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||
const len0 = WASM_VECTOR_LEN;
|
||||
wasm.crypto_encrypt(retptr, this.ptr, ptr0, len0);
|
||||
var r0 = getInt32Memory0()[retptr / 4 + 0];
|
||||
var r1 = getInt32Memory0()[retptr / 4 + 1];
|
||||
return getStringFromWasm0(r0, r1);
|
||||
} finally {
|
||||
wasm.__wbindgen_add_to_stack_pointer(16);
|
||||
wasm.__wbindgen_free(r0, r1);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param {string} ciphertext
|
||||
* @returns {string}
|
||||
*/
|
||||
decrypt(ciphertext) {
|
||||
try {
|
||||
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
||||
const ptr0 = passStringToWasm0(ciphertext, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||
const len0 = WASM_VECTOR_LEN;
|
||||
wasm.crypto_decrypt(retptr, this.ptr, ptr0, len0);
|
||||
var r0 = getInt32Memory0()[retptr / 4 + 0];
|
||||
var r1 = getInt32Memory0()[retptr / 4 + 1];
|
||||
return getStringFromWasm0(r0, r1);
|
||||
} finally {
|
||||
wasm.__wbindgen_add_to_stack_pointer(16);
|
||||
wasm.__wbindgen_free(r0, r1);
|
||||
}
|
||||
}
|
||||
}
|
||||
__exports.Crypto = Crypto;
|
||||
|
||||
async function load(module, imports) {
|
||||
if (typeof Response === 'function' && module instanceof Response) {
|
||||
if (typeof WebAssembly.instantiateStreaming === 'function') {
|
||||
try {
|
||||
return await WebAssembly.instantiateStreaming(module, imports);
|
||||
|
||||
} catch (e) {
|
||||
if (module.headers.get('Content-Type') != 'application/wasm') {
|
||||
console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e);
|
||||
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const bytes = await module.arrayBuffer();
|
||||
return await WebAssembly.instantiate(bytes, imports);
|
||||
|
||||
} else {
|
||||
const instance = await WebAssembly.instantiate(module, imports);
|
||||
|
||||
if (instance instanceof WebAssembly.Instance) {
|
||||
return { instance, module };
|
||||
|
||||
} else {
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getImports() {
|
||||
const imports = {};
|
||||
imports.wbg = {};
|
||||
imports.wbg.__wbg_alert_0cc0cb8b17d72dde = function(arg0, arg1) {
|
||||
alert(getStringFromWasm0(arg0, arg1));
|
||||
};
|
||||
imports.wbg.__wbg_new_abda76e883ba8a5f = function() {
|
||||
const ret = new Error();
|
||||
return addHeapObject(ret);
|
||||
};
|
||||
imports.wbg.__wbg_stack_658279fe44541cf6 = function(arg0, arg1) {
|
||||
const ret = getObject(arg1).stack;
|
||||
const ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||
const len0 = WASM_VECTOR_LEN;
|
||||
getInt32Memory0()[arg0 / 4 + 1] = len0;
|
||||
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
|
||||
};
|
||||
imports.wbg.__wbg_error_f851667af71bcfc6 = function(arg0, arg1) {
|
||||
try {
|
||||
console.error(getStringFromWasm0(arg0, arg1));
|
||||
} finally {
|
||||
wasm.__wbindgen_free(arg0, arg1);
|
||||
}
|
||||
};
|
||||
imports.wbg.__wbindgen_object_drop_ref = function(arg0) {
|
||||
takeObject(arg0);
|
||||
};
|
||||
imports.wbg.__wbindgen_throw = function(arg0, arg1) {
|
||||
throw new Error(getStringFromWasm0(arg0, arg1));
|
||||
};
|
||||
|
||||
return imports;
|
||||
}
|
||||
|
||||
function initMemory(imports, maybe_memory) {
|
||||
|
||||
}
|
||||
|
||||
function finalizeInit(instance, module) {
|
||||
wasm = instance.exports;
|
||||
init.__wbindgen_wasm_module = module;
|
||||
cachedInt32Memory0 = null;
|
||||
cachedUint8Memory0 = null;
|
||||
|
||||
|
||||
return wasm;
|
||||
}
|
||||
|
||||
function initSync(module) {
|
||||
const imports = getImports();
|
||||
|
||||
initMemory(imports);
|
||||
|
||||
if (!(module instanceof WebAssembly.Module)) {
|
||||
module = new WebAssembly.Module(module);
|
||||
}
|
||||
|
||||
const instance = new WebAssembly.Instance(module, imports);
|
||||
|
||||
return finalizeInit(instance, module);
|
||||
}
|
||||
|
||||
async function init(input) {
|
||||
if (typeof input === 'undefined') {
|
||||
input = script_src.replace(/\.js$/, '_bg.wasm');
|
||||
}
|
||||
const imports = getImports();
|
||||
|
||||
if (typeof input === 'string' || (typeof Request === 'function' && input instanceof Request) || (typeof URL === 'function' && input instanceof URL)) {
|
||||
input = fetch(input);
|
||||
}
|
||||
|
||||
initMemory(imports);
|
||||
|
||||
const { instance, module } = await load(await input, imports);
|
||||
|
||||
return finalizeInit(instance, module);
|
||||
}
|
||||
|
||||
wasm_bindgen = Object.assign(init, { initSync }, __exports);
|
||||
|
||||
})();
|
BIN
lib/crypto_helper_bg.wasm
Normal file
BIN
lib/crypto_helper_bg.wasm
Normal file
Binary file not shown.
BIN
sound/0.mp3
Normal file
BIN
sound/0.mp3
Normal file
Binary file not shown.
BIN
sound/1.mp3
Normal file
BIN
sound/1.mp3
Normal file
Binary file not shown.
BIN
sound/2.mp3
Normal file
BIN
sound/2.mp3
Normal file
Binary file not shown.
BIN
sound/3.mp3
Normal file
BIN
sound/3.mp3
Normal file
Binary file not shown.
BIN
sound/4.mp3
Normal file
BIN
sound/4.mp3
Normal file
Binary file not shown.
BIN
sound/5.mp3
Normal file
BIN
sound/5.mp3
Normal file
Binary file not shown.
BIN
sound/6.mp3
Normal file
BIN
sound/6.mp3
Normal file
Binary file not shown.
BIN
sound/7.mp3
Normal file
BIN
sound/7.mp3
Normal file
Binary file not shown.
BIN
sound/8.mp3
Normal file
BIN
sound/8.mp3
Normal file
Binary file not shown.
BIN
sound/9.mp3
Normal file
BIN
sound/9.mp3
Normal file
Binary file not shown.
BIN
sound/ok-ready-go.mp3
Normal file
BIN
sound/ok-ready-go.mp3
Normal file
Binary file not shown.
BIN
sound/silence.mp3
Normal file
BIN
sound/silence.mp3
Normal file
Binary file not shown.
Loading…
Reference in a new issue