Alternative to Cron

For Linux systems what is a good alternative to cron?

ANSWER

(1) systemd

A lot of Linux distros are already using systemd. I’d say the major ones have been on systemd for a long time. It is capable of scheduling tasks just like cron, and has other features such as setting CPU/memory limit, randomized schedules to name a few. I haven’t used it yet. But I’ve seen some and creating a task is very different from what you may be used to with your traditional cron. It’s verbose. The good thing is there’s a lot of examples and documentation about it, plus it is built-in to your Linux system already.

(2) jobber

There’s an alternative to cron that I like to use called jobber. You can find it here: https://dshearer.github.io/jobber/

Quoting from the jobber website:

Jobber is a utility for Unix-like systems that can run arbitrary commands, or “jobs”, according to a schedule. It is meant to be a better alternative to the classic Unix utility cron

I’ve used jobber several times in little projects and some even in production. It is pretty robust and stable. As with anything new, using it requires some reading. The time format to schedule a task, or job, in jobber is not at all different from cron. It has other features such as error handling and reporting, as well as execution history.

jobber tasks are defined in a YAML file. That file can be placed in a user’s home directory. It’s not so hard to create a task for jobber. Their site has a good documentation found here: https://dshearer.github.io/jobber/doc/v1.4/#

There are pre-packaged binaries officially available to download for Debian/Ubuntu, and Red Hat. Or check your Linux distro’s application repository if it’s there. If not you could always compile it yourself. The last time I used this tool I also compiled it on the server. Easy to do that, and is explained also at their website.

Getting an MYSQLDump error

I upgrade MySQL DB from 5.6 to 5.7 version not too long now with no issues happened after. But at that time I did not use mysqldump command. Now I tried to backup the database and gettting this error message:

mysqldump: Error: ‘Access denied; you need (at least one of) the PROCESS privilege(s) for this operation’ when trying to dump tablespaces

How to fix this error.

ANSWER

The PROCESS privilege requirement was added only in MySQL version 5.7.31. This is an expected behavior and affects mysqldump utility. There is a report here and some discussions –

https://bugs.mysql.com/bug.php?id=100219

If your user has no admin privilege to the MySQL database, the quick workaround is to add the –no-tablespaces option. The usage like below.

mysqldump --no-tablespaces -u user -p DB_NAME > BACKUP_FILE.sql

On the other hand, if you have admin access, then grant that user the PROCESS privilege like this:

GRANT PROCESS ON *.* TO user@localhost;

Be warned that such privilege is usually reserved for server administrator users. It works on a global context, so it cannot be specified on a per database approach. Granting just any user this PROCESS privilege is not a good idea. It may cause “data leaks” when sensitive queries gets exposed because this privilege can allow a user to see queries being executed in active sessions. This becomes more critical when the server instance is shared.

Accidentally deleted all in Git branch

HELP! What to do?

I made first commit. Noticed a file that is not supposed to be save with sensitive values. Did not want to get the history for this one file in there, that would be viewable still.

Proceed to revert that first commit, thinking it will go back when no files was committed.

All files are gone now as result! I cannot find in my project folder even recycle bin.

ANSWER

First commit? But you want to undo for a file or two? Easy peasy. No need for revert. It’s only 1 commit! Then you would not have been in this trouble you are now.

Delete the .git folder! Mind you this is before you should have done any git voodoo. Re-init git, add files, then commit. Then you’re done. You’re back in business without having so much down time.

Now going to the other solution. I have encountered this before like you. The files are still there. So to speak. Git knows it, since it has the history for that action. A simple git log will prove.

Normally, you can pick the files back one by one simply by using the checkout command. But first, get a list of these files, including full path to it. This will show all the files that have been affected or deleted in your case.

git status

THEN

git checkout path/to/filename

For a few files, this approach works. Not very convenient when you have dozens to hundreds of files to recover. This may be your situation too. For some reason, using a wildcard will not work.

git checkout *
git checkout path/to/*

It executes but does nothing.

Sometimes commands like below will do the trick. Or it won’t. YMMV. But may be limited to *NIX-compatible OSes. For Windows, use Git Bash for one.

git ls-files -d | xargs git checkout --

In my experience, I did the following steps in git.

git log
git checkout COMMIT_ID
git commit -m "Restore my files"
git checkout master

The first command is to get the commit ID.

Second is to checkout at that commit. Now you’ll be in limbo. You’re not back at master branch where you started out. Instead this checkout will be outside of master. You’ll see a message such as

HEAD detached at COMMIT_ID_SHORTENED

This is all good. Don’t worry. Just commit those files again. That’s the third command up there.

Then once done, checkout to master. The last command shown up there.

If for some reason there are files that conflict, the switch to master branch won’t succeed. Just add those conflicting files too.

git add path/to/file/name
git commit -m "Some more files"
git checkout master

Now all is good. Look at your folder. All files are there again.

Auto-create MySQL Database in Java

Many Java / JDBC / JPA examples show only how to create DB table(s) if not existing. Like putting the table defintion or DDL in a .sql file, where the program can pick it up and execute on run-time.

But not with the database itself.

How can database be created on the fly?

ANSWER

With JDBC this can be done as a parameter to the URL connection string.

In the example shown below –

datasource.url=jdbc:mysql://localhost:3306/SCHEMA_NAME?createDatabaseIfNotExist=true

The parameter (comes after ?) – createDatabaseIfNotExist – must be set at value of true.

As I recall, this works only after MySQL version 5.1.

Note: SCHEMA is MySQL speak for database. It is common to call that even with other products. Other databases or code implementations may also term it as CATALOG.

Create Fat .gitignore in Intellij

Rather than create my .gitignore file by hand or copy from a previous project, I do not prefer this method. Is there a quicker way to generate the .gitignore file with many of the things I don’t want to be tracked by Git to be included in it.

ANSWER

Intellij IDEA

Plugin: https://plugins.jetbrains.com/plugin/7495–ignore/

Add that to your Intellij IDEA app. There is a button in that page to automatically download and install this plugin. Make sure the Intellij app is running before hitting that button.

Or you could simply download, then install manually. Select the Versions tab in the plugin page. Choose the version you want to download. Find the zipped file in your “downloads” folder.

To install manually, head over to: Settings > Plugins > (gear icon) > Install Plugin from Disk

The gear icon might be different with other versions of IntelliJ.

The plugin should be activated already, not needing an app restart.

Eclipse

For Eclipse, I’m not sure of a plugin that has pre-defined lists. I can right click on a folder/file and add to .gitignore (Team > Ignore), is what I did before. Haven’t tried an Eclipse Marketplace search.

Visual Studio Code (VS Code)

Click extension then type in “gitignore” in the search box. Look for the extension by CodeZombie. Versions as of this writing is 0.7.0.

To use, do the following:

Start command palette (with Ctrl+Shift+P or F1) and start typing Add gitignore

Other

Another way is to go to gitignore.io OR github.com/github/gitignore and get a generated .gitignore template from there. Search/select the application, OS you want. Then copy/download the generated templates.

Fatal: Refusing to Merge Unrelated Histories

fatal: refusing to merge unrelated histories

I get this error every now and then. This happens when I created a new branch first right after a new Git project was started (by me), without bothering to base it from the Master branch. The reason is the lack of permission/access to being able to write or put anything on the latter branch.

Rather than waiting for someone to kick off the Master branch, I just go ahead and start my own branch as I’ve mentioned earlier. Later on, somebody from the team who has write permissions to Master, starts a README file just to initiate it. Thus the “unrelated histories” issue happens from then on. Two branches that started off independently from each other and with no common base.

The issue appears when I want to merge my branch to Master. Git will say my branch is behind on commit on the branch it will be merged into. If I try to merge it, it gets rejected. The pipeline also won’t allow for merge conflicts like this, and advises me to fix it first.

ANSWER

As I recall, this behavior started after a certain Git version only. This to avoid to unnecessarily create a parallel history being merged into the project, because a previous merge happened between to branches that didn’t have a common base.

I’ve used Git’s “–allow-unrelated-histories” option to fix this problem. I’ll do this via command line.

Pull the Master branch into mine with the option above included.

Fix the merging conflict.

Commit the changes.

Push to remote repository.

Then this time the merge request to Master will not warn that my branch is behind a commit.

Others have commented saying that rebasing also does the trick for them. I do not recall having gone that route though.

The paragraph is green. Why?

I came across this sort of “CSS riddle” recently.

It goes something like this.

Given this CSS definition,

body {
  max-width: 28em;
  margin: auto;
  padding: 1em;
}

html {
  --color: green;
}

body {
  color: yellow;
}

p {
  --color: inherit;
  color: red;
  color: var(--color, blue);
}

what would be the color of the <p> element?

<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent bibendum, lorem vel tincidunt imperdiet, nibh elit laoreet felis, a bibendum nisl tortor non orci. Donec pretium fermentum felis, quis aliquet est rutrum ut. Integer quis massa ut lacus viverra pharetra in eu lacus. Aliquam tempus odio adipiscing diam pellentesque rhoncus. Curabitur a bibendum est. Mauris vehicula cursus risus id luctus. Curabitur accumsan venenatis nibh, non egestas ipsum vulputate ac. Vivamus consectetur dolor sit amet enim aliquet eu scelerisque ipsum hendrerit. Donec lobortis suscipit vestibulum. Nullam luctus pellentesque risus in ullamcorper. Nam neque nunc, mattis vitae ornare ut, feugiat a erat. Ut tempus iaculis augue vel pellentesque.</p>

Source: https://codepen.io/shshaw/pen/wvJmOOq

ANSWER

The output color is Green. As if the title wasn’t a giveaway.

Try it out yourself too.

Here is an explanation: https://twitter.com/SelenIT2/status/1400832345016606722

Quoting from that Tweet:

It does inherit it. But then the color gets overridden with the inherited value of the *custom property* named `–color`, which doesn’t know anything about the actual `color` property and gets independently inherited all the way down from `html`

What Password Managers available in Linux

List of Password Managers that are available in Linux?

Aside from BitWarden. I want to know some alternatives you guys are using. Prefer it’s standalone program instead of browser plugin or extensions.

ANSWER

I am using KeePassXC personally for some time. 1Password for work-related stuffs.

The first one is a KeePass variant and open-source. It has a Qt-based application that has been available for Linux for a while. Then, 1Password support in Linux was in beta since last year. Recently it has been moved out of beta.

Others I know off the top of my head,

  • AuthPass
  • Password Safe (for Gnome DE)
  • KeePassX (where KeePassXC was forked)

View what’s inside the Keystore

I have a file with java keystore type that I would like to inspect. Can the contents of the keystore of java be viewed if I don’t have it password? I want to verify an SSL certificate is inside of it. Maybe also check the details are correct, expiration date and so on. What tool can be used to open the keystore?

ANSWER

The normal notion that because the Java Keystore (JKS for short) asks for a password, then I cannot see what is in it is not entirely correct. The password for the JKS does not prevent that. Instead the purpose of the password is to protect the integrity of the JKS. The intention is that without the password, I should not be able to modify the contents, such as adding certificates or deleting some.

With the proper tool I can still read what is inside of a JKS. Normally we just use the keytool. This command line tool usually comes with the Java installation in your system. Try to find it in the installation directory of Java. It resides together with other Java binaries in the ../bin/ directory.

Without password warnings will be displayed, like this one:

*****************  WARNING WARNING WARNING  *****************
* The integrity of the information stored in your keystore  *
* has NOT been verified!  In order to verify its integrity, *
* you must provide your keystore password.                  *
*****************  WARNING WARNING WARNING  *****************

How to print what is inside the JKS:

(1) View all as a list

:~$ keytool -list -keystore /path/to/keystore/file

(2) View all as a list with details

:~$ keytool -list -v -keystore /path/to/keystore/file

(3) View a specific entry only using alias with details (The alias is the text that comes out in command #1 before the date, without the comma)

:~$ keytool -list -alias "the alias text" -v -keystore /path/to/keystore/file

How to fix error: snap “telegram-desktop” has “install-snap” change in progress

I enconter this error message when installing a Snap app Telegram for Desktop from the terminal command line. I followed instructions on how to do this from the Install button of the snapcraft.io website.

First one I select is use the GUI app store. But nothing happens when click install button. Installing progress starts but go back to install. Click again and same thing is happens.

When using the command line that is I got the error of:

error: snap "telegram-desktop" has "install-snap" change in progress

How to fix?

ANSWER

The error is because you are telling Snap to install an app that has already been scheduled for installation. It’s in the queue. The GUI app store is not very informative about this scenario. Hence, it will seem like the installation process failed when in fact that is not the case.

My guess is it is put on schedule for installation because a higher priority install needs to be done first, most likely Snap core updates that have not yet been applied to the system yet.

Either wait for the core updates to finish and wait for Telegram to get installed after, or force it to update right away.

At the command line, do:

:~$ snap changes

It will show something such as:

ID Status Spawn Ready Summary
101 Done yesterday at 20:33 PST yesterday at 20:34 PST Auto-refresh snap "intellij-idea-community"
102 Doing today at 11:36 PST - Install "slack" snap

Abort the scheduled install for the app listed there, in your case “telegram-desktop” snap using the following command:

:~$ sudo snap abort 102

In the example above, I chose to abort install scheduled with ID 102. Choose the ID of the app you are trying to install that you will see on your terminal after the command above.

Then install the snap app manually:

:~$ sudo snap install telegram-desktop

This should force snap to go ahead with the install, but first it may start with its core updates, followed by the telegram-desktop snap app.

Change default app to open torrent magnet link

I installed a Popcorn-time desktop software on my Ubuntu linux to try that out. It appears to use a torrent technology to stream content as it downloads at the same time. Somehow that now gets the default to open magnet links for torrent files. Have not remembered any setting asking me to make the app open by default during installation or at download.

I don’t want this, don’t know how to change to my default torrent software – Transmission BitTorrent.

How to change back?

ANSWER

Add/edit it into the following files. Either or both is fine, but better to have it in for the system-wide list if you have multiple users.

  • System-wide: /usr/share/applications/defaults.list
  • User-specific: ~/.local/share/applications/mimeapps.list

The value of this entry – x-scheme-handler/magnet – needs to be set to the application you prefer.

For example, since you want it to be Transmission it will be similar as shown below:


x-scheme-handler/magnet=transmission-gtk.desktop

Just make sure the .desktop file for the desired application is correct. Again you can check for that file in the same directory where this list is found.

As an alternative, the following terminal commands will also help.

Find out what is the existing default app that will handle such mime-type for your existing user:

:~$ xdg-mime query default x-scheme-handler/magnet

Replace that by using the next command:

:-$ xdg-mime default transmission-gtk.desktop x-scheme-handler/magnet

Lastly, you can check again if the last command was successful by running the first one.

Base64-encoded value is slightly different at the end of string

Why is there slight differences in base64 encoding at the end of the encoded string. It could be one or more of characters that’s different.

Here an example done on base64encode.org using this text – Hey, Diddle Diddle – the output value is:

SGV5LCBEaWRkbGUgRGlkZGxl

But when I do same in base64 command line, I get this instead:

SGV5LCBEaWRkbGUgRGlkZGxlCg==

It is 4 more characters longer. Which one is correct encoding?

ANSWER

The most likely answer is caused by a non-visible character, or characters, being appended at the end of the text you are trying to encode that is causing the slight variation.

Normally this would be caused by the new line, or line feed character, that you won’t see but is there at the end of the text. It is a valid character that the base64 command will include when it encodes the text you give it.

It is not wrong, but most times it is not the intention to have the new line character encoded with it.

Thus, when doing so in command line make sure the new line character is trimmed off. It can be done this way,

:~$ echo -n "hello world" | base64

The result would be: aGVsbG8gd29ybGQ=

Without it, the output is: aGVsbG8gd29ybGQK

Of course, the case of the character/characters being encoded will also matter.

There any free, lightweight app to merge PDF files as one?

As the name of the title in this post says it all. Okay, maybe not all it says because I want it on Linux desktop.

Looking for a tool that can combine different PDF into one big PDF file. I don’t need to modify the content of the PDFs. All important is merging them together as a group.

Sorting it probably comes as second important feature. But I can get on without that as long as it stays in sequence however I added each PDF file.

Lastly simple. No over the top effects. Prefer GUI app. Open to command line.

ANSWER

For that purpose, I have personally used PDF-Shuffler, It is a GUI desktop application on Linux. I used it back then on Ubuntu, but it should be available in all other major distros. Google for it. I know it is included in the official package management repositories of Ubuntu.

PDF-Shuffler can collate, sort (through drag and drop) and rotate the PDF files individually. As an added bonus, it can crop PDFs too.

It is a straightforward app. Stable for all those times I’ve used. But my usage is fairly moderate only.

I also suggest using pdftk for command line if you fancy that kind of stuff. You can combine PDFs into one as simple as:

:~$ pdftk file-1.pdf file-2.df file-3.pdf output my-merged.pdf

This tool can do other stuff. You can read its manual for more information. Google about pdftk too for more examples.

Support for Ubuntu Unity Desktop after 16.04 LTS

Can still use the Unity Desktop after Ubuntu 16.04 Xenial Xerus? Is it still supported?

I like the Unity desktop way of things. Been using it many years now. Read about and tried the new Ubuntu that with Gnome Shell, but I don’t like it much at all. It look clunky with many of missing things from it.

Come April 2021 Ubuntu 16.04 will EOL. Starting to find alternatives, but if Unity is still out there, I’d pick it over the others.

ANSWER

In one word, Yes.

Still can run on both LTS versions of 18.04 and 20.04. Go ahead and install it with:

sudo apt install ubuntu-unity-desktop

Choose Lightdm display manager when asked during install. Best to restart your computer afterwards. Then enjoy.

Consider that many people have said some weird looks of Unity when installed on said LTS versions appear. I forget, but I think its the window decorations and such. This is supposedly caused by the newer Gnome versions, and unpatched by Ubuntu. Unlike before.

You may also like to try out an alternative in the Ubuntu Unity Desktop spinoff. Can be found at this website – https://ubuntuunity.org/

It is not official Ubuntu flavor, but being maintained by some other 3rd party group. The experience is different from just installing 20.04 and then install Unity DE afterwards. Try it out if it suits you.

How to convert For loop using Stream in Java

Creating a Map of Applicant object, where I filter out on the applicant’s age. I only need the first name and last name of the applicant. Using the application ID as the key. The ID is generated integer and unique. Also, testing for null, don’t want that in there. I am using a traditional for loop where I am most comfortable at. But I want to use the Java 8 Stream instead. How is it done?

My code for this is below:

        Applicant a1 = new Applicant();
        a1.setId(1001);
        a1.setFirstName("Joseph");
        a1.setLastName("Dey");
        a1.setAge(25);

        Applicant a2 = new Applicant();
        a2.setId(2001);
        a2.setFirstName("Maxine");
        a2.setLastName("Summers");
        a2.setAge(21);

        Applicant a3 = new Applicant();
        a3.setId(3001);
        a3.setFirstName("Jimmy");
        a3.setLastName("Cox");
        a3.setAge(17);

        Applicant a4 = null;

        List<Applicant> list = new ArrayList<>();
        list.add(a1);
        list.add(a2);
        list.add(a3);
        list.add(a4);

        Map<Integer, String> map = new HashMap<>();
        for (Applicant a : list) {
            if (a != null && a.getAge() > 18) {
                map.put(a.getId(), a.getFirstName() + " " + a.getLastName());
            }
        }

ANSWER

By Statement Lambda in Collectors.toMap – right-hand side is a block. This can become longer to write but sometimes when you have to do more transformations, then it can’t be avoided.

1       Map<Integer, String> map = list.stream()
2                .filter(applicant -> applicant != null)
3                .filter(applicant -> applicant.getAge() >= 18)
4                .collect(Collectors.toMap(applicant -> applicant.getId(), applicant -> {
5                    return applicant.getFirstName() + " " + applicant.getLastName();
6                }));

By Expression Lambda in Collectors.toMap – right-hand side is an expression.

1       Map<Integer, String> map = list.stream()
2                .filter(applicant -> applicant != null)
3                .filter(applicant -> applicant.getAge() >= 18)
4                .collect(Collectors.toMap(applicant -> applicant.getId(), applicant -> applicant.getFirstName() + " " + applicant.getLastName()));

In both cases above, line #2 the Lambda can be replaced with method reference too. It will look like:

.filter(Objects::nonNull)

And on line #4, the same can be done for the Lamba replacing it with a method reference. It will look like:

.collect(Collectors.toMap(Applicant::getId,  // rest of code ommitted