add posts

This commit is contained in:
jetstream0
2023-08-05 14:50:06 -07:00
parent 192331d27f
commit 6e31b888d8
9 changed files with 344 additions and 16 deletions

View File

@@ -9,7 +9,7 @@ The original faucet... I was not very good at CSS back then:
![Picture of the original faucet](/images/og_faucet.png)
I launched the faucet sometime in October, and it was a great success thanks to everyone in the Banano community. Soon after, SaltyWalty opened an awesome PR that got the faucet looking a lot better. Later, Nano and xDai support was also added to the faucet.
I launched the faucet sometime in October, and it was a great success thanks to everyone in the Banano community. Soon after, SaltyWalty made an awesome PR that got the faucet looking a lot better. Later, Nano and xDai support was also added to the faucet.
For the next 2 years or so, the faucet was sustained by the generosity of many donors, and I was able to help dozens of others to launch their own Banano faucet, or faucets for other currencies.
It's great to see the Banano faucet scene now thriving, and along the way I've also been commissioned to make faucets to help first time users with gas fees on other chains, like Polygon and Arbitrum Nova.
@@ -19,7 +19,4 @@ A couple months ago, I decided I was not satisfied with the code quality of the
HalfBakedBread and I finally finished Faucet v2, and the current version of faucet.prussia.dev is using it! I also added Vite support with the help of KaffinPX. Of course, it is open source on [Github](https://github.com/jetstream0/Faucet-v2).
Since the faucet was having problems with Replit (specifically connecting to the mongodb database), the host was also migrated from Replit to Render, which will hopefully work better.
## Future Plans
Currently, there are plans to add Algorand support, and also change the xDai faucet to support any EVM chain.
Since the faucet was having problems with Replit (specifically connecting to the mongodb database as well as bad uptime), the host was also migrated from Replit to Render, which will hopefully work better.

View File

@@ -1,19 +1,19 @@
{
"meta": {
"title": "meta",
"title": "Meta",
"slug": "meta",
"filename": "meta",
"date": "01/08/2023",
"author": "jetstream0/Prussia",
"tags": ["code", "project", "web", "markdown", "typescript/javascript", "css"]
"tags": ["code", "project", "web", "markdown", "typescript_javascript", "css"]
},
"adding-commas": {
"title": "Adding Commas to Numbers",
"slug": "adding-commas",
"filename": "adding_commas",
"date": "15/11/2022",
"month-start-unix": {
"title": "Finding the Unix Timestamp of the Start of the Month with Javascript",
"slug": "month-start-unix",
"filename": "month_start_unix",
"date": "01/04/2023",
"author": "jetstream0/Prussia",
"tags": ["code", "typescript/javascript"]
"tags": ["code", "web", "typescript_javascript"]
},
"190k-faucet": {
"title": "190000 Payouts!",
@@ -23,13 +23,37 @@
"author": "jetstream0/Prussia",
"tags": ["project", "web", "milestone", "crypto"]
},
"adding-commas": {
"title": "Adding Commas to Numbers",
"slug": "adding-commas",
"filename": "adding_commas",
"date": "15/11/2022",
"author": "jetstream0/Prussia",
"tags": ["code", "typescript_javascript"]
},
"solving-problems-with-a-timeout": {
"title": "Solving Problems With a Timeout",
"slug": "solving-problems-with-a-timeout",
"filename": "solving_problems_with_a_timeout",
"date": "19/08/2022",
"author": "jetstream0/Prussia",
"tags": ["bot", "typescript_javascript"]
},
"fake-typing-effect": {
"title": "Making a Fake Typing Effect",
"slug": "fake-typing-effect",
"filename": "fake_typing_effect",
"date": "27/01/2022",
"author": "jetstream0/Prussia",
"tags": ["code", "web", "typescript_javascript"]
},
"ryuji-docs": {
"title": "Ryuji Documentation",
"slug": "ryuji-docs",
"filename": "ryuji_docs",
"date": "02/08/2023",
"author": "jetstream0/Prussia",
"tags": ["code", "project", "web", "docs", "typescript/javascript"]
"tags": ["code", "project", "web", "docs", "typescript_javascript"]
},
"saki-docs": {
"title": "Saki Documentation",
@@ -37,6 +61,14 @@
"filename": "saki_docs",
"date": "02/08/2023",
"author": "jetstream0/Prussia",
"tags": ["code", "project", "web", "build", "docs", "typescript/javascript"]
"tags": ["code", "project", "web", "build", "docs", "typescript_javascript"]
},
"eve": {
"title": "Eve",
"slug": "eve",
"filename": "eve",
"date": "06/08/2023",
"author": "jetstream0/Prussia",
"tags": ["cryptography"]
}
}

View File

@@ -20,13 +20,15 @@ I think the most interesting part of this code was the 5th line (`let position =
![Demo](/images/commas.gif)
Here is a version that can handle decimals and invalid inputs:
Here is a version that can handle decimals (keep in mind that Javascript does cut off decimals after a certain point), negative numbers and invalid inputs:
```js
function format_commas(amount) {
if (isNaN(Number(amount))) {
return amount;
}
let negative = amount < 0;
amount = Math.abs(amount);
let before_dec = String(amount).split('.')[0];
let amount_mod = before_dec;
//iterate the amount of commas there are
@@ -37,6 +39,9 @@ function format_commas(amount) {
if (String(amount).split('.')[1]) {
amount_mod = amount_mod+"."+String(amount).split('.')[1];
}
if (negative) {
amount_mod = `-${amount_mod}`;
}
return amount_mod;
}
```

1
posts/eve.md Normal file
View File

@@ -0,0 +1 @@
![A stick figure is sitting, looking at a book that says: 'Baby Names', with the name 'Eve' underlined. Caption: Cryptographers say the best defense is a good offense.](/images/c/eve.png)

116
posts/fake_typing_effect.md Normal file
View File

@@ -0,0 +1,116 @@
Let's make a fake typing effect. When an user types on the keyboard, instead of showing the user the real text they typed, we will instead show them some other text (something similar to [hacker typer](https://hackertyper.net/)).
## HTML
Normally, to get user keyboard input, an element like `<input>`. The problem is, `<input>` actually shows what the user types. Usually, this is good. For us, not good.
So we will instead be using `<textarea>`, with user input disabled (meaning users cannot type into the `<textarea>`), so `<textarea disabled>`. Let's also give it a placeholder so the user knows what to do, and an id, maybe `"ouput"`?
```html
<textarea id="output" placeholder="Type something!" disabled></textarea>
```
## Javascript
This is the bulk of the program.
First of all, we have to detect when the keyboard is pressed. To do this, we just need to add an event listener to the document.
```js
document.addEventListener("keyup", function(_event) {
//we haven't written this code yet
});
```
The first parameter is the event name we are listening for: `"keyup"`. The `"keyup"` event is emitted whenever a key on the keyboard is released.
The second parameter of the `addEventListener` function is the callback function that is run whenever the `"keyup"` event is emitted. The `_event` parameter of that function is a [KeyboardEvent](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent), that contains information about the emitted event, like what key was pressed. In this case, we don't need any of that information, so I put an underline in front of the parameter name (`_event`) to indicate we will not use it. In Javascript, we can actually get rid of the `_event` parameter all together, and the code will still work. But I'm keeping it since I like knowing it exists.
Now that we can detect key presses, we want the `<textarea>` element's content to change. Specifically, for every key press, a character from the predetermined text needs to show up. We will have to keep track of the number of keypresses, since the characters have to go in the right order.
To keep track of the number, we can use a global variable which we can increment every key press.
Oh, plus we need a variable to store the text we want to display.
So, so far we have:
```js
const text = "Lorem ipsum something something blah blah blah...";
let letter_index = 0;
document.addEventListener("keyup", function(_event) {
//we haven't written this code yet
});
```
Next, let's add the code that does the actual adding of the text:
```js
const text = "Lorem ipsum something something blah blah blah...";
let letter_index = 0;
document.addEventListener("keyup", function(_event) {
let output = document.getElementById("output");
if (letter_index === text.length) {
output.innerHTML = "";
letter_index = 0;
} else {
output.innerHTML += text[letter_index];
letter_index++;
}
});
```
Whenever a `"keyup"` event is emitted, we see if `letter_index` is equal to the length of the predetermined text. If it is, that means the user finished typing the fake text. So, we clear the textarea's content, and reset the `letter_index` to `0`.
If `letter_index` is less than the length of the predetermiend text (it will never be greater since we reset it before it gets large than `text.length`), we just add the next character to the textarea, and increment `letter_index`.
That's it.
Now, what if we want to cycle between different fake texts after an user finishes typing one of them, instead of restarting and typing the same fake text over and over? That should be fairly simple - we'll make an array that has all the fake texts we want to cycle through, and add another index variable like `letter_index`:
```js
const texts = ["Lorem ipsum something something blah blah blah...", "She sells seashells by the seashore.", "Si shi si, shi shi shi. Shi si shi shi si, si shi shi si shi.", "So long and thanks for all the fish."];
let text_index = 0;
let letter_index = 0;
document.addEventListener("keyup", function(_event) {
let output = document.getElementById("output");
if (letter_index === text.length) {
output.innerHTML = "";
text_index++;
if (text_index === texts.length) {
text_index = 0;
}
letter_index = 0;
} else {
output.innerHTML += texts[text_index][letter_index];
letter_index++;
}
});
```
## Result
Here's the code put together:
```html
<textarea id="output" placeholder="Type something!" disabled></textarea>
<script>
const texts = ["Lorem ipsum something something blah blah blah...", "She sells seashells by the seashore.", "Si shi si, shi shi shi. Shi si shi shi si, si shi shi si shi.", "So long and thanks for all the fish."];
let text_index = 0;
let letter_index = 0;
document.addEventListener("keyup", function(_event) {
let output = document.getElementById("output");
if (letter_index === texts[text_index].length) {
output.innerHTML = "";
text_index++;
if (text_index === texts.length) {
text_index = 0;
}
letter_index = 0;
} else {
output.innerHTML += texts[text_index][letter_index];
letter_index++;
}
});
</script>
```
See a demo of the above [here](https://demos.prussiafan.club/demos/fake-typing-effect).

156
posts/month_start_unix.md Normal file
View File

@@ -0,0 +1,156 @@
I came across a problem while making a new faucet for Astral Credits. This faucet had a limited amount of claims each month, so once that amount of claims were made, the faucet would stop dispensing coins for the rest of the month. So, an useful feature to have would be a countdown on the page telling users when a new month would begin and faucet claims would be reset.
The beginning of the month would depend on your timezone, but we want the faucet to reset at the same time for everyone. The obvious solution is to make the faucet reset on the beginning of the month in the standard UTC timezone.
Now, for writing the code for the countdown, I could just use Javascript's built in `Date` class. This is a slightly modified version of the code I came up with:
```js
function get_next_month_unix() {
let current_date = new Date();
//get Date object set to the beginning of the next month
//if current month is january, next month will technically give the date of december 31st midnight but that's fine since that's the same time as january 1st 00:00:00
let next_month = new Date(Date.UTC(current_date.getUTCFullYear(), current_date.getUTCMonth()+1));
//get difference in seconds between current time and the start of the next month
return (next_month.getTime() - current_date.getTime()) / 1000;
}
setInterval(function() {
let seconds_until = get_next_month_unix();
//... rest of the code omitted
}, 1000);
```
This works perfectly fine, but wouldn't it be cool if we could do this, without using `Date.UTC()`?
Did I hear someone say "Not really"? Get out!
Anyways, Unix time starts on 00:00 UTC on January 1st, 1970. So to find the Unix timestamp at the start of a month, we would see how many years it has been since 1970, and add the number of years times the number of seconds in a year. Then, we would see what number month it is, and add the number of months since the beginning of the year times the number of seconds in a month. We don't need to worry about days or hours or seconds, since we are only calculating the Unix timestamp of the start of the a month (which is the 1st day, 0 hours and 0 minutes and 0 seconds).
Here's the code:
```js
function get_next_month_unix() {
let current_date = new Date();
let current_year = current_date.getUTCFullYear();
let current_month = current_date.getUTCMonth();
let next_year = current_year;
let next_month = current_month + 1;
//this time next month being january needs to be properly handled
if (current_month == 11) {
//if december, next year is +1 and month is 0
next_year = current_year + 1;
next_month = 0;
}
let unix_timestamp = 0;
//years since 1970 * seconds in a year
unix_timestamp += (next_year-1970)*(60*60*24*365);
//months * seconds in a month
unix_timestamp += next_month*(60*60*24*30);
return unix_timestamp;
}
```
But wait! Months don't always have 30 days. Oops.
That's not too hard to fix. We can just hardcode in a object that stores how many days each month has:
```js
let days_months = {
"0": 31,
"1": 28,
"2": 31,
"3": 30,
"4": 31,
"5": 30,
"6": 31,
"7": 31,
"8": 30,
"9": 31,
"10": 30,
"11": 31
};
function get_next_month_unix() {
let current_date = new Date();
let current_year = current_date.getUTCFullYear();
let current_month = current_date.getUTCMonth();
let next_year = current_year;
let next_month = current_month + 1;
//this time next month being january needs to be properly handled
if (current_month == 11) {
//if december, next year is +1 and month is 0
next_year = current_year + 1;
next_month = 0;
}
let unix_timestamp = 0;
//years since 1970 * seconds in a year
unix_timestamp += (next_year-1970)*(60*60*24*365);
//months * seconds in a month
for (let i=0; i < next_month; i++) {
unix_timestamp += 60*60*24*days_months[String(i)];
}
return unix_timestamp;
}
```
And don't forget leap days...
Leap days are apparently on years that are divisible by 4, with the exception being if they are divisible by 100 but not 400.
```js
let days_months = {
"0": 31,
"1": 28,
"2": 31,
"3": 30,
"4": 31,
"5": 30,
"6": 31,
"7": 31,
"8": 30,
"9": 31,
"10": 30,
"11": 31
};
const is_leap_year = (year) => year%4 == 0 && (year%100 != 0 || year%400 == 0);
function get_next_month_unix() {
let current_date = new Date();
let current_year = current_date.getUTCFullYear();
let current_month = current_date.getUTCMonth();
let next_year = current_year;
let next_month = current_month + 1;
//this time next month being january needs to be properly handled
if (current_month == 11) {
//if december, next year is +1 and month is 0
next_year = current_year + 1;
next_month = 0;
}
let unix_timestamp = 0;
//years since 1970 * seconds in a year
unix_timestamp += (next_year-1970)*(60*60*24*365);
//add leap days
for (let year=1970; year < next_year; year++) {
if (is_leap_year(year)) {
unix_timestamp += 60*60*24;
}
}
//months * seconds in a month
for (let i=0; i < next_month; i++) {
unix_timestamp += 60*60*24*days_months[String(i)];
//if feburary, and is leap year, add another day
if (i == 1 && is_leap_year(next_year)) {
unix_timestamp += 60*60*24;
}
}
return unix_timestamp;
}
```
At this point, while thinking about leap days, I realized one huge problem: [leap seconds](https://en.wikipedia.org/wiki/Leap_second). It's a pretty bizzare concept.
Time is defined by the rotation of the Earth and Earth's orbit around the sun, which does not take a constant amount of time, because the orbit changes or something like that. Don't ask me, I'm not an astronomer. But since there can only be 24 hours in a day, sometimes the difference between our measured time (aka "precise time") and the real time (aka "solar time") can drift, and it needs to be corrected.
So, similar to how sometimes leap days happen, the international time keeping authorities (known as the "International Earth Rotation and Reference Systems Service"), occassionally issue leap seconds (if a leap second is issued, instead of the second after 23:59:59 being 00:00:00, it wil be 23:59:60). But unlike leap days, the issuance of leap seconds cannot be predicted, and does not follow any pattern, making it a huge pain in the ass to deal with. There would be no practical way to account for leap seconds (hardcoding all the leap seconds in, and update them when new leap seconds are announced is not practical^citation needed^), so I thought I had to give up.
Luckily, I did a quick [search](https://stackoverflow.com/questions/16539436/unix-time-and-leap-seconds), and it turns out Unix time **ignores leap seconds**, so the above code works correctly. Yay!

View File

@@ -0,0 +1,21 @@
Recently, I've been working on a discord bot game for Beer Goggles NFT on Algorand.
The specifics aren't too important, but essentially the game works like this: A game is started by an admin, and a secret number of hp is specified. Then, players can click a button, and depending on the amount of NFTs they hold, they will do "damage". All the damage is added up, and the person who crosses the secret number of hp wins. Like a pinata. Or in the case of our bar themed game, a huge opaque mug of beer that is passed around, with the goal being the one to finish the drink.
Now, onto the more technical details. Whenever a user clicks the button, the callback for the button interaction event is run.
First, the program reads the database (MongoDB) and sees the current hp left for the current game. If the current hp is less than zero, or a game over flag is set, the user is notified that the game is over, and the click does nothing. If that isn't the case, it then calculates the damage done by the player (a combination of luck, the amount of NFTs they hold, and powerups they bought). The damage done is subtracted from the hp (new hp is written to the db). Finally, the program checks if the user has won (hp at or under 0). If so, it ends the game and announces the winner.
However if one player clicks, then another player clicks milliseconds after, in some cases there just hasn't been enough time for the db writes to take place, and so there can be multiple winners. This is **bad**!!!
![This is kinda bad, a screenshot of two winners](/images/screenshot_double_win.png)
The main problem is, the two functions being run at the same time aren't aware of the existence of the other, and can't communicate to ensure only one winner. I tried a variety of methods, like adding another check to make sure the game didn't end already. None of it worked, unfortunately.
What did work though, is adding a random delay using `setTimeout` and `Math.random`, if the program thought the user won (`hp <= 0`). After the random delay, a global array variable would be looked at. If the array was empty, then the winner would be announced, and something (doesn't matter what) would be added to the array. I'm not sure why I made it an array, and not an dictionary, but it worked^tm^ (only one game can be run at a time, but if the bot had multiple games running, a dictionary with the keys as game ids set when the winner was found would work better). I probably had a good reason at the time, or at least fooled myself into thinking I did. Anyways, so if there was another winner about to be announced, the program would see the array was not empty, and not announce the extra winner(s).
Technically, if the random delay was the same or only a few milliseconds different, the global variable could be looked at the same time, and two winners (or more) could still be announced.
... let's not worry about that
> (A quick update: in several dozen games, after the fix, the two winner situation never happened again. It wasn't elegant and it was a dumb solution, but it worked! Maybe there was a better solution by fiddling with the database settings, like making database calls queue one at a time?)

BIN
static/images/c/eve.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB