RUNNING AIX v7.2 VM ON QEMU HYPERVISOR ON AN UBUNTU HOST

This procedure documents setting up the latest available QEMU on Ubuntu in order to run an AIX v7.2 VM.
Most of the steps are from http://aix4admins.blogspot.com/2020/04/qemu-aix-on-x86-qemu-quick-emulator-is.html?m=1

The host in this case is an AWS t3.xlarge compute instance running Ubuntu 22.04.1 LTS (Jammy Jellyfish)
I also attached a secondary EBS volume (55G) to the instance which I mounted on /wip and where I stored all the relevant files.


- Login to the Ubuntu host and install QEMU:

root@ip-172-31-23-252:~# apt update -y
root@ip-172-31-23-252:~# apt install -y gcc make ninja-build
root@ip-172-31-23-252:~# wget https://download.qemu.org/qemu-7.2.0.tar.xz
root@ip-172-31-23-252:~# tar xvf qemu-7.2.0.tar.xz
root@ip-172-31-23-252:~# cd qemu-7.2.0/
root@ip-172-31-23-252:~/qemu-7.2.0# apt install libglib2.0-dev
root@ip-172-31-23-252:~/qemu-7.2.0# apt-get install -y libpixman-1-dev
root@ip-172-31-23-252:~/qemu-7.2.0# apt install ncurses-dev
root@ip-172-31-23-252:~/qemu-7.2.0# ./configure
// ALTERNATIVELY - build only PPC64 support: # ./configure --target-list=ppc64-softmmu --enable-curses --disable-gtk && make
root@ip-172-31-23-252:~# make
root@ip-172-31-23-252:~# make install


- Partition the secondary volume and format the file system:

root@ip-172-31-23-252:~# lsblk
NAME         MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
loop0          7:0    0 24.4M  1 loop /snap/amazon-ssm-agent/6312
loop1          7:1    0 55.6M  1 loop /snap/core18/2632
loop2          7:2    0 63.2M  1 loop /snap/core20/1695
loop3          7:3    0  103M  1 loop /snap/lxd/23541
loop4          7:4    0 49.6M  1 loop /snap/snapd/17883
nvme0n1      259:0    0    8G  0 disk
├─nvme0n1p1  259:1    0  7.9G  0 part /
├─nvme0n1p14 259:2    0    4M  0 part
└─nvme0n1p15 259:3    0  106M  0 part /boot/efi
nvme1n1      259:4    0   55G  0 disk
root@ip-172-31-23-252:~#
root@ip-172-31-23-252:~# fdisk /dev/nvme1n1
root@ip-172-31-23-252:~# partprobe
root@ip-172-31-23-252:~# mkfs -t ext4  /dev/nvme1n1p1
root@ip-172-31-23-252:~# blkid
/dev/nvme0n1p1: LABEL="cloudimg-rootfs" UUID="687fab62-1ba5-4282-890e-9266064f7d27" BLOCK_SIZE="4096" TYPE="ext4" PARTUUID="895d8984-5441-4c70-b87c-a6b6ebb8c95e"
/dev/nvme0n1p15: LABEL_FATBOOT="UEFI" LABEL="UEFI" UUID="B2B4-82AC" BLOCK_SIZE="512" TYPE="vfat" PARTUUID="0cf1c52c-98f5-48ae-8a07-fff782190e30"
/dev/loop0: TYPE="squashfs"
/dev/nvme1n1p1: UUID="a5051753-344e-43da-ba1f-cc785cab98b0" BLOCK_SIZE="4096" TYPE="ext4" PARTUUID="d816173f-01"
root@ip-172-31-23-252:~# vi /etc/fstab
root@ip-172-31-23-252:~# grep wip /etc/fstab
UUID="a5051753-344e-43da-ba1f-cc785cab98b0"  /wip  ext4  defaults 0 0
root@ip-172-31-23-252:~#
root@ip-172-31-23-252:~# mkdir /wip
root@ip-172-31-23-252:~# mount /wip


- Copy the AIX v7.2 ISO files to the Ubuntu instance. Please ensure you get it from a legal source.

root@ip-172-31-23-252:~# cd /wip
root@ip-172-31-23-252:/wip# mkdir AIX72ISOs
root@ip-172-31-23-252:/wip# cd AIX72ISOs/
root@ip-172-31-23-252:/wip/AIX72ISOs# scp -i ~/.ssh/wipalinux ubuntu@172.31.18.141:/wip/AIX72ISOs/aix_7200-04-02-2027_1of2_072020.iso .


- Create a disk for the AIX VM:
root@ip-172-31-23-252:~# cd /wip/
root@ip-172-31-23-252:/wip# qemu-img create -f qcow2 hdisk0.qcow2 20G


- Install AIX (you can change install settings e.g., to include SSH client and server). The installation tool approx 110 mins 
root@ip-172-31-23-252:/wip# qemu-system-ppc64 -cpu POWER8 -machine pseries -m 4096 -serial stdio -drive file=hdisk0.qcow2,if=none,id=drive-virtio-disk0 -device virtio-scsi-pci,id=scsi -device scsi-hd,drive=drive-virtio-disk0 -cdrom /wip/AIX72ISOs/aix_7200-04-02-2027_1of2_072020.iso -prom-env "boot-command=boot cdrom:"

   - NOTE: the VM will get stuck in a reboot loop at the end of installation. Use CTRL+C to terminate the VM
   
   
- Fix/solve the fsck64 issue to fix the reboot loop by booting the VM into maintenance mode:
root@ip-172-31-23-252:/wip# qemu-system-ppc64 -cpu POWER8 -machine pseries -m 4096 -serial stdio -drive file=hdisk0.qcow2,if=none,id=drive-virtio-disk0 -device virtio-scsi-pci,id=scsi -device scsi-hd,drive=drive-virtio-disk0 -cdrom /wip/AIX72ISOs/aix_7200-04-02-2027_1of2_072020.iso -prom-env "boot-command=boot cdrom:"
   - menu options to select:  1 to "define the System Console" > 1 for English > 3 for Maintenance mode > 1 to access root VG > 0 to continue > 1 to select VG/disk > 1 to "Access this Volume Group and start a shell"
  - NOTE: no keyboard BACKSPACE key, and don't use CTRL+C as that terminates the VM.

  # cd /sbin/helpers/jfs2
  # cp fsck64 fsck64.org

  - truncate the fsck64 exeutable binary file and replace content with shell script
  # > fsck64
  # cat > fsck64 << EOF
  #!/bin/ksh
  exit 0
  EOF
  #
  # cat fsck64
  #!/bin/ksh
  exit 0
  #

  - Alternative to the cat sequence above is to edit the fsck64 file after truncating it and add the 2 lines to the file:
  # > fsck64
  # export TERM=vt100
  # vi fsck64
  # cat fsck64
  #!/bin/ksh
  exit 0
  #


  - Shutdown the VM:
  #
  # sync; sync
  # halt


- Create a snapshot of the AIX O/S disk for backup purposes:
root@ip-172-31-23-252:/wip# qemu-img create -f qcow2 -b hdisk0.qcow2 -F qcow2 hdisk0.snap.qcow2 10G


- Boot the VM to AIX O/S 7.2 using the O/S disk, and accept license (I excluded cdrom since I no longer need it):
root@ip-172-31-23-252:/wip# qemu-system-ppc64 -cpu POWER8 -machine pseries -m 4096 -serial stdio -drive file=hdisk0.qcow2,if=none,id=drive-virtio-disk0 -device virtio-scsi-pci,id=scsi -device scsi-hd,drive=drive-virtio-disk0 -prom-env "boot-command=boot disk:"
   - choose vt100 (type it and press ENTER) when prompted for terminal type
   - choose to accept the license (default is no, press TAB key to change it to yes) then ENTER to accept
   - Esc+0 (hold down ESC then press 0) to go back
   - accept the software maintenance terms/conditions
   - Esc+0 (hold down ESC then press 0) to go back
   - Set any of the additional settings as required (date/time; root password; etc)
   - Option "Tasks completed - Exit to Login"
   
   - Login as root on the console (prompt)
-----------------------------------------------
   
- Fix the RPM DB error:  https://bobcares.com/blog/rpm-db_runrecovery-errors/
# cd /opt/freeware
# tar -chvf `date +"%d%m%Y"`.rpm.packages.tar packages
# rm -f /opt/freeware/packages/__*
# /usr/bin/rpm --rebuilddb
# /usr/bin/rpm -qa

-----------------------------------------------
   
   
- Setup networking: https://kwakousys.wordpress.com/2020/09/06/run-aix-7-2-on-x86-with-qemu/
    - in this example, we assign IP address 10.0.2.16 to AIX and 10.0.2.20 to the bridge we defined on the Ubuntu host.

- Setup a bridge (br0) on the Ubuntu host:
    root@ip-172-31-23-252:/wip# apt-get install bridge-utils
    root@ip-172-31-23-252:/wip# mkdir -p /usr/local/etc/qemu
    root@ip-172-31-23-252:/wip# echo "allow br0" > /usr/local/etc/qemu/bridge.conf
	
    NOTE: you can put the following network-related commands a single script that you can just run as a single command
	
    root@ip-172-31-23-252:/wip# ip link add name br0 type bridge
    root@ip-172-31-23-252:/wip# ip link set dev br0 up
    root@ip-172-31-23-252:/wip# ip addr add 10.0.2.20/24 dev br0


- Setup the tap NIC for the AIX VM:
    root@ip-172-31-23-252:/wip# ip tuntap add tap0 mode tap
    root@ip-172-31-23-252:/wip# ip link set dev tap0 up
    root@ip-172-31-23-252:/wip# ip link set dev tap0 master br0

    NOTE: tap0 interface comes up when the VM is started


- Setup the Ubuntu host for routing (including Internet access from the AIX VM):
    root@ip-172-31-23-252:/wip# echo 1 > /proc/sys/net/ipv4/conf/tap0/proxy_arp
    root@ip-172-31-23-252:/wip# ip route add 10.0.2.16 dev tap0
    root@ip-172-31-23-252:/wip# arp -Ds 10.0.2.16 eth0 pub
    root@ip-172-31-23-252:/wip# echo 1 > /proc/sys/net/ipv4/ip_forward
    root@ip-172-31-23-252:/wip# iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
    root@ip-172-31-23-252:/wip# iptables -I FORWARD 1 -i tap0 -j ACCEPT
    root@ip-172-31-23-252:/wip# iptables -I FORWARD 1 -o tap0 -m state --state RELATED,ESTABLISHED -j ACCEPT
        

- Start the AIX VM normally (assign a randomly selected MAC address to the VM's NIC):
root@ip-172-31-23-252:/wip# qemu-system-ppc64 -cpu POWER8 -machine pseries -m 4096 -serial stdio -drive file=hdisk0.qcow2,if=none,id=drive-virtio-disk0 -device virtio-scsi-pci,id=scsi -device scsi-hd,drive=drive-virtio-disk0 -prom-env "boot-command=boot disk:" -net nic,macaddr=be:16:43:37:16:ec -net tap,script=no,ifname=tap0,downscript=no


- Assign the IP address 10.0.2.16 to the en0 NIC in AIX  (use SMIT to make it permanent)
# chdev -l en0 -a netaddr=10.0.2.16 -a netmask=255.255.255.0 -a state=up

- Make the IP assignment permanent with SMIT (assign any IP on the same network as the gateway e.g., 10.0.2.254):
# smit tcpip > Min Config & Startup > en0 > (setup hostname/netmask/IP/nameserver & domain name & gateway e.g., aix7vm/10.0.2.16/255.255.255.0/8.8.8.8 & acme.com/10.0.2.254) > "START Now" = yes (TAB key to change it) then ENTER key to execute the change
   NOTE: the name server (e.g., Google's 8.8.8.8 DNS server) and a domain name MUST be provided if you decide to set the name server.


- Install BASH shell in AIX VM (bash is easier to use than the default Korn shell):

- increase /opt as the bash instal requires about 40MB space:
# chfs -a size=+60M /opt

# wget http://www.oss4aix.org/download/latest/aix71/libiconv-1.16-1.aix5.1.ppc.rpm
# wget http://www.oss4aix.org/download/latest/aix71/bash-5.0-8.aix5.1.ppc.rpm
# wget http://www.oss4aix.org/download/latest/aix71/gettext-0.19.8.1-1.aix5.1.ppc.rpm
# wget http://www.oss4aix.org/download/RPMS/gcc/libgcc-6.3.0-1.aix7.2.ppc.rpm
# rpm -ivh bash_5_0_8_aix5_1_ppc.rpm gettext_0_19_8_1_1_aix5_1_ppc.rpm libiconv_1_16_1_aix5_1_ppc.rpm libgcc_6_3_0_1_aix7_2_ppc.rpm

- In AIX, after installing bash, "authorize" AIX to allow bash shell to run:
# export TERM=vt100
   - Edit file /etc/security/login.cfg, append "/usr/bin/bash" (without the double quotes)  to the line containing "shells ="
   - Edit file /etc/shells, append this on a new line "/usr/bin/bash" (without the double quotes)
   

--------------- END OF PROCEDURE ---------------


- Extra step in order to access the AIX VM using SSH from outside the Ubuntu host (particularly useful if you are using the "--daemonize" headless option when starting the AIX VM):
Summary is to use iptables to redirect incoming attempts to connect to the Ubuntu instance on some alternate port (e.g., 2222/tcp) to port 22 on the AIX VM. Note that you also need to allow incoming traffic on this alternate port in your AWS/OCI/GCP VPC/subnet using the relevant security group rule.

root@ip-172-31-23-252:/wip# iptables -A INPUT -p tcp --dport 2222 -j ACCEPT
root@ip-172-31-23-252:/wip# iptables -t nat -A PREROUTING -p tcp --dport 2222 -j DNAT --to-destination 10.0.2.16:22


You can then connect to the AIX with putty (Ubuntu IP address and port 2222) or using SSH with a command such as: ssh root@<ubuntu-ip> -p 2222


   
References:
http://aix4admins.blogspot.com/2020/04/qemu-aix-on-x86-qemu-quick-emulator-is.html?m=1
Run AIX 7.2 on x86 with QEMU
https://worthdoingbadly.com/aixqemu/
http://www.visidon.com/blog/2015/02/bash-on-aix-7-1/
RPM DB_RUNRECOVERY errors: How to resolve
http://www.oss4aix.org/download/latest/aix71/ - download RPMs for various packages http://www.oss4aix.org/download/RPMS/gcc/ https://public.dhe.ibm.com/aix/freeSoftware/aixtoolbox/RPMS/ppc/ - Some useful commands: # qemu-system-ppc64 ... -daemonize (to run the VM in "headless" mode so access it using SSH). If you use this option, delete the "-serial stdio" from the command. QEMU starts the VM and gives a message such as "VNC server running on 127.0.0.1:5900" so you can use VNC to manage the VM as well. root@ip-172-31-23-252:/wip# mount -o loop /wip/bash51-aix71.iso /iso root@ip-172-31-23-252:/wip# ip link set dev br0 down root@ip-172-31-23-252:/wip# ip link delete dev br0 root@ip-172-31-23-252:/wip# ip a # mount -vcdrfs -oro /dev/cd0 /mnt # entstat -d en0 | grep -i hard Hardware Address: be:16:43:37:16:ec #aix# chsh <username> /bin/bash logout from session, after AIX shutdown is possible using "~~.", same as in HMC console root@ip-172-31-23-252:/wip# apt install -y genisoimage root@ip-172-31-23-252:/wip# mkisofs -max-iso9660-filenames -o bash50.iso ./bash50 - boot the AIX with the ISO image containing the bash rpm package; qemu-system-ppc64 -cpu POWER8 -machine pseries -m 4096 -serial stdio -drive file=hdisk0.qcow2,if=none,id=drive-virtio-disk0 -device virtio-scsi-pci,id=scsi -device scsi-hd,drive=drive-virtio-disk0 -prom-env "boot-command=boot disk:" -net nic,macaddr=be:16:43:37:16:ec -net tap,script=no,ifname=tap0 -cdrom /wip/bash50.iso - Some notes: "make" of QEMU took about 85 mins on t3.xlarge when compiling all supported platforms, but under 10 mins when compiling for ppc64 support only) ensure you have plenty of space for the compiler. qemu-7.2.0.tar.xz is 117M, extracted folder qemu-7.2.0 is 799M, compiled, the extracted folder goes to almost 6GB! if you didn't include the ssh client/server during the installation, you will need to start the VM with the ISO image inserted in the CDROM so you can install them. - Optionally disable some un-needed services to speed up the boot process: - edit file /etc/rc.tcpip and comment out # some services if not required e.g., sendmail, snmpd, hostmibd, snmpmibd, aixmibd (look for lines similar to: start /usr/sbin/aixmibd "$src_running") - to disable the NFSD server, edit file /etc/rc.nfs and comment out the line: start biod /usr/sbin/biod - you may use the "stopsrc -s <service-name>" command to shut them down in the current session as well. - Optionally disable additional services defined in the /etc/inittab file to make subsequent boot ups faster (using the following commands): # rmitab rcnfs # rmitab cron # rmitab piobe # rmitab qdaemon # rmitab writesrv # rmitab naudio2 # rmitab naudio # rmitab aso # rmitab clcomd # chrctcp -S -d tftpd
- The networking setup, and AIX VM launch command scripts (execute the network script before the AIX VM launch script so that the VM will have network access):

root@ip-172-31-23-252:/wip# cat setup_networking_for_aix.sh
#!/usr/bin/bash

#- Setup the tap NIC for the AIX VM:
ip tuntap add tap0 mode tap
ip link set dev tap0 up

#NOTE: tap0 interface comes up when the VM is started:

#- Setup the host for routing (including Internet access from the AIX VM):
echo 1 > /proc/sys/net/ipv4/conf/tap0/proxy_arp
ip route add 10.0.2.16 dev tap0
arp -Ds 10.0.2.16 eth0 pub
echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
iptables -I FORWARD 1 -i tap0 -j ACCEPT
iptables -I FORWARD 1 -o tap0 -m state --state RELATED,ESTABLISHED -j ACCEPT

#- Setup port forwarding so that the AIX VM is accessible remotely:
iptables -A INPUT -p tcp --dport 2222 -j ACCEPT
iptables -t nat -A PREROUTING -p tcp --dport 2222 -j DNAT --to-destination 10.0.2.16:22



root@ip-172-31-23-252:/wip# cat launch_aix72_vm.sh
#!/usr/bin/bash

/usr/local/bin/qemu-system-ppc64 -cpu POWER8 -machine pseries -m 4096 -drive file=hdisk0.qcow2,if=none,id=drive-virtio-disk0 -device virtio-scsi-pci,id=scsi -device scsi-hd,drive=drive-virtio-disk0 -prom-env "boot-command=boot disk:" -net nic,macaddr=be:16:43:37:16:ec -net tap,script=no,ifname=tap0,downscript=no --daemonize
#/usr/local/bin/qemu-system-ppc64 -cpu POWER8 -machine pseries -m 4096 -drive file=hdisk0.qcow2,if=none,id=drive-virtio-disk0 -device virtio-scsi-pci,id=scsi -device scsi-hd,drive=drive-virtio-disk0 -prom-env "boot-command=boot disk:" -net nic,macaddr=be:16:43:37:16:ec -net tap,script=no,ifname=tap0,downscript=no

- VNC connection to the AIX VM
When qemu is executed with the --daemonize option, it also creates a VNC session that you can connect to. By default the VNC session is started on only the loopback (127.0.0.1) interface. In the sample command below, it is started on the primary interface of the Ubuntu host with the IP 172.31.23.252. I can then use any VNC viewer such as tightvnc to connect to the VM's console using the Ubuntu hosts' public IP:
root@ip-172-31-23-252:/wip# /usr/local/bin/qemu-system-ppc64 -cpu POWER8 -machine pseries -m 4096 -drive file=/wip/hdisk0.qcow2,if=none,id=drive-virtio-disk0 -device virtio-scsi-pci,id=scsi -device scsi-hd,drive=drive-virtio-disk0 -prom-env "boot-command=boot disk:" -net nic,macaddr=be:16:43:37:16:ec -net tap,script=no,ifname=tap0,downscript=no --daemonize -vnc 172.31.23.252:0

RUN ORACLE LINUX 8.X DOCKER CONTAINER ON WINDOWS 10 WITH WSL2

The purpose of this guide is to run an Oracle Linux container on a Windows 10 system using Windows Subsystem for Linux v2.
(This may be an alternative to using a full-blown hypervisor type 2 such as Oracle VirtualBox or VMWare Player/Workstation.)

NOTE: Using container images from the official Oracle repository
NOTE: You will need to be running Windows 10 build 18917 or higher to use WSL 2. If you are on an earlier Windows 10 build, launch Windows Update Settings, you should be able to update it to the latest available version.
NOTE: there are docker images for 7/8/9 and slim versions of 7/8/9 (minimal environment with minimal number of packages) from the ghcr.io repository.

1. Prepare an Oracle Linux 8.x container and export it to a single TAR file using an existing Linux system as the work platform:

[root@wip]# yum install -y docker
[root@wip]# usermod -aG docker root
[root@wip]# newgrp docker
[root@wip]# id
uid=0(root) gid=992(docker) groups=992(docker),0(root)
[root@wip]#
[root@wip]# systemctl start docker.service
[root@wip]# systemctl enable docker.service

– Create the Dockerfile to use to build the container:
[root@wip]# vi Dockerfile
[root@wip]# cat Dockerfile
FROM ghcr.io/oracle/oraclelinux:8

CMD [“/bin/bash”]

– Build the docker container:
[root@wip]# docker build -t ghcr.io/oracle/oraclelinux:8 .
Sending build context to Docker daemon 23.04kB
Step 1/2 : FROM ghcr.io/oracle/oraclelinux:8
8: Pulling from oracle/oraclelinux
4c770e098606: Pull complete
Digest: sha256:07a995ecaf9db1ce613648a08facc162de69f26c39712f1acc93629c2e6c4e73
Status: Downloaded newer image for ghcr.io/oracle/oraclelinux:8
—> b0045ea7bbde
Step 2/2 : CMD [“/bin/bash”]
—> Running in 168cb6d08c9e
Removing intermediate container 168cb6d08c9e
—> 53be01d92e18
Successfully built 53be01d92e18
Successfully tagged ghcr.io/oracle/oraclelinux:8

– Test the container:
[root@wip]# docker run -it 53be01d92e18
[root@ec6e4b0f7c3b /]# cat /etc/oracle-release
Oracle Linux Server release 8.7
[root@ec6e4b0f7c3b /]# exit

– List all containers (note the container id ec6e4b0f7c3b associated with the image id 53be01d92e18 from the earlier build command output):

[root@wip]# docker ps -a
CONTAINER ID    IMAGE          COMMAND       CREATED              STATUS                         PORTS     NAMES
ec6e4b0f7c3b    53be01d92e18   "/bin/bash"   About a minute ago   Exited (0) 23 seconds ago                reverent_ellis

– Export the container into a single TAR file (222M size):
[root@wip]# docker export –output=”oellinux8.tar” aa565b335857

– Optionally zip the file (85MB zipped) to reduce the amount of data transferred when copying it to the Windows 10 system:
[root@wip]# gzip oellinux8.tar

– Transfer the container output TAR file to the Windows 10 system. In this case I will be using pscp to pull the file down into the Windows 10 system using a user other than root, so I copied the file to /tmp which is accessible to all users and changed the permission on the file so other users can read it:
[root@wip]# cp oellinux8.tar.gz /tmp/
[root@wip]# chmod 666 /tmp/oellinux8.tar.gz

2. SETUP WSL2 on Windows 10:
– Using elavated/admin powershell, run: Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux
– Using elavated/admin command or powershell, run: dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
– Reboot the Windows 10 system (WSL2 upgrade fails without a reboot after installing WSL)
– Upgrade WSL to WSL2 via the installer https://wslstorestorage.blob.core.windows.net/wslblob/wsl_update_x64.msi

3. Pull down the container file to the local Windows 10 system with WSL2 installed:
C:\Users\user1> md wsl2\oellinux8
C:\Users\user1\wsl2\oellinux8>cd wsl2\oellinux8
C:\Users\user1\wsl2\oellinux8>pscp -i ….\Downloads\centos8.ppk ec2-user@my-linux-wip-server:/tmp/oellinux8.tar.gz .

4. Unzip the container file oellinux8.tar.gz (if you compressed the original TAR file):

5. Import the TAR file into WSL (syntax: wsl –import [DISTRO NAME] [STORAGE LOCATION] [FILE NAME]):
C:\Users\user1\wsl2\oellinux8>wsl –import oellinux8 “C:\Users\user1\wsl2\oellinux8” oellinux8.tar

NOTE: the import step extracts the TAR file into rootfs and temp directories:
C:\Users\user1\wsl2\oellinux8>dir
12/07/2022 11:47 PM 232,101,888 oellinux8.tar
12/07/2022 11:59 PM 84,593,746 oellinux8.tar.gz
12/08/2022 12:25 AM rootfs
12/08/2022 12:46 AM temp

6. Start the new WSL container (which ends at the running Linux prompt):
C:\Users\user1\wsl2\oellinux8> wsl -d oellinux8
[root@mywinpc wsl2]#

7. Execute some commands in the running container:
[root@mywinpc wsl2]# ping google.com
PING google.com (172.217.7.110) 56(84) bytes of data.
64 bytes from slc08s01-in-f14.1e100.net (172.217.7.110): icmp_seq=1 ttl=59 time=4.64 ms
64 bytes from slc08s01-in-f14.1e100.net (172.217.7.110): icmp_seq=2 ttl=59 time=5.59 ms
^C
— google.com ping statistics —
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 4.639/5.116/5.594/0.482 ms
[root@mywinpc wsl2]#
[root@mywinpc wsl2]# yum repolist
repo id repo name
ol8_appstream Oracle Linux 8 Application Stream (x86_64)
ol8_baseos_latest Oracle Linux 8 BaseOS Latest (x86_64)
[root@mywinpc user1]#
[root@mywinpc user1]# yum provides gdisk
Oracle Linux 8 BaseOS Latest (x86_64) 805 kB/s | 53 MB 01:07
Oracle Linux 8 Application Stream (x86_64) 926 kB/s | 42 MB 00:45
Last metadata expiration check: 0:00:14 ago on Thu 08 Dec 2022 12:29:18 AM MST.
gdisk-1.0.3-6.el8.x86_64 : An fdisk-like partitioning tool for GPT disks
Repo : ol8_baseos_latest
Matched from:
Provide : gdisk = 1.0.3-6.el8

gdisk-1.0.3-9.el8.x86_64 : An fdisk-like partitioning tool for GPT disks
Repo : ol8_baseos_latest
Matched from:
Provide : gdisk = 1.0.3-9.el8

gdisk-1.0.3-11.el8.x86_64 : An fdisk-like partitioning tool for GPT disks
Repo : ol8_baseos_latest
Matched from:
Provide : gdisk = 1.0.3-11.el8

[root@mywinpc user1]#

8. Optionally ENTER exit command to quit the running Linux container:
[root@mywinpc user1]# exit
C:\Users\user1\wsl2\oellinux8>

—————— END OF PROCEDURE ———————————

The following setup is to allow remote connectivity to the container

- Start a  temporary container (e.g., using the image id) to copy SSHD config files from it:
[root@ip-172-31-6-136 ~]# mkdir /oel8_etc_ssh
[root@ip-172-31-6-136 ~]# docker run --name wip -it -v /oel8_etc_ssh:/tmp/mpoint 18a22840eed9
[root@609b0ec071bb /]#
[root@609b0ec071bb /]# cp -a /etc/ssh /tmp/mpoint/
[root@609b0ec071bb /]# exit

- Delete the temporary container:
[root@ip-172-31-6-136 ~]# docker rm wip

- Start the "production" container with /oel8_etc_ssh/ssh on the host mounted to /etc/ssh in the container (running headless or detached mode with "-d"):
  NOTE: mapped port 2222/tcp on the host to the SSH port in the container. This is handy to access the container remotely from outside the host.
[root@ip-172-31-6-136 ~]# docker run --name oel87c -it -p 2222:22 -v /oel8_etc_ssh/ssh:/etc/ssh -d 18a22840eed9

- Attach to the console of the container:
[root@ip-172-31-6-136 ~]# docker attach d99789174764

- Create the ssh host keys (one-time task since they are stored persistently on the underlying host):
[root@d99789174764 /]# ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key -N ''
[root@d99789174764 /]# ssh-keygen -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key -N ''
[root@d99789174764 /]# ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N ''

- Create the system log file (otherwise SSHD will be unable to authenticate login attempts):
[root@d99789174764 /]# touch /var/log/messages

- Start SSHD service:
[root@d99789174764 /]# /usr/sbin/sshd &

- Add a user to the container to login remotely:
[root@d99789174764 /]# useradd user1
[root@d99789174764 /]# passwd user1

- Optionally install/configure visudo to allow "user1" switch to the root user:
[root@d99789174764 /]# yum install -y sudo
[root@d99789174764 /]# visudo
[root@d99789174764 /]# grep user1 /etc/sudoers
user1   ALL=(ALL)       NOPASSWD: ALL
[root@d99789174764 /]#

- Detach from the container and keep it running: Press Ctrl-P, followed by Ctrl-Q,
  NOTE: if you mistakenly typed exit in the container which causes it to stop, start it again with "docker start <container-id>" on the host

- It is now possible to access the container remotely from outside the host. SSH to the container using the hosts' IP address on port 2222/tcp e.g.
  From a Windows/Linux system (you can also use Putty): ssh user@<host-ip> -p 2222

------------------- END -------------------

- Sample command to retrieve the IP of the container from the underlying host. [root@ip-172-31-6-136 ~]# docker ps    (command to get the container id)
[root@ip-172-31-6-136 ~]# docker container inspect -f '{{ .NetworkSettings.IPAddress }}' d99789174764
172.17.0.2

- Note: mounting the whole /etc and /var/log to directories on the underlying host should help to "persist" all the relevant configuration of the container.

References:
https://learn.microsoft.com/en-us/windows/wsl/install-manual
https://www.sanner.io/posts/2022/03/create-a-custom-linux-setup-for-wsl2/
https://learn.microsoft.com/en-us/windows/wsl/use-custom-distro
https://www.sanner.io/posts/2022/03/create-a-custom-linux-setup-for-wsl2/
https://learn.microsoft.com/en-us/windows/wsl/install-manual
https://hub.docker.com/_/oraclelinux?tab=tags
https://github.com/oracle/container-images/pkgs/container/oraclelinux
https://yum.oracle.com/oracle-linux-isos.html
https://social.technet.microsoft.com/Forums/en-US/e655c45f-3a74-4acb-8df1-3607e4fe6b49/issue-with-installing-linux-subsystem?forum=winserverhyperv
https://community.oracle.com/mosc/discussion/3949381/yum-update-error-rhn-plugin-network-error-connection-reset-by-peer


Eulogy for Debo

Good morning. I am Tunde, Debo’s cousin.

Thank you for your presence here physically or via zoom today. We gather to recognize this painful reality, to remember Debo’s joyful spirit, to reaffirm our beliefs, and to release Debo’s spirit into the arms of our Heavenly Father.

I pray that God comfort all of us at this time and in the days, weeks, months and years to come.

It is impossible to do justice to the person Debo was with mere words. Debo was the best of us. No mean bone in his body. Always bubbly and ready to go. Never a dull moment with him. He will party with people, and party by himself. He liked music and he is always playing some artist’s album or another. You can expect him to ask if you have heard some new track by one artist or another. I would tell him regularly, that if we could find a way to bottle that spark he had inside him for resale, we would be billionaires.

I looked briefly through the pictures in his Facebook profile, as well as the comments on the remembrance page put up by Bayo on the Internet, and the theme is similar – the pictures and comments describe a person that was caring, easy to talk to, and unforgettable. Ever the life of the party.

“Egbon e je ka jade” was his refrain on Fridays in particular. And while facing his own challenges he was concerned about how others were doing.

“Egbon, you can’t spend your birthday alone o. Where’s the party?”

“Egbon, you can’t be drinking instant coffee. You can get a cheap coffee maker at Walmart.” He took off, and arrived later with a coffee maker, coffee grounds, and paper filters. I knew he demonstrated similar care for all his friends and family. If he can assist or solve a problem, he was all action. Even if he can’t directly help, he’s already thinking of someone he can link you up with that may be able to help. Debo had contacts in every zip code.

Debo praised people and gave compliments sincerely. His admiration of friends and family and their achievements in their professional and personal lives was genuine. He spoke glowingly of people such as Akin, Dare, and Patrick to name a few.

Debo made friends everywhere. He saw the good in people, and believed in you even when you didn’t believe in yourself. You can’t help but like Debo. He gave you no choice in the matter. Family was important to him, and work colleagues and casual acquaintances became his lifelong friends. He worked hard and played hard. He was always present in the moment wherever he was and he made his presence known in a way that drew people to him.

He found his calling in supply chain management and logistics. He enjoyed his job and delivered results. SAP was his bread and butter. He had anecdotal stories from his vast work experience especially his days in BAT. Debo had very strong opinions on everything. He loved to debate politics.

Debo was not everything to everyone. Instead Debo was a few important things to everyone. He was loyal, he was dependable, he was caring, he was fun. Debo loved, and was and is loved.

He made an impact everywhere he went and on everyone he met. He spent about a month in Utah late 2019 early 2020. People that met him only a couple of times during that month still remember him to this day.

I feel I need to mention some names. I apologize because I know I am going to leave out names I should mention, so please forgive me. But looking at the faces here and some not present: Dare, Patrick, Akin, Leye, Jumai, Banqee, Bayo, Dapo, Victor, Tunji, Ben, Simi and Dami, Uduak, Lola, Femi, Damola, Tony, Samuel, Daplosyne, Michael, Laide, the Adegokes , the Odumosus, the Adelekes, the Itayemis, the list is endless. Everyone here and on zoom was important to him. Know that he held you all in a special place in his heart.

Edward J. Stieglitz said: “It is not the years in your life that count. It Is the life in your years”. Debo packed a lot of living into his 41 years. But he also had a lot more he wanted to do. We had plans. He had plans. He wanted to get married. He wanted kids. He wanted all that was possible by hardwork, and a little bit of luck. He wanted his own unique version of the American dream, a hybrid Nigerian-American dream because Nigeria was home as well, and because Debo was unique, Debo was in a category all his own. Debo was ever optimistic. He was a naturally happy person. Every time we reminisce about him, some new adventure we had comes into mind.

While we necessarily mourn his passing, I am sure he wants us to celebrate his life, and find as much happiness as possible in remembering those fun times we had with him.

Rest on Debo, Mr Debo, Debasco, Lafog, Lafogido, Adeborich, the prince. Till we meet again.

My faith is convenient

I came out of the store. There’s a man in a wheelchair. I think he is quadriplegic. One arm is bandaged and he might have had a feeding tube as well (I am not sure). As I maneuver the small table unto the back seat of my car, he must have greeted me or so. He then asked for my name; and I asked for his too – Nate. He said he liked my car and asked for the year. He asks where I am from. I told him Nigeria. “How do you like the USA?” he asked. I said I liked it just fine. He said he thinks I am around his age (35). I laughed and told him my age (I am much older than him). He said I didn’t look it. I said my bones tell me otherwise. Even as I made that statement, I felt awkward. What are my aches and pains compared to his? I asked if he was waiting for someone to pick him up. He said his mum is still in the store. I bid him good day, and he returned the wishes.

I sat in my car and kept watching him. I had a strong urge to go back and pray with him. But I felt the weight of my unbelief, and my numerous sins. What point is it to pray with him if I cannot pray him to full health; if I cannot ask him to get up and pick up his wheelchair?

So I watched and despaired. His mum and possibly much younger brothers came out of the store. They got into a small van but didn’t leave immediately.

My faith is convenient. We can be tested by a lot of things and appear to still have total faith in God. But the worst trial above divorce; above heartbreak; above financial troubles and so on is a health crisis. If you haven’t undergone one, your faith hasn’t been tested. Whether it is you personally or someone close like a sibling, a parent, or a child.

It is easy to sing in church when one is healthy. To believe or think one believes. To be completely without doubt. To be like Nathaniel – an Israelite in whom there’s no guile (John 1:47).

Has my faith really been tested if I have not lived in some part of the world where your (religious) believe determines if you are a second or third class citizen? Where you live under a cloud of the possibility of violence to your person and all you hold dear without provocation at any moment?

It is when health challenges occur that a lot of people love the Lord with their whole might, body and soul or try their hardest to do so (the greatest commandment – one of two on which all the law and prophets rest – Matthew 22:37-40). But therein can lie disappointment beyond measure, for like king David what we fast and pray for – the miracle we want does not usually come to pass. So like him, we dust ourselves off, take a bath, oil our skin, eat and attempt to carry on as best as we can (2 Samuel 12:20). After all, the lord giveth and taketh (Job 1:21).

. . . .

And the more I thought about Nate in his wheelchair, the more I despaired. So I cried for my father; and for my brother; and for my cousin; and for Nate.

After a while I dried my tears and watched a young lady walk to her car. I thought to myself that since I am single, I was not doing anything wrong. But woe unto me, “for I have the desire to do what is good, but I cannot carry it out. For I do not do the good I want to do. Instead, I keep on doing the evil I do not want to do. And if I do what I do not want, it is no longer I who do it, but it is sin living in me that does it.” (Romans 7:18-20). Because as a man of flesh and blood, it wasn’t just admiration of God’s handiwork that crossed my mind.

Jesus did not do any “there’s someone here …” miracles. We let our pastors get away with being no better than “life coaches”.

Jesus said we will do his works (including miracles) and much more (John 14:12). So, since no one is doing all His works, it begs the question “when the Son of Man returns, will He find faith on earth? (Luke 18:8).

Jesus was always specific. He did not send his disciples to catch 100 fishes, and maybe by chance there will be a coin in one of them. Instead, he said to take the very first fish they (the disciples) caught and it will contain a coin with which they should pay the tax man (Matthew 17:27). And when He sent his disciples ahead to go prepare a place to eat the Passover, He was specific about exactly what they will see – “a certain man” (Matthew 26:18) not “there is a (random) man in that city …” Even on His triumphant entry into Jerusalem, he told them specifically where to get the young donkey (Mark 11:2). He didn’t use the get-out-of-jail-free card “there’s an ass somewhere in that village that’s never been ridden …” which is equivalent to the “there is someone here …” modern-day preachers are known for.

Pastors preach fervently about everything in the Bible, and claim (rightly) they are to be taken literally (except the obvious parables) – pay tithe; obey the commandments; fast;  but when it comes to healing, they are quick to say it is God who heals but ignore the fact that people like Peter and John were flesh like us, and yet they were able to pray and heal (Acts 3:4-8). Even Paul says if anyone is sick/ill, he should call the elders of the church to pray over him and he will be healed (James 5:14). I have even heard some preachers claim miracles were needed in the early days of the church to help in propagating the gospels, which is why they (miracles) are no longer commonplace now. I am yet to see a bible verse that backs up that position (on miracles).

If God can send Elijah (the prophet) to a specific widow (Luke 4:26), God can tell you (the pastor/preacher/etc.) particular names or attributes that’s peculiar to the person the miracle is intended for in your church or service. Otherwise, we are no better than those who conduct séances – after all, going by probability, same as there’s likely for someone present at a séance (session) to have a dearly departed named John (for example), in a church there’s likely to be someone that’s barren or someone that’s in dire financial straits. So should we say it is lack of true spiritual gift or spiritual laziness to throw out the generic all-encompassing “there is someone here …” message?

God knows the number of hairs on our head (Luke 12:7) and not a bird drops out of the sky without His knowledge (Matthew 10:29). If He intends you to “deliver” a miracle to someone, He will be specific. He can tell you his/her name instead of having people guessing and hoping the “word” (miracle) is meant for them. If you are sure God is talking to you, then ask Him for specifics – so you can in turn say “Mr. XYZ, God said” or “the hunchback sitting 5 rows from the back of this hall, please step forward”. After all, if Elijah had turned up in Zarephath and announced God sent him to a widow without being specific, he would have either had a stampede on his hands, or alternatively, if not for their (widows) hunger/lack, they would likely have laughed him to scorn (1 King 17:9).

. . . .

The van has left. So I finally headed home too.

(12:21am 09/07/2022)

Analysis of an attempted Facebook Scam

I have an “extra” iPhone that’s completely new, and still in its unopened original box.
I posted it for sale on the Facebook marketplace.
I soon got a request someone wanted to send me a message which I approved
The “lady” then engaged me as follows via FB messenger:

Friday last week:
Bonnie Monalisa: Hi. I’d like to purchase the Apple iPhone XS Max 64GB space gray$720

Monday this week:
Me: Hi. Ok. no shipping though. Would have to exchange it for cash or venmo at any convenient location in the neighborhood. I can go up as far as SLC or south as far as Provo if necessary.

Bonnie Monalisa: do you still have the purchase receipt and for how long have you had it ? I Hope it is in good condition and can I ask you why you selling it?
Bonnie Monalisa: What is your username and email

Today (Friday this week):
Me: Yeah. I should have it somewhere. Never opened it. I mistakenly purchased a second phone while waiting for another to arrive. itaba—-h@gmail.com

Bonnie Monalisa: Sending now
Bonnie Monalisa: Payment sent, let me know when you get it

Me: Ha ha. Payment sent to where?

Bonnie Monalisa: Here: itaba—-h@gmail.com

Me: got an email that you sent me money by Venmo, but no money in Venmo. If you are attempting to scam me, you have to try harder! 😅🤣

PS: I knew it was likely a scam once she said she sent me money. But I went ahead and checked my email (got an email) and Venmo before my final response above. From the screenshot, you can see she/he has seen my last message, but no reaction.

Her profile on IG (I guess since FB owns IG now, you don’t need an FB profile for the FB marketplace) has only 4x posts, all of them of 4x different women.
https://www.instagram.com/bonnie_barnes_/?fbclid=IwAR3WR14WUbJurkDprk24xD9mplmZ2DnKRIf2z9bXg7a0QrerqaLBd8Yi8c0

Look closely at the email which looks very official and is supposedly from Venmo:
– But the sender is venmo.pay@yandex.com
– It is addressed to @Reilyn-Miguel who supposedly received a Business payment of $720.00 (same amount I listed the iPhone for)
– The signature says “The Venmo Team”
– I called the listed number “+1 (702) 660-5409” and it showed up as a Las Vegas (Nevada) number even though the address in the email says “The Venmo Team” is based in Scottsdale, Arizona.
– the first time it connected, it appeared someone cut the call, so I tried again
– the second time I got the automated message “The party you are trying to reach is unavailable, please leave a message and someone will get back to you later.” (I didn’t bother to leave a message)
– By the way, Venmo’s contact page (obviously) lists a different number: +1 (855) 812-4430

Air-fried Plantain

So let’s start with the fact that all the good stuff will kill you. But then, like Red Sonja said to Conan, “do you want to live forever?”. So you should limit your consumption of plantain. On top of that, the way I like it most is “fried”. And now, we know anything deep-fried is not good for you either. So I decided to explore the air-fried option. Air-frying works by circulating a little amount of oil around your food using hot air to do the frying. So it is much healthier – not sure whether it will taste as good though.

There are lots of recipes out there, and contrary to what I am always complaining about, I am dong exactly the same thing – “front-loading” this post with everything but the recipe – well, disclaimer, this is not primarily a recipe post – consider it an article about air-frying plantains.

So, I cut up the plantain, don’t make them too thick, otherwise they don’t cook through properly. I then put about 6 tablespoons of peanut oil in the container with the plantain (I would estimate I cut up about 6 to 8 ripe plantains). Shake the pot to get the oil to coat all the plantain pieces. You should consider a sprayer instead. I do have am olive oil sprayer that I use to coat cake pans, but I didn’t want to fry the plantain with Olive oil.

I then transferred a single layer of plantain pieces to the airfryer (I have a Ninja AirFryer AF101) on the metal grate that came with the unit. The problem is that after the airfrying is done, the plaintain pieces stuck to the metal grill. So I decided to use the flat plate that came with the unit instead of the grate. (pics below)

So, I ran one layer of plantains through the fryer at 330F for 15mins. Once I had gone through all the plantains. I mixed them all up and then put a double layer of them at a time back into the fryer and ran it at 315F for 10 mins.

I future, I would likely try the doubling the layer and running it through the fryer for 20 mins at 315F. mixing up all the runs, then running it through the fryer again at 315F for another 20mins.

The problem is that with the plate, only the top of the plantain pieces get browned, while I think with the grate, both sides would likely get browned in one run.

So I cut the plantains at 90 degrees (i.e., straight down). But traditionally, it is cut diagonally. I think that will give the pieces more surface area and allow them to stay properly on the grate. They might still stick to the grate, but because they would be larger, they should be easier to pry off the grate.

Air-Fried plantain

Ninja Air-Fryer AF101

Deep-fried plantain

Air-Fryer grates (had better luck with the plate on the right)

Fresh plantain from Ranchos (an Hispanic supermarket chain)

Oil Sprayers (the vegetable oil on the right is about $1.60 at WinCo supermarket)

The Booster shot put me down

It’s 3:20 am. After tossing and turning for about 3 hours, I got up to do two things: write this, and drink some water – let’s help my kidneys get rid of any wastes that’s contributing to how bad I was feeling.
So I have an early day today. Around 9pm yesterday, I broke a 10mg melatonin tablet into two, downed one half, put the other half in the pills bottle, changed my mind, got the remaining half out of the bottle and sent it down the hatch with some water as well.
Then I went to bed around 11pm. Read part of a book I borrowed from the Libby app on my iPhone courtesy of the Lehi public library. Finally turned in around 11:30pm. I like some white noise so I had one of those 10-hour rain video on YouTube playing on the TV.
First thing I noticed was I was shivering like crazy. So I doubled up on the blanket (one on top of another on top of me). Didn’t do a lot. I finally fell asleep.
At some point I dreamt about what it would be like to have powers like the Greek gods of old. I am sure this is due to the book. I was on book 3 of the “Olympus Bound” trilogy by author Jordanna Max Brodsky. (Book 3 of the series).
All this while, I believe I was partially awake because I knew I was feverish and tossing and turning and rubbing my legs together – good thing I sleep alone, but not so good in the sense of “bros, at your age, you are still single?”.
Just before I got up I started “dancing” (in my mind) to the song Essence by Wizkid (and no I didn’t remember who sang it or the title at the time). Which triggered an idea for something I have been thinking of, and putting off for a couple of years. I even have an alarm on my phone to go off at 3pm weekdays with the message “Do the video”. Each of the video clips will go on my YouTube channel and possibly TikTok, Instagram, and Snapchat. It will consist of me dancing to a popular song cutting across culture, country, currency, and genres (got tired of looking for that fourth “C” word 🙂 ). Anyway I will be dressed all in black, with a white plastic face mask, the official video of the song will be playing on the TV behind me. Near the one minute mark a voice in Yoruba will say something like “bros, oya, let’s come and be going” to which I stop, cuff my hand behind my ear like I was listening, waive then walk out of the video frame.
I knew I had a thermometer around here somewhere but it took a minute to find it. I got it off eBay so not sure how accurate it is. It read 35.5C when I put it on, rinsed it, stuck it under my tongue, pulled it out when it started beeping. It read 37.9C.
Time to drink that water, get back in bed and try to sleep. I get up at 6:50am and it’s 3:37am now. First COVID shot, the effect was really mild, with the second shot I had a mild fever throughout the next day. But this booster shot put me down: wiped the floor with me.

Still awake at 4:30am
PS: I should have taken paracetamol to lessen the fever but it didn’t cross my mind 5:30am. So I definitely take some of the blame for how shitty I felt.

Porting Replit (Phaser) game to IONIC/ANGULAR

I mentored three D-Tech high school student over two weeks that came up with the game  https://blank-game.lorenzoharrold.repl.co/

Source code available at https://replit.com/@LorenzoHarrold/blank-game#index.html (requires invitation)

I decided to investigate how to port it to a locally hosted environment as well as the possibility of generating an Android/IOS from the code.

(Phaser is a JavaScript game development library)

– Setup the game development environment on CentOS/OEL 8.x or Mac OSX

[opc@phaser ~]$ sudo firewall-cmd –add-port=8000-8199/tcp
[opc@phaser ~]$ sudo firewall-cmd –add-port=8000-8199/tcp –permanent
[opc@phaser ~]$ wget https://download-ib01.fedoraproject.org/pub/epel/8/Everything/x86_64/Packages/s/screen-4.6.2-12.el8.x86_64.rpm
[opc@phaser ~]$ sudo yum localinstall -y screen-4.6.2-12.el8.x86_64.rpm
[opc@phaser ~]$ sudo setenforce 0
[opc@phaser ~]$ sudo yum install -y curl wget git

– You can download the MAC OSX installer or zip file from https://nodejs.org/ (e.g., node-v16.13.0-darwin-x64.tar.gz)

[opc@phaser ~]$ wget -O node-v16.13.0-linux-x64.tar.xz “https://nodejs.org/dist/v16.13.0/node-v16.13.0-linux-x64.tar.xz
[opc@phaser ~]$ VERSION=v16.13.0
[opc@phaser ~]$ DISTRO=linux-x64
[opc@phaser ~]$ sudo mkdir -p /usr/local/lib/nodejs
[opc@phaser ~]$ sudo tar -xJvf node-$VERSION-$DISTRO.tar.xz -C /usr/local/lib/nodejs
[opc@phaser ~]$ sudo chown -R opc:opc /usr/local/lib/nodejs
[opc@phaser ~]$ cp .bash_profile .bash_profile.org
[opc@phaser ~]$ cat >> .bash_profile <<EOF
# Nodejs
VERSION=v16.13.0
DISTRO=linux-x64
export PATH=/usr/local/lib/nodejs/node-$VERSION-$DISTRO/bin:$PATH
CAPACITOR_ANDROID_STUDIO_PATH=/home/opc/android-studio/bin/studio.sh
export LANG=en_US.UTF-8
EOF
[opc@phaser ~]$ 

– NOTE: on Mac OSX, the default shell is zsh, so the profile file is .zprofile and not .bash_profile

[opc@phaser ~]$ . ~/.bash_profile
[opc@phaser ~]$ rm -rf .npm-global
[opc@phaser ~]$ npm –version
8.1.0
[opc@phaser ~]$ npm i -g @ionic/cli
[opc@phaser ~]$ /usr/local/lib/nodejs/node-v16.13.0-linux-x64/bin/ionic –version
6.18.1
[opc@phaser ~]$ npm remove -g  formidable@1.2.6
[opc@phaser ~]$ npm i -g formidable@v3


--- Install Angular globally. Alternatively, you can install it per project
aitayemi@aitayemi-mac ~ % npm install -g @angular/cli
aitayemi@aitayemi-mac ~ % npm install -g @angular/core

—- List globally installed packages (“npm ls”  in the top level directory of a project will list only packages installed in that project)

aitayemi@aitayemi-mac ~ % npm ls -g
/usr/local/lib/nodejs/node-v16.13.0-darwin-x64/lib
\__ @angular/cli@13.0.3
\__ @angular/core@13.0.2
\__ @ionic/cli@6.18.1
\__ corepack@0.10.0
\__ formidable@3.1.3
\__ npm@8.1.4

——————- PORTING THE EXISTING SCAVENGER GAME FROM REPLIT —————-

—– create a blank Ionic project

aitayemi@aitayemi-mac ~ % ionic start scavenger blank –type=angular
aitayemi@aitayemi-mac ~ % cd scavenger
aitayemi@aitayemi-mac scavenger % npm audit fix 
aitayemi@aitayemi-mac scavenger % 

—– INSTALL phaser into the project, then update index.html to use a local copy (alternative to downloading the phaser from the repl.co as configured in the index.html)
aitayemi@aitayemi-mac scavenger % npm install -D phaser
aitayemi@aitayemi-mac scavenger % npm audit fix
aitayemi@aitayemi-mac scavenger % cp node_modules/phaser/dist/phaser.min.js src/assets

———- COPY the replit game files from replit to the assets sub-folder ————————–
– index.html goes in the src folder, while all other files go in the src/assets folder 

aitayemi@aitayemi-mac scavenger % ls
angular.json            e2e                     karma.conf.js           package-lock.json       src                     tsconfig.json
capacitor.config.ts     ionic.config.json       node_modules            package.json            tsconfig.app.json       tsconfig.spec.json
aitayemi@aitayemi-mac scavenger % ls src
app             assets          environments    global.scss     index.html      main.ts         polyfills.ts    test.ts         theme           zone-flags.ts
aitayemi@aitayemi-mac scavenger % ls src/assets
GridLayout.js           addons.js               endPage.jpg             firespritesheet.json    inhouse2.jpg            phaser.min.js           sounds                  wall-e.jpg
Scene1.js               brick.png               finalBook.png           firespritesheet.png     main.js                 robot01.png             spritesheet.json        well.png
Scene2.js               broken_robot.png        fire_spritesheet.json   helper.js               open-book.png           robot_sprite.png        spritesheet.png
SimpleScene.js          dude.png                fireezgif.png           icon                    openbook.png            seedPack.png            tilesets
aitayemi@aitayemi-mac scavenger % ls src/assets/tilesets
door.png        floor.png       green.png       hazard.png      mario.png       purple.png      stair.png
aitayemi@aitayemi-mac scavenger % ls src/assets/sounds
terminator2b.mp3
aitayemi@aitayemi-mac scavenger %

————- remove dependency on Replit by downloading the various Javascript files referenced in index.html to the src/assets folder and updating the index.html to reference the local files instead

aitayemi@aitayemi-mac scavenger % curl -o src/assets/phaser.js https://game-lib.leonyoung.repl.co/phaser.js   (optional since we will use the installed phaser.min.js file)
aitayemi@aitayemi-mac scavenger % curl -o src/assets/helper.js https://game-lib.leonyoung.repl.co/helper.js
aitayemi@aitayemi-mac scavenger % curl -o src/assets/addons.js https://game-lib.leonyoung.repl.co/addons.js
aitayemi@aitayemi-mac scavenger % curl -o src/assets/GridLayout.js https://game-lib.leonyoung.repl.co/GridLayout.js
aitayemi@aitayemi-mac scavenger % curl -o src/assets/SimpleScene.js https://game-lib.leonyoung.repl.co/SimpleScene.js

——– EDIT index.html to update the location of relevant files including Scene1.js and Scene2.js scripts:
aitayemi@aitayemi-mac scavenger % grep script src/index.html
    <script src=”https://game-lib.leonyoung.repl.co/phaser.js”></script>
    <script src=”https://game-lib.leonyoung.repl.co/helper.js”></script>
    <script src=”https://game-lib.leonyoung.repl.co/addons.js”></script>
    <script src=”https://game-lib.leonyoung.repl.co/GridLayout.js”></script>
    <script src=”https://game-lib.leonyoung.repl.co/SimpleScene.js”></script>
    <script src=”Scene1.js”></script>
    <script src=”Scene2.js”></script>
    <script src=”main.js”></script>

aitayemi@aitayemi-mac scavenger % vi src/index.html 

aitayemi@aitayemi-mac scavenger % vi src/index.html
aitayemi@aitayemi-mac scavenger % 
aitayemi@aitayemi-mac scavenger % grep script src/index.html
    <script src=”assets/phaser.min.js”></script>
    <script src=”assets/helper.js”></script>
    <script src=”assets/addons.js”></script>
    <script src=”assets/GridLayout.js”></script>
    <script src=”assets/SimpleScene.js”></script>
    <script src=”assets/Scene1.js”></script>
    <script src=”assets/Scene2.js”></script>
    <script src=”assets/main.js”></script>
aitayemi@aitayemi-mac scavenger %

————- ADD  <base href=”/”>  to the index.html so that all the referenced files can be located
aitayemi@aitayemi-mac scavenger % grep -B1 “</head>” src/index.html
    <base href=”/”>
  </head>

aitayemi@aitayemi-mac scavenger %


————- RUN the game with either ionic or ng. (“npm run build” creates the “www” sub-directory).
aitayemi@aitayemi-mac scavenger % ionic serve –external
aitayemi@aitayemi-mac scavenger % npm run build
aitayemi@aitayemi-mac scavenger % ng serve

———— ACCESS the game using a web browser with either the loopback interface or the IP address of the system running the ionic environment e.g., http://<ip-address>:<port>/ )

————————————- END OF GAME PORT ——————————————————

————————————————————————————————————————–

—————– OPTIONAL SECTION BELOW – BUILD GAME FOR ANDROID/IOS ————–

—— Install Android studio: https://vitux.com/how-to-install-android-studio-on-centos/ and https://developer.android.com/studio/install
[opc@phaser ~]$ sudo yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm
[opc@phaser ~]$ sudo yum install -y java-1.8.0-openjdk

— for Mac OSX, download JAVA from https://java.com/en/download/ (e.g., jre-8u311-macosx-x64.dmg) and install it

—- Download Android Studio from https://developer.android/com/studio (e.g., android-studio-2020.3.1.25-mac.dmg for MAC OSX)
[opc@phaser ~]$ tar xf android-studio-2020.3.1.25-linux.tar.gz
[opc@phaser ~]$ cd android-studio/bin/

—- RUN the Android Studio installer from a X-session such as MobaXterm and follow the prompts in the GUI wizard installer to complete the install:
[opc@phaser android-studio]$ ./studio.sh

—- INSTALL Cocoapods and (full) Xcode Developer Tools (from App Store)  – both are required to add “ios” to the project (one-time installation task for both). You need to accept the Xcode license after installation. Either launch the IDE and accept the license when prompted, or run “sudo xcodebuild -license” from Terminal session).

aitayemi@aitayemi-mac scavenger % sudo gem install cocoapods       (see https://guides.cocoapods.org/using/getting-started.html#installation to install it only for a specific user, instead of “globally”)

aitayemi@aitayemi-mac scavenger % xcode-select install

———– OPTIONALLY ADD Android & iOS application support/code – you need to install the necessary libraries/tools so the iOS support will only work on a MAC —————————-
aitayemi@aitayemi-mac my-game % export CAPACITOR_ANDROID_STUDIO_PATH=/home/opc/android-studio/bin/studio.sh

— installing locally for this project only as opposed to globally or linking the globally-installed packages to this project. Installing locally to the project only ensures that the correct versions of packages this project requires are installed in the project.
aitayemi@aitayemi-mac scavenger % npm install @capacitor/cli @capacitor/core
aitayemi@aitayemi-mac scavenger % npm audit fix
aitayemi@aitayemi-mac scavenger % npm install @capacitor/android
aitayemi@aitayemi-mac scavenger % npm audit fix
aitayemi@aitayemi-mac scavenger % npm install @capacitor/ios
aitayemi@aitayemi-mac scavenger % npm audit fix
aitayemi@aitayemi-mac scavenger % ionic cap add android
aitayemi@aitayemi-mac scavenger % npx cap add android
aitayemi@aitayemi-mac scavenger % ng build
aitayemi@aitayemi-mac scavenger % ionic cap add ios
aitayemi@aitayemi-mac scavenger % npx cap add ios
aitayemi@aitayemi-mac scavenger % ng build

—- IN ORDER to build the Android version of the game code, you can either:
   (1) launch Android Studio from the MAC OSX Lauchpad, then select “File -> Open” menu in the Android Studio IDE, and select the top-level folder of the project (e.g., my-game), then select the “android” sub-folder, then the “open” button to open the project, OR
   (2) setup the CAPACITOR_ANDROID_STUDIO_PATH to point to the Android Studio executable so that the “ionic cap open android” command can launch the Android Studio IDE. On Linux, execute the “ionic” command from an X-session such as MobaXterm. On MAC OSX, launch the Android Studio IDE from the Launchpad, and then select the menu option “Tools -> Create Command-line Launcher…” to generate a terminal-executable file as /usr/local/bin/studio which you can then set as the value of the CAPACITOR_ANDROID_STUDIO_PATH variable. 
aitayemi@aitayemi-mac scavenger % export CAPACITOR_ANDROID_STUDIO_PATH=/home/opc/android-studio/bin/studio.sh
aitayemi@aitayemi-mac scavenger % export CAPACITOR_ANDROID_STUDIO_PATH=usr/local/bin/studio

NOTE: an alternate setup on an OCI instance (with no physical video card) couldn’t launch the emulator. I see “Starting AVD…” at the bottom right of the IDE but the emulator (device) never shows up. I think this is due to the lack of a video card on the instance.

NOTE: Open “Tools -> SDK Manager” from the Android Studio IDE menu, select/check “Android 11.0 (R)” under the “SDK Platforms’ tab. This line shows 30 under the “API Level” column and and that corresponds to the line “targetSdkVersion = 30” in the my-game/android/variables.gradle file. Android Studio will ask you to confirm the download of the SDK (click OK), then follow the installation wizard prompts to complete the installation (without this step, you will get a “module not specified” error and won’t be able to compile or run the project. You may also see a message concerning failed gradle sync at the bottom of the interface. Without this step, you may not be able to build the project (especially if it depends on the “Android 11.0 (R)” SDK.

— IF you don’t have a real/physical Android device connected, then use the “AVD Manager” (“Tools -> AVD Manager” menu option) to create a suitable emulated (Emulator) device

NOTE: I couldn’t build the native apps successfully in Android Studio or X-code if I use “ionic cap add android/ios” instead of “npx cap add android/ios”

NOTE:  if you are using NPM/NPX as opposed to ionic, see my other note for similar commands: https://confluence.oraclecorp.com/confluence/display/~ayotunde.itayemi@oracle.com/Phaser3+and+IONIC+on+NodeJS%3A+Game+Development

—- IN ORDER to build the iOS version of the game code, either run “npx cap open ios” from the project top-level folder, OR launch Xcode, then  open the project by selecting the App sub-folder  e.g., ~/scavenger/ios/App). Once the project is loaded, click on the top-level “App” in the “tree’ to the left of the IDE, then click on “Signing & Capabilities” tab in the main section of the IDE, you will need to select your team (you have to login to your iCloud account then select an existing team or create a new one – Xcode will popup the wizard), then also update your “Bundle Identifier” accordingly. Mine is “com.itayemi”. The default of “io.ionic.starter” or “org.cocoapods.Capacitor” will cause the project build to fail since it does not exist in your iCloud config by default). 
aitayemi@aitayemi-mac scavenger % export LANG=en_US.UTF-8
aitayemi@aitayemi-mac scavenger % ionic cap open ios
aitayemi@aitayemi-mac scavenger % npx cap open ios

NOTE: enable “Developer Mode” (and then under it, enable “USB Debugging”) on your real/physical Android device (“Settings” -> “About Phone” -> tap 5 times on the “build number” field to enable “Developer Mode”).
If your physical Android device doesn’t automatically appear in the available devices list in the Android Studio IDE after you connect it via your USB cable, you can click the “devices” drop down and select “Troubleshoot Device Connections” which gives you a “Rescan devices” button. My test android device had some issue with its power port so I have to wiggle the cable a little to get Android Studio to detect it)

References:

https://www.cyberithub.com/install-ionic-framework-in-linux-rhel-centos/
https://gamedevacademy.org/creating-mobile-games-with-phaser-3-and-cordova/
https://medium.com/swlh/easy-peasy-setup-of-a-phaser-3-project-with-ionic-fb4f4dc01625
https://www.tomspencer.dev/blog/2017/05/29/a-guide-to-installing-cordova-on-your-mac/
https://cordova.apache.org/docs/en/10.x/guide/platforms/osx/
https://ccoenraets.github.io/cordova-tutorial/create-cordova-project.html
https://ionicframework.com/docs/v1/guide/installation.html
https://github.com/nodejs/help/wiki/Installation
https://medium.com/enappd/how-to-create-mobile-games-pwa-with-ionic4-and-phaser-7fb1e917678e
https://vitux.com/how-to-install-android-studio-on-centos/ and https://developer.android.com/studio/install
https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm
https://phaser.io/phaser3/gettingstarted
https://www.joshmorony.com/create-native-html5-games-with-phaser-and-capacitor/
https://github.com/joshuamorony/phaser3-typescript-webpack-capacitor.git
https://guides.cocoapods.org/using/getting-started.html#installation
https://github.com/ourcade/phaser3-ionic-example
https://wpbeaches.com/installing-node-js-on-macos-big-sur-and-earlier-macos-versions/
https://www.knowledgehut.com/blog/web-development/install-angular-on-macos
https://www.zeolearn.com/magazine/setup-angular-mac
https://vuedose.tips/build-a-game-in-vuejs-with-phaser
https://www.freecodecamp.org/news/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-bdc94719135/
https://ionicframework.com/docs/cli/commands/serve

Converting WMA/MP3 and SWF/MP4 using FFMPEG

Using Apple MAC OSX to convert WMA to MP3

  • in terminal app, install brew, run: ruby -e “$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)” < /dev/null 2> /dev/null
  • in terminal app, run “brew install ffmpeg”
  • then you can run a command such as “ffmpeg -i input.wma -q:a 0 output.mp3” to convert a file called input.wma to output.mp3
  • if you have all the WMA files in the same directory/folder, you can create a script that will convert them all in one go
  • save the 6 lines below into a text file in the same directory as the WMA files e.g., called the file my_converter
  • make the script executable with the command “chmod 700 my_converter”
  • run the script with the command “./my_converter” (without the double-quotes)
  • you can change the 128k to something like 192k or smaller/bigger depending on the quality you want to MP3 to have
  • the 44100 frequency can also be increased to something like 48000 if you want
  • Below is the script (assumes all the source files are in the same directory)

#!/bin/bash
echo WMA to mp3 converter! Work begins!
for FILE in *.wma; do
echo -e “Processing file ‘$FILE'”;
ffmpeg -i “${FILE}” -vn -ab 128k -ar 44100 -y “${FILE%.wma}.mp3”;
done;

Convert Flash SWF to MP4 using Linux

– Install ffmpeg (CentOS 7)
$ sudo yum install epel-release
$ sudo yum localinstall –nogpgcheck https://download1.rpmfusion.org/free/el/rpmfusion-free-release-7.noarch.rpm
$ sudo yum install ffmpeg ffmpeg-devel

– Below is the script (assumes all the source files are in the same directory)

#!/bin/bash
echo SWF to MP4 converter! Work begins!
for FILE in *.swf; do
echo -e “Processing file ‘$FILE'”;
ffmpeg -i “${FILE}” “${FILE}.mp4”;
done;

NOTE: the conversion didn’t work out.

– Then I found some reference to using SWFtools and Gnash

git clone git://git.sv.gnu.org/gnash.git
sudo yum install -y agg-devel boost-devel SDL-devel GConf2-devel expat expat-devel libjpeg-devel speex-devel fontconfig-devel giflib-devel dejagnu curl-devel haxe

cd gnash/
/autogen.sh
./configure –enable-renderer=agg –enable-gui=dump –disable-menus –enable-media=ffmpeg –disable-jemalloc
make
sudo make install

NOTE: the conversions didn’t work properly, but old Firefox versions such as 47 can play the flash files. You can find Firefox 47 portable with flash on the Internet.
Just download it, run it, and choose “File -> Open File …” from the Firefox menu (ALT+F) and select the flash file
do not use this browser for regular browsing since it is hold and likely hackable 🙂