Monday, October 23, 2023

React JS Material UI icons for Mastodon and Blogger

Other than the Linkedin icon, I couldn't find the Mastodon and Blogger React Material UI (MUI) icons in the React @mui/icons-material library so I had to make my own with Inkscape and a good old text editor. The results are shown in the screenshot below.

 Here is the MastodonIcon.js code for the Mastodon icon:

import * as React from 'react';
import SvgIcon from '@mui/material/SvgIcon';

export default function MastodonIcon() {
  return (
    <SvgIcon>
      <svg className="mastodon" width="16" height="16" fill="currentColor" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
        <path d="m10.751 11.617c1.7387-0.20699 3.2514-1.2721 3.4412-2.2449 0.30012-1.5334 0.27598-3.7421 0.27598-3.7421 0-2.9926-1.9715-3.8706-1.9715-3.8706-0.99355-0.45451-2.7002-0.6451-4.4734-0.65976h-0.043122c-1.774 0.014661-3.48 0.20526-4.4734 0.65976 0 0-1.9706 0.87709-1.9706 3.8706l-0.00173 0.57093c-0.00345 0.55195-0.00603 1.1643 0.0095 1.8033 0.071582 2.9271 0.53988 5.8128 3.26 6.5286 1.2539 0.33031 2.3311 0.39931 3.1988 0.35188 1.5722-0.08625 2.4554-0.55799 2.4554-0.55799l-0.05176-1.1358s-1.1237 0.3536-2.3864 0.31047c-1.2505-0.04312-2.57-0.13454-2.7728-1.6628a3.1169 3.1169 0 0 1-0.028456-0.42777s1.2281 0.2984 2.784 0.36912c0.95126 0.04312 1.843-0.0552 2.7495-0.163zm1.3911-2.1302h-1.4429v-3.5188c0-0.74083-0.31393-1.1168-0.94091-1.1168-0.69339 0-1.041 0.44587-1.041 1.329v1.9258h-1.4351v-1.9266c0-0.88313-0.34756-1.329-1.041-1.329-0.62699 0-0.94091 0.37602-0.94091 1.1177v3.5179h-1.4429v-3.6239c0-0.74083 0.18973-1.329 0.56921-1.7646 0.39327-0.43553 0.90728-0.6589 1.5463-0.6589 0.73824 0 1.2971 0.28288 1.6671 0.84777l0.35964 0.5994 0.35964-0.5994c0.36998-0.5649 0.92884-0.84777 1.668-0.84777 0.6382 0 1.1522 0.22337 1.5446 0.6589 0.38119 0.43553 0.57007 1.0237 0.57007 1.7646z" strokeWidth=".86244" />
      </svg>
    </SvgIcon>
  );
}

And here is the BloggerIcon.js code for the Blogger icon:

import * as React from 'react';
import SvgIcon from '@mui/material/SvgIcon';

export default function SvgIconChildren() {
  return (
    <SvgIcon>
      <svg width="50.664mm" height="50.575mm" version="1.1" viewBox="0 0 179.52 179.2" xmlns="http://www.w3.org/2001/svg">
        <defs>
          <clipPath id="clipPath8">
            <path d="m111.47 137.84c6.8936-0.96075 12.296-3.7837 17.364-9.0736 3.6662-3.8268 5.9611-7.9689 7.4609-13.466 0.62305-2.2837 0.67529-3.3956 0.78946-16.804 0.0863-10.12 0.0143-14.86-0.24367-16.056-0.37384-1.7344-1.4336-3.345-2.6427-4.0165-0.37209-0.20664-2.7561-0.47002-5.2978-0.58526-4.2591-0.19314-4.7356-0.278-6.08-1.0829-2.1324-1.2768-2.7197-2.6555-2.7255-6.3987-0.0111-7.152-2.9243-13.792-8.6802-19.785-4.1006-4.2694-8.6751-7.1592-13.896-8.7785-1.2498-0.38765-4.0484-0.51957-13.422-0.63274-14.708-0.17757-17.973 0.13047-22.98 2.1682-9.2314 3.7568-15.864 11.674-18.284 21.824-0.45444 1.9064-0.54266 4.9618-0.65 22.513-0.13448 21.988 0.01386 25.217 1.3586 29.575 1.111 3.6002 2.232 5.8063 4.5414 8.9376 4.3994 5.9652 10.993 10.273 17.585 11.49 3.137 0.57911 41.84 0.72399 45.804 0.17161z" display="none" fill="#fff" strokeWidth=".86401" />
            <path className="clip" d="m8.0345 6.3499h163.45v166.5h-163.45zm103.44 131.49c6.8936-0.96075 12.296-3.7837 17.364-9.0736 3.6662-3.8268 5.9611-7.9689 7.4609-13.466 0.62305-2.2837 0.67529-3.3956 0.78946-16.804 0.0863-10.12 0.0143-14.86-0.24367-16.056-0.37384-1.7344-1.4336-3.345-2.6427-4.0165-0.37209-0.20664-2.7561-0.47002-5.2978-0.58526-4.2591-0.19314-4.7356-0.278-6.08-1.0829-2.1324-1.2768-2.7197-2.6555-2.7255-6.3987-0.0111-7.152-2.9243-13.792-8.6802-19.785-4.1006-4.2694-8.6751-7.1592-13.896-8.7785-1.2498-0.38765-4.0484-0.51957-13.422-0.63274-14.708-0.17757-17.973 0.13047-22.98 2.1682-9.2314 3.7568-15.864 11.674-18.284 21.824-0.45444 1.9064-0.54266 4.9618-0.65 22.513-0.13448 21.988 0.01386 25.217 1.3586 29.575 1.111 3.6002 2.232 5.8063 4.5414 8.9376 4.3994 5.9652 10.993 10.273 17.585 11.49 3.137 0.57911 41.84 0.72399 45.804 0.17161z" strokeWidth=".86401" />
          </clipPath>
        </defs>
        <path d="m-82.995 87.838v-171.9h1020v343.8h-1020v-171.9z" fill="none" />
        <g transform="matrix(.92141 0 0 .92141 7.0545 7.0421)" fill="#fff" strokeWidth=".86401">
          <path d="m30.568 167.24c-2.8716-0.77176-5.3495-1.9071-7.6348-3.4982-1.9292-1.3431-4.7488-4.1198-5.8212-5.7323-1.3096-1.9694-2.815-5.342-3.4285-7.6809-0.62576-2.3858-0.6359-3.336-0.64713-60.605-0.01116-56.98 0.0015-58.233 0.61488-60.681 2.169-8.6596 8.8857-15.248 17.548-17.214 2.4907-0.56514 113.75-0.66398 116.44-0.10343 7.2734 1.5175 12.991 5.979 16.299 12.719 2.6303 5.3583 2.3951-0.53816 2.5156 63.081 0.0767 40.479 6e-3 57.473-0.24689 59.59-1.1845 9.9072-7.8732 17.592-17.498 20.103-2.462 0.64225-3.3184 0.65142-59.215 0.63395-54.046-0.0166-56.821-0.0454-58.928-0.61194z" clipPath="url(#clipPath8)" />
          <path d="m70.797 77.476c-3.5242-0.9925-4.841-6.1585-2.2508-8.8303 1.6555-1.7077 2.1132-1.7727 12.476-1.7727 9.3029 0 9.6156 0.02079 10.982 0.72599 1.9748 1.0193 2.8328 2.4564 2.8328 4.7444 0 2.0665-0.80586 3.5146-2.6034 4.6784-0.96518 0.62486-1.542 0.66375-10.657 0.71844-5.6283 0.0338-10.112-0.07615-10.78-0.26416zm-0.44157 34.766c-1.5128-0.67346-2.9215-2.5442-3.165-4.203-0.23192-1.5801 0.54532-3.7524 1.7367-4.854 1.5018-1.3886 2.161-1.435 20.63-1.4498 18.999-0.0152 18.9-0.0234 20.701 1.6952 2.5446 2.4274 2.0078 6.749-1.0585 8.5234l-3.151 0.52354-16.423 0.19641c-14.431 0.17258-18.519-0.0973-19.271-0.43172z" />
        </g>
      </svg>
    </SvgIcon>
  );
}

Hope these help somebody.

Monday, June 5, 2023

How to sync the time between 2 Ubuntu systems on an isolated network

I wanted to match the times between two systems on an isolated network running Ubuntu 22. This can be done using chrony (https://chrony.tuxfamily.org) on the two systems - one system serves as the local time server to the other client system. 

Setting up the Server

  1. Optional. If chrony is not installed, run the following command in the Terminal to install it.

    $ sudo apt install chrony

  2. Using a text editor, add the following lines to the file /etc/chrony/chrony.conf.


    local stratum 8
    allow xxx.xxx.xxx.xxx


    Note 1: The keyword local tells chrony to server isolated networks.
    Note 2: The allow keyword specifies the IP address of the client to server


  3. Restart the chrony service using the following command. Or you can reboot.

    $ sudo systemctl restart chronyd

Setting up the Client

  1.  Optional. If chrony is not installed, run the following command in the Terminal to install it.

    $ sudo apt install chrony

  2. Using a text editor, add the following to the file /etc/chrony/chrony.conf.

    server yyy.yyy.yyy.yyy minpoll 0 maxpoll 5 maxdelay 0.1

  3. Restart the chrony service using the following command. Or reboot.

    $ sudo systemctl restart chronyd

  4. To verify whether the syncing is working, the following command can be used.

    $ chronyc sources -v



    Note: If the sync is successful, the MS column should be showing the symbols ^* for the IP address of the server entry.


 

Monday, April 3, 2023

How to create a Arm64 Ubuntu virtual machine using Virt-Manager

I wanted to run Ubuntu on an Arm64/Aarch64 virtual machine on a host Intel Linux computer for the longest time for compiling binaries for Raspberry Pis and other SBC boards. I finally figured out how to do it with virt-manager, and it is quite simple as clicking and selecting options on the virt-manager graphical user interface. The instructions below show how it is done.

Download and install prerequisites

  1. In Ubuntu, open up a Terminal and enter the following commands to install the prerequisite software.

    $ sudo apt install qemu-kvm \
    libvirt-daemon-system \
    libvirt-clients \
    bridge-utils \
    virt-manager \
    qemu-system-arm \
    qemu-efi-aarch64 \
    qemu-utils
    

  2. Open up an Internet browser. Download an Ubuntu Arm64 image to install. For example: https://cdimage.ubuntu.com/releases/22.04/release/ubuntu-22.04.2-live-server-arm64.iso

 Create the virtual machine

  1. In Ubuntu, click the Virtual Machine Manager icon.

    The Virtual Machine Manager application appears.


  2. Select File | Create New Virtual Machine.

    The New VM dialog box pops up.


  3. Choose Local install media (ISO image or CDROM).

  4. In the Architecture options, choose aarch64 architecture. Click Forward.

    Step 2 of 5 pages appears.

  5. In the Choose ISO or CDROM install media field, choose the iso image downloaded previously.



  6. Click Forward. If necessary, change the memory size and the number of CPUs.

    Step 3 of 5 pages appear.


  7. Click Forward. If necessary, change the disk image size to a suitable size.

    Step 4 of 5 appears.


  8. Click Forward.

    Step 5 of 5 appears.


  9. Optional. In the Name field, type in a desired name.

  10. Toggle On the Customize configuration before install field.




  11. Click Finish.

    The 'vm name' on QEMU/KVM dialog box appears.



  12. In the Hypervisor Details group, change the Firmware to UEFI aarch64.


  13. Click Apply. Then click the Begin Installation button and follow the prompts to complete the installation.

    The installation begins...


Monday, March 27, 2023

Convert a sequence of JPG images into a MP4 video using FFMPEG

If you have a sequence of images like the screen shot below, it is quite straightforward to use ffmpeg to concatenate them into a single video file. 


Obviously, you need to specify the image file name and sequence pattern, the frame rate to show each image as shown in the example ffmpeg command below.

$ ffmpeg -hide_banner \
-f image2 \
-framerate 1 \
-start_number 1 \
-i %02d.jpeg \
-vcodec mpeg4  \
output.mp4

where -f specifies the input format as image,

-framerate specifies the rate in Hz at which to display each image frame,

-start_number specifies the starting number of the image frame sequence,

-i specifies the file name and sequence pattern, e.g. %02d means a pattern of 2 digits with a prefix character '0' for single digit numbers,

-vcodec tells ffmpeg to output mpeg4 format.

 Running the command will display the following output and generate the output video file output.mp4.


Monday, January 30, 2023

Fixing a kernel panic error when installing Ubuntu 20.04 in VirtualBox

I was trying to create an Ubuntu 20.04 virtual machine using Oracle VirtualBox but I kept encountering this error with the message "...end kernel panic - not syncing: Attempted to kill the idle task!..." The screenshot below shows the error in VirtualBox.

Eventually, I found out the error was caused by inadequate alllocated CPU resources in VirtualBox. By default, the number of CPU allocated for the VM is 1, as shown in the screen shot below.

Simply increasing the number of CPU to at least 2 helped to solve the kernel panic error in this case.

Monday, December 12, 2022

How to read an array from a ROS1 launch file into a C++ vector variable

I was having problems reading an array of doubles in a ROS launch file into a vector variable in a C++ ROS1 program node. After some digging around, I found I was doing it the wrong way; instead of using the <param> tag in the ROS launch file, I should be using the <rosparam> tag. 

The example ROS launch file listing shows the correct way to enter an array, e.g. [0.01, 0.1, 0.2] with the <rosparam> tag:

?xml version="1.0" encoding="UTF-8"?>
<launch>
  <node pkg="learning_tutorial" type="my_node" name="my_node">
        <param name="my_string_param" value="hello" />
        <rosparam param="my_array_param">[0.01, 0.1, 0.2]</rosparam>
  </node>
</launch>

Then in the ROS C++ code, I could do the following to read the array:

// ...etc...

using namespace ros;
using namespace std;

vector<double> myArrayParam;
NodeHandle nh;

// Read the my_array_param from the launch file into the myArrayParam variable
nh.param<vector<double>> ( "my_array_param", myArrayParam, { 1, 2, 3});

// Just print out the array parameter
ROS_INFO ( "My array: %f, %f, %f", myArrayParam[0], myArrayParam[1], myArrayParam[2]);
 
// ...etc...

Hope this helps somebody.


Monday, December 5, 2022

Using GIMP to copy an image layer into a channel

In GIMP, it is possible to copy a colored image layer into a single grayscale channel. Here's how to do the job.

Create an empty channel

  1. In GIMP, open up the image file.



  2. Click the Channels tab on the bottom right.



  3. Then click the Create a new channel icon.

    The New Channel dialog box appears.


  4. Optional. In the Channel name field, type in a name, e.g. flats. In the Fill opacity field, slide to 50.0.
     
  5. Click OK.

    A new channel is created.

Copy and paste the colored image into the channel

  1. Click the Layers tab. Click the image layer, e.g. bored-tiger.jpg to make sure it is active.




  2. In the menu, choose Select | All. Then choose Edit | Copy.

    The layer is copied to the clipboard.

  3. Click the Channels tab. Click the previously created channel, e.g. flats.



  4. In the menu, select Edit | Paste in Place



  5. Then click the Layers tab.

    A Floating Selection (Pasted Layer) is visible in the Layers list.



  6. Click the green Anchor the floating layer icon.

    The pasted layer is added to the active channel.

  7. Optional. Click the Channels tab.

    Note the channel thumbnail has been updated with a grayscale image of the pasted layer.