I’ve always wanted to write my own tetris clone. I wrote one in javascript. To give it a retro feel, I implemented the game using text graphics.
Archives
All posts by Justin A. Parr
Some ass hat took it upon itself to kill another human being because it didn’t agree with Charlie Kirk’s opinion.
This is a reprehensible act of terrorism designed to suppress free speech, committed by a deranged minority in a pathetic attempt to force the mainstream in to accepting their ridiculous ideology. In fact, this is more of a religion than an ideology, since religion requires nothing but faith.
So in addition to being an act of terrorism, this was also a religious hate crime aimed at mainstream America.
I choose to draw the line here.
I choose to reject some woke nutbag’s vision of what my world should be. I choose to reject the premise that I shall not speak up, lest I be struck down.
Please join me in celebrating Charlie Kirk the human being. Please join me in sending prayers and well wishes to his family. Please join me in rejecting ideological and religious extremism in all forms.
To those who disagree with me, I sincerely wish you a happy, peaceful life, and a peaceful soul. Please choose the path of peace. We need to build a world where people can use reason and logic, and disagree with eachother without killing eachother. We need to stop the hatred and the violence, and live with eachother in peace.
My old work laptop, a HP, was a complete piece of crap. When they sent me my new laptop, as a bit of a Dell fanboy, I was excited to see that it was a Dell. However, I quickly began to question some of the design choices. After using it for a couple of weeks, I have solidly decided that the Dell Latitude 7450 Laptop…Thing is badly designed.
Camera technology has evolved over the last couple of decades to the point where consumer-grade cameras are decent quality, but fairly inexpensive, and therefore cameras have become fairly pervasive. In general, having a camera is a good thing – it is a way to increase your awareness, and if the camera is being recorded, the camera can be a witness on your behalf. However, in certain situations, having a camera can work against you as well. We will explore several scenarios where your privacy and / or rights could be compromised, as well as technology recommendations for protecting them.
I’ve been meaning to get my thoughts down for quire some time.
Mrs. ParrTech and I went to Vegas last year for our 30th anniversary. After having visited Vegas many times previously, I was completely disappointed, and here’s why.
Excel – Number of Sundays – A better Answer
I looked up how to count the number of Sundays between two dates…. the so-called answer shocked me. There are a couple of popular answers, but they are horribly inefficient.
Let me show you a better way…..
Update 4/22/2025
Due to a severe copy and paste error, the formulas were completely wrong. 8-(
These have now been corrected.
Solution
Let’s say we have the following cells:
A | B | |
1 | Start | 1/1/2025 |
2 | End | 5/1/2025 |
3 | Which Day | 1 |
We will follow the Excel convention, where Sunday = 1, to find the number of “1” days (cell B3) between 1/1/2025 (cell B1) and 5/1/2025 (cell B2).
Between the two dates:
=INT((B2-(B1+B3-WEEKDAY(B1)+7))/7)+1
Correctly returns 17
Between and including the two dates:
=INT((B2-(B1+B3-WEEKDAY(B1)+7))/7)+1+IF(WEEKDAY(B1)=B3,1,0)
Correctly returns 17. If we were to change B1 to 1/5 (a Sunday), the result would be 16 without the extra IF term.
For a more detailed explanation…
Cache Busting using Javascript
Problem
Google Chrome (and possibly, other browsers) don’t properly honor the Cache-Control header.
If you are on Page A, click a link for Page B, then hit the back button to go back to Page A, Chrome uses a pre-rendered, cached version of Page A, which may now have stale content.
Action | Location |
---|---|
Start | Page A 8:05 AM |
Click link on Page A | Page B 8:10 AM |
Hit browser back button | Page A 8:05 AM |
At this point, Page A is basically static. Any dynamic content won’t be refreshed, even if it executes in Javascript.
Disrupting this behavior is known as “cache busting”.
Solution
Add this Javascript to your page’s <HEAD> section:
<SCRIPT> function nocache(){ var tc3=new Date(); var delta=tc3-tc1; if (delta>2000) { window.location.reload(); } else { tc1=tc3; } } var tc1=new Date(); setInterval(nocache,1000); </SCRIPT>
How it Works
When the page first executes, it creates a Javascript variable tc1 with a current timestamp.
Then, it sets up a timer callback function, nocache(), which executes every 1 second.
When nocache executes, it creates a new timestamp (tc3), and if the difference between the two is greater than 2 seconds, it reloads the current page. If not, it updates the tc1 timestamp to current.
The result is that if the page remains static for more than 2 seconds, it will refresh. However, as long as the page is active, it keeps updating the timestamp in tc1 instead.
If you click the link to Page B, wait 2 or more seconds, then hit the browser’s back button, the timestamp in tc1 will be the point in time from when the link was clicked (more than 2 seconds ago). One second after you hit the back button, the nocache function sees that tc1 is more than 2 seconds out of date and reloads the page. If the page successfully reloads, tc1 is updated in the process. If not, it simply retries the reload every 1 second.
Also, if your page uses JSON or XML to dynamically render content, the nocache timer function can simply call your page’s update function rather than reload the entire page.
Conclusion
When you hit the browser’s back button, Chrome tries very hard to use a pre-rendered page from cache rather than use the Cache-Control header or contact the server to see if the page is stale (which it should be doing). This means that when you hit the back button, any dynamic code has already executed, and the page picks up where it left off from a script execution standpoint. Unfortunately, this includes any events that have fired, which means that the pre-rendered version of the page is basically static.
I have seen other solutions that use the onpageshow event, or other event hooks. However, I have found these to be unreliable in Chrome for cache busting. In contrast, the timer hook must be honored for basic page functionality, and therefore can’t simply be killed off like other events.
A side effect of this approach is that if the server is unavailable and the page tries to refresh, it will get stuck in a refresh loop until the server is available again. This is not necessarily a negative behavior, but could easily be fine tuned using a counter, for example, to only try to refresh a set number of times and then stop. During page load, “retries” is set to some number, n. “Retries > 0” is then added as a condition to the if block, which then decrements retries during each execution. If retries hits zero, it updates tc1 to current, which stops all attempts. In another variation, retries can be its own, outer “if” block, so that some other exit action can be executed, for example, alerting the user that the server is offline and the page is stale.
A fleshed-out version would look like this:
<SCRIPT> function nocache() { var tc3=new Date(); var delta=tc3-tc1; if (retries>0) { // Normal action if (delta>2000) { retries-=1; window.location.reload(); } else { tc1=tc3; } } else { // When retries hits zero, set error text, make the element visible, and disable the nocache timer var e=document.getElementById("ErrorText"); e.innerHTML="The server is offline and this page is dead. Have a nice day."; e.style.visibility="visible"; clearInterval(nocachetimer); } } var tc1=new Date(); var retries=3; var nocachetimer=setInterval(nocache,1000); </SCRIPT> <DIV ID=ErrorText STYLE='visibility:hidden; display:block;'> </DIV>
I hope you find this useful, and thanks for reading!
Update, 5/14/2023: Version 3.2
Update, 5/11/2023: Version 3.1. Original: Version 2
I wrote a javascript calculator while I was waiting for something the other day. Here it is:
Permalink: Here
Technical Details
- Single, self-contained HTML file with embedded CSS and Javascript.
- The display width is configurable via a variable – currently 20 digits
- The top line is a “register” – normally this would be hidden on a desktop calculator. The two variables, “register” and “display” are global, which simplifies the architecture.
- The buttons are created using a function
- Binary math functions are performed by a wrapper that sanitizes the input values and then performs a callback to the underlying math operation – the pointer to the callback function is passed via onclick.
- Unary math functions are basically handled the same as binary operations, where onclick calls a wrapper, and the wrapper executes a callback.
To Do
(Updated, 5/11/2023)
Add MS, MR, M+, and M-, which will require a separate register.Add a configurable table of constants.Tool tips with enable/disable button.- Hex and binary functions, although these might be a separate calculator
Update: I think I will just make a dedicated programming calculator the next time I’m bored :-)
Funny Story about 3.1 vs 3.2
I uploaded version 3.1, and patted myself on the back for having done such a great job. Right-click, save as HTML, fire it up in Chrome, and…everything was rendering twice.
What happened??
The UI is dynamic, but the saved version of the page had BOTH a static copy of the dynamically-generated HTML, as well as the javascript code to dynamically generate the HTML. So every UI element was rendered TWICE. Worse, if you modify the Javascript at the top of the file to alter the constants or the display size, you would have one copy that’s correct because it’s dynamic, but the static copy would still be wrong.
Interestingly, if you View Source and save from there, it won’t have that problem, but that’s not what I was after.
To fix this, I changed from document.write to using extra SPANs for each block of UI elements, and setting innerHTML. Despite the fact that saving the file includes a static copy of the HTML, the dynamic code simply overwrites it each time the page is loaded. So if you change a Javascript variable and reload, the dynamic code blows away the static HTML and replaces it with a correct version.
Do you like it? Feel free to copy it. Click the permalink. Then right-click the calculator, and select “Save as html”.
Ideas or suggestions? Please feel free to leave me a comment.
After 7 months of continuous issues, I think I finally beat the problems with the front gate, but the way I did it might surprise you.
Two bad lines of code took this entire site down. Here is what you can learn from my mistake.