Skip to content

Learning pieces

The goal of this section is to group issues that I faced during code development and its correspondent solutions.

Linux system admin

About systemd

systemd is the linux equivalent to mac's launchd. It is a service manager that offers interesting tool for system administrators, namely, process initialization.

Here are excellent articles about systemd: 1. Linode - What is systemd 2. Freedesktop - systemd

Set up ssh on Ubuntu

More information here

# Install the openssh-server
sudo apt update
sudo apt install openssh-server

# After installation, the service is started automatically. Check it with
sudo systemctl status ssh

# Tell the firewall to allow ssh connections (using the ubuntu firewall manager tool `ufw`)
sudo ufw allow ssh

Listen to open tcp ports

More information here

netstat -lntu

This will print all listening sockets (-l) along with the port number (-n), with TCP ports (-t) and UDP ports (-u) also listed in the output.

Include a exception rule in the ubuntu firewall

sudo ufw allow 4958

Other linux distributions

iptables -A INPUT -p tcp --dport 4958 -j ACCEPT
sudo service iptables restart
sudo systemctl restart iptables

Check the status of an open port

nmap localhost -p 4958

MAC system admin

Starting up services on startup for MAC

Article

HTML

Text area starting at random position

I was puzzled by this problem. I thought that was related with some css properties such as align:center. The reason was extra spaces in the declaration of the textarea input in the html.

To solve this problem, instead of

<textarea>

</textarea>
write as
<textarea></textarea>

CSS

Updating CSS variables programmatically

I would like to update the color pallete of my icons programmatically. In order to do that, I need to change the css variables that I have defined. I can do that by accessing the style attribute of document.documentElement.

let root = document.documentElement;
function set_pallete_brazil() {
  root.style.setProperty('--pallete-1', '#00520c');
  root.style.setProperty('--pallete-2', '#f5c800');
  root.style.setProperty('--pallete-3', '#ddecdd');
  root.style.setProperty('--pallete-4', '#1e5fba');
  root.style.setProperty('--pallete-5', 'white');
}

Mask + Clipping

I am using the Mask+Clipping technique to programmatically change the color pallete of icons.

The technique consists in creating a <div> element and set a background on it (the dynamic color pallete is added here). With the --webkit-mask property, I set the image file containing the mask. The latter is typically a png file with transparent background and the mask colored in black.

In my case, I also need to cut part of a second masked object to create the effect of the object inside the lens.

<div class="button-image-common lens"></div>
<div class="button-image-common zoomed-interrogation-mark circle-clip"></div>

.lens{
  background-color: var(--pallete-4);

  -webkit-mask-image: url("/games/assets/icons/masks/mask-lens.png");
  -webkit-mask-repeat: no-repeat;
  -webkit-mask-size: contain;
  z-index:2;
  top: calc(25%);
  left: calc(-15%);
}

.circle-clip{
  --b-clip-circle-radius: calc( 0.27*var(--b-width) );
  --b-clip-circle-center-x: var(--b-clip-circle-radius);
  --b-clip-circle-center-y: var(--b-clip-circle-radius);

  clip-path: circle( var(--b-clip-circle-radius) at var(--b-clip-circle-center-y) var(--b-clip-circle-center-x));
}

.zoomed-interrogation-mark{
  background-color: var(--pallete-4);

  -webkit-mask-image: url("/games/assets/icons/masks/mask-interrogation.png");
  -webkit-mask-repeat: no-repeat;
  -webkit-mask-size: contain;
  -webkit-mask-position: calc(0.2*var(--b-width)) 0px;

  z-index:2;
  top: calc(31%);
  left: calc(20%);
  height: 50%;
}

The mask property: https://developer.mozilla.org/en-US/docs/Web/CSS/mask

Web Standards

Specifying IPV6 address in browser

iPut in between brackets. For example, http://[ipv6].

Setting up a domain

  1. Register a domain: I've registered barriguinhas.fr in google domains.
  2. Register a dynamic DNS in Google Domains. In the menu, click on DNS.
    Next, look for Show advanced parameters.
    Click in the Dynamic DNS tab and register a DNS rule. For example, I've created a rule that maps word-detective.barriguinhas.fr to the IP address of my home router.
  3. Update the mapped IP Address. You can do via a https request like the following:
    https://username:password@domains.google.com/nic/update?hostname=subdomain.yourdomain.com&myip=1.2.3.4
    The username and passwords are generated in the google domains webpage. Nonetheless, the best is to set up ddclient that automatically updates that for you.

Certificate authority and HTTPS

TSL

Create a self-signed certificate authority

openssl req -x509 -sha256 -days 1825 -newkey rsa:2048 -keyout rootCA.key \
-out rootCA.crt

Generate the private key for my server

openssl genrsa -out word-detective.key 2048

Create a certificate signing request (csr)

openssl req -key word-detective.key -new -out word-detective.csr

Create a configuration file

authorityKeyIdentifier=keyid,issuer                                             
basicConstraints=CA:FALSE                                                       
subjectAltName = @alt_names                                                     
[alt_names]                                                                     
DNS.1 = localhost

Sign my certificate (via my .csr) with my certificate authority

openssl x509 -req -CA rootCA.crt -CAkey rootCA.key -in word-detective.csr \
-out word-detective.crt -days 365 -CAcreateserial -extfile word-detective.ext

Add the certificate authority in firefox

Setup the https server

const options = {
    key: fs.readFileSync('certificates/word-detective.key'),
    cert: fs.readFileSync('certificates/word-detective.crt')
};

let httpsServer = https.createServer(options,app);
httpsServer.listen(4958);

More info in:https://www.baeldung.com/openssl-self-signed-cert

And also in:https://nodejs.org/en/knowledge/HTTP/servers/how-to-create-a-HTTPS-server/

Programmatically uploading files

The easiest way is to use the FormData object which is available in most browsers. An instance of FormData passed as the body of a fetch call will behave exactly as if you are sending a form with encoding set to multipart/form-data.


      let text = `#text#`;
      const formData = new FormData();
      formData.append('text_file', new Blob([text]));

      return fetch('/api/puzzle-from-file', {
        method: 'POST', 
        mode: 'cors', 
        cache: 'no-cache', 
        credentials: 'same-origin', 
        redirect: 'follow', 
        referrerPolicy: 'no-referrer', 
        body: formData 
      })

In this case, the fetch will automatically fill up the content-type field. Including the boundary token.

Read more about the FormData object: https://developer.mozilla.org/en-US/docs/Web/API/FormData

More about CORS: https://javascript.info/fetch-crossorigin

Content-type and fetch method

When sending a file, we should use the multipart/form-data content type. However, there is an extra field that need to be set, which is the boundary field. It is in fact a delimiter, as it is the & in get requests. The boundary tells you when an input field starts and when it ends.

If you do not manually set the Content-Typein the fetch method, then it automatically fills up for you. But if you write something like

Content-type: multipart/form-data
You'll get a bad request error saying that the boundary is missing.

https://stackoverflow.com/questions/3508338/what-is-the-boundary-in-multipart-form-data


POST /foo HTTP/1.1
Content-Length: 68137
Content-Type: multipart/form-data; boundary=---------------------------974767299852498929531610575

-----------------------------974767299852498929531610575
Content-Disposition: form-data; name="description"

some text
-----------------------------974767299852498929531610575
Content-Disposition: form-data; name="myFile"; filename="foo.txt"
Content-Type: text/plain

(content of the uploaded file foo.txt)
-----------------------------974767299852498929531610575--

The MIME type: application/octet-stream is kind of a joker type. It is the basic type for binary files.

More about Content-Type header here. Mime types: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types

Form enctypes

enctype description
application/x-www-form-urlencoded Default. All characters are encoded before sent (spaces are converted to "+" symbols, and special characters are converted to ASCII HEX values)
multipart/form-data This value is necessary if the user will upload a file through the form
text/plain Sends data without any encoding at all. Not recommended

C++

Object slicing

Let A and B two classes such that B inherits from A. Object slicing happens in the following situation


A a;
B b;
a = b;

That is, when you try to assign the derived object o the base one. It is a natural thing to happen, since the base class may not have all the specialized members of B.

Apparently, there is no compiler flag that emits a warning when this happens. You can avoid that by making the assignment operator a virtual method.

Reading binary data from stdin

From: How to construct a c fstream from a posix file descriptor

AFAIK, there is no way to do this in standard C++. Depending on your platform, your implementation of the standard library may offer (as a nonstandard extension) a fstream constructor taking a file descriptor as input. (This is the case for libstdc++, IIRC) or a FILE*.

#include <ext/stdio_filebuf.h>
#include <iostream>
#include <fstream>
#include <string>

using namespace std;

int main()
{
    ofstream ofs("test.txt");
    ofs << "Writing to a basic_ofstream object..." << endl;
    ofs.close();

    int posix_handle = fileno(::fopen("test.txt", "r"));

    __gnu_cxx::stdio_filebuf<char> filebuf(posix_handle, std::ios::in); // 1
    istream is(&filebuf); // 2

    return 0;
}

More on this here

Reading binary data from cin

I was not able to achieve this. It seems that cin is configured to interpret the input data as something non-binary, and by not doing that, it may interpret a sequence of bits as being the newline character or some other character that stops the reading. Nonetheless, I was not able to change cin to read in binary though.

Reading from cin after a pipe

In order to do this type of reading, I cannot use some functions provided by the api of istream. Namely, seekg and tellg. There is no definition of file position in a pipe stream.

More info in: https://stackoverflow.com/questions/53981505/cin-tellg-returns-1-when-receiving-input-from-a-pipe

Javascript

Promises error handling

Promises are great dealing with exceptions. Inside the executor function and also inside every handler (then method), we have an implicity try...catch block. Any exception that is thrown there will be catched by the next catch method in the promise chain.

let assets_promise = fetch(messages_json_location)
.then((response) => response.json())
.then((response_json) => {
  assets.messages = response_json;
})
.then(() => getPuzzle())
.then((puzzle_json) => {
  cm.set(JSON.stringify(puzzle_json));
  assets.puzzle = puzzle_json;
})
.then(() => new Promise(function (resolve) {
  resolve(assets);
}))
.catch( (error) => config.fatal_error_handler(error) );
}
In the snap above, each handler potentialy throws a different error. Whenever these errors are throw, the catch block is executed and I handled all of them in a single function config.fatal_error_handler.

Error handling

I am basically extending the builtin javascript object Error to create my custom errors; and I use instanceof to check the error type.

class MyError extends Error {
  constructor(message) {
    super(message);
    this.name = this.constructor.name;
  }
}

class NoPuzzleGenerated extends MyError {};

if (error instanceof NoPuzzleGenerated) {
  document.location.href = `/error/no-puzzle-generated?errorMessage=${error.message}`;
} else {
  document.location.href = "/error/500";
}

Page redirection

I was getting the following error with production code:

Error type: error to fetch

The error was caused everytime the recently_visited cookie was expired, and a redirection was made to the puzzle selector page. It happens that, even after the redirection instruction

window.location = new_address

the remaining of the code continue to execute. The, when it tried to fetch the assets, it raised the error, because the address of the assets is given via a relative path, and the page address has changed.

To solve the issue, I redefined the redirect_to_today_puzzle function. Instead, I named it should_redirect_to_today_puzzle and conditioned the fetch portion of the code to execute only when redirection was not done.