Wednesday, 26 February 2020

The Rise of Canvas and WebAssembly

Before the time of Canvas and WebAssembly there were these kinds of web embeds:
  • ActiveX - C/C++ code, for browsers on Windows only
  • Flash/Flex - ActionScript code, for all platforms
  • Java Applet - Java code, for all platforms
  • Java FX - Java code, for all platforms
  • And some more
Since the introduction of Canvas in HTML5, most of all embeds can be done with 'canvas' tag and JavaScript; browsers JIT-compile JS to native code but no types, so it's slow.

However, for high performance, WebAssembly is, near-native performance. WebAssembly works in its own embed (window). WebAssembly has a drawback: no simple way to access DOM presently.

Solutions to choose:
  • JS/Canvas: Draw UI with something like Zebkit, or raw canvas APIs
  • C++(Emscripten)/Canvas: Draw UI with Qt, or raw OpenGL (browser renders as WebGL)
  • Basically go for these canvases only when complex graphics, or native performance needed.
Compile to WebAssembly with:
  • C/C++: Emscripten (WebGL, Qt, etc.)
  • Python, Rust: Google will tell :)
Hello World in Emscripten:

1) Download
git clone https://github.com/emscripten-core/emsdk.git
cd emsdk
./emsdk install latest
./emsdk activate latest
source ./emsdk_env.sh

2) Check version
em++ -v

3) Hello World (hello.cpp)
#include <iostream>
using namespace std;
int main(int Argc,char* Args[]){
  cout <<"Hello!" <<endl;
}

4) Build (output files: .wasm, .js, .html)
em++ hello.cpp -o hello.html

5) Config web server
micro /etc/nginx/mime.types
#Add 1 line to types:
application/wasm wasm;

6) Edit /etc/hosts, create .conf file in /etc/nginx/conf.d
127.0.0.1 hello.local

7) Clone hello.html to show canvas only
cp hello.html hello.custom.html

8) Open web browser to http://hello.local/hello.custom.html

Reference:

Monday, 24 February 2020

The Easy Understanding of YAML

YAML compared to JSON is like Python compared to JavaScript. YAML is smarter with tree of nodes instead of opening and closing blocks.

For a parent-child relation, it is read with the parent first in JSON:
  • Starting with { is an object
  • Starting with [ is an array
However, with the same parent-child relation, it is read with the child first in YAML:
  • A node followed by ':' (colon) means the parent is an object
  • A node starts with '- ' (dash and space) means the parent is a list
  • A node starts with '- ' (dash and space) and followed by ':' (colon) means it's starting key of an object and the parent is a list.
  • Indent below an object key to make child object key.
Examples of YAML
Example 1. Root is object
Foo: "value1"
Bar: "value2"

Example 2: Root is list
- "value1"
- "value2"

Example 3: Object (root) of objects
Foo:
  Child1: "value1"
  Child2: "value2"

Example 4: Object (root) of lists
Foo:
  Child1:
  - "value1"
  - "value2"
  Child2:
  - "value3"
  - "value4"

Example 4: List of items
List:
- "value1"
- "value2"

Example 5: List of objects
List:
- Foo: "value1"
  Bar: "value2"
- Foo: "value3"
  Bar: "value4"

Friday, 21 February 2020

Change Jupyter (Not JupyterLab) Terminal Background Colour and Foreground Colour

Jupyter (Classic), not the new JupyterLab has black background terminal. The terminal is a canvas and stuff are drawn inside, CSS won't work. To change the terminal:

1) Install Tampermonkey for browser

2) Go to OpenUserJS.org and create account

3) Add this script:
// ==UserScript==
// @name     localhost:8888
// @include  http://localhost:8888/*
// @run-at   document-start
// @license  MIT
// ==/UserScript==

setTimeout(()=>{
  terminal.term.setOption(
    "theme",
    {background:"#bbbbbb",foreground:"black"}
  );
},3000);
//EOF

Public Tampermonkey script:
https://openuserjs.org/scripts/datdinhquoc/localhost8888

Thursday, 20 February 2020

Work with 2D Array and Floating-point Numbers in Bash

Bash supports only 1D array, however, there's a work-around, for example:

List=("value00 value01" "value10 value11" "value20 value21");

#Example I,J
I=1;
J=1;
Row=(${List[I]}); #Wrap in parentheses
Cell=${Row[J]};

Bash supports only integers, the work-around to do floating-point maths is creating new functions based on something like Perl:

function + {
  perl -e "print($1 + $2)";
}

function - {
  perl -e "print($1 - $2)";
}

function x { #Can't use *, Bash expands * to files
  perl -e "print($1 "'*'" $2)";
}

function / {
  perl -e "print($1 / $2)";
}

function p { #A to power B
  perl -e "print(($1) ** $2)"; #Parentheses for negative values
}

function random {
  printf $(/ $RANDOM 32767);
}

#Examples of using those functions:
echo $(+ $(random) $(random));
echo $(- $(random) $(random));
echo $(x $(random) $(random));
echo $(/ $(random) $(random));
echo $(p $(random) $(random));

Tuesday, 18 February 2020

SSH Port Forwarding for Jupyter without Wasting a Terminal Just to Channel

When launching Jupyter on server, Jupyter generates a token and it is used as access token to the Jupyter notebook.

However, the URL with the generated token is accessed through 'localhost' (at the server), and Google Colab only supports adding 'localhost' at desk machine.

In order to have server-based Jupyter added as run-time to Colab, pipe the port between desk machine and server:

ssh -L 8888:localhost:8888 SOMESERVER

However, the command above will waste a whole terminal just to do port forwarding (port channelling), 2 lines below save a whole terminal :)

#!/bin/bash
sudo pkill -f localhost:8888 & wait $!;
ssh -fNL 8888:localhost:8888 SOMESERVER;
#EOF

The option 'L' is for port forwarding as usual.
The option 'f' is to but the 'ssh' to background.
The option 'N' is a must to go along with option 'f'.

Use Colab with Private Server Instead of Free Run-time Environment

Google Colab by default provides free run-time environment, in order to connect to personal or private servers, do these:
  1. Install jupyterlab on server:
    1. ssh MYSERVER
    2. sudo yum install jupyterlab
  2. Open terminal, create SSH port channelling:
    1. ssh -L 8888:localhost:8888 MYSERVER
    2. Leave this terminal open
  3. Open another terminal, start Jupyter
    1. ssh MYSERVER
    2. jupyter notebook [THIS WON'T WORK]
    3. jupyter notebook like in this guide:
      https://research.google.com/colaboratory/local-runtimes.html
    4. Get the localhost URL shown
  4. Switch to Colab to connect
    1. Click the run-time box at top-right
    2. Click 'Connect to local run-time'
    3. Use the URL gotten above.
    4. Edit the IPython notebook as usual
  5. To edit other files:
    1. Open new browser tab
    2. Paste the localhost link above
    3. Navigate and click a file to edit.

Use 'expect' in Bash Script to Automate Entering Inputs

expect <<HEREDOC
  spawn some long command;

  expect {
    "some text 1" {
      set timeout -1;
      send "some input\r";
      exp_continue;
    }
    "some text 2" {
      set timeout -1;
      send "some input\r";
      exp_continue;
    }
    "some text 3" {
      set timeout -1;
      send "some input\r";
      exp_continue;
    }
  }
HEREDOC

Nginx Config File for Web Service with HTTPS Cert Provided by Let's Encrypt

Certbot has a few modes to create free certs:
  • --standalone
    • Certbot needs port 80 to start a temporary server for domain verification
    • Nginx will need to be shut down for a while
    • Not suggested method, big down time during creating or renewing certs
  • --webroot
    • Certbot won't start temporary server
    • Nginx stays intact
    • Suggested method, fast verification, no down time.
  • --certbot-dns-SOMESERVICE
    • Certbot supports domain verification by DNS
    • Some supported plugins available fro Google Cloud, Amazon AWS, etc.
      • --certbot-dns-route53
      • --certbot-dns-google
      • --certbot-dns-digitalocean
      • etc.
    • Not suggested method, DNS verification is slow
Nginx config file for HTTP/HTTPS with cert by Let's Encrypt, using --webroot method,
File /etc/nginx/conf.d/MYDOMAIN.EXT.conf:
server {
  listen 80;
  server_name MYDOMAIN.EXT;

  listen 443 ssl;
  ssl_certificate /etc/letsencrypt/live/MYDOMAIN.EXT/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/MYDOMAIN.EXT/privkey.pem;

  location /.well-known/acme-challenge {
    alias /usr/share/nginx/html/.well-known/acme-challenge;
  }

  location / {
    if ($scheme = "http"){
      return https://$host$request_uri;
    }

    root /some/dir;
    #OR:
    #proxy_pass http://localhost:SOMEPORT;

    #OR:
    #if ($host = "...")         { proxy_pass ... }
    #if ($host ~ "(...)|(...)") { proxy_pass ... }
  }
}


1) Create the file above, comment out the 3 SSL lines, and restart Nginx:
sudo systemctl restart nginx

2) Get cert, and run:
sudo certbot certonly --webroot --webroot-path /usr/share/nginx/html \
--cert-name MYDOMAIN.EXT --domains MYDOMAIN.EXT

3) Got the cert, enable back the 3 SSL lines, and restart Nginx:
sudo systemctl restart nginx

4) Renew cert any time later with:
sudo certbot renew --webroot --webroot-path /usr/share/nginx/html \
--cert-name MYDOMAIN.EXT --expand --domains MYDOMAIN.EXT

Monday, 17 February 2020

Route Domains to Different Service Ports Using Pure Google Cloud Balancer or Nginx

Solution 1: Use Google Balancer for simple mapping domains to service ports:
  1. Create different backends for different service ports
  2. Create host and path rules for mapping domains to backends
  3. Create the frontend (proxy) to receive requests
  4. Notes:
    1. Client -> Proxy -> Host/path rules -> Backend:Port
    2. Use SSL/TLS cert on frontend, not necessary elsewhere
  5. Pros:
    1. Multiple healthchecks for multiple services
  6. Cons:
    1. No advanced config on proxy
Solution 2: Use Google Balancer + Nginx for advanced mapping domains to service ports:
  1. Create a single backend to Nginx at port 80
  2. No need host/path rules
  3. Create frontend (proxy) to receive requests
  4. Config Nginx on all instances to add custom configurations, e.g. HTTP Upgrade for socket.io, etc.
  5. Notes:
    1. Client -> Frontend (Proxy) -> Skip:Host/path rules --> Nginx --> Service:Port
    2. Use SSL/TLS cert on frontend, not necessary elsewhere.
  6. Pros:
    1. Advanced config on Nginx proxy
  7. Cons:
    1. Only a single healthcheck, when deploying services on an instance, shutting down Nginx is required to notify the healthcheck; all services on this instance is down at the same time. When all services on this instance are up back, turn on Nginx to notify healthcheck again.

Saturday, 15 February 2020

XMinG for Local Use and XMinG for X11 Forwarding

Windows 10 has WSL (Windows Subsystem Linux) and it launches a terminal by default. Here's how to run Linux GUI apps from that terminal:
  • On Windows, install XMinG
  • In terminal:
    • Open ~/.bashrc
    • Add a line: 
      • export DISPLAY=0.0
    • Run: 
      • source ~/.bashrc
    • Test: 
      • sudo yum install xclock -y && xclock
VNC is boring with all remote apps shown in a virtual display rectangle, here's how to use X11 Forwarding to open remote apps in separate windows:
  • Install and test XMinG as above.
  • Enable X11 Forwarding on server:
    • ssh someserver
    • sudo micro /etc/ssh/sshd_config
    • Find and set these:
      • X11UseLocalhost no
      • X11Forwarding yes
    • sudo systemctl restart sshd
    • sudo yum install xauth -y
    • logout
  • Run test:
    • ssh -Xv someserver
    • It says: ".Xauthority does not exist", run again:
    • ssh -Xv someserver
    • xclock