[{"categories":null,"contents":"1. Introduction In my recent endeavour to upgrade my digital security, I started using Pass, the command-line based password manager for my online accounts. While there were a few online guides that I could follow to get started with Pass, I did feel a need of a comprehensive guide for new users of Pass. In my attempt to fill the gap, I will try to touch upon various aspects that one needs to be mindful of to use Pass in the most secure and optimal way.\n2. Why a (dedicated) password manager The days are over when you remembered the passwords for all your online accounts. In this age, you need to use an online account virtually for every other service. And even though many services are offering multi-factor authentication (MFA) options today for securely logging into your accounts, the importance of a strong password is still as high as ever. And the best security practices say that a password is the strongest when it is as random as possible, something that an average human mind can neither create nor remember easily. And this is where the importance of a password manager lies. It\u0026rsquo;s far easier to rather lock all your keys behind a master lock and have one very secure key than to carry around separate unique keys with you for all the locks.\nBut when in today\u0026rsquo;s age, effectively all major browsers provide password storage and sync features, it may not sound very practical to have a separate piece of software for storing your passwords. There can be arguments on both sides but it\u0026rsquo;s generally a more secure practice to not give away too many responsibilities to one software and trust a browser for what it does best - browse the internet.\n3. Why Pass Pass is a command-line password manager. It may not sound very attractive compared to various cloud-based alternatives that are available today especially if you are not a command-line person but the main power of Pass comes from it\u0026rsquo;s simplicity and transparency. At it\u0026rsquo;s core, Pass does not do much by itself and makes use of other Unix software that are already available and are industry standards. Namely it uses gpg for encryption of the stored passwords and git for version control and cloud syncing.\nAnother inspiration to use Pass could be that if you do not feel too inclined to blindly trust the cloud-based and closed-source password managers available in the market.\nIn the next sections, I will discuss about different aspects of installing and using Pass.\n4. GPG key for Pass Before we can use Pass, the very first step is to create a GPG key that will be used by Pass. If you already have an existing one and you wish to reuse it, you can skip this step. If you are using a Linux or Mac system, chances are that GPG is already installed in your system. Try entering this command which will print the installed version of GPG to make sure that it\u0026rsquo;s already installed.\ngpg --version If not, use your package manager to install it.\n4.1 Coming up with a good pass phrase Before you create your GPG key, it\u0026rsquo;s extremely important to come up with a good pass phrase that you can use with your key. And the characteristics of a good pass phrase are that it should as random as possible and yet it should be easy to remember. The Diceware method is an excellent way to generate a truly random pass phrase.\nYou can use the diceware command-line tool for this. It\u0026rsquo;s available in the Debian package repository. You can also install it using pip. To generate a random 6-words long pass phrase with space as the delimiter, use the following command:\ndiceware -d \u0026#39; \u0026#39; 4.2 Creating the GPG key Creating a GPG key is easy, just use the following command to interactively create one:\ngpg --full-gen-key Go with the default crypto algorithm. Use the maximum allowed length: 4096. It\u0026rsquo;s not recommended to have keys that never expire. 2y should be a reasonable expiry period. Enter your name and email address. You can use the comment field to put a unique value for uniquely identifying keys sharing the same email address. Enter the pass phrase from the above section when prompted. This ought to create a private and public key pair for you.\n4.3 Taking back up of the GPG key It\u0026rsquo;s awfully crucial to take backup of the GPG private key that you just created. It will help you to restore access to your passwords from backups and also to share the passwords between computers.\nUse the following command to list all your GPG keys:\ngpg --list-secret-keys The above image highlights the ID part of a GPG key. Copy the ID of the key that you created from your output list. Next use the following command to export it to a file. Use the actual path of where the private key will be exported to in the below command and replace the \u0026lt;key ID\u0026gt; with the ID copied from the above step.\ngpg --export-secret-keys --armor --output \u0026lt;/path/to/secret-key-backup.asc\u0026gt; \u0026lt;key ID\u0026gt; The above exported private key is already secure with the pass phrase that you entered earlier. But to put an additional layer of security around it, let\u0026rsquo;s compress and encrypt the exported keys. Also remove the secret-key-backup.asc file afterwards.\ntar -cvJf - \u0026lt;/path/to/secret-key-backup.asc\u0026gt;|gpg --symmetric --output keys.tar.xz.gpg rm \u0026lt;/path/to/secret-key-backup.asc\u0026gt; Enter a new password for the encryption when prompted. This password will be required again when you will decrypt the content of the archive later, so make sure that you can remember it again when needed. You can now safely store the keys.tar.xz.gpg file in a CD or in your back up hard drive.\n5. Initializing Pass You need to initialize Pass before you can start using it. It\u0026rsquo;s a very easy step to initialize Pass.\npass init \u0026lt;key ID\u0026gt; Replace \u0026lt;key ID\u0026gt; with the actual GPG key ID. And that\u0026rsquo;s it.\n6. Storing and retrieving a password in Pass Pass encrypts your passwords with the GPG key and keeps the encrypted files organizes in a directory structure under the default root directory ~/.password-store. To insert a new password for the website example.com into Pass, use the following command:\npass insert example.com Enter the password for example.com when prompted. This will create an encrypted file named example.com.gpg inside ~/.password-store and store the password in it. If you have multiple accounts for a website, you may use the following convention:\npass insert example.com/username1 This will an encrypted file named username1.gpg inside ~/.password-store/example.com to store the password.\nTo print a password to the terminal, use the following:\npass example.com You will need to enter your GPG pass phrase. Alternatively to copy the password securely in your clipboard, use the -c flag without printing it on the terminal.\npass -c example.com This command also automatically clears the copied password from the clipboard after 45 seconds to prevent you from inadvertently pasting it in some other place.\nYou can also auto-generate a random password with the following command:\npass generate example.com 7. Integrating Pass with Git Pass also provides integration with Git - the revision control system. This in turn can be used to back up the stored passwords to an online remote repository like GitHub or GitLab. This is also useful if you want to share your passwords between multiple computers.\nIn this example, I will be using GitHub. But any other online version control system that uses Git can also be utilized instead of GitHub. Follow this guide to create a private GitHub repository.\nNow, to initialize the Pass root directory as a git repository, run the following:\npass git init And to add the remote Git repository URL, use the following:\npass git remote add origin git@github.com:\u0026lt;username\u0026gt;/\u0026lt;repository-name\u0026gt;.git Replace your username and the newly created repository name in the above command.\nWith every insert , edit and generate operations, Pass will automatically make a new commit to your local Git repository. You can use the following commands to push or pull your changes to and from the remote repository.\npass git push pass git pull 8. A common problem and the solution Pass has clients for many platforms including Firefox and Chrome. But I prefer using it without the clients which means copying the passwords to the clipboard from Pass and then pasting them directly in the browser. The problem with this approach is that some websites block users from copying or pasting anything on them for some unfounded security reasons. Follow this guide for a workaround to this problems on Firefox and Chrome.\n9. Conclusion I understand that Pass may not be to everyone\u0026rsquo;s taste and it\u0026rsquo;s completely fine to use another, a more user friendly password manager as long as you are using one. But to the ones who want to use it and are looking for a way to get started, I hope you find this article useful.\n","permalink":"https://www.subhadig.net/posts/a-practical-guide-to-get-started-with-pass/","tags":["command-line","pass"],"title":"A practical guide to get started with Pass"},{"categories":null,"contents":"1. Introduction To someone coming from the Java world to the world of Kotlin, the concepts of Covariance and Contravariance can be somewhat overwhelming to grab at first. But they don\u0026rsquo;t have to be once you start understanding the basic cadence of it. This article is going to be a step by step depiction of how I have come to understand these two topics.\n2. Let\u0026rsquo;s create some classes! First let\u0026rsquo;s create a small class hierarchy that we can use to understand these concepts. Paper is the parent class of the Regular paper and the Premium paper.\nopen class Paper { } class Regular: Paper() { } class Premium: Paper() { } 3. Let\u0026rsquo;s create some lists!! First let\u0026rsquo;s create a List of Regular papers called regularPapers.\nval regularPapers: List\u0026lt;Regular\u0026gt; = listOf(Regular()) And now if we declare a List of the parent type Paper called papers and try to assign the just created regularPapers List to it, we will see that it works without any compilation errors.\nval papers: List\u0026lt;Paper\u0026gt; = regularPapers Sure a List of Regular paper is still a List of Paper, you say. There is nothing earth-shattering about it!\nBut when you look at the following example you will surely think that there is more going on under the hood than meets the eye.\nval mutableRegularPapers: MutableList\u0026lt;Regular\u0026gt; = mutableListOf(Regular()) val mutablePapers: MutableList\u0026lt;Paper\u0026gt; = mutableRegularPapers //This line gives compilation error When you replace the List with a MutableList in our example, you will see that the compilation fails with this error: Type mismatch: inferred type is MutableList\u0026lt;Regular\u0026gt; but MutableList\u0026lt;Paper\u0026gt; was expected.\nBut what could be so different between a List and a MutableList so that a List of Regular papers can be used as a List of Paper but a MutableList of Regular papers can not be used as a MutableList of Paper? As it turns out, the answer lies in the definitions of List and MutableList.\npublic interface List\u0026lt;out E\u0026gt; : Collection\u0026lt;E\u0026gt; { .. } public interface MutableList\u0026lt;E\u0026gt; : List\u0026lt;E\u0026gt;, MutableCollection\u0026lt;E\u0026gt; { .. } The out keyword in the List declaration makes all the difference. This means that a List\u0026lt;T\u0026gt; is assignable to any List\u0026lt;U\u0026gt; where U is a subtype of T. But the same is not true for a MutableList since it\u0026rsquo;s declared as MutableList\u0026lt;E\u0026gt; and not as MutableList\u0026lt;out E\u0026gt;. This is Covariance for you in a nutshell.\n4. Covariance Covariance follows the natural inheritance order where a less generic subtype can be used in place of a more generic supertype. Covariant is expressed with the out keyword.\nLet\u0026rsquo;s declare a Covariant class called Box.\nclass Box\u0026lt;out T\u0026gt; { } Now we can create a Box of Regular papers and assign it to a Box of Paper. The following code compiles without any error.\nval regularPaperBox = Box\u0026lt;Regular\u0026gt;() val paperBox: Box\u0026lt;Paper\u0026gt; = regularPaperBox So Covariance is the Kotlin Generics feature that allows us to pass a Box of Regular papers as a Box of Paper.\n5. Contravariance Contravariance is the inverse of Covariance where a more generic subtype can be used in place of a less generic supertype. Contravariance is expressed with the in keyword.\nLet\u0026rsquo;s declare a Contravariant class called Printer.\nclass Printer\u0026lt;in T\u0026gt; { } When your office Printer that uses Premium papers is out of order, it may be okay to have a temporary replacement Printer that uses any Paper. The following code compiles without any error.\nval paperPrinter = Printer\u0026lt;Paper\u0026gt;() val premiumPrinter: Printer\u0026lt;Premium\u0026gt; = paperPrinter So Contravariance is the Kotlin Generics feature that allows us to use a Printer of parent type Paper in place of a Printer of Premium papers.\n6. Limitations of Covariance and Contravariance Covariance and Contravariance do not come without their limitations over the Invariant types (types that do not use either of the out or in keywords and are rigid in terms of accepting either the subtypes or the supertypes) generic types.\nA Class using a Covariant type can only be used as a Producer of the Covariant type, never a Consumer. What this means is that our Box class can only have functions that output T but never a function that takes T as an input.\nclass Box\u0026lt;out T\u0026gt; { fun take(): T { //OK! ... } fun put(t: T) {} //This line does not compile } This is not an unreasonable ask when you think about it from the perspective of the compiler - given that the generics type information is erased during the compilation and is unavailable in the runtime, if we could somehow use a Covariant type as an input to the add function of a MutableList, there would have been nothing to stop us from inserting a Premium paper in a list of purely Regular papers which could have caused all types of issues afterwards.\nval regularPapers: List\u0026lt;Regular\u0026gt; = listOf(Regular()) val papers: List\u0026lt;Paper\u0026gt; = regularPapers papers.add(Premium()) //This line does not compile, thankfully! Similarly a Class using a Contravariant type can only be used as a Consumer of the Contravariant type, never a Producer. In other words, our Printer class can only have functions that take T as inputs but never a function that outputs T.\nclass Printer\u0026lt;in T\u0026gt; { fun take(t: T) {} //OK! fun eject(): T { //This line does not compile! } } Which is again understandable since the Contravariant mutableRegularPapers has no way to ensure in the runtime that the paper it returns is of type only Regular.\nval mutablePapers: MutableList\u0026lt;Paper\u0026gt; = mutableListOf(Paper()) val mutableRegularPapers: MutableList\u0026lt;in Regular\u0026gt; = mutablePapers val regular: Regular = mutableRegularPapers.removeAt(0) //This line does not compile as the mutableRegularPapers.removeAt(0) returns an object of type Any? 7. Conclusion The Covariant and Contravariant examples used in this article are called Declaration-site variance as they are used in Class or Interface declaration. When Covariant and Contravariant types are used in function declaration, it\u0026rsquo;s called Use-site variance. Although both work in the same way, it is important to know the distinction. Even though Kotlin supports both, Java only supports the latter.\n","permalink":"https://www.subhadig.net/posts/understanding-kotlin-covariance-and-contravariance/","tags":["kotlin"],"title":"Understanding Kotlin Covariance and Contravariance"},{"categories":null,"contents":"Introduction Although Debian 11 codenamed Bullseye was released almost 7 months back on 14th August, 2021, it was only in January, 2022 that I upgraded all my computers running Debian 10 to Debian 11. Admittedly a little late to the party, I like to take a cautious approach to upgrading my systems, which is not very difficult to predict given my Linux distribution of choice! In this post, I am going to share my experience and the steps I used while doing the actual upgrade.\nA word of caution This post should not be considered as a guide about how to do Debian upgrades. The simple reason is that every system is configured differently and there is no one guide that can cover all types of system configurations. So what worked for me may not work for your systems. This post should give you some practical experience on how to go about it and the obvious pitfalls. But it is strongly suggested that you go through the Official Debian guide to upgrade from Debian 10 before you actually do the upgrade.\nPlan for the worst Even the best-laid plans can sometimes fail spectacularly. So I can\u0026rsquo;t stress enough on the importance of taking backup of important files and directories before starting the upgrade process. Additionally download the Live Install CD image for Debian 11 and follow the instructions to prepare a USB stick with the CD image. If things go sideways, you can always use the USB to live boot your system and diagnose the problems and even recover.\nRemove the third party packages and sources If you have installed any third party packages (packages that do not come from the official Debian repositories) in your system, it\u0026rsquo;s always a good idea to uninstall them before doing the upgrade so that there are least chances of surprises. You can install them back once your upgrade is complete.\nTo find out such packages, use the following command (you may need to install aptitude if not already installed):\naptitude search \u0026#39;?narrow(?installed, ?not(?origin(Debian)))\u0026#39; Uninstall the packages from the output list using the following command:\nsudo apt remove \u0026lt;package-name(s)\u0026gt; Also disable the third party sources. The third party sources should have their own .sources files in the /etc/apt/sources.list.d directory or added to the /etc/apt/sources.list file. Rename the *.sources files under the /etc/apt/sources.list.d directory by appending .disabled at the end of the file names. If any third party sources are added in the /etc/apt/sources.list file, comment out the lines by prefixing them with a #.\nUpdate the Buster system Run the following commands to make sure that the Buster system is fully updated before continuing with the upgrade.\nsudo apt update sudo apt upgrade Remove the obsolete packages To search for the obsolete packages, use following the command:\nsudo aptitude search \u0026#39;~o\u0026#39; And to remove, use:\nsudo aptitude purge \u0026#39;~o\u0026#39; Modify the apt sources Before modifying the apt sources to point to the bullseye release, make a copy of the existing /etc/apt/sources.list file.\nsudo cp /etc/apt/sources.list /etc/apt/sources.list.buster After this, open the /etc/apt/sources.list file as root with your favourite text editor and replace the following:\nbuster/updates with bullseye-security. buster with bullseye in the remaining places. Start recording the session It\u0026rsquo;s a good idea to record the terminal session when the upgrade is running. If something goes wrong, the session can be replayed to debug the issue. To record the session, an utility called script will be used. Install it if it is not already installed.\nTo start the recording, use this command:\nscript -t 2\u0026gt;~/upgrade-bullseye.time -a ~/upgrade-bullseye.script After this all the commands are run from the same terminal session and their outputs will be recorded in those two files. To exit the recording, simply enter exit. After that, to replay the session later, use the following command:\nscriptreplay ~/upgrade-bullseye.time ~/upgrade-bullseye.script Update the package cache Update the APT\u0026rsquo;s package cache with the bullseye package information:\nsudo apt update Dry run upgrade Before running the actual upgrade, do a dry run of the upgrade process to make sure that there are sufficient disk spaces for doing the upgrade.\nsudo apt -o APT::Get::Trivial-Only=true full-upgrade Minimal system upgrade While the upgrade can be done in one go, I prefer to do it in two steps. In the first step, do minimal system upgrade where only the installed packages are upgraded and no new packages are installed or existing packages are removed.\nsudo apt upgrade --without-new-pkgs Full system upgrade Finally to fully upgrade the system, run this command:\nsudo apt full-upgrade Purge removed packages The last two commands may take a long time to complete depending on the Internet speed. But once complete, use the following command to remove the left-over configuration files from the removed packages during the upgrade:\ndpkg -l | awk \u0026#39;/^rc/ { print $2 }\u0026#39;; sudo apt purge $(dpkg -l | awk \u0026#39;/^rc/ { print $2 }\u0026#39;) Restart the system You should restart the system at the end of the upgrade so that the system can boot with the shiny new packages and the kernel.\nConclusion That\u0026rsquo;s it. Run the command: cat /etc/debian_version to print the Debian version you are currently on and hopefully it will print 11.\nThe upgrade process in Debian is not as straight forward as you would see in many other Linux distributions that ship with specific tools that hide the complexities and automatically take care of the system upgrades. But in my opinion the Debian way gives you greater control and more insight into how your system is upgraded, which in turn will help you diagnose the problems should something go wrong.\n","permalink":"https://www.subhadig.net/posts/upgrading-to-debian-11-bullseye/","tags":["debian"],"title":"Upgrading to Debian 11 Bullseye"},{"categories":null,"contents":"Introduction Since I don\u0026rsquo;t have a scanner at home, if I need to quickly share a soft copy of a physical document online, usually I take a picture of the document from my mobile phone and share. But the problem with pictures is that the sides of the document do not appear parallel in the image. I used to use Google Photos to crop an image to the edges of the document so that it appears somewhat like a scanned document and not an obvious crappy picture taken from a mobile phone camera.\nThis solution works well for the most part. The problem with this is that:\nThis feature is only available on Google Photos for Android. Doing this on a small screen is not the easiest thing to do. I am not much of a fan of relying too much on proprietary software. So I use GIMP now for cropping a document image and I will explain how quick and painless the process is in this post.\nThe Image Here\u0026rsquo;s a picture of an empty notebook page that we will use for demonstration. I placed it on a reddish background and took this picture from my mobile phone camera.\nWe will open the image with GIMP for editing.\nCrop it first First we will crop the document to a rectangular frame with it\u0026rsquo;s edges as close as possible to the actual edges of the document with the help of the Crop tool.\nOpen the Crop tool from Menu \u0026gt; Tools \u0026gt; Transform Tools \u0026gt; Crop. Draw a rectangle around the edges of the document like this. Drag the edges and the corners of the rectangle to change the crop area. Once you are satisfied with it, press enter to actually crop it. Delete the remaining areas outside of the document In this step we will remove the remaining background areas from the image. Go to Menu \u0026gt; Tools \u0026gt; Selection Tools and open Free Select.\nPut a point on each of the corners of the document in the image to select it like this.\nGo to Menu \u0026gt; Select \u0026gt; Invert to invert the selection so that the outer area is selected instead of the document. Press Delete to delete the selected area.\nDo Perspective transformation In this step we will transform the shape of the document so that becomes a perfect rectangle.\nFirst invert the selection again so that the inner document is selected instead of the outer area.\nGo to Menu \u0026gt; Tools \u0026gt; Transform Tools and select Perspective to open the Perspective tool. Drag the corners so that the inner document area fills the whole frame.\nWhen you are satisfied with the result, click on the Transform button on the Perspective tool pop-up window.\nExport the image Click on Menu \u0026gt; File \u0026gt; Export As\u0026hellip; to export the final image. This is how our final image looks like.\nConclusion GIMP is a free and open-source alternative of the more popular photo-editing tool Adobe Photoshop and it\u0026rsquo;s a rather capable one. Although I am neither an expert on photo editing nor a GIMP pro, I still wanted to share this quick tutorial as someone else may find this helpful.\n","permalink":"https://www.subhadig.net/posts/gimp-crop-to-the-edges-of-a-document-and-change-perspective/","tags":["gimp"],"title":"GIMP - Crop to the edges of a document and change Perspective"},{"categories":null,"contents":"Introduction Creating markdown tables in Vim is not very intuitive. Out of the box Vim does not have the capability of formatting markdown tables. And manually keeping them formatted is no less than a tedious job. For reasons like these, I have for years avoided using tables in markdown. But a good thing about Vim is that it\u0026rsquo;s very easy to customize it and add new functionalities. Recently I spent some time to make the task of creating and keeping markdown tables formatted a little easier in Vim.\nVim plugins that could do the job Although there were a handful of Vim plugins available out there that had the ability to format markdown tables, they seemed bloated to me with additional functionalities that I do not need. Here are a couple of plugins that I explored before coming up with a solution of my own:\nvim-easy-align - a very good plugin for basically aligning anything in Vim. vim-table-mode - another good plugin which is for creating and formatting tables in Vim and has support for markdown tables also. The script So I wrote a very simple Python script that basically does three things:\nReads the markdown table as text from the standard Unix input. Formats it so that the columns of the table are all aligned properly. Prints it in the standard output. Here\u0026rsquo;s the script: {% gist 6083306f990fad35fd010aa8d0e60069 markdown_table_format.py %}\nYou can also download the script from my GitHub here.\nPut the script somewhere on your computer from where you can invoke it. I have conveniently stored it in my dotfiles directory.\nNow you may ask why I wrote the script in Python instead of Vimscript. The reasons are simple - I am more familiar with Python and with Vim I have a choice!\nInvoking the script from Vim Before invoking the script, you need to visually select the entire markdown table in Vim. Then the script can invoked manually from Vim like this in command mode:\n:!/path/to/markdown_table_format.py But for ease of use, you should create a keymap like this in your .vimrc file for Vim or in init.vim file for NeoVim:\nvnoremap \u0026lt;localleader\u0026gt;mft :!/path/to/markdown_table_format.py\u0026lt;cr\u0026gt; After this, the script can be invoked by just pressing \u0026lt;Leader\u0026gt;mft in visual mode.\nConclusion I am not a fan of adding plugins to my Vim configuration unless I am very sure of the additional value they bring to the table. And sometimes simple problems require simple solutions. This was one such example.\n","permalink":"https://www.subhadig.net/posts/easily-format-markdown-tables-in-vim/","tags":["vim","markdown"],"title":"Easily format markdown tables in Vim"},{"categories":null,"contents":"Introduction After tinkering with it for a while now I finally have got a very much functional global menu working on my Xfce4 desktop running on Debian 10. I will list down the steps I followed to get the global menu configured on my Debian Xfce box in this post.\nGlobal menu vs Local menu For those of you who might be wondering what a global menu is, it is a way of displaying the application menus on the top of the screen like the way MacOS does. By default the Xfce4 desktop displays the menus right below the Window title bar separately in each Window.\nBut if you have a small display screen (eg. a laptop display), this may not be the most efficient use of the vertical screen space. The MacOS does a better job at this by displaying the application menus on the top panel.\nApart from MacOS, global menu was most prominently featured in the Unity DE by Ubuntu.\nxfce4-appmenu-plugin The Xfce plugin that makes it all possible is called the xfce4-appmenu-plugin. This plugin uses the same global menu implementation used by the aforementioned Unity DE and supports all the features found in the Unity implementation.\nTo install the xfce4-appmenu-plugin on Debian, run\nsudo apt install xfce4-appmenu-plugin Load appmenu-gtk-module on startup The xfce4-appmenu-plugin does not support every menu implementations out of the box. The appmenu-gtk-module exports the unsupported menus to the supported format so that xfce4-appmenu-plugin can display them. appmenu-gtk-module is automatically installed as a transitive dependency of the xfce4-appmenu-plugin but it needs to be loaded on start up.\nTo do that, edit the /etc/environment file with root permisson and append the following:\nGTK_MODULES=\u0026#34;appmenu-gtk-module\u0026#34; And restart the system.\nConfigure the top panel Edit the top panel and replace the Windows Buttons plugin with the AppMenu Plugin. Edit the Separator plugin that appears right after the AppMenu Plugin and uncheck the Expand option. Here\u0026rsquo;s how it looks like in the end.\nConclusion The steps have been tested in Debian 10. This plugin is quite functional and I have rarely noticed any glitches for the applications that I use day-to-day including LibreOffice. One notable exception was IntelliJ Idea. Although it supports the global menu plugin but at times the menu will not be automatically refreshed. I need to switch to some other window and switch back to it so that the menu items are refreshed.\n","permalink":"https://www.subhadig.net/posts/functional-global-menu-on-xfce-with-appmenu-plugin/","tags":["xfce","debian"],"title":"Functional Global Menu with Xfce Appmenu plugin"},{"categories":null,"contents":"Introduction I primarily take notes in vim in markdown format. The upside is that editing in vim is a pleasure. But one downside of this approach is that my notes often contain images and rich texts (as opposed to plain texts) and vim out of the box is not a good tool to view anything that is more than just text. In this post, I discuss about how you can easily preview your markdown notes in your browser directly from your vim editor with the help of a small vim script and an utility called pandoc in just a couple of keystroke. All without a fancy external vim plugin.\nMy note-taking setup Disclaimer: I actually now-a-days use neovim, a fully backward compatible fork of vim that offers better out-of-the-box defaults and more ease in configuring certain things compared to vim. But the steps listed in this post should work well for both vim and neovim and for the purpose of this post, I will use the terms vim and neovim interchangeably.\nNow that out of the way, I wanted to take a moment to describe my note-taking setup. My notes are written in markdown syntax and synced to a private repository on my GitHub account so that I can access them from multiple computers. And I use vim from a terminal to access and edit my notes. This setup works because I mainly use traditional computers (laptops or desktops as opposed to mobiles) for my note-taking. If you have used vim as your full-time editor, they you\u0026rsquo;d probably know that vim is awesome. But one area where vim probably falls short is to display formatted text or images. And my notes have plenty of those. I can view the formatted notes and images directly on GitHub if I want to, on the website or by using the GitHub mobile app (GitHub is very good at rendering markdown). But it does make it a lot easier if I can preview the them directly on my local computer without pushing them to GitHub first.\nPandoc Pandoc is the secret sauce in this solution. Pandoc is a small command-line utility that champions in text file conversion from one format to another. I will be using pandoc to convert the markdown files to html for comfortably viewing them in browsers.\nTo install pandoc on Debian Linux or a on Debian based Linux distribution, use\nsudo apt install pandoc Or on Mac with Homebrew, use\nbrew install pandoc The script Here is the vim script in it\u0026rsquo;s simplest form that will get the job done.\n\u0026#34; View markdown files as HTML on browser function! MarkdownView() execute \u0026#34;silent !\u0026#34; . \u0026#34;pandoc \u0026#34; . \u0026#34;%:p\u0026#34; . \u0026#34; -o \u0026#34; . \u0026#34;%:p\u0026#34; . \u0026#34;.html\u0026#34; execute \u0026#34;silent !\u0026#34; . \u0026#34;firefox\u0026#34; . \u0026#34;%:p\u0026#34; . \u0026#34;.html \u0026amp;\u0026#34; call getchar() execute \u0026#34;silent !\u0026#34; . \u0026#34;rm \u0026#34; . \u0026#34;%:p\u0026#34; . \u0026#34;.html \u0026amp;\u0026#34; endfunction \u0026#34; Custom key bindings nnoremap \u0026lt;localleader\u0026gt;v :call MarkdownView()\u0026lt;cr\u0026gt; The function MarkdownView() does the following things:\nConverts the currently opened file to html assuming that it is in markdown using pandoc. Opens the converted html file in Firefox web browser. Waits for any user key press to confirm that the converted html file has been rendered in the browser, after which it deletes it (you don\u0026rsquo;t want your notes folder to be polluted with the converted html files). The custom key binding tells vim to call the MarkdownView() function when a combination of the leader key (by default mapped to the \\ key) and v is pressed.\nAdd this script snippet to your .vimrc (init.vim if you use neovim).\nYou can replace the firefox command in the script with the full path to your Firefox browser command or with a different browser altogether if you are not a fan of Firefox. For example on Mac, you may want to use the whole path /Applications/Firefox.app/Contents/MacOS/firefox instead of just firefox.\nIf you are interested in having a common vimrc shared between your Linux and Mac and intelligently detect the browser command based on the platform, take a look at my nvim init.vim\nRestart your vim or source your .vimrc for the changes to take effect.\nPreview in action Now that we have all the pieces ready, it\u0026rsquo;s time to see them in action. I have saved the following markdown content in a file from vim.\n# This is a header ## This is a subheader **Bold** *Italic* ![An image](a-grumpy-frog.png) And assuming that the image file a-grumpy-frog.png is also present in the same location as the markdown file, if I press the \\ (localleader) and v keys, it will open the preview in my Firefox browser.\nAnd now going back to vim, if I press Enter, it will place the cursor back inside the editor.\nConclusion I am a fan of minimalism. Even though there were a number of vim plugins available out there that would have done job and some more, the installations were not very straightforward and not necessarily supported by the native vim package manager (which I use to manage the handful of vim plugins that I use). So instead I wrote my own solution which is simple, does not depend on external dependencies that I wouldn\u0026rsquo;t otherwise have in my system and gets the job done. And it only shows how powerful an editor vim is.\n","permalink":"https://www.subhadig.net/posts/preview-markdown-files-from-vim-the-easy-way/","tags":["vim","markdown","pandoc"],"title":"Preview markdown files from Vim - The easy way"},{"categories":null,"contents":"Introduction Connecting to an IRC room may not be a difficult task but if you communicate with a group of members connecting from different locations across the globe and are in different timezones and if you don\u0026rsquo;t want to miss out messages from them while you are offline, you may find yourself in a tricky situation. In this post I am going to share the easiest and the most cost-effective way to always stay connected on IRC using Matrix.\nInternet Relay Chat Chances are that if you are reading this post then you already know about IRC. For others, IRC is an old decentralized messaging protocol that used to drive much of the online group chatting before the era of the more modern instant messaging platforms began. Although the usage of IRC has been in steady decline since 2003, it\u0026rsquo;s still heavily used in many of the open source projects from that era for real-time communications.\nWhy do you need to be always connected? In today\u0026rsquo;s world of Slack, Teams and Discord, the idea of always being connected to the servers to not to miss out any messages may seem a little difficult to grasp at first. At its core, IRC is a client and server protocol where the server relays a message to the clients connected to it when the message arrives. The server does not store any history of the messages. So when the message arrives, if you are not connected to the server, you lose the message. This is why if you want to reliably communicate on IRC, you need a mean to stay always connected to the server.\nWhat are the available options? If you have a computer that is always connected to the internet or if you can rent a VM on the cloud, then it is not much of an issue for you provided the command line does not turn you off. If it does, you can look into the IRCCloud. You can think of it as your own cloud IRC client. After you create an account, you can log into it from any web browser or your mobile phone and when you log out your client still stays connected collecting messages from the IRC server. Although their paid accounts are okay, their free version suffers from frequent disconnections when you are inactive or away.\nMatrix and Riot.im From the Wikipedia:\nMatrix (stylized as [matrix]) is an open standard and lightweight protocol for real-time communication. It is designed to allow users with accounts at one communications service provider to communicate with users of a different service provider via online chat, voice over IP, and video telephony.\nWhat this basically means is that the Matrix protocol allows the users to communicate with other users across different communication service providers. This is not a new concept in other areas of the Internet powered communication services (think email). But it\u0026rsquo;s pretty useful for instant messaging as well where you can choose to use your own service provider and still be able to communicate with someone who\u0026rsquo;s on a different service provider.\nMatrix has a server and a client component and Matrix being an open protocol there are multiple implementations available for both the server and client components. The Matrix core team runs a server implementation at matrix.org that can be openly accessed.\nRiot.im is a model implementation for the matrix client protocol. It is also freely hosted as the Riot.im app. We will be using this along with the matrix.org to set up our IRC client.\nUsing Riot.im to connect to IRC Create an account on Riot.im First things first. Go to riot.im/app and create an account with [matrix.org]. After completing all the formalities, log in to your account.\nJoining an IRC room on OFTC I usually hang out at the OFTC.net because the Debian IRC rooms are hosted there. The following instructions are specific to the OFTC IRC rooms.\nStart a chat with @oftc-irc:matrix.org Click on the + button beside Direct Message on the left-side pane. Search for @oftc-irc:matrix.org and start a new chat.\nLog in with your nick Optionally, if you have a registered nick with OFTC, send the following message to @oftc-irc:matrix.org:\n!nick \u0026lt;your-nick\u0026gt; You should receive a direct message from NickServ. You can reply with IDENTIFY \u0026lt;your-OFTC-password\u0026gt; to identify yourself with your registered nick.\nJoin a room Now go back to the chat window for @oftc-irc:matrix.org and send /join #_oftc_#debian. This should join you to the #debian IRC room. Follow the same format to join other rooms.\nFor other IRC services eg. Freenode, the steps are similar but the Matrix addresses are different.\nConclusion IRC is still an excellent protocol for internet messaging. It may never get its old popularity back but it has not lost all of its usefulness even in today\u0026rsquo;s age. Matrix makes chatting over IRC and staying always connected easier than ever.\n","permalink":"https://www.subhadig.net/posts/the-easiest-way-to-stay-always-connected-on-irc/","tags":["irc","debian"],"title":"The easiest way to stay always connected on IRC"},{"categories":null,"contents":"Introduction Running Apache Kafka with Docker can be harder than it should be. Or perhaps it\u0026rsquo;s easy once you know what exactly you need to do. In this post, I\u0026rsquo;m going to discuss about how I run Kafka in Docker.\nWhat is Kafka? Apache Kafka is a distributed real-time event streaming and ingestion platform that is capable of handling very large volume of data. With the rise in the Microservices architecture in recent years, Kafka has gained a lot of popularity.\nIs this going to be a production or a development setup? Contrary to the popular belief that Docker is an amazing tool only meant for production deployments, Docker can be pretty useful for development environments also. While the steps listed here are applicable for a production environment as well, there are many more things one needs to take into consideration for a production setup. This article is more geared towards creating a development setup than a production one.\nWhy Bitnami images over Confluent? Unlike many other software, Apache Kafka does not have an official Docker image. Apache Kafka as an open source project only releases compiled tarball packages that can be extracted and executed on Linux, MacOS or Windows. There are other third-party companies including Confluent and Bitnami that package and release Kafka Docker images. Although Confluent images are more popular as they are from a company that provides commercial support for Kafka deployments, the reason I chose Bitnami over Confluent is that their images seemed simpler to start with for a development environment, were up to date with upstream and had good documentation.\nSetting up a Docker network In a Kafka environment, usually there will be multiple components interacting with each other. I will be creating a dedicated Docker network that will be used by the containers to connect with each other. The following command creates a Docker network named kafka-net.\ndocker network create kafka-net Starting Zookeeper Zookeeper is another software from Apache that is used by Kafka to store metadata information. We will need to start a Zookeeper instance before spawning the Kafka broker containers.\ndocker run -d --rm --network kafka-net \\ -p 2181:2181 \\ --name zookeeper \\ -e ALLOW_ANONYMOUS_LOGIN=yes \\ bitnami/zookeeper:latest A few points about the above command:\n-d: The container runs in detached mode, freeing up the command prompt. --rm: The container is automatically removed as soon as it is stopped. --network kafka-net: Our container attaches itself to the kafka-net Docker network that we created in the previous step. -p 2181:2181: The 2181 port of the container will be exposed on localhost. Starting one Kafka broker The next step is to start a Kafka broker instance with the following command.\ndocker run -d --rm --network kafka-net \\ -p 9092:9092 \\ -p 29092:29092 \\ --name kafka \\ -e ALLOW_PLAINTEXT_LISTENER=yes \\ -e KAFKA_CFG_ZOOKEEPER_CONNECT=zookeeper:2181 \\ -e KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=INTERNAL:PLAINTEXT,EXTERNAL:PLAINTEXT \\ -e KAFKA_CFG_LISTENERS=INTERNAL://:9092,EXTERNAL://:29092 \\ -e KAFKA_CFG_ADVERTISED_LISTENERS=INTERNAL://kafka:9092,EXTERNAL://localhost:29092 \\ -e KAFKA_CFG_INTER_BROKER_LISTENER_NAME=INTERNAL \\ bitnami/kafka:2.5.0 A few points to note about the above command:\n--network kafka-net ensures that our Kafka broker also joins the same Docker network as Zookeeper. -e KAFKA_CFG_ZOOKEEPER_CONNECT=zookeeper:2181: Our Kafka container reads this environment variable to know where to reach our Zookeeper container on the kafka-net Docker network. -e KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP: This map specifies the security protocol to use for each listener that we are going to use. The INTERNAL listener will be used by the clients internal to the kafka-net Docker network and the EXTERNAL listener will be used by the clients outside the kafka-net network. -e KAFKA_CFG_LISTENERS: This map specifies that our INTERNAL listener will listen on port 9092 and the EXTERNAL listener will listen on port 29092 for any incoming connection from clients. -e KAFKA_CFG_ADVERTISED_LISTENERS: This contains the host and port combinations of Kafka brokers which are passed on to the clients when they first connect, depending on which listener they connect to. These are the Kafka broker addresses that the clients will finally connect to. This means that the internal clients will connect to the broker on kafka host and the external clients will connect to localhost. This is expected since our Kafka broker container has the host name kafka inside the kafka-net Docker network and is exposed on the localhost for the outside clients. -e KAFKA_CFG_INTER_BROKER_LISTENER_NAME: Apart from the clients, the Kafka broker instances also communicate with each other. They will use the INTERNAL listener for this. I have used the Kafka 2.5.0 version. This can be replaced by latest or any other future tags. Testing the cluster Now that we have our local Kafka cluster up and running, it\u0026rsquo;s time for testing it out. For this we will need a Kafka producer that will publish data to our Kafka cluster and a consumer that will listen to it. While we can use the kafka-console-producer.sh and the kafka-console-consumer.sh scripts that ship with Kafka, I will use a utility called kafkacat. Although kafkacat can be installed in multiple ways, it can also be used as a Docker container without the need to install it. This is the method that I am going to use here.\nConnect from within the kafka-net The producer The following command creates a kafkacat Docker container that reads input from the stdin and publishes to the test-topic. Topics will be automatically created on use.\ndocker run -it --network kafka-net edenhill/kafkacat:1.5.0 \\ -b kafka:9092 \\ -t test-topic \\ -P Noticed the --network kafka-net flag? It tells Docker to attach our kafkacat container to the kafka-net network that we created earlier. And probably you have already guessed that we are going to use the INTERNAL listener here. This is the reason why we are passing kafka:9092 as the broker address.\nThe consumer In a separate terminal, use the following command to create a kafkacat Docker container that reads from the test-topic and prints to the stdout.\ndocker run -it --network kafka-net edenhill/kafkacat:1.5.0 \\ -b kafka:9092 \\ -t test-topic \\ -C Now when you type something in the producer terminal and press enter, you should see the same text being printed by our consumer on the consumer terminal.\nPress Ctrl + D to end the producer session.\nConnect from outside of kafka-net Now if we want to do the same thing using the EXTERNAL listener, here are the commands:\n# producer docker run -it --network host edenhill/kafkacat:1.5.0 \\ -b localhost:29092 \\ -t test-topic \\ -P And in a separate terminal,\n# consumer docker run -it --network host edenhill/kafkacat:1.5.0 \\ -b localhost:29092 \\ -t test-topic \\ -C Start/stop scripts It\u0026rsquo;s inconvenient to use the individual commands every time we need to start a Kafka cluster for development and shutting it down and cleaning it up. Most people use Docker Compose for this, a reasonable solution from Docker. But I prefer using a plain old bash script with the individual commands over using Docker Compose. Because it\u0026rsquo;s more customizable and therefore more useful and it also makes one less thing to learn for me.\nHere\u0026rsquo;s how my start and stop script looks like:\n#!/bin/sh echo \u0026#34;Creating network kafka-net..\u0026#34; docker network create kafka-net echo \u0026#34;Starting zookeeper..\u0026#34; docker run -d --rm --network kafka-net -p 2181:2181 \\ --name zookeeper \\ -e ALLOW_ANONYMOUS_LOGIN=yes \\ bitnami/zookeeper:latest echo \u0026#34;Starting kafka broker..\u0026#34; docker run -d --rm --network kafka-net -p 9092:9092 \\ -p 29092:29092 --name kafka \\ -e ALLOW_PLAINTEXT_LISTENER=yes \\ -e KAFKA_CFG_ZOOKEEPER_CONNECT=zookeeper:2181 \\ -e KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=INTERNAL:PLAINTEXT,EXTERNAL:PLAINTEXT \\ -e KAFKA_CFG_LISTENERS=INTERNAL://:9092,EXTERNAL://:29092 \\ -e KAFKA_CFG_ADVERTISED_LISTENERS=INTERNAL://kafka:9092,EXTERNAL://localhost:29092 \\ -e KAFKA_CFG_INTER_BROKER_LISTENER_NAME=INTERNAL \\ bitnami/kafka:2.5.0 echo \u0026#34;Printing all running docker containers..\u0026#34; docker ps #!/bin/sh echo \u0026#34;stoping kafka..\u0026#34; docker stop kafka echo \u0026#34;stoping zookeeper..\u0026#34; docker stop zookeeper echo \u0026#34;stopping network kafka-net\u0026#34; docker network rm kafka-net Conclusion As always, the code is available on my GitHub. The step to create the Kafka broker container can be repeated to create a cluster with multiple broker instances. The steps were tested on MacOS and Debian but they should also work under Windows. Hopefully this article should save some time if you are looking for an easy way to run Kafka in Docker for your development environment. And once you understand the steps, it\u0026rsquo;s easy to even customize it further to suit your requirements.\nHere are a few references that might come handy:\nBitnami Docker image for Kafka on GitHub Kafka Listeners - Explained ","permalink":"https://www.subhadig.net/posts/running-kafka-in-docker/","tags":["kafka","docker"],"title":"Running Kafka in Docker"},{"categories":null,"contents":"Introduction This is my second article in the Kubernetes with Minikube series. In the first article I discussed about how to create a local Kubernetes cluster with Minikube. In this article, I will be talking about deploying an application in a local Minikube cluster.\nSimple Web service Simple Web service is a Spring Boot application written it Java. It has the following REST endpoint: GET /details. And here is how the response looks like:\n{ \u0026#34;Host name\u0026#34;: \u0026#34;simple-web-service-deployment-66c45446b8-9x8bh\u0026#34;, \u0026#34;IP address\u0026#34;: \u0026#34;172.17.0.6\u0026#34; } It basically returns the host name and the IP address of the container or VM it is running on.\nThe source code for the Simple Web service is available on this GitHub link. The application is dockerized and published on Docker Hub as well. I am going to use it as a sample application for deploying in our Minikube cluster.\nDeployment Deployments are a way to tell Kubernetes how you want to have your application deployed. And a Deployment is described by a Deployment resource. Following is an example of a Deployment resource named deployment.yaml. I am going to use it to deploy our Simple Web service.\napiVersion: apps/v1 kind: Deployment metadata: name: simple-web-service-deployment labels: app: simple-web-service spec: replicas: 2 selector: matchLabels: app: simple-web-service template: metadata: labels: app: simple-web-service spec: containers: - name: simple-web-service-application image: subhadig/simple-web-service ports: - containerPort: 8080 A few important points about the above Deployment resource:\nThe metadata.name field specifies the name of our Deployment. The metadata.labels field asks Kubernetes to add the app: simple-web-service label to our Deployment. In the spec section, the replica field tells Kubernetes to create 2 replicas of our application. The spec.template.metadata.labels field defines which tags (app: simple-web-service) will be added to the Pods running our application and the spec.selector field tells that our Deployment will only manage the Pods labeled with app: simple-web-service. The template.spec field says that each Pod will run one container with the name simple-web-service-application. The container will be created from the subhadig/simple-web-service image which is available on the Docker Hub and it will have the 8080 port exposed. Now to apply this deployment.yaml in our Minikube cluster, use the following command:\n# cd to the directory containing the deployment.yaml file kubectl apply -f deployment.yaml To check the created Pods and their status, use:\nkubectl get pods And you should see something like this:\nService In the previous section, I deployed our Simple Web service which is running inside Pods. But Pods are mortal, they are not static, they are automatically created and destroyed by Kubernetes. Because of this, the Pod IP addresses can not be relied upon if I need to access them from outside or from another Pod. So I will need a level of abstraction that will talk to the Pods on behalf of me and will be static in nature. Services are that abstraction.\nHere is how our service.yaml, the definition of our Service will look like:\napiVersion: v1 kind: Service metadata: name: simple-web-service-cluster-ip spec: ports: - port: 80 protocol: TCP targetPort: 8080 selector: app: simple-web-service type: ClusterIP A few points to note:\nThe metadata.name specifies the name of this service. This is going to be used in the next section to refer to this service. In the spec section, I am mapping the TCP 8080 port of all the Pods that have the label app: simple-web-service to the 80 port of this service. The type field tells which type of Service this is. A ClusterIP service exposes the service on a cluster-internal IP address. Ingress Stress on the last line of the previous section. Although our application has a stable IP address now, it is still not reachable from the outside world. What this means for us is that we can\u0026rsquo;t invoke the /details REST endpoint of our Simple Web service from outside Minikube yet. To fix this, I will have to set up our Ingress controller first.\nAn Ingress controller is a component within Kubernetes that acts as a bridge between the services and the external world, allowing HTTP(S) connection to reach from the outside world to the services running inside Kubernetes.\nMinikube comes with a built-in NGINX Ingress Controller but it\u0026rsquo;s disabled by default. To enable it, run the following command:\nminikube addons enable ingress After that, use the following command to check for the Ingress controller status.\nkubectl get pods -n kube-system Wait for the nginx-ingress-controller to be running.\nAfter our Ingress controller is up, I need to configure it. I will need to prepare an Ingress resource similar to the other resources that we used in the previous sections. I am going to call it the ingress.yaml.\napiVersion: networking.k8s.io/v1beta1 kind: Ingress metadata: name: simple-web-service-ingress spec: rules: - http: paths: - path: / backend: serviceName: simple-web-service-cluster-ip servicePort: 80 A few points to note about the ingress.yaml:\nThe kind field says that it is an Ingress type resource. The metadata.name field specifies the name of this resource. The path field specifies that all the HTTP requests coming to the / context root from outside should be forwarded to the 80 port of the simple-web-service-cluster-ip service that I created in the previous section. To push the Ingress resource, execute the following command:\nkubectl apply -f ingress.yaml Accessing the web service Now that we have everything in place, it\u0026rsquo;s time to access our Simple Web service. Minikube is exposed to the host system with a host-only IP address. This IP address can be obtained with the below command:\nminikube ip In my case, this outputs the following IP address: 192.168.64.24. Now if I go to the following link from my web browser: http://192.168.64.24/details, I will get the below response:\nIf I try the link multiple times, I will get another response where the Host name and the IP address will be different.\nThis is because in the Deployment section, I have deployed two pods of our Simple Web service application and the simple-web-service-cluster-ip Service will route the incoming requests to both the Pods alternatively.\nConclusion This article gives a basic idea about the steps involved in deploying an application in Kubernetes. The steps were tested with the Minikube version v1.9.2. For accessing the service simple-web-service-cluster-ip from outside, alternatively I could have used NodePort or LoadBalancer methods as explained here.\nThe source code of the resources files along with the source code of the Simple Web service can be found in this GitHub repository. If you have any feedback or comment about any of the steps, please let me know in the comments.\n","permalink":"https://www.subhadig.net/posts/getting-started-with-kubernetes-using-minikube-deploying-an-application/","tags":["kubernetes","minikube"],"title":"Getting started with Kubernetes using Minikube - Deploying an application"},{"categories":null,"contents":"Introduction This is the second article in my Application Monitoring System (AMS) series where I am building an open source application to monitor performances of other applications. In this post, I will be discussing about the second component, the Data Collection Service.\nData Collection Service The Data Collection Service is a Spring Boot application written in Java. As the name suggests, it is the collector component of our Application Monitoring System and it has the ability to pull metrics data from various source systems and send to various destination systems.\nThe API page The Data Collection Service does not have a traditional UI. It exposes a set of REST APIs for various administrations and configurations related tasks. It uses the Swagger API Documentation tool to generate a webpage that lists all the REST APIs and the best part is that the REST APIs can be tried directly from the webpage.\nThe API page uses the default URI for Swagger UI which is /swagger-ui.html. This URL and the all other REST URLs of the Data Collection Service are protected by a basic authentication. The default username is admin and the password is also admin although it can be configured to use something else. Once you go past the authentication page, here\u0026rsquo;s how the API page looks like:\nDataCollectionConfig A DataCollectionConfig contains the required details for the Data Collection Service to start collecting data (metrics) from a source system and push to a destination system. One Data Collection Service is capable of collecting data from multiple source systems and publishing to multiple destination systems.\nSource configs Although the Data Collection Service includes a flexible enough framework which is capable of supporting data collection from various source types and also publishing to multiple destination types, currently it uses a polling based mechanism for data collection and only the applications exposing the Spring Boot Actuator APIs like the Data Provider Service are supported.\nA SourceConfig specifies the source system details within a DataCollectionConfig.\nDestination configs Currently only pushing data to a MongoDB database is supported but in future Data Collection Service is also going to support publishing data to a Kafka stream. While the destination type can be selected in a DataCollectionConfig, the destination system details are not exposed and it is not user-configurable.\nHere\u0026rsquo;s how a complete DataCollectionConfig looks like:\n{ \u0026#34;id\u0026#34;: \u0026#34;an-auto-generated-uuid-value\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;An arbitary user input field\u0026#34;, \u0026#34;destination\u0026#34;: \u0026#34;Database\u0026#34;, \u0026#34;source\u0026#34;: \u0026#34;SpringActuator\u0026#34;, \u0026#34;sourceConfig\u0026#34;: { \u0026#34;pollInterval\u0026#34;: 60, \u0026#34;protocol\u0026#34;: \u0026#34;http\u0026#34;, \u0026#34;ipAddress\u0026#34;: \u0026#34;source-ip-address-or-hostname\u0026#34;, \u0026#34;port\u0026#34;: 8080, \u0026#34;userName\u0026#34;: \u0026#34;admin\u0026#34;, \u0026#34;password\u0026#34;: \u0026#34;admin\u0026#34; } } Config operations Several DataCollectionConfig operations are supported by the Data Collection Service REST APIs. Here\u0026rsquo;s a list of supported operations.\nStore A DataCollectionConfig can be created or updated. If the payload DataCollectionConfig contains the id field, then the existing DataCollectionConfig with the input id is modified with the new values, else a new DataCollectionConfig is created with an auto generated id.\nRetrieve DataCollectionConfigs can be searched by ids or they can be retrieved as a collection.\nRemove DataCollectionConfigs can be removed from the database by their ids.\nData collection Although the data collection is started as soon as a DataCollectionConfigs is added to the Data Collection Service and stopped when it is deleted, REST APIs are available for monitoring or administering the data collection status for a DataCollectionConfigs.\nConclusion The source code for the Data Collection Service can be found here. While the Data Collection Service does not support most of the source and destination system types yet, with it\u0026rsquo;s loosely coupled and pluggable source processor and destination processor pipeline, it can be easily enhanced to support additional array of protocols and systems.\nIn the next post, I will talk about the next component which is the Data Streaming Service and pushing data from the Data Collection Service to the Data Streaming Service.\n","permalink":"https://www.subhadig.net/posts/ams-data-collection-service/","tags":["application-monitoring-service"],"title":"AMS: Data Collection Service"},{"categories":null,"contents":"The problem Recently I encountered an issue in code when I tried to call the Spring MongoRepository from a non-Spring-managed thread in a Java Spring Boot application. Here is a brief description of the issue.\nThe Repository interface public interface ResponseRepository extends MongoRepository\u0026lt;Response, String\u0026gt; { } It\u0026rsquo;s a standard Spring Repository interface without any custom methods.\nThe calling class @Component //A Spring Component public class AnImaginaryComponent { @Autowired private ResponseRepository responseRepo; public void saveResponseInANewThread(Response r) { //Create an Executor service ExecutorService executor = Executors.newSingleThreadExecutor(); //Submit a Runnable instance executor.submit(() -\u0026gt; responseRepo.save(r)); } } When anImaginaryComponent.saveResponseInANewThread(r) is invoked, it never saves the r Response into the database. And the worst part is that it doesn\u0026rsquo;t throw any exceptions or print any log messages for the failure.\nThe solution Rewrite the ResponseRepository interface as below:\nimport org.springframework.scheduling.annotation.Async; public interface ResponseRepository extends MongoRepository\u0026lt;Response, String\u0026gt; { @Async \u0026lt;S extends Response\u0026gt; S save(S entity); } And enable sync.\nimport org.springframework.scheduling.annotation.EnableAsync; @SpringBootApplication @EnableAsync public class MySuperImportantSpringBootApplication { Apparently the @Async annotation tells Spring to execute the annotated methods asynchronously and not to wait for the main thread.\nIt was not easy to find the workaround as there were very few resources on the internet on this issue (which is why I decided to post it on my blog) but this StackOverflow post did help.\n","permalink":"https://www.subhadig.net/posts/how-to-call-spring-mongorepository-from-an-executorservice/","tags":["java","spring-boot"],"title":"How to call Spring MongoRepository from an ExecutorService"},{"categories":null,"contents":"Introduction I am working on a series of opinionated posts on how to get started with the basics of Kubernetes using Minikube. In these posts, I will discuss on a range of topics starting from the installation of Minikube to the deployment of pods and also workarounds for a few annoying issues I faced along the way. This is the first article of the series where I talk about how to install Minikube in your local computer.\nKubernetes From the Wikipedia:\nKubernetes is an open-source container-orchestration system for automating application deployment, scaling, and management.\nKubernetes is probably the most popular and widely used system for deploying and managing scalable and highly available applications world wide. Not only that Kubernetes can be self-hosted, managed Kubernetes cluster services are available on most of the major cloud service providers including AWS, Azure and Google Cloud.\nMinikube Minikube is a command line tool for running single node Kubernetes clusters in local workstations. Although Minikube only supports a subset of all the Kubernetes features, considering the fact that a full blown Kubernetes installation requires considerable hardware resources, Minikube is a fantastic tool meant for users or developers who want to try out Kubernetes in local computer or deploy services in local Kubernetes before pushing to an actual multi-node test or production environment.\nIt is worth noting that Minikube is not the only available learning environment solution for Kubernetes but Minikube is one of the most mature ones and is supported on all three major platforms - MacOS, Linux and Windows.\nInstallation In this section, I will share the steps of installing Minikube and the required components on MacOS and Debian Linux. These steps should work on any other Debian based Linux distributions including Ubuntu. However if you are using a different variant of Linux, the steps might be different. To install on other operating systems, follow this official guide from Kubernetes.\nKubectl Kubectl is not exactly a part of Minikube but it\u0026rsquo;s a command-line tool for interacting with a Kubernetes cluster and perform various administrative tasks including deployment of pods.\nTo install kubectl on Debian, follow the below steps:\n#Install the repository key curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add - #Add the Kubernetes repository to sources echo \u0026#34;deb https://apt.kubernetes.io/ kubernetes-xenial main\u0026#34; | sudo tee -a /etc/apt/sources.list.d/kubernetes.list #Update the APT package index sudo apt update #Install kubectl sudo apt install -y kubectl On MacOS, if you have Docker Desktop installed then you already have kubectl installed. Otherwise the package can be easily installed using Homebrew\nbrew install kubectl VM Driver Minikube can be deployed as a VM, a container or on bare-metal. My preferred way is to run it as a VM. To do so, we are going to need a hypervisor or a VM driver. On Linux I prefer using kvm and on MacOS, I prefer using Hyperkit. If you are using any VPN software on your Mac, then you might want to check this section before selecting a VM driver.\nTo install kvm on Debian 10, run the following command:\nsudo apt install qemu-kvm \\ libvirt-clients \\ libvirt-daemon-system For more information, refer to the Debian wiki on KVM. Also you may need to turn on Intel VT-x or AMD-V depending on your chipset to benefit from the hardware acceleration capabilities of your CPU.\nOn MacOS, if you are running Docker Desktop then you already have Hyperkit installed. If not, you can install it using Homebrew.\nbrew install hyperkit Minikube Install on Debian To install Minikube on Debian follow the steps.\nDownload the .deb file from the latest Minikube release page. At the time of writing the post, the latest version was 1.9.2. curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube_1.9.2-0_amd64.deb Install the downloaded package. Replace minikube_1.9.2-0_amd64.deb with the actual downloaded package name. sudo dpkg -i minikube_1.9.2-0_amd64.deb Install on MacOS With Homebrew, it\u0026rsquo;s fairly easy to install Minikube on MacOS.\nbrew install minikube Starting up To start Minikube on Debian, I use the following command:\nminikube start --driver=kvm2 The \u0026ndash;driver=kvm2 flag tells Minikube to use the kvm2 VM driver.\nIf everything is properly configured and Minikube is successfully started, you should see something like this:\nSimilarly here is the command to start Minikube on MacOS:\nminikube start --driver=hyperkit The \u0026ndash;driver=hyperkit tells Minikube to use the hyperkit VM driver.\nDNS issue on Mac when Docker Desktop is running I have Docker Desktop installed on my Mac and if Docker Desktop is started first, then I get the following error while starting Minikube:\nI could not determine whether the Docker Desktop or the VPN software running on my Mac was causing this error. Because of this problem, the Minikube VM fails to resolve any domain name and deployment of Docker images from Docker Hub fails. As a workaround, I use the following command to start Minikube on my Mac:\nminikube start --driver=hyperkit \\ --hyperkit-vpnkit-sock=/Users/${USER}/Library/Containers/com.docker.docker/Data/vpnkit.eth.sock The \u0026ndash;hyperkit-vpnkit-sock=/Users/${USER}/Library/Containers/com.docker.docker/Data/vpnkit.eth.sock flag tells minikube to use the Docker Desktop vpnkit sock.\nRouting issue on Mac with Hyperkit when Cisco Anyconnect VPN is running In recent years, I have had less success in running Minikube with hyperkit or even virtualbox as the VM driver on a Mac where Cisco Anyconnect is also running. As a workaround, I am now using the Docker Desktop as the VM driver for running Minikube even though I am not a fan of it especially after their recent licence update.\nTo start Minikube on MacOS with docker as the VM driver, use the following command:\nminikube start --driver=docker A few additional Minikube commands To check the running status of the Minikube cluster, use the following command:\nminikube status To stop the Minikube cluster, use:\nminikube stop To delete the local Minikube cluster, use:\nminikube delete To launch the Kubernetes Dashboard, use:\nminikube dashboard Conclusion These steps were tested on Debian 10 Buster and MacOS Mojave. kubectl and minikube can be installed in various other ways including downloading as executable binaries and using without installing. But I like the above approaches because they give me the flexibility of managing the packages with a package manager.\nIn the next post, I will discuss about deploying pods in our Minikube cluster.\n","permalink":"https://www.subhadig.net/posts/getting-started-with-kubernetes-using-minikube-installation/","tags":["kubernetes","minikube"],"title":"Getting started with Kubernetes using Minikube - Installation"},{"categories":null,"contents":"Introduction This is the first article in a series of upcoming articles on designing and creating an Application Monitoring System. An Application Monitoring System (AMS) is a system that can monitor performance of other running applications. I am building this application component by component from scratch and I will publish it here on this blog. In this post, I talk about how to create and run services that provide application performance metrics using Java, Spring Boot and Docker.\nWhat are applications performance metrics? Understanding the health and performance of the deployed applications is crucial to ensure availability and usability of the services. Application performance metrics are the raw measurements of various resource usage or behaviours of an application at any given time. To monitor and analyze the performance of an application, these metrics are periodically collected and stored. Here are some examples of application performance metrics:\nCPU usage Memory usage System uptime What the data-provider-service is and what it\u0026rsquo;s not The data-provider-service is not exactly a part of the Application Monitoring System. This service is an example of how to generate various application performance metrics with the help of Spring Boot Actuator. This service will then be used to test the actual Application Monitoring System.\nCreating a basic Java service using Spring Boot Spring Framework is probably the most popular application framework and IoC container for Java and Spring Boot is Spring\u0026rsquo;s convention-over-configuration solution for easily creating ready-to-run, production-grade Spring applications.\nTo create a basic Spring Boot project, head over to start.spring.io, populate the required details and click on Generate.\nIn the above screenshot, I have selected the following Spring modules under the Dependencies section:\nSpring Boot Actuator: The Spring Boot module that monitors a running application and generate performance metrics. Spring Web: Since we will be exposing the Spring Actuator generated metrics over REST. Configuring Spring Boot Actuator for generating runtime metrics The Spring Boot Actuator module has the capability of monitoring a running application among other things. It has an inbuilt set of application performance metrics that it reports by default which can be exposed via either JMX or REST. Custom metrics are also supported. Here in this section, I will only use the default metrics supported by Spring Boot Actuator and I will expose those over REST.\nEnabling the required endpoints over HTTP In the data-provider-service/src/main/resources/application.properties file add the following lines:\nmanagement.endpoint.metrics.enabled=true management.endpoints.web.exposure.include=health, metrics Now if I run the application and head over to http://localhost:8080/actuator, I should see all the available Spring Boot Actuator endpoints.\nIn this example, I have only enabled the health and metrics endpoints. Here is the full list of available endpoints.\nhttp://localhost:8080/actuator/metrics should show a list of available metrics.\nAnd if I want to see the current value of any metric from the list like jvm.memory.max, I can go to the URL http://localhost:8080/actuator/metrics/jvm.memory.max and it should show me something like the below screenshot.\nSecuring the endpoints with Spring Security Additionally, you might want to secure the metrics REST endpoints exposed by Spring Boot Actuator in the previous step with authentication. With Spring Security, it\u0026rsquo;s simple enough to do. Here are the steps to add a basic authentication to the endpoints.\nImport the maven dependency In the data-provider-service/pom.xml, add the following dependency.\n\u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.springframework.boot\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;spring-boot-starter-security\u0026lt;/artifactId\u0026gt; \u0026lt;/dependency\u0026gt; Use fixed passwords By default Spring Security will generate a new password every time you boot up your application which may not be the desired behaviour if you plan to poll the endpoints from a different system.\nTo use a fixed username and password, add the following two lines in the data-provider-service/src/main/resources/application.properties file.\nspring.security.user.name=admin spring.security.user.password=admin@123 Now if you restart your application and go to http://localhost:8080/actuator, you should be presented with the following login screen:\nRunning as a Docker container I usually package my applications as Docker images due to the ease of running them both locally and remotely. Also Docker containers provide a more predictable runtime environment for the applications.\nTo package the data-provider-service as a Docker image, copy the following content to data-provider-service/Dockerfile file.\nFROM openjdk:8-alpine MAINTAINER subhadig@github ARG jarfile COPY $jarfile /opt/app.jar ENTRYPOINT [\u0026#34;/usr/bin/java\u0026#34;, \u0026#34;-jar\u0026#34;, \u0026#34;/opt/app.jar\u0026#34;] EXPOSE 8080 The following command creates the Docker image.\nmvn package docker build -t data-provider-service:latest --build-arg jarfile=\u0026#34;target/data-provider-service-*.jar\u0026#34; data-provider-service/ In the above docker command, I am passing the maven generated jar file location to the Dockerfile.It copies and packages the jar file from the location with the final image.\nThe following command runs the image created in the previous step as a Docker container and also exposes the data-provider-service REST endpoints on the 8080 port of the localhost of the host machine.\ndocker run -d --rm -p 8080:8080 --name provider data-provider-service:latest Conclusion Here is the source code of the data-provider-service.\nAlthough there are multiple ways to generate application performance metrics Spring Boot Actuator provides an easy yet powerful approach to start with. One more thing to keep in mind is that, generating these performance metrics also impacts the overall performance of the application, so one should be cautious about generating too many of them too frequently.\nIn the next post, I will discuss about how to create a data-collection-service and configure it to collect application performance metrics from the data-provider-service.\n","permalink":"https://www.subhadig.net/posts/ams-data-provider-service-generating-performance-metrics-with-spring-boot-actuator/","tags":["application-monitoring-service","java","spring-boot","spring-boot-actuator","spring-security","docker"],"title":"AMS: Data Provider Service - Generating performance metrics with Spring Boot Actuator"},{"categories":null,"contents":"Introduction Most mainstream web-browsers including Firefox now-a-days come with a feature where your browser sends your preferred colorshemes to websites when you visit them. If the website supports this feature, then you are presented with a light or dark version of the website based on your preference. In this post I will share how to manually configure it in Firefox.\nprefers-color-scheme prefers-color-scheme is a CSS feature that can be used by websites to detect if the browser has requested a light or a dark color theme. And if your browser sends the preference of dark theme and if a visited website chooses to implement an alternate dark CSS colorsheme then the web content will be displayed in dark mode. Here are the allowed values for prefers-color-scheme:\nno-preference light dark Just to mention, this is different from the browser extensions that converts the web contents into dark mode on the client side.\nAutomatic detection of preferred themes If your browser has implemented this feature, then it should be able to automatically detect the preferred theme from your OS theme for websites you are visiting . Here is the duckduckgo.com search website in both dark and light mode.\nDuckduckgo in dark mode Duckduckgo in light mode But sometimes this does not work properly where your browser fails to detect the theme of your OS or you may want a different themes for your websites and your OS.\nManually updating the preferred colorscheme in Firefox Here are the steps to manually configure Firefox to send dark colorscheme preference.\nType about:config in the address bar of Firefox and press Enter. Accept the warning. Enter ui.systemUsesDarkTheme in the search box. Select Number and click on the + button. Enter 1 as the value and click on the tick button. The steps for opting out the dark colorscheme preference is similar to the above steps except for step 5 where instead of 1, enter 0 and save.\nAnd now Firefox should automatically update the opened tabs with your preferred colorsheme.\nConclusion These steps were tested on Firefox 73 (latest version at the time of writing this post) on Debian Linux 10.\nOne thing I like about this feature is that it works even after you clear your browser cache or when browsing in Private mode.\nBased on your personal preference, you may or may not like the content of the websites in dark mode but luckily Firefox provides a manual configuration option to override the automatically detected preference.\nResources Firefox: How to test prefers-color-scheme? - Stack Overflow Can the system dark mode preference implemented in release 70.0 be changed? - Mozilla Support Forum ","permalink":"https://www.subhadig.net/posts/requesting-dark-mode-to-websites-on-firefox/","tags":["firefox"],"title":"Requesting dark mode to websites on Firefox"},{"categories":null,"contents":"Introduction The command line has always seemed to me something that is both fascinating and under-utilized to a large extent at the same time. Creating a document on the command line is easy and sometimes it is more straightforward than using WYSIWYG tools like LibreOffice or MS Office or Google Docs. In this post I share how I use Pandoc, Vim and Markdown for creating good professional grade documents on the command line.\nPandoc From the Wikipedia:\nPandoc is a free and open-source document converter, widely used as a writing tool and as a basis for publishing workflows.\nBasically what Pandoc does is that it converts one document format to another. It has a large array of supported document types including Markdown, .doc and .pdf.\nI will be using Pandoc for converting the raw documents to the final presentable formats(pdf).\nSomething to note here is that Pandoc uses another software called Latex internally to convert the raw document files to some intermediate format before finally converting them to the intended output format, which is PDF in this case. So some of the Latex project packages will also be needed to be installed along with Pandoc in the next section.\nInstallation Pandoc and Latex packages are available in the official repository of almost all major Linux distributions although the package names may vary. Here\u0026rsquo;s how I install them on Debian:\nsudo apt install pandoc \\ texlive \\ texlive-pstricks \\ texlive-latex-extra \\ texlive-xetex For MacOS, the required packages can be installed with HomeBrew.\nbrew install pandoc brew cask install mactex-no-gui Markdown Markdown is a simple markup language that is easy-to-read and easy-to-write. It first appeared in 2014 and over the years, it has gained acceptance in the developer community and is widely used as a tool to write software documentations and README files.\nIt has very intuitive syntaxes and it supports most of the common text stylings. Markdown will be used here for writing the raw document files.\nVim Vim is a fantastic text editor for the command line that needs little introduction. It has inbuilt support for highlighting multiple languages including Markdown among other things. I use Vim as the editor for this job. But any capable editor with Markdown support should be fine.\nInstallation For Debian\nsudo apt install vim Or for MacOS HomeBrew\nbrew install macvim Connecting the pieces Now that we have all the required tools for our job, here are the steps.\nCreate the document in Markdown in Vim (or any other editor) Markdown has a very simple set of syntaxes for styling the texts. It\u0026rsquo;s very straight-forward once you get the hang of it. Although at times especially in the beginning you\u0026rsquo;d find yourself in situations where you\u0026rsquo;re not sure how to do certain things. Here is a list of a few tricks that I learnt along the way:\nFront matter This is not really a part of the Markdown specifications but it\u0026rsquo;s something that is supported by Pandoc. If you want to include title, author and other metadata in the document, there\u0026rsquo;s a designated place for it. Insert a section like below at the top of the document:\n--- title: My Super Important Document author: Subhadip --- You can include other metadata also like data, tags, description etc.\nResizing an image Here\u0026rsquo;s how you\u0026rsquo;d normally include an image in Markdown:\n![](media/my-awesome-image.png) where media/my-awesome-image.png is the relative path to my-awesome-image.png file. Now if the image is too large or too small, you\u0026rsquo;d probably want to resize it. The easiest way to do that is:\n![](media/my-awesome-image.png){width=50%} You can specify height also along with width.\nBlock quotes Block quotes are easy. Just put a \u0026gt; at the beginning of the line that you want to include in the quote:\n\u0026gt; This is a quoted line. \u0026gt; This is another quoted line. Or if you are feeling lazy\n\u0026gt; This is a quoted line. This is another quoted line. If the first line in a paragraph starts with a \u0026gt;, then the whole paragraph becomes quoted.\nCode blocks If you want to insert a code block inside, here\u0026rsquo;s the way to do it:\n```python print(\u0026#39;I am a Python code!\u0026#39;) ``` And during conversion, Pandoc will automatically create a code block and add syntax highlighting based on the specified language type. Most common languages are all supported.\nHere is a Markdown cheat sheet for you if you are new to it. This official Pandoc manual contains plenty of configuration options and tricks.\nTables Tables in markdown is the only unintuitive feature that I have found so far. Tables were not supported by the original markdown specifications designed by John Gruber. But Pandoc markdown is an extended version of the original markdown that has support for tables.\nPandoc supports four formats to create tables. I prefer using the pipe_tables format.\nHeader 1 | Right aligned header | Left aligned header | Center aligned header ---------|---------------------:|:--------------------|:---------------------: Value 1 | The quick brown fox jumps over the lazy dog | Another long text | 156.76 Value 1 | 60 | A string | The next row is a blank row | | | When Pandoc converts it to PDF, it looks like this. A few points about creating tables in markdown:\nThe | character works as a delimiter between two cells. Leave a blank line above and below the table. Note the positions of the colons in the row below the header row in the table definition. These colons determine if a column will be treated as right-aligned or left-aligned. Merging cells are not allowed. Although it works fine, creating complex tables should be avoided whenever possible in my opinion. Refer to the Pandoc manual on tables to learn about the other table formats.\nConvert the Markdown document to PDF using Pandoc Now comes the fun part. I use the following Pandoc command to convert Markdown files to PDF documents.\npandoc \\ -V geometry:margin=0.8in \\ #Customize the margin -V fontsize:10pt \\ #Customize the fontsize -V mainfont=\u0026#39;DejaVu Serif\u0026#39; \\ #Customize the main font -V monofont=\u0026#39;DejaVu Sans Mono\u0026#39; \\ #Customize the mono font -V urlcolor=blue \\ #Customize the hyperlink color -V toccolor=NavyBlue \\ #Customize the table of content color -s \\ #Create a standalone document, default when converting to PDF -N \\ #Number the sections --toc \\ #Generate table of content automatically -f markdown-implicit_figures \\ #Input document type. --pdf-engine=xelatex\\ #The engine it will use for the conversion -o my-printable-document.pdf\\ #Output document my-raw-document.md #Input document I use markdown-implicit_figures as the input file type instead of plain markdown because it has better support for images. The default pdf-engine that Pandoc uses is called pdflatex but I use xelatex because it provides a few additional customization options including the font types.\nThis command may look a lot but it does not have to be. The additional options I use are hardly something that I need to change daily. So I have created an alias and stored it in my .bashrc or .bash_alias file and use the alias as the actual command.\nalias pandoc-convert-doc=\u0026#34;pandoc \\ -V geometry:margin=0.8in \\ -V fontsize:10pt \\ -V mainfont=\u0026#39;DejaVu Serif\u0026#39; \\ -V monofont=\u0026#39;DejaVu Sans Mono\u0026#39; \\ -V urlcolor=blue \\ -V toccolor=NavyBlue \\ -s \\ -N \\ --toc \\ -f markdown-implicit_figures \\ --pdf-engine=xelatex\u0026#34; pandoc-convert-doc -o my-printable-document.pdf my-raw-document.md Conclusion As with many other software, I started with the defaults and then changed them according to my need. There are a lot of other configuration options including header and footer settings available. Pandoc can also be instructed to use custom Latex templates for the intermediate latex conversion it does, this will give you even greater control on the document formatting.\nTo conclude, this solution may not have all the bells and whistles of the full featured office suites but for quick reports or letters, it should be more than enough. I have even read about people publishing e-books with Pandoc. The best advantage in my opinion is that, it puts your focus back on the contents where it is more required than the styling and presentation.\n","permalink":"https://www.subhadig.net/posts/creating-word-documents-on-the-command-line/","tags":["command-line","pandoc"],"title":"Creating word documents on the command line"},{"categories":null,"contents":"Introduction I have been using a Mac at my work for a few months now and there\u0026rsquo;s one command line utility in MacOS that I am quite impressed with called open. In this post I talk about a similar alternative in Linux world.\nWhat is open? From the open man page:\nOpen a file or folder.\nThe open command opens a file (or a folder or URL), just as if you had double-clicked the file\u0026rsquo;s icon.\nThat is what it is, a command line utility for MacOS that will open a file or folder with it\u0026rsquo;s default application. It may not sound a lot but in reality it\u0026rsquo;s very handy. You don\u0026rsquo;t need to remember what type of a file it is or what is the preferred application to open these kind of files, you simply type:\nopen \u0026lt;file-name\u0026gt; And it opens the file with the default application for its type in the background and leaves the prompt.\nLinux equivalent of open Surprisingly in Linux world, there was already an available alternative with the same functionality, it\u0026rsquo;s called xdg-open. From the man page of xdg-open:\nxdg-open opens a file or URL in the user\u0026rsquo;s preferred application. If a URL is provided the URL will be opened in the user\u0026rsquo;s preferred web browser. If a file is provided the file will be opened in the preferred application for files of that type. xdg-open supports file, ftp, http and https URLs.\nxdg-open is for use inside a desktop session only. It is not recommended to use xdg-open as root.\nSimilar to open, xdg-open also opens the files in the background. The only problem that I noticed with xdg-open is that although xdg-open does not print anything on the screen by default when launched the actual applications used to open the file (eg. libreoffice) can sometimes, which may not what you would want. To work around it, I have defined an alias in my .bash_alias file like this:\nwhich xdg-open 1\u0026gt;/dev/null \u0026amp;\u0026amp; alias open=\u0026#39;xdg-open 2\u0026gt;/dev/null\u0026#39; The which xdg-open 1\u0026gt;/dev/null is useful if you share your .bash_alias between Linux and other flavour of Unixes including MacOS. Also I have renamed it to open so that I don\u0026rsquo;t have to remember which OS I am on before opening a file.\n","permalink":"https://www.subhadig.net/posts/linux-equivalent-for-macos-open/","tags":["command-line"],"title":"Linux equivalent for MacOS open"},{"categories":null,"contents":"Introduction I like the fact that Debian does not do a lot of customizations over the upstream packages by default but this also means extra work for you for setting up things after installing Debian on the PC. The upside is that you get to customize things exactly the way you like it. It definitely helps to have a list to start with and this post lists down some of the customizations I make after installing a fresh copy of Debian.\nUpdate apt sources The Debian package archive contains the following areas:\nmain: the Debian distribution contrib: supplemental packages intended to work with the Debian distribution, but which require software outside of the distribution to either build or function; non-free: supplemental packages intended to work with the Debian distribution that do not comply with the DFSG or have other problems that make their distribution problematic. non-free-firmware: non-free firmware related packages that have a separated archive area for easy preparation of the installation media containing these packages. On a default installation of Debian, the apt sources.list only includes the main archive area. To also include the other archives, edit the /etc/apt/sources.list with root permission and add them as below.\ndeb http://deb.debian.org/debian/ bookworm main contrib non-free non-free-firmware deb-src http://deb.debian.org/debian/ bookworm main contrib non-free non-free-firmware deb http://security.debian.org/debian-security bookworm-security main contrib non-free non-free-firmware deb-src http://security.debian.org/debian-security bookworm-security main contrib non-free non-free-firmware deb http://deb.debian.org/debian/ bookworm-updates main contrib non-free non-free-firmware deb-src http://deb.debian.org/debian/ bookworm-updates main contrib non-free non-free-firmware Adding a swap file Nowadays I prefer having swap files over swap partitions, mainly because files can be resized more easily than partitions. This is useful when I want to change the swap size. To create a swap file and use as swap, execute the following commands:\nsudo dd if=/dev/zero of=/swapfile bs=1024 count=$((4*1024*1024)) #create an empty file of size 4GB sudo chmod 600 /swapfile #restrict the permissions of the file sudo mkswap /swapfile #convert the file type to a swap file sudo swapon /swapfile #use the file as swap And to reload the swap configurations after restart, append the following to /etc/fstab:\n# Swap file created on DATE /swapfile none swap sw 0 0 More details can be found on the Debian wiki.\nInstall updates and required packages This section lists the commands to install the packages that I absolutely need to have on my system and does not come pre-installed with Debian.\nsudo apt update sudo apt upgrade sudo apt install \\ tmux \\ fzf \\ neovim \\ git \\ wget \\ bash-completion \\ chromium \\ bsd-mailx \\ unattended-upgrades \\ apt-listchanges \\ pass \\ pwgen \\ firewalld \\ thunderbird Here are the brief descriptions about the installed packages:\ntmux - tmux is a multiplexer for the Terminal. I spend a lot of time on the Terminal and tmux makes it easy to manage multiple open Terminals. fzf - A fuzzy finder for the command line. neovim - vim is my text editor of choice. neovim is my vim of choice. git - git command line client. wget - a download manager. bash-completion - a utility for autocompletion on bash. chromium - the open source variant of the Google Chrome browser. bsd-mailx - a very simple mail client for Unix mails. unattended-upgrades - required for installation of automatic system updates. apt-listchanges - required by unattended-upgrades for sending change-list of installed updates. pass - a command-line based password manager. More here. pwgen - a command-line based random password generation utility. firewalld - a command-line based firewall. thunderbird - an email client. Enable bash completion In the earlier versions for Debian, tab-completion for bash did not come enabled by default. But at least in Debian 12, this automatically gets enabled. If it is not enabled by default for you, uncomment the following section in /etc/bash.bashrc to enable it for all users:\nif ! shopt -oq posix; then if [ -f /usr/share/bash-completion/bash_completion ]; then . /usr/share/bash-completion/bash_completion elif [ -f /etc/bash_completion ]; then . /etc/bash_completion fi fi If you only want to enable it for selected users, paste the above content in the ~/.bashrc file.\nEnable auto-update The Gnome and KDE variants of Debian come with pre-installed utilities for automatic installation of system updates but not the XFCE variant, the one that I use. But it can be achieved through unattended-upgrades.\nTo enable unattended upgrades, make sure that the in the /etc/apt/apt.conf.d/50unattended-upgrades file the following section has at least the Debian and Debian-Security lines uncommented:\nUnattended-Upgrade::Origins-Pattern { // Codename based matching: // This will follow the migration of a release through different // archives (e.g. from testing to stable and later oldstable). // Software will be the latest available for the named release, // but the Debian release itself will not be automatically upgraded. // \u0026#34;origin=Debian,codename=${distro_codename}-updates\u0026#34;; // \u0026#34;origin=Debian,codename=${distro_codename}-proposed-updates\u0026#34;; \u0026#34;origin=Debian,codename=${distro_codename},label=Debian\u0026#34;; \u0026#34;origin=Debian,codename=${distro_codename},label=Debian-Security\u0026#34;; // Archive or Suite based matching: // Note that this will silently match a different release after // migration to the specified archive (e.g. testing becomes the // new stable). // \u0026#34;o=Debian,a=stable\u0026#34;; // \u0026#34;o=Debian,a=stable-updates\u0026#34;; // \u0026#34;o=Debian,a=proposed-updates\u0026#34;; // \u0026#34;o=Debian Backports,a=${distro_codename}-backports,l=Debian Backports\u0026#34;; }; If you also have Google Chrome installed and you want unattended upgrade to take care of the Google Chrome updates automatically, add the following line to the above section.\n\u0026#34;origin=Google LLC,codename=stable,label=Google\u0026#34;; To enable update reports over mail, uncomment the following section and add the user to which the reports should be sent:\nUnattended-Upgrade::Mail \u0026#34;subhadip\u0026#34;; To enable the unattended-upgrades to run periodically, run the following command:\nsudo dpkg-reconfigure -plow unattended-upgrades Add firewall rules By default the Debian firewall policy allows all incoming and outgoing network traffics. This is not necessarily insecure but I prefer restricting what goes in and comes out of my system. In the past, I used to use an iptables based script to customize the firewall policy. But as of Debian 10, iptables is replaced by nftables and the usage of firewall management utilities like firewalld is recommended.\nfirewalld does not come installed by default and needs to be installed manually. OOTB, firewalld uses the public zone as default which allows outgoing traffic but blocks incoming traffic on all ports except ssh and dhcpv6-client. To disable them, use the following commands:\nsudo firewall-cmd --remove-service=ssh --permanent sudo firewall-cmd --remove-service=dhcpv6-client --permanent Install latest Firefox Debian comes with the ESR version of Firefox. To install the latest stable version of Firefox, I use a bash script which is hosted on my GitHub account. Download and run the script as executable.\nwget -O firefox-updater.sh https://raw.githubusercontent.com/subhadig/dotfiles/master/bin/firefox-updater chmod u+x firefox-updater.sh ./firefox-updater.sh The script downloads the latest tarball package of Firefox from the official site and unpacks it under /opt along with creating a .desktop file in /usr/share/applications. It automatically detects if the user has sudo privileges and prompts for the user or the root password accordingly during the installation. This script can also be used to update Firefox when a new version is available.\nThe script already links the firefox executable to /usr/bin/firefox-latest to make sure that it\u0026rsquo;s on the PATH. Execute the following command to also link it to /usr/bin/firefox:\nsudo ln -s /opt/firefox/firefox /usr/bin/firefox Enable showing user lists at login Debian by default does not display the available usernames on graphical login screen but I like to show the user list so that usernames can easily be selected at login. To enable user lists at login for lightdm, my display manager of choice, paste the following content in /etc/lightdm/lightdm.conf.d/01_my.conf:\n[Seat:*] greeter-hide-users=false Create users To create new users, use the following Debian command:\nadduser \u0026lt;username\u0026gt; To change/update passwords of the created users:\npasswd \u0026lt;username\u0026gt; Desktop Environment specific customizations I use XFCE as the desktop environment. So the customizations here are specific to XFCE only.\nPanel customizations By default XFCE comes with two panels, one at the top and one at the bottom of the screen. I move the bottom panel which is a launcher for applications to the left. Also in the top panel, I make the following changes:\nAdd the following plugins: System Load Monitor PulseAudio Plugin Remove the following plugins Workspace Switcher Update appearances This section includes changing themes, updating fonts settings and general look and feel of the desktop.\nChange the theme: I use WhiteSur Gtk Theme theme for both the desktop and the windows. Also I move the window\u0026rsquo;s controls (minimize, maximize and close buttons) to the left to mimic the MacOS behaviour. Change the font settings: Fonts on Debian do not look the best out of the box. This is how my font settings looks like: I usually play with the Hinting and Sub-pixel order settings till I get the best combination because these settings is dependent on the hardware and can vary from one hardware combination to another.\nConclusion The steps are tested on a Debian 12 Bookworm installation. The choices made in this post are based on my personal requirements and preferences, it almost certainly will be different in your case. So the steps shared in this post should not be followed without understanding what they are meant for and if they are required for your case. For me, this post will definitely make it a lot easier when next time I install Debian on a new system.\n","permalink":"https://www.subhadig.net/posts/my-list-of-things-to-do-after-installing-debian-on-the-pc/","tags":["debian"],"title":"My list of things to do after installing Debian on the PC"},{"categories":null,"contents":"Introduction I recently moved my personal blog to GitHub Pages from Wordpress.com. I have been thinking about doing it for sometime and this time I finally did it. And in this post I wanted to share the a few things about it.\nWhat this post is and what it is not This post talks about about how I made the switch to Jekyll and GitHub Pages from Wordpress.com and the reasons behind it. It is not a rant about Wordpress.com.\nWhat are GitHub Pages? GitHub Pages are public static webpages hosted and published through GitHub, completely free of cost. The source code of the website is also hosted in a public repository in GitHub.\nWhat is Jekyll? Jekyll is a static site generator. Contents are written in simple HTML or Markdown and it creates static HTML pages out of it. It uses Liquid, a simple templating language which makes it very easy to have custom templates designed for all your pages and when you run Jekyll, it automatically combines the contents and the templates togethe and creates the final static pages.\nWhy Jekyll? Although I did not do any extensive comparison between Jekyll and the other similar solutions, Jekyll seemed one of the best choice to start with because:\nGitHub Pages have supports for Jekyll out of the box. Although it is written in Ruby, it does not require any knowledge of Ruby to use it. It seemed to have the right blend of simplicity and features. Why did I do it? I have been blogging with Wordpress since 2011 and when I started, it did seem one of the best choices out there. It\u0026rsquo;s easy to start with, it has a nice editor, there are a lots of ready-to-use themes to choose from, there is a vast community of users, so finding help was never much difficult. But over the years, my expectations about the way I blog have evolved, new needs have emerged. Here are the main reasons why I made the switch.\nFreedom Although Wordpress.com has supports for themes and many aspects of the themes are customizable, the free version does not allow one to completely edit the themes and have a completely customized look and feel. Often times I don\u0026rsquo;t need all the bells and whistles that come with a full blown theme but I want certain things in certain way. For example, I like to show a page listing all my post titles and links to my visitors which was apparently very hard to accomplish if not impossible with Wordpress.com.\nSimplicity With GitHub Pages and Jekyll, everything is very transparent. The whole project is just a collection of a few markup files, images and configurations. There is no database. There is no fancy editor. There is no bloat of features. Out of the box, you get nothing more than a static HTML page. But it\u0026rsquo;s easy to add the features you need whether they are natively available or by using third party services.\nVim and Markdown Vim is my editor of choice and I extensively use it wherever I can. And when in some cases, I have to use another editor, I always look for ways to enable vi like key bindings. Markdown is a simple markup language that makes it stupidly simple to write in rich text and is way better than WYSIWYG editors in browser in my opinion. Blogging with Jekyll and GitHub Pages gives me an option to use both vim and markdown.\nThe ability to work offline Because the whole repository of source files including the posts are cloned locally and Jekyll server is so easy to setup and run, an added advantage of this approach is the ability to create posts and preview them locally without the need to reach to the internet before publishing them on GitHub.\nHow did I do it? The starting point was to head over to the GitHub Pages Getting Started page and follow the instructions for creating a project with one simple HTML page with one of their featured css themes. After that I followed the Step by step tutorial for setting up a Jekyll blog that walked me through from installing Jekyll to creating HTML templates for the pages to writing my first blog post in markdown.\nBut at this point, the resulting site is so basic that if you are coming from a feature-rich platform like Wordpress.com, you\u0026rsquo;ll see a lot of missing features, features that you always took for granted. Here you will have to add them manually either by adding small snippets of code or plugins or by using third party services.\nSite map Site map is a dedicated link on your blog that will contain the list of pages and URLs from your blog. Adding a site map is effortless in Jekyll if you use the Jekyll-sitemap plugin.\nBut what about comments? An essential part of a blog site is the support for comments for the posts. But Jekyll being a static site generator lacks inbuilt ability to support comments. For that, I used a third party service called Disqus. They offer a Basic tier that should be more than sufficient for a personal blog site.\nBut isn\u0026rsquo;t the site looking empty? So I imported my older posts from the previous blog to this one and with the Jekyll-import plugin, it was not much of a hassle. True, I had to do some editing to the imported posts to fix a few style related issues.\nSearch engine optimization Jekyll-seo-tag plugin automatically generates metadata and tags for search engines and social networks sites for better indexing. Also you can manually add tags and metadata to each posts.\nIs it worth it? Absolutely. Now every time I want to write a new post, I just need to do this in my terminal.\nvim \u0026lt;Type content in markdown\u0026gt; git add git commit git push And my new post post is published without ever having to leave the comfort of the command line. Can it get any simpler than this?\n","permalink":"https://www.subhadig.net/posts/moving-my-blog-to-github-pages-from-wordpress/","tags":["github-pages"],"title":"Moving My Blog to GitHub Pages from Wordpress.com"},{"categories":null,"contents":"The Problem After the release of Debian 10 Buster, I installed it on my Dell Inspiron 3558 laptop which comes with onboard Intel HD Graphics. I am using Xfce desktop environment instead of the default Gnome desktop. After the installation, I would intermittently face the problem where the whole desktop would suddenly just freeze and stop responding to the mouse and the keyboard. Even after hours of waiting the system would never come back to the normal state and the only solution was to hard reboot the whole system. It seemed really weird as prior to installing Debian 10, I had Debian 9 running on it for more than a year and I never had any such issues.\nThe Solution This issue was very difficult to reproduce as it did not necessarily follow any pattern and was really unpredictable. After researching on the Internet for days, I finally found out a solution that fixed the issue. As per the official Debian documentation on video drivers, the use of X.org xf86-video-intel driver is discouraged in favour of the newer builtin modesetting driver especially if your hardware is newer than or from 2007. This was the default setting that came with the default Debian Xfce installation. And this was what was causing the freeze. To fix it and use the old xf86-video-intel driver instead, here is what I did.\nEdit the file /etc/X11/xorg.conf and update it with the following content. If the file does not exist, create a new one.\nSection \u0026#34;Device\u0026#34; Identifier \u0026#34;Intel Graphics\u0026#34; Driver \u0026#34;intel\u0026#34; Option \u0026#34;AccelMethod\u0026#34; \u0026#34;SNA\u0026#34; Option \u0026#34;TearFree\u0026#34; \u0026#34;true\u0026#34; EndSection That's it. I have been having this setting for 3 months now and I never had any freezing issue after that.\n","permalink":"https://www.subhadig.net/posts/fix-for-debian-buster-system-freeze/","tags":["debian"],"title":"Fix for Debian Buster System Freeze"},{"categories":null,"contents":"If you have never heard of Alpine Linux before, it's a distribution of Linux, a very lightweight one . In fact it's so small, an empty container of Alpine Linux can be run with less than 8 MB of memory. And that's one of the reasons why it's extensively used in containers. Docker Hub has an official image of Alpine Linux. So it's fairly easy to run Alpine Linux as a docker container or build one on top of it.\nDownload the image To download the alpine image from Docker Hub, run the below command, assuming you already have Docker installed in your system. I am using Alpine version 3.9 which is the latest at the time of writing the post. This link has a list of available tags and versions.\ndocker pull alpine:3.9 Run the image in interactive mode To run the alpine image in interactive mode, run the following command:\ndocker run -it --rm --name alpine alpine:3.9 This should launch an alpine container and land you at a shell prompt. The \"-it\" flags tells Docker that the image should be run in interactive mode and a tty should be allocated. \"--rm\" flag ensures that the container is removed as soon as you exit the shell and come out of the interactive mode.\nTo check the version of Alpine Linux while inside the shell, run\ncat /etc/alpine-release Build your own Docker image While it can be fun to run it in interactive mode, it's not very useful. To make something useful with docker, you need to create your custom image. In this post, I will create a custom docker image with Alpine Linux that will run a simple HTTP server and I will access the server from the host. Here are the steps.\nCreate the Dockerfile Create a file with name Dockerfile and paste the following content.\nFROM alpine MAINTAINER Subhadip Ghosh RUN apk update RUN apk add python3 RUN echo \u0026#34;Hello from Alpine Linux\u0026#34; \u0026gt;index.html ENTRYPOINT [\u0026#34;/usr/bin/python3\u0026#34;, \u0026#34;-m\u0026#34;, \u0026#34;http.server\u0026#34;] EXPOSE 8000 Create the Docker Image Run the following command to create the Docker image. Make sure you are in the same directory as the Dockerfile.\ndocker build -t alpine-python-server:latest . Execute the following command to verify that an image has been created with the name \"alpine-python-server\".\ndocker images Run the image To run the image that was created in the previous step, execute the following command:\ndocker run -d -p 8000:8000 --name test-server alpine-python-server This command does the following things:\n- Creates a container from the \"test-server\" image created in the previous step.\n- \"-d\" tells docker to run the container in detached mode ie in the back ground.\n- Maps port 8000 of the container with port 8000 of the host so that you can open a web browser in your host system and point to http://localhost:8000 to visit the web-server running inside the container.\n- I named our container as \"test-server\" for ease of reference.\nVisit the web-server from host Since we have mapped the container port on which the web-server is running to the same port on host, if you visit the URL http://localhost:8000 from any web-browser from your host system, you should see something like this:\nNote These steps were tested on a Debian Linux host. If you are using Docker desktop on Windows or MacOS, the docker container port mapping with the host OS may not work the way it is described in the post or may require additional steps as I have come to know. Please do your research before proceeding. ","permalink":"https://www.subhadig.net/posts/run-alpine-linux-as-a-docker-container/","tags":["docker"],"title":"Run Alpine Linux as a Docker Container"},{"categories":null,"contents":"Event though Debian is considered as one of the most stable Linux distributions out there, part of it's stability comes from the fact that a large portion of it's package base consists of well-tested but outdated packages. This should be a blessing most of the times but if you are a developer like me, some times you may need a latest or specific version of a package. In this case, I needed the latest version of the mysql-server package. Although official apt repository is available from MySQL to install the latest version of it on Debian, to be able to run something in containers has it's own advantages including having the ability to run multiple versions of the same package simultaneously and can be easily cleaned up after using.\nWhile one could use my earlier post on creating LXC containers on Debian and run MySQL inside it, it's a lot easier to use the official MySQL docker image from Docker Hub. If you are yet to install Docker, you can follow this official documentation from Docker to install the community edition of it on Debian. Post installation of Docker, follow the below steps to run MySQL as a Docker container. To be able to connect to the docker instance of MySQL from the MySQL client or MySQL workbench available in the Debian repository, I will be using a few additional tweaks.\nDownload the required version of MySQL docker image from the Docker Hub. I am using MySQL version 8 which is the latest version of MySQL at the time of writing the post. Replace 8 with the required tag in your case. A full list of supported tags for MySQL docker image can be found at this link. docker pull mysql:8 Run the docker image. docker run --name test-mysql -e MYSQL_ROOT_PASSWORD=test -d -p 3306:3306 mysql:8 --default_authentication_plugin=mysql_native_password A few things to note:\n- The name of the docker instance in this case is \"test-mysql\". It can be any arbitrary name.\n- \"test\" value has been passed as the MYSQL_ROOT_PASSWORD environmental variable while starting the container. This value will be used as the MySQL root password by the container. In absence of this value, it will generate a random root password every time you start the container and print in the log.\n- \"-d\" option is to run the container in the background as a detached instance.\n- The 3306 port, which is the default port of MySQL is mapped with the 3306 port of the host. This is helpful if you want to connect to the MySQL docker instance on localhost.\n- The \"default_authentication_plugin\" has been set as \"mysql_native_password\". This is required if you want to connect to the MySQL docker instance from the MySQL client or the Workbench available in the Debian repository, which are old and does not support the new default authentication methods introduced in MySQL 8. The container should take a few seconds to initialize itself. After which, you can use the following command to connect to it. mysql --protocol=tcp -u root -ptest If you don't have MySQL client installed in your Debian host, use the following command to install it.\nsudo apt install -y mysql-client If you want to connect to MySQL from within the container itself, use the following command docker exec -it test-mysql mysql -u root -ptest That's it. This should give you enough information to start and run MySQL as a Docker container on your Debian host. For additional information and configuration options, visit the following listed pages\nMysql page on Docker Hub Official Mysql documentation on running Mysql as a Docker container on Linux ","permalink":"https://www.subhadig.net/posts/run-mysql-in-docker-on-debian/","tags":["docker","debian"],"title":"Run MySQL as Docker Container  on Debian"},{"categories":null,"contents":"Debian Stretch, the current stable release of Debian now comes with Firefox ESR 60. One strange issue I have noticed with the out of the box configuration of Firefox on Debian is that it does not correctly render the Indic fonts on the websites. Most notable issue is that it breaks the connected letters while showing. Here's how I fixed it.\nInstall the fonts-indic package.\nsudo apt install fonts-indic Now open Firefox and go to Preferences \u0026gt; General \u0026gt; Language and Appearance \u0026gt; Fonts \u0026amp; Colors and click on Advanced. Select the language you want to set fonts for from the \"Fonts for\" dropdown and select fonts with your specific language support for Serif and Sans-serif fonts, click Ok. Here's how my settings looks like:\n","permalink":"https://www.subhadig.net/posts/fix-for-incorrect-rendering-of-indic-fonts-in-firefox-on-debian/","tags":["debian","firefox"],"title":"Fix for incorrect rendering of Indic fonts in Firefox on Debian"},{"categories":null,"contents":"I am using Eclipse IDE (version 2018-12 at the time of writing) on Debian 9 Xfce and the issue with it is that the Eclipse editor windows would flicker around the edges. Sometimes so much so that it's impossible to type inside it. Here's how I fixed it:\nFirst check the value of GTK_IM_MODULE in your environment by executing\necho $GTK_IM_MODULE In my case the output was \"xim\". But Eclipse expect it to be \"ibus\". So enter the following command in a terminal session to set it to the value.\nexport GTK_IM_MODULE=\u0026#34;ibus\u0026#34; Now if you launch Eclipse from the same terminal session, you should not experience any flickering issue. If you launch eclipse from a desktop menu entry, then edit the .desktop file and put the following string in the beginning of the Exec command:\nenv GTK_IM_MODULE=ibus ","permalink":"https://www.subhadig.net/posts/how-to-fix-eclipse-ide-flickering-issue-on-debian/","tags":["debian","eclipse","java"],"title":"How to fix Eclipse IDE flickering issue on Debian"},{"categories":null,"contents":"If you have used an USB drive to write iso images to before installing Debian or recent versions of Ubuntu, here are the steps to reclaim it after installation is over.\nOpen a terminal and list the available device names using the following command: lsblk which should show you an output like the one below:\nIdentify the device name of your USB drive. Extreme caution should be taken while at it because wrong device names can potentially wipe your entire hard disk. In this case, the USB drive that we want to format is sdb. Writing the iso image to the USB drive has made it a read-only device. To change it back, the partition table needs to broken. Issue the below command after replacing sdb with the device name identified in the previous step: sudo dd if=/dev/zero of=/dev/sdb bs=1M \u0026amp;\u0026amp; sync This step might take some time to complete depending upon the size of the USB drive. So be patient. When it is over, you should see an output like the below:\nNext you need to create a new partition. First enter the following command after replacing sdb with your device name: sudo fdisk /dev/sdb You should see a prompt like below\nEnter n to create a new partition, press enter to go with the default options until the next Command prompt comes, then enter w to write the changes to disk.\nEnter the following command to check if the device partition settings have been refreshed. If not, unplug and replug the USB drive. lsblk Enter the following command to format the partition to FAT after replacing sdb with your device name and \u0026lt;label\u0026gt; with your label of choice. sudo mkfs.vfat /dev/sdb1 -n \u0026lt;label\u0026gt; And now your USB drive should become usable again.\n","permalink":"https://www.subhadig.net/posts/format-usb-drive-after-installing-debian-from-it/","tags":["debian","ubuntu"],"title":"Format USB drive after installing Debian from it"},{"categories":null,"contents":"After a few earlier failed attempts, today I was successfully able to create an unprivileged LXC container on Debian Stretch for the first time. I had experience of using LXC's more user friendly cousin LXD before I moved to Debian but unfortunately LXD is not available on Debian yet. While LXC is more low level compared to LXD, if you just need a basic container, it's still pretty solid. The Debian wiki on LXC container is fairly straight forward and easy to follow, but still for someone who is a novice to both Debian and LXC, it is very easy to get lost. So I am writing this post so that it can be a good place to start if you need a very basic setup.\nLXC containers can be of two types depending on the level of access they have to their host system:\nPrivileged containers will have root access to your system. Unprivileged containers will not have root access and is more secure by nature but requires a bit more configurations before you can start using them. In this guide, I will be showing how to configure and create one. Before I start with the steps, I want to talk a little bit about my system configuration. The installed version of Debian is Stretch and the architecture is amd64. It has two users - root and test which is a non-sudo user. This guide will assume that you will modify the commands as per your system specific configuration instead of blindly copying and running.\nInstalled the required packages as root. apt install lxc libvirt0 libpam-cgroup libpam-cgfs bridge-utils cgroupfs-mount Create networking related configurations: I will be using a virtual interface to create a network bridge that will make use of of the lxc-net package which comes as part of lxc 2.0. This bridge will be shared by the container but will not be accessible from outside of the host. Create /etc/default/lxc-net with the following line: USE_LXC_BRIDGE=\u0026#34;true\u0026#34; Run the following command as root: service lxc-net restart Configuring the host system: The following steps configures the host system for creation of an unprivileged lxc container. Run the following command which should return everything as 'enabled' in green. If not, restart your system. $ lxc-checkconfig Run the following as root: sh -c \u0026#39;echo \u0026#34;kernel.unprivileged_userns_clone=1\u0026#34; \u0026gt; /etc/sysctl.d/80-lxc-userns.conf\u0026#39; sysctl --system Run the following command as the unprivileged user to get the subuids and subguids of the current user: $ cat /etc/s*id|grep $USER In my case, it produced a output like the following:\ntest:100000:65536 test:100000:65536 But it can be different in your case. Note the first number ie 100000. Run the following commands as root after replacing 'test' with your username. The first number in the range is the number we noted in the previous step, the last number should be obtained after adding 65536 to the first number: usermod --add-subuids 100000-165536 test usermod --add-subgids 100000-165536 test Run the following command as root to change permission of some of the directories after replacing test with your username: cd /home/test setfacl -m u:100000:x . .local .local/share Run the following command as root to configure the virtual network interface for your user after replacing test with your username: echo \u0026#34;test veth lxcbr0 10\u0026#34;| tee -i /etc/lxc/lxc-usernet Configure LXC for your user by performing the following steps as your user. Create the lxc config folder: $ mkdir -p .config/lxc Configure the default template for all the future unprivileged containers after replacing 100000 with the number noted in the \"Configuring the host system\" step: $ echo \\ \u0026#39;lxc.include = /etc/lxc/default.conf # Subuids and subgids mapping lxc.id_map = u 0 100000 65536 lxc.id_map = g 0 100000 65536 # \u0026#34;Secure\u0026#34; mounting lxc.mount.auto = proc:mixed sys:ro cgroup:mixed # Network configuration lxc.network.type = veth lxc.network.link = lxcbr0 lxc.network.flags = up lxc.network.hwaddr = 00:FF:xx:xx:xx:xx\u0026#39;\u0026gt;.config/lxc/default.conf Reboot the system. Creating the unprivileged container: Now we are at the end of the guide and hopefully with all the right configurations to create our first unprivileged container. Run the following command as your user to create an ubuntu xenial container: $ lxc-create --name ubuntu -t download Give the following inputs when prompted:\nDistribution: ubuntu Release: bionic Architecture: amd64 Start the container by running the following command: $ lxc-start --name ubuntu --logfile $HOME/lxc_ubuntu.log --logpriority DEBUG The extra log options will be helpful in debugging if something goes wrong but can be ignored from next time onward. To access the newly created container, run the following command: $ lxc-attach --name ubuntu If you have followed all the steps correctly, hopefully you are now running an unprivileged container on your Debian Stretch. Please consider reading the article mentioned in Further Reading section to understand each steps used in this guide in details.\nFurther Reading:\nLXC - Debian wiki ","permalink":"https://www.subhadig.net/posts/creating-an-unpriviledged-lxc-container-on-debian-stretch/","tags":["debian","lxc/lxd"],"title":"Creating an unpriviledged lxc container on Debian Stretch"},{"categories":null,"contents":"I have a wireless Bluetooth speaker that I use with my laptop running Debian 9 with Xfce. My laptop also has a primary speaker. So when I connect my Bluetooth speaker to my laptop, my laptop is actually connected to both the primary and secondary speaker at the same time. The laptop volume up/down keys will still be mapped to the primary speaker and if I wish to control the volume of the secondary speaker, I needed to open the Volume Control window from the Panel volume plugin, which was a pain if you had to do it every time.\nHere's what I did to simplify it. Debian Linux and most other major Linux distributions use pulse audio to manage all audios and there's a command line utility that comes installed by default to manage pulse audio. It's called pactl. When you connect a speaker to your computer, it creates an audio sink for it to manage it. To get a list of audio sinks that your computer has access to, run the following command in Terminal:\npactl list sinks And from the output, look for the speaker you need to manage and the corresponding \"Name\" string. In my case, it looks like \"bluez_sink.\u0026lt;hardware-address\u0026gt;.a2dp_sink\" where \u0026lt;hardware-address\u0026gt; is the address by which the computer identifies the particular hardware device. The good thing about this address string is that, it remains unchanged even if you remove it and then connect it back.\nOnce you determine the sink name of your audio device, you can do a bunch of operation from the command line on it including setting the volume, increasing/decreasing the volume or mute it. Example: the following command will increase the sink volume by 5%\npactl set-sink-volume \u0026lt;sink-name\u0026gt; +5% and to decrease it by 5%\npactl set-sink-volume \u0026lt;sink-name\u0026gt; -5% Replace \u0026lt;sink-name\u0026gt; with the name you copied from the previous step.\nAnd then you can assign keyboard shortcuts to do those operations, so that you can perform them without opening a Terminal. To do that in Xfce, go to Settings \u0026gt; Keyboard \u0026gt; Application Shortcuts and then Add a new shortcut. For other desktop environments, follow the desktop environment specific instructions.\n","permalink":"https://www.subhadig.net/posts/assigning-volume-up-down-shortcut-keys-for-secondary-speaker-in-linux/","tags":["debian"],"title":"Assigning volume up/down shortcut keys for secondary speaker in Linux"},{"categories":null,"contents":"One of the few software that I like to keep always updated to the latest version on my system is Libreoffice, because of the compatibility improvements with the other office suite each new version brings. And while Debian Stable provides a solid and stable base system, the libreoffice package becomes outdated with time. A lot of the guides on updating Libreoffice in Debian on the Internet speak about installing the latest binaries from the Libreoffice website. But the main shortcoming with this approach is that updating to the next version is again a manual task.\nI prefer to install it from the Debian backports repository (libreoffice version in stretch-backports is at par with testing repository). Following are the simple steps to install the latest LIbreoffice on Debian Stretch (steps will be slightly different if you're on a different version of Debian).\n1. Add the Stretch backports repository to apt sources if you have not done already by adding the following line to /etc/apt/sources.list file.\ndeb http://ftp.debian.org/debian stretch-backports main contrib And update repository information.\nsudo apt update 2. Uninstall the older libreoffice packages and dependencies.\nsudo apt purge libreoffice* sudo apt autoremove 3. Install the latest libreoffice and a couple of other additional packages from the backport repository\nsudo apt install -t stretch-backports libreoffice libreoffice-gnome libreoffice-help-en-us And that should be all. Open Libreoffice and check the version from Libreoffice \u0026gt; Help \u0026gt; About Libreoffice which should reflect the latest version. A couple of things to note here:\nFor Xfce and other gtk based desktop environments, libreoffice-gnome should work fine. If you are using KDE, you should install libreoffice-kde instead. If you want to access the built-in Libreoffice help in some other language than US English, replace the libreoffice-help-en-us package with the help package for your language of choice. I hope it helps.\n","permalink":"https://www.subhadig.net/posts/installing-the-latest-libreoffice-on-debian-stable/","tags":["debian"],"title":"Installing the latest Libreoffice on Debian stable"},{"categories":null,"contents":"Recently I had to downgrade my main laptop from Debian testing to Debian stable (Stretch at the time of writing). Since I did not have a separate home partition, re-installation meant formatting the entire partition that would erase all my personal data and settings. But this time I did not want go over the pain of configuring everything from scratch, so I went ahead without formatting my root partition. After a few times of failures and analyzing the installation logs, I learnt the trick.\nYou need to boot using a live CD instead of the regular one that will just let you install, then enter into a live session. Now you need to open a terminal or a file manager, go to the actual hard disk partition that you are going to use for the installation, remove all the files and directories except the /home directory. Now if you proceed with the installation, it will not fail anymore because of unclean target.\nSomething you should keep in mind that if you're like me downgrading from a more recent release to an older release, some of the settings might not work after re-installation, especially the DE related settings. In those cases, drop to a shell (Ctrl + Alt + F1) if you are not able to access the desktop environment and delete or rename the old settings directory or file.\n","permalink":"https://www.subhadig.net/posts/install-debian-on-an-unclean-target/","tags":["debian"],"title":"Install Debian on an unclean target"},{"categories":null,"contents":"MediaWiki is a very popular free and open-source wiki software that powers some of the most visited wikis on the Internet including the Wikipedia. You can also host it in your own environment for your own wiki requirements or for your organization.\nAt my work, we use MediaWiki for our developer's wiki site. When I started working for a new product team sometimes back, I came to know about this wiki format for the first time and I didn't like it very much.\nI usually like to contribute to the wikis more often than not but when I first went on to add my first page to this wiki, I noticed a few annoying things:\nWe were using an older version of MediaWiki that does not come with a fancy editor. The web-based editor was pretty dull and inefficient. Also it lacked rich text highlighting. The mediawiki source language was having it's own syntax for writing rich text, sort of like markdown but not the same. And I was in no mood to learn a new set of syntax just to write a wiki page. Then I turned towards the Internet looking for a solution. The first thing that came to my mind was to use a WYSIWYG editor that generates output in MediaWiki format instead of HTML But the thought of using a web based editor was repulsion enough for me to drive myself towards looking for a better solution.\nThen I came to know about this wonderful command line utility called pandoc that can magically convert virtually any text format into another including markdown to mediawiki. This solution had at least two benefits:\nI was already fond of using markdown. So no learning curve for me. I could use Vim! If you know how to use Vim, you'd know that there's no other editor that can make you more productive. And also Vim supports syntax highlighting for markdown out of the box. Converting a markdown file to mediawiki is as simple as the below command:\npandoc -f markdown -t mediawiki -o sample_wiki.mediawiki sample_wiki.markdown Although initially I had to go through the markdown documentation page for pandoc to learn a few tricks to ensure that my markdown texts get converted to mediawiki the way I want it to but after a day or two, it felt painless. And the best thing is that you can convert between these two text formats both ways without any distortion.\n","permalink":"https://www.subhadig.net/posts/how-to-easily-write-in-mediawiki/","tags":["vim","markdown","pandoc"],"title":"How to easily write in MediaWiki"},{"categories":null,"contents":"After my previous post about why I chose Debian Testing as my current distribution, I wanted to share how I installed and configured Debian Testing. So that somebody out there looking for a guide to install their own Debian rolling system, will have at least a starting point.\nBefore I proceed with the post, please know that although I am a long time Linux user, with Debian, I just started my journey a couple of months back. And by no mean I am a seasoned Debian user. So whatever steps I am going to list in this post are the ones that I thought would be best suited for my requirement when I installed it on my system.\nGet the image: The Debian Free Software Guidelines (DFSG) does not allow to ship non-free software with the default cd-image. That means, if you are planning to install it on a Laptop and if your laptop has a wifi which is the case in most of the times, chances are that wifi will not work out of the box (OOTB) after your installation. Because the default cd image does not come with any non-free firmware and you need to install it separately after completing the default installation. Which may not be a great choice if wifi is the only way you can access the internet. But there is a better way. Debian also publishes separate cd images with the non-free firmware components. So if you also need wifi support OOTB, choose one of the latest stable release iso-dvd installers(current) from the location: https://cdimage.debian.org/cdimage/unofficial/non-free/cd-including-firmware/ Install the image: I am going to assume that you picked the non-free image and will skip the driver installation part after the installation. But the installation procedure is same irrespective of if you're using free or non-free image. I wrote the cd-image on a USB stick. The steps are fairly simple. Just follow the documentation. The installer is pretty standard and I am not going to explain the step by step installation procedure. You will be required to choose your desktop environment of choice during the installation procedure, the default is Gnome. Also I kept the root password blank because I wanted the root account to be disabled. I prefer to use sudo whenever root privilege is required. After you are done with the installation, restart your computer. Enabling USB keyboard: This step may not be required for you. I use a USB keyboard with my laptop as I am not very fond of my laptop keyboard. In Ubuntu, I didn't have to do anything special in order to have my keyboard detected but in Debian, you need to have certain kernel modules enabled to be able to use it. Follow the first option on this page and change the driver-policy to include most modules. Updating the apt sources: This is one of the most important steps after installation. After installation you will have something like below in your /etc/apt/sources.list: deb http://deb.debian.org/debian/ stretch main non-free contrib deb-src http://deb.debian.org/debian/ stretch main non-free contrib deb http://security.debian.org/debian-security stretch/updates main contrib non-free deb-src http://security.debian.org/debian-security stretch/updates main contrib non-free deb http://deb.debian.org/debian/ stretch-updates main contrib non-free deb-src http://deb.debian.org/debian/ stretch-updates main contrib non-free Edit the file with root privilege and replace the word stretch with testing. Update and dist-upgrade your system.\nsudo apt update \u0026amp;\u0026amp; sudo apt dist-upgrade After you reboot, you will have your system updated to the current testing branch of Debian. In my case, it was Buster.\nEnable tapping on touchpad: Although the touchpad on my Laptop was automatically detected, clicking by tapping was not enabled by default. Follow this link to add this configuration to /etc/X11/xorg.conf.d/40-libinput.conf and then restart lightdm to enable tapping on touchpad. If you are not using a laptop, then this step is not required. Installing latest Firefox: The current Debian testing version ie Buster repository does not contain the latest version of Firefox ie Firefox Quantum. It has the Firefox ESR which is the long term support version of Firefox and lags behind the current release. If your primary browser of choice is Chrome or Chromium, you can go ahead and install it very easily. The repo does contain the latest version of Chromium. The latest Firefox is available in the Debian unstable repository ie Sid. To install Firefox from the unstable repo, perform the below 2 steps: Add the below content in /etc/apt/preferences.d/preferences. This tells the system not to install packages from unstable unless told otherwise. This is very important as it will prevent the system to install any untested/unstable package without your consent. Package: * Pin: release a=testing Pin-Priority: 900 Package: * Pin: release o=Debian Pin-Priority: -10 Add the below two lines in /etc/apt/sources.list deb http://deb.debian.org/debian/ unstable main non-free contrib deb-src http://deb.debian.org/debian/ unstable main non-free contrib Then install Firefox.\nsudo apt install firefox/unstable Install a couple of additional packages: These packages will warn you if there is any serious bug or important change in any of the packages you install or upgrade. sudo apt install apt-listbugs apt-listchanges That's it. You should now have a fully functional Debian testing system. Be sure to go through the links in the References section before you actually make the switch. If you have any question/suggestion, do let me know in the comments.\nReferences Debian Wiki - Debian Testing Debian Wiki - Best Practices for Testing Users ","permalink":"https://www.subhadig.net/posts/installing-debian-testing/","tags":["debian"],"title":"Installing Debian Testing"},{"categories":null,"contents":"A few weeks back, I switched my home laptop to Debian and I wanted to write about my reasons behind choosing Debian and my experience with it for the first few days. But before I dive into that, here's a little background about myself. I have been using Ubuntu and later Xubuntu at home and later at office on my Desktop and on my Laptop for more than 7 years now and on the server front, I have worked on both Redhat/Centos and Ubuntu based systems. So I am not new to Linux at all.\nBefore I switched, I was using the latest LTS (Long Term Support) version of Xubuntu. Why? Because\nI did not want to upgrade to the releases in between 2 LTS releases because from my past experience, I have seen that bugs introduced in the regular releases are sometimes fixed in the next releases which are released every six months. Which is not very helpful, if there's a bug in one of the packages you rely on. Too many up-gradations to interim releases leave the system with a lot of junks. Sometimes, a new release replaces a software with something else from the same category. And if you upgrade to it from a previous release, the up-gradation process installs the newer software but also keeps the old one. Why did I want a change? The release process of Ubuntu means that if you are using the current version of LTS, packages can be up to 2 and a half years old. That means, if you are using a package from universe repository (still an official Ubuntu repository but packages rarely receive any update after the final release) and it has a bug, you have to wait till up to 2 years to get a fix or you have the following options - start hunting for a PPA or install the upstream release by some other mean. Either of which are not very productive.\nWhy did I choose Debian? I wanted a change but I did not want to leave the comfort of using the tools that I have been using for all these years and tools that I have become fond of, including apt. I wanted to still have the ability to use the same set of packages that I was using. I wanted to use a distribution that was maintained and developed completely by the community and without any direct involvement from a business entity and at the same time dependable and trustworthy. So Debian!\nWhy did I choose Debian Testing? I did not want my system to be stuck to a particular release. I did not want to upgrade the whole system to a new release when it comes out. But I still wanted the latest versions of the packages in my system. In other words, I wanted a rolling release distribution. But I also wanted a little bit of stability and some sanity for my system and possibly for me. Testing provides the best balance between the two worlds!\nHow is it like using Debian Testing? In short, it's a learning experience without going through too much of hassles. Immediately after I installed Debian on my laptop, I found that my external keyboard was not working. I had to load a few extra modules before it started working. I had to add the Debian Unstable repository to install the Firefox regular version from Unstable (Testing has only Firefox ESR). I had to tweak the font settings to get at least a decent font rendering. So you get the idea! It's not quite like a walk in the park. But after the first couple of days, I started to feel at home. Everything began to look familiar. I could use the same apt to update my system except that this time it would also upgrade my Libreoffice to the latest release without me adding any PPA. All my hardwares work flawlessly. And after using it for a few weeks, now I am quite comfortable with my new system. So far I haven't faced any breakage. The system runs quite smoothly. I can use all my software that I was using before. So all in all, it has been a good experience so far!\n","permalink":"https://www.subhadig.net/posts/my-rolling-debian-system/","tags":["debian"],"title":"My Rolling Debian System"},{"categories":null,"contents":"If you are on Ubuntu 16.04 using radeon open source driver for your graphics card and having issues with playing mp4 or mkv files with VLC media player then read on. If you are not sure what graphics driver is in use in your system, paste the below line in Terminal.\nlspci -v -s lspci | awk \u0026#39;/VGA/{print $1}\u0026#39; And check for the below line in the output:\nKernel driver in use: radeon\u0026lt;br /\u0026gt; The issue occurs as soon as you open a media file of type mkv or mp4 with VLC media player. Immediately after opening, it crashes silently. But if you check the /var/log/syslog, you should be able to see segmentation fault messages.\nThe issue probably occurs because VLC by default uses VDAPU (a shared API between a number of graphics driver for Linux) for video decoding. To turn it off, go to VLC Player \u0026gt; Tools \u0026gt; Preferences \u0026gt; Input / Codecs and select Disable from the dropdown.\nAlso, I changed the Output value at VLC Player \u0026gt; Tools \u0026gt; Preferences \u0026gt; Video to XVideo output (XCB).\nAnd after that, VLC started working fine on my friend's computer. I hope it helps.\nHelpful link:\nvlc cannot play mkv and mp4 formats - AskUbuntu ","permalink":"https://www.subhadig.net/posts/vlc-player-not-playing-nice-with-radeon/","tags":["ubuntu"],"title":"VLC Player not playing nice with Radeon?"},{"categories":null,"contents":"Higher order functions are those functions that can return functions as their results. The returned function can then be invoked in the same way as you would invoke a normal function. In programming languages like Python, where functional programming is treated as a first class citizen, you can easily define higher order function like this.\ndef adder(a): def add(b): return a + b return add add_with_5 = adder(5) final_value = add_with_5(1) Java on the other hand introduced functional programming in version 1.8. The support is still very primitive and it does not allow one to create higher order functions that return functions.\nToday I had a situation where I desperately needed something similar to a higher order function in Java. I needed the function I was passing to hold something in memory that will be given while the function was created and would be used when executed. After giving it some thought, I came up with a solution. I told myself, you may not create an inner function in Java but there's something you can. Inner classes! Ans so this is what I did.\nclass Adder { int a; Adder( int a ) { this.a = a; } addWith( int b ) { return a + b; } } Function\u0026lt;Interger, Interger\u0026gt; addWith5 = new Adder( 5 )::addWith int finalValue = addWith5.apply( 1 ) This is the cleanest piece of code I could come up with to achieve the same functionality. It has a lot of similarities with AbstractFactory in Java except that it finally creates functions not class objects and also it's less verbose. I am going to call it FunctionFactory!\n","permalink":"https://www.subhadig.net/posts/higher-order-functions-in-java/","tags":["java"],"title":"Higher Order Functions in Java?"},{"categories":null,"contents":"I had a weird problem today when my perfectly indented code comments from Vi editor were looking like a mess in Geany.\nThe pound signs were all out of line though they look perfectly aligned when opened in Vi editor. Initially I thought that it was a problem with the tab settings in Geany. But after tweaking some of the tab settings did not produce any result, I noticed that spaces in Geany were having lesser width compared to other characters, which was the root of the problems. I found that the font that I was using in Geany was not fixed width. And for that I should use Mono variation of the fonts. So I changed the font setting in Edit \u0026gt; Preference \u0026gt; Interface \u0026gt; Fonts \u0026gt; Editor to below:\nAnd after that, everything was perfectly aligned.\n","permalink":"https://www.subhadig.net/posts/inconsistent-space-width-across-editors/","tags":["geany"],"title":"Inconsistent space width across editors"},{"categories":null,"contents":"A few days back at work I was trying to open a fairly large unformatted (a single line) JSON file generated through one of the junit tests. At first I tried to open it in Eclipse since my Eclipse JEE IDE contains an inbuilt JSON formatter but it ended in a disaster! So much so that I had to kill the Java process running Eclipse. Then I tried to open it using Mousepad, the default text editor that comes pre-installed with Xubuntu. It also failed and got hung. I even tried with Gedit but still no luck. I copied the file to a Windows machine and opened it using Notepad++. The online JSON formatters were able to prettify it, so I went on with it then. But the fact that I was not able to open it natively on my system was bugging me.\nThen later in that day, I was sitting idle and I was thinking about it when suddenly the thought came to my mind that how the other text editors on Linux would handle a file with that size. I had Geany installed, so first tried with that and to my surprise, it opened the file in less than a second! It also detected the source type from the extension and coloured the JSON key values. A quick Googling also gave me the way to format it too. I added the below command to Geany \u0026gt; Edit \u0026gt; Format \u0026gt; Send Selection to \u0026gt; Set Custom Command\npython -m json.tool And formatted with it. I was so impressed with it that I made Geany my default text editor and small purpose IDE. Thought about sharing!\n","permalink":"https://www.subhadig.net/posts/opening-large-json-files-with-geany/","tags":["geany"],"title":"Opening large JSON files with Geany"},{"categories":null,"contents":"This week and last week I spent a lot of time writing code to implement the persistence feature for our module with EJB 3 at work. This is the first time I was working with EJB so there was quite a bit of learnings involved. During this time, I noticed that even some of the most seasoned developers don't have a very clear idea about how the whole Persistence thing in JPA works under the hood. They would take some of the things for granted like if they use an EntityManager in their managed objects, something will auto-magically manage everything for them and in the process, did some rookie mistakes.\nFirstly, you should get one thing clear, EntityManager is not thread-safe. No matter what others say and no matter which application server you are using, you should never design your code based on the assumption of thread safety of the underline implementation of EntityManager. So if you are writing a Singleton EJB, you can not write the below code:\n@Singleton public class PersistenceService { @PersistenceContext(name=\u0026#34;somePU\u0026#34;) EntityManager em; In other words, you can not use Container managed persistence context. Then what is the way around? Application managed persistence context is to the rescue!\nNow the second thing to remember, EntityManagerFactory is guaranteed to be thread-safe, always. And injecting it in to your Singleton EJB is as simple as injecting the EntityManager itself. Literally.\n@Singleton public class PersistenceService { @PersistenceUnit(name=\u0026#34;somePU\u0026#34;) EntityManagerFactory emf; And creating EntityManager as below:\npublic void persistenceMethod(Entity myEntity) { EntityManager em = emf.createEntityManager(); ... //Persistence operations em.close(); } Calling the close() method before leaving the method is important. That's it. You can use the above code snippet in any multi-threading environment and rest assured, you will not run into any thread-safety related weird issues related to EntityManager. And the best part is that, you still get to use the Container managed transaction, so you don't need to manually open and commit/rollback transactions (Bean managed transaction).\n","permalink":"https://www.subhadig.net/posts/correct-way-of-using-entitymanager-in-singleton-ejb/","tags":["java"],"title":"Correct Way of Using EntityManager in Singleton EJB"},{"categories":null,"contents":"try-with-resource is the new feature introduced in Java 1.7 to automatically close a resource after using. It basically helps you to avoid a finally block at the end of the try-catch block to close any resource that needs closing like the BufferedReader. But there's a catch. You can not use any type of resource with a try-with-resource block, only those classes that extend java.lang.AutoCloseable can be used, an interface that has a single method:\npublic void close() Today I was writing a Persistence class that uses javax.persistence.EntityManager. Every time I created an instance of EntityManager, I had to manually close it in a finally block. The EntityManager interface also has a close() method with similar signature as above. Only had there been an alternate EntityManager that extended the AutoCloseable interface, I could have avoided the finally block to close it explicitly. Just a thought!\n","permalink":"https://www.subhadig.net/posts/entitymanager-with-try-with-resource/","tags":["java"],"title":"EntityManager with try-with-resource"},{"categories":null,"contents":"Before the final release, I like to test my Python scripts the way these are supposed to be invoked in actual environment, usually with command line arguments. And this is apart from the unit testing and integration testing that I have for the individual modules. I also use Python venv for development because I don't like to directly install all the required libs in my operating system, thus keeping the system PATH clean from the development libs. Invoking a Python script within the test cases is easy, you just need to use the os.system() function. But running a Python script from os.system() using the 'python script-name.py' syntax invokes the python executable from the OS even if I am running the outer Python test case from withing a venv.\nAfter looking for a solution for days, I finally found one. It may not be very elegant but it does it's job and it's simple. The code looks as below:\nimport os, sys executable = sys.executable result = os.system(\u0026#39;{} path-to-your-python-script.py\u0026#39;.format(executable)) assert result == 0 It first gets the Python executable used to run the original script and then use that to invoke the script to test.\n","permalink":"https://www.subhadig.net/posts/invoking-python-scripts-from-test-cases-running-within-a-venv/","tags":["python"],"title":"Invoking Python scripts from test cases running within a venv"},{"categories":null,"contents":"This is my second post on LXD containers. Sometimes, using a container is a cleaner way to install and use applications for a number of reasons:\nYou can install packages from any version of any distribution. That means, even if you are using an LTS release of Ubuntu like me, you don't necessarily have to stick to an older version of a package. Or if some package is only supported on rpm based distributions, you don't need to worry about it. You can go ahead and completely uninstall/reinstall it at any time without worrying about residual files or configurations. You can roll back to a previous state in no time if something goes wrong unexpectedly (lxd snapshots!) And then there is the security perspective also (lxd containers are secure by nature). Last weekend I tried running mysql database from a local container and connect to it from my local system. Here's how:\nCreate a brand new lxd container: lxc launch ubuntu:xenial mysql-test Create a bash session inside the container: lxc exec mysql-test bash Install mysql database server within the container: sudo apt install mysql-server Access the mysql database from inside the container as the root user: mysql -u root -p Allow remote access to root from any host: GRANT ALL PRIVILEGES ON *.* TO \u0026#39;root\u0026#39;@\u0026#39;%\u0026#39; IDENTIFIED BY \u0026#39;password\u0026#39; where password is the password to be used while accessing mysql from outside of the container. Enable built-in firewall configurer and allow mysql access from outside: sudo ufw enable \u0026amp;\u0026amp; sudo ufw allow mysql Exit the mysql client. Open the file '/etc/mysql/mysql.conf.d/mysqld.cnf' in your favourite text editor and comment the following line out by typing # at the starting of the line: #bind-address = 127.0.0.1 Restart the mysql service: sudo service mysql restart Now exit the container. We need to check the IP of the container to access the database from the host. 'lxc list' should do the trick:\nNow from your host machine, try accessing the mysql server with the root password that you set in step #5: mysql -h 10.182.248.44 -u root -p You should be all set now. But the IP address of the container box will change every time you start your container. There's a way to stop it from changing. In my next post, I will share how to bind a static IP address to an lxd container.\n","permalink":"https://www.subhadig.net/posts/accessing-mysql-database-installed-in-an-lxd-container/","tags":["lxc/lxd","ubuntu"],"title":"Accessing Mysql database installed in an LXD container"},{"categories":null,"contents":"Lately I have been playing around with LXD containers and I must say that I am quite impressed with it. LXD is the virtualization technology that can be used to run a Linux container on a Linux host using the same kernel as the host.\nWell, it's a little difficult to grab the idea at first. Unless of course you interacted with it before. You can think of it as a virtual machine that you run using VirtualBox or VMWare on your Linux or Windows host machine but the difference is that when you run a virtual machine, you are running a separate kernel inside the virtual machine but in this case, you are fooling the guest OS running inside the LXD container into thinking that it's running its own kernel whereas it's just using the same kernel running on the host OS. And the result is that you get an isolated container with a much smaller memory footprint and little overhead compared to a full blown virtual machine.\nLXD is built on top the low level Linux container LXC and it provides a set of cleaner commands and a number of extra features. To install LXD on Ubuntu 16.04 (or flavours), use the command:\nsudo apt-get install lxd It installs lxd and its client. Before you can start using it, you need to set the default preferences for LXD. The below command takes care of it:\nsudo lxd init It will set some of the default options including setting up a bridge network that can be used by the containers. LXD is image based. That means, you need to get an image first to create a container. An image can be used from any sources, remote or local. To view all the available sources, use:\nlxc remote list To get all the available images from the 'images' source:\nlxc image list images: You can choose any of the images from the list. To launch a container with the Ubuntu 17.04 64 bit image, use:\nlxc launch images:ubuntu/zesty my-container Where 'my-container' is the name of the container. To see a list of the existing containers and their running status, use:\nlxc list To create and access a bash session inside the container:\nlxc exec my-container bash To stop the container:\nlxc stop my-container At this point, you should be able to launch and manage a basic container. In my next post, I will share some more uses of LXD and about changing some of the basic preferences.\n","permalink":"https://www.subhadig.net/posts/lxd-containers-first-experience/","tags":["lxc/lxd","ubuntu"],"title":"LXD Containers - First Experience"},{"categories":null,"contents":"In my last post, I discussed about how I created my first Amazon EC2 instance and ran our Java web server on it. One of the most important things that I have realized over the years is that if you work with a small group of developers, you ought to think about automating certain jobs like testing, deployment, setting up server etc. So that you can concentrate on the real work rather than spending valuable time in doing repetitive tasks. The benefit against spending extra time in writing scripts may not be prominent at first, but over time you will realize the gain in terms of person hours and headaches saved because of the automated scripts.\nSoon after creating the remote instance on cloud, I created a simple script to push and deploy the changes to AWS. Nothing fancy, you will still need to trigger it manually, but helpful nonetheless. My plan is to later create a script hooked to our online code repository to detect any changes being pushed and trigger the deployment automatically. But in the next weekend after that, I created a script to quickly configure the server after being created, installing and configuring the most basic packages including Java, Mysql-server, firewall etc.\nThe script basically does the below jobs:\nIt installs the following packages - default-jre and mysql-server. Along with that, it also installs a couple of packages which are needed to automate the installation of other packages or the execution of other scripts. It executes the 'mysql_secure_installation' script to make the mysql server permissions more restricted and to disable some of the default configurations. It uses an expect script to automatically provide the input while the script is executed and it does not require any user interaction. It enables the ufw (uncomplicated firewall) and allows the given http port. The port number is mentioned as a configuration in the script itself. The script should be run with administrative privilege and the root password for the mysql-server should be passed as the only command line argument to the script. Sample usage command is as followed -\nsudo ./automate.sh \u0026lt;mysql_root_password\u0026gt; The script is tested on Ubuntu Server 16.04. To execute the script on other versions of Ubuntu, the mysql-server version number needs to be updated in the script. The source code is hosted on my Github account and it can be accessed via this link.\n","permalink":"https://www.subhadig.net/posts/automated-package-installation-and-configuration-script-for-ubuntu/","tags":["ubuntu","java","mysql"],"title":"Automated Package Installation and Configuration Script for Ubuntu"},{"categories":null,"contents":"Today I will be writing about setting up an Ubuntu instance on the Amazon AWS cloud and running a Java web application on it. We are working on a hobby project that has its back-end written in Java. The app back-end was first hosted on Heroku but due to some issues, we decided to move it to Amazon AWS. I was given the responsibility to set up our server. This was the first time I had an opportunity to work with Amazon AWS. But it turned out to be quite fun.\nI did not have an account in Amazon AWS so I had to create one. The process was not complex but a tad lengthy. Although my intention was to use the free tier (an alltotal 750 hours of uptime for any number of t2.micro instances) for now, at least till the project was ready to be rolled out, I still needed to provide the Credit card information. At the end of the registration process, there were links to a a few tutorials including How to Launch a Linux Virtual Machine which was quite helpful.\nThe default tutorial takes through the process of creating an instance of Amazon Linux which is a spin of RedHat Enterprise Linux. But the steps are identical for any available Linux image (I chose Ubuntu 16.04 since I was more familiar with Ubuntu). The free tier was only available for t2.micro instances which with 1 Gig of primary memory and 1vCPU was sufficient for the kind of usage we were looking for. But before I could proceed, I had to create a .pem key which will be needed to access the VMs later on. Be sure to keep the key safely because after it is created, as it can be downloaded only once.\nNext is accessing the newly created instance from my local system using ssh.\nssh -i [path to your .pem key] [username]@[remote machine ip] The user name for all Ubuntu images are \"ubuntu\" by default. The remote machine ip changes every time you stop and start the instance.\nAfter I was done with creating the instance, I installed the pending updates and also some required packages for our server eg. default-jre, mysql-server. Also I ran the mysql_secure_installation to tweak some of the default configurations to enhance the security of mysql.\nAlthough AWS comes with it's own firewall I enabled Ubuntu's own firewall ufw which comes disabled by default. And a word of caution, now if you restart the server without allowing the 22 port, your server is lost! Because the default configuration of ufw is to block all the ports and you specifically need to tell it to allow any port you need to access from outside. Something that cost me the server first time!\nThe last step was to allow the http port of our application in the firewalls ( in ufw and in the Amazon AWS Security Group). Enabling the port in ufw was fairly straight-forward. To enable the port in Amazon AWS security group, log in to AWS, go to Security Group, select the appropriate security group, go to the Inbound tab and add the custom TCP rule with the http port.\nThat's it. The server is now ready to deploy the application. Since our application was packaged as a jar file with embedded server, I did not need to install the server separately. I copied the jar file using the below command and ran it as a Java application.\nscp -i [path to your .pem key] [path to your local jar file] [username]@[remote machine ip]:/tmp Or you can also use Filezilla or similar applications to access your remote EC2 instance but for that, there will be some additional steps to make it work with the AWS specific .pem key.\nI am working on an automated script to at least do the package installations and configurations automatically and I will share it in another post hopefully when it's done.\n","permalink":"https://www.subhadig.net/posts/running-java-app-server-on-aws-ec2-ubuntu-instance/","tags":["ubuntu","aws","java"],"title":"Running Java app server on AWS EC2 Ubuntu instance"},{"categories":null,"contents":"I have been working on a home project these days for which I needed to use a Javascript framework on the UI. But to select a JS framework is a difficult task because there are a overwhelmingly lot to choose from. And each of those has its own strengths and flaws. Still after considering a few of them, I finally chose React. The reasons why I selected React are a) it's more Javascript-centric than some of its close competitors which means, you write your app in JS with pieces of HTML embedded inside JS and b) it uses the Node.js and the npm ecosystem, so it's easier to grasp for somebody with prior Node experience. So I decided to learn React.js.\nA few things that I noticed were that it's a little hard for a beginner to choose the right material to start learning React because React is more of an ecosystem than a framework where you can choose from different third party components to build the whole framework, so you will have to exactly know what you want. And also in React, they have this component way of thinking which is nothing but breaking the whole app into smaller components and design the application in a top-down approach. One more problem I faced was that a lot of the tutorials were old and the codes were not compatible with newer version of the libraries. In addition to all these, I needed to choose between ES5 and ES6 to write my React app in.\nI finally managed to put all the bits together and write a simple and minimal Hello World app in React with Webpack 1.13, Babel 6+ and React 15+. And I used ES5 all the ways since it has better support than ES6 and I am more familiar with it. The code is hosted on my Github account in case you'd like to check it out. Also, if you're looking for a good basic material on React, The React.js Way: Getting Started Tutorial might be useful.\n","permalink":"https://www.subhadig.net/posts/my-experience-with-react-the-hello-world/","tags":["javascript","react","node"],"title":"My Experience with React: The Hello World"},{"categories":null,"contents":"I bought a Dell Inspiron laptop recently which came with Ubuntu 14.04 preinstalled. Something I noticed with the factory Ubuntu 14.04 image was that some of the settings were tweaked to work better with the laptop. One fine example was that the laptop display would automatically dim when I switched to laptop battery from the power supply. It would again go back to full brightness once I connected the adapter back.\nI needed to upgrade the system to 16.04 which is the latest LTS version. I instead chose to do clean install with a standard Ubuntu 16.04.1 image. The installation was very smooth and almost everything worked out of the box. Everything except the automatic dim feature. Which was something I really liked because it did save some battery power. Anyway I looked up on the internet and I found something very useful. I did some manual hack and brought back the exact feature. Here's what I did:\nInstall laptop-mode-tools: Laptop-mode-tools is a package available in the standard Ubuntu repository which enables a Linux kernel feature that saves considerable battery power of a laptop. It can be installed from Terminal with the below command or from Synaptic or any other package manager. sudo apt-get install laptop-mode-tools Laptop-mode-tools also has a very premitive gui where a module can be checked/unchecked to enable/disable power management for a specific section of your system. Enable and set the brightness settings in laptop-mode-tools: The brightness management module is disabled in laptop-mode-tools by default. I needed to enable it and set some of the values related to settings. The brightness settings is stored in /etc/laptop-mode/conf.d/lcd-brightness.conf file. The settings in this file vary depending upon laptop hardware and the most confusing task is to find the BRIGHTNESS_OUTPUT file. The developers do mention a few tricks to find the file for your system in the config file itself. If your system has the file \"/proc/acpi/video/VID/LCD/brightness\" (VID may be VID1 or similar), use this file as BRIGHTNESS_OUTPUT. If you have a file /sys/class/backlight/.../brightness, then you can use that file as BRIGHTNESS_OUTPUT. If the file is found using any of the above two ways (in my case, it was \"/sys/class/backlight/intel_backlight/brightness\"), then the process is pretty straightforward from there. The value inside the BRIGHTNESS_OUPUT file is the max value for brightness. Anything between 0 and the max value can be chosen as the min value. I had to update the below values in the /etc/laptop-mode/conf.d/lcd-brightness.conf file (opened with root priviledge):\nCONTROL_BRIGHTNESS=1 BATT_BRIGHTNESS_COMMAND=\"echo \u0026lt;min-value\u0026gt;\" LM_AC_BRIGHTNESS_COMMAND=\"echo \u0026lt;max-value\u0026gt;\" NOLM_AC_BRIGHTNESS_COMMAND=\"echo \u0026lt;max-value\u0026gt;\" BRIGHTNESS_OUTPUT=\"/sys/class/backlight/intel_backlight/brightness\" \u0026lt;min-value\u0026gt; and \u0026lt;max-value\u0026gt; need to be updated with the chosen min and max brightness value where as /sys/class/backlight/intel_backlight/brightness needs to be changed with the actual BRIGHTNESS_VALUE found.\nIn case of Toshiba laptops, the author of the tool says to use the command \"toshset\" with the -lcd or -inten command. Read the toshset(1) manual page for more information on the parameters for this command. If you use this command, set BRIGHTNESS_OUTPUT to \"/dev/null\". When everything is done, I unplugged the AC power to check if it was working and to my surprise, it really worked! I hope this helps. If you use any other method, I would be glad to learn about it.\nSource: Ask Ubuntu, Arch Wiki\n","permalink":"https://www.subhadig.net/posts/dim-display-when-switching-to-battery-power-on-ubuntu/","tags":["ubuntu"],"title":"Automatically dim display when switching to battery power on Ubuntu"},{"categories":null,"contents":"Being primarily a Java developer using Eclipse IDE, there are two things I always look for in any IDE - content assist/code completion and syntax checking/highlighting. While the latest version of Eclipse (Neon) has made a lot of improvements over the previous versions in terms of the JSDT plugin for Javascript developers, it's far from perfect. The syntax highlighting works upto some extent but the content assist is still very primitive if at all useful.\nMeet Atom - 'A hackable text editor for the 21st Century '. Actually it's much more than just an editor and with the right combination of additional packages installed, you can very well use it like an IDE. Here's how I got the perfect Javascript editor out of it:\nTo install Atom, head to atom.io, download and install the appropriate binary for your platform. Ubuntu users can install from the 'webupd8team/atom' ppa to get regular updates. The autocomplete-plus package which is responsible for code completion comes preinstalled in Atom but it alone cannot do code completion. I needed to install a code completion provider plugin for Javascript. I chose atom-ternjs package. To install a package, go to Edit \u0026gt; Preferences \u0026gt; Install tab, search for a package and click on Install. Mere installing of the provider plugin is not enough though. I need to configure it for every project for which I want the autocomplete feature. To configure, first I added a project folder in Atom via File \u0026gt; Add Project Folder... After which, I clciked on Packages \u0026gt; Atom Ternjs \u0026gt; Configure project. Then I had a tab opened with full of configuations where I had to choose the below options: ecmaVersion: The default is ecmaVersion6 and I let it be. libs: If you need autocomplete suggestion from browser or jquery lib, check the appropriate checkboxes. plugins: This is where I chose which Javascript framework I am using. There are a number of checkboxes and if you are not sure, my suggestion would be to check all the available ckeckboxes. I usually need nodejs related plugins only so I unchecked the angular and requirejs plugin. Click on Save \u0026amp; Restart Server at the bottom of the tab. The step number 3 and 4 are needed to be executed for every new project.\nThat should do it. Now I have a perfect Javascript editor. Try writing some real code and see the magic!\n","permalink":"https://www.subhadig.net/posts/the-perfect-javascript-editor/","tags":["javascript","node","ubuntu"],"title":"The Perfect Javascript Editor"},{"categories":null,"contents":"I have mostly used Ubuntu and Debian-based distributions till now which means the other side of the Linux world, where the RHEL based distributions reside is still a grey area to me. Recently I needed to install CentOS server in VirtualBox to test something out. But soon I found that it's a little cumbersome to work in the VirtualBox vm window because I can't copy/paste texts normally to/from the VirtualBox as I can do in Terminal and I can't cycle through the open windows in my guest machine using Alt+Tab when I am using the vm. So I decided to ssh to the CentOS guest from the host machine and work from the host Terminal instead.\nAfter I did a little searching on the Internet, it turned out to be rather easier than I thought. I had the CentOS 7 minimal image installed and running in VirtualBox already. Here's what I did to get the ssh working:\nAdded a VirtualBox Host-only network. The option can be found at VirtualBox -\u0026gt; File -\u0026gt; Preferences -\u0026gt; Network tab -\u0026gt; Host-only network tab. After that, I restarted the vm. Since it was a minimal install of CentOS, I had to install net-tools package to use the ifconfig command. The below command took care of the installation. sudo yum install net-tools I ran the ifconfig command and got the below output:\nThe network interface in the middle with name enp0s8 is the one that I set up in step 1. Next I created a file named \"ifcfg-enp0s8\" in \"/etc/sysconfig/network-scripts/\" location. The second part of file name after the hyphen (-) had to match with the network interface name in step 3. And then typed the below content in the file:\nThe \"NAME\" should match with the network interface name. And the \"IPADDR\" could be any valid IPv4 address value and it will be used to ssh to the guest vm from host machine. After saving the file I just had to reboot the vm. I could have only restarted the networking service though instead of rebooting. Anyway, the next step is quite simple. Ssh into the CentOS vm from the host. And it's done! ","permalink":"https://www.subhadig.net/posts/ssh-into-centos-7-guest-from-host-machine-using-virtualbox/","tags":["centos","ubuntu"],"title":"SSH into CentOS 7 guest from host machine using VirtualBox"},{"categories":null,"contents":"I have used Oracle Virtualbox before. It has an easy and intuitive UI, supports all the features I needed and is open-source. But this time I decided to use another widely recognized virtualization solution on Linux, qemu, along with kvm.\nFirst of all, let me give some brief idea about qemu, virt-manager and kvm. Qemu is the software which can be used to install and run a guest OS on top of the actual OS to put it in a very simple way although it's much more powerful than that. It can be compared to Virtualbox except that qemu itself does not have a UI, instead it's a command line utility. Virt-manager is some thing that provides a GUI to qemu. Together virt-manager and qemu can be thought of as the Virtualbox. On the other hand, kvm is the Linux kernel module that can help qemu execute the virtualized instructions directly on the CPU which can improve the performance greatly. This is to be kept in mind that qemu can run even without kvm but the speed will be much slower.\nThe system that I have comprises of an AMD Fx6300 processor with 6 cores and AMD-V capability and 4 gigs of RAM. AMD-V is similar to Intel vt-x and it enhances the virtualization capability of a processor. I am running Xubuntu 14.04 as my main OS with Linux kernel 3.19.0-56 64 bit at the time of writing.\nFirst of all, I needed to enable the AMD-V from the BIOS menu to take full advantage of the processor. For my system, the option could be found in BIOS Settings \u0026gt; Advanced BIOS Features \u0026gt; Virtualization. I just had to enable the flag. After that, I restarted the system and logged into my computer. I installed the following packages:\nsudo apt-get install qemu virt-manager virt-viewer libvirt-bin I didn't install the qemu-kvm package as this package is not needed for a x86_64 hardware.\nTo install on Debian 10, following commands should be used.\n#Install the required packages. sudo apt install qemu-kvm libvirt-clients libvirt-daemon-system virt-manager #Required to create and manage vms without root. \u0026lt;user-name\u0026gt; should be replaced with actual user name. sudo adduser \u0026lt;user-name\u0026gt; libvirt After I restarted the system, I launched the Virtual Machine Manager and it looked like this.\nNext few screenshots quickly show the steps of creating and launching a new VM where I had to provide a name for the VM, select the installation CD image and specify the amount of RAM, number of cores and the size of the hard disk image for the virtual machine.\nI selected the Virt type as kvm to take advantage of the virtualization capabilities of the Linux kernel. After clicking on the Finish button, the VM is launched with the selected ISO image in the second step. Well that's about it. Pretty easy, I would say!\nThe advantage of using qemu + kvm over Virtualbox is that it does not require me to install any additional module in the kernel. I haven't taken any benchmark of the performance though. If you have any suggestion/correction please let me know in the comments.\n","permalink":"https://www.subhadig.net/posts/installing-qemu-with-kvm-and-virt-manager/","tags":["ubuntu","kvm","qemu"],"title":"Installing qemu with kvm and virt-manager"},{"categories":null,"contents":"Have you ever faced a situation where you are using an IDE like Eclipse that uses a lot of Control + some other key combination shortcuts to do various tasks and you are pretty much used to those shortcuts but those shortcuts do not work under Xfce? Well I like Xubuntu because of the lightweight Xfce desktop environment but being primarily a Java developer, I also use Eclipse IDE a lot and not being able to use the keyboard shortcuts that I am very much used to was a pain. Not anymore. After spending some time looking up on the internet, I found the solution. Here it goes.\nXfce reserves some key combinations for it's Global Keyboard Shortcuts which can not be overridden in any other application. These keyboard shortcuts also include the Control + Function keys that make use of all the F keys from F1 to F12 which are used for switching to different desktop workspaces.\nSince I don't use a lot of workspaces on my desktop, I cleared those combinations from Global Keyboard Shortcut menus. I went to Settings \u0026gt; Window Manager \u0026gt; Keyboard tab, selected the shortcut keys one by one that I wanted to free for using in other applications and clicked on the Clear button. And that's it.\nThanks to this post from Stackoverflow.\n","permalink":"https://www.subhadig.net/posts/keyboard-shortcuts-with-control-key-not-working-under-xubuntuxfce/","tags":["xubuntu","xfce"],"title":"[Solved] Keyboard Shortcuts with Control key not working under Xubuntu/Xfce"},{"categories":null,"contents":"Go (sometimes referred as Golang) is the system programming language from Google which is my new interest these days. Some of my favourite points about Go so far:\nIt's a compiled language and I like compiled languages. To somebody who has used C/C++ and later Java for programming, this should come as no surprise. It has fairly easy syntax and it's not a lot different from C which definitely helps to learn the language quickly. It can be used like a scripting language. It has a fairly large built-in package collection. It has first class Linux support. Here's what I did to get my workstation ready to code with Go:\nInstalling Go: Since I am using Ubuntu 14.04 LTS and the Golang version in the official repository is very old, I downloaded the tar.gz for my platform from official Golang website and installed manually (the downside is that it will not be automatically updated when a new version comes out). The installation steps are given on the website itself. The steps are easy enough for a newbie in Go like me to follow (I installed Go in a custom location, so I had to do some extra steps). A word of advice, if you are using Ubuntu and if you are to set an environment variable (like GOROOT, PATH), use .pam_environment instead of writing in the .bash_rc or .profile file (read the official documentation). Getting the editor ready: I am using Atom editor with the go-plus plugin. To install the go-plus plugin, go to Atom -\u0026gt; Preferences -\u0026gt; Install, search for go-plus package and install. It provides syntax and compilation error highlighting, auto-completion and some other features. One important point though, do not forget to set the GOPATH environment variable or else the go-plus plugin will not function properly. If Atom does not suit your taste, you can use one from a bunch of other editors listed here. Coding with Go: One of the good things about Go is the quality of the official documentation. Instructions from here should give you enough idea about compiling and running the Go code. Although, things are looking great now, something that I am missing a lot is a good debugger for Go. You can debug Go with GDB but it's not fully supported. There are some other debuggers available though, but I haven't had the time to evaluate them yet.\n","permalink":"https://www.subhadig.net/posts/coding-with-go-part-1-the-workspace-setup/","tags":["golang","ubuntu"],"title":"Coding with Go - Part 1 : The Workspace Setup"},{"categories":null,"contents":"Though Vim is my favourite command-line text editor, not all the default configurations suit my taste. Luckily, changing the default configurations of Vim editor on my Xubuntu 14.04 LTS (any Linux based OS for that matter) is fairly easy and so is persisting the changes. Here's what you need to do in order to persist the changed configurations for Vim editor (so that the changes do not disappear after you restart your Vim editor): Create a file with name .vimrc and save it in your home directory. So whatever configurations you write in that .vimrc file of yours, will be picked when you start your Vim editor (after modifying .vimrc, you may need to restart the Vim editor in order for the changes to take effect).\nHere's how my .vimrc looks like:\n\" Indent automatically depending on filetype filetype indent on set autoindent \" Turn on line numbering. Turn it off with \"set nonu\" set number \" Change colorscheme from default to elflord colorscheme elflord About the last point, I don't like the look of shell scripts under the default colorscheme of Vim editor. So I changed it. Here's how shell scripts look like under elflord.\nI hope that helps.\n","permalink":"https://www.subhadig.net/posts/my-custom-vim-configuration/","tags":["vim"],"title":"My Custom Vim Configuration"},{"categories":null,"contents":"Recently I have been playing with Node.js and for every developer, getting the perfect IDE/Editor and setting up the workspace is very important. Here's how I got my set up ready:\nI am using Xubuntu 14.04.3 LTS. So the steps that I am going to share will work in any of the Ubuntu flavours.\n1. Installing Node.js: Node.js is already there in the default Ubuntu 14.04 repository and the version is 0.10.25. If you need more updated version, you have 2 ways. You can either download it from the official Node.js site, or you can follow this tutorial and add a third-party repository or use nvm to get it installed. In the first case, it will not be auto-updated though. However, I chose to use the default repository version as I didn't see the point in going through all these hassle unless I specifically want a feature that is only available in the newer versions.\nTo install the default nodejs in Ubuntu 14.04, type the below command (or use your favourite package manager to install the package):\nsudo apt-get install nodejs 2. Installing Atom editor: While this is something that is not exactly required for Node.js and Node.js can be developed with any editor, I preferred Atom for it's set of features and open source nature. To install Atom on my system, I used the WebUpd8 PPA so that I get regular updates and I don't need to build from source to install the latest one. To use the WebUpd8 PPA, use the below commands:\nsudo add-apt-repository ppa:webupd8team/atom sudo apt-get update sudo apt-get install atom For further information, visit the WebUpd8 site. You can also download the latest version of the software from Atom official site.\n3. Configuring Atom to run Node within Atom: While you can write your code in Atom and run it from the terminal separately, I prefer to run it within the IDE itself, it saves a lot of Alt + Tab. It's not supported by default, you need to add a package to get this functionality.\nOpen Atom and go to Edit -\u0026gt; Preferences -\u0026gt; Install. Search for the package atom-runner and hit Install. Atom-runner will now be installed. Although you need to change the default configuration to run Node using atom-runner. The reason is that in Ubuntu, the name of the Node.js package (hence the command) is not node (it is the default everywhere else) due to the conflict with some other package, rather it's nodejs.\nTo update the configuration, open ~/.atom/config.cson with your favourite text editor where ~ stands for your home directory. Paste the below lines:\nrunner: scopes: js:\u0026#34;nodejs\u0026#34; Do take care of the indentation. The first line of the above text should be indented a little right and the next two lines should each be indented further right.\nIf you do the above steps correctly, you have your Atom editor ready to write some Node. Create a new file and name it to somename.js. Paste console.log('It's working.') in the editor and save it. Press Alt + R and it should print the output in a new tab.\nThat's it for now. I will be adding more contents to it as I go with Node. Let me know in the comments if you have better suggestions about Node.js development. I will be sure to take a look.\nIf you are looking into ways of tuning your Atom editor to be better suited for coding Javascript with the features like content-assist, go through this post about The Perfect Javascript Editor.\n","permalink":"https://www.subhadig.net/posts/developing-node-js-with-atom-editor/","tags":["javascript","node","ubuntu"],"title":"Developing Node.js with Atom Editor"},{"categories":null,"contents":"Although I use both Firefox and Chrome on my Linux box, for playing any flash video (yes, I know flash is going to go away and I hate it too but for the time being, it's still here), sometimes Chrome is the only option as the Flash player plugin for Linux is very old and many websites do not support it already (Chrome separately packages it's own flash player which is not dependent directly upon your platform (which means it is available for Linux also) and it's version is regularly updated, if you didn't know already).\nBut one issue I have faced with Chrome that while playing a video, the flash player keeps getting stuck (I have fairly low spec computer bought 7 years ago and didn't upgrade it much, so this problem might not be present for most people with newer hardware). I quickly realized that this was because my computer CPU was already running at its maximum speed and could not process the video any faster (so it would keep getting stuck). Here's what I did to fix the problem.\nGo to Google Chrome -\u0026gt; Settings -\u0026gt; 'Show advanced settings' -\u0026gt; System. Then uncheck \"Use hardware acceleration when available\". Now restart Chrome.\n","permalink":"https://www.subhadig.net/posts/solved-flash-player-in-google-chrome-keeps-getting-stuck-under-ubuntulinux/","tags":["ubuntu"],"title":"[Solved] Flash player in Google Chrome keeps getting stuck under Ubuntu/Linux"},{"categories":null,"contents":"I own a Logitech c170 web-cam which has very good Linux support. I bought this web-cam almost 2 years ago and at that time, it worked like a charm on Ubuntu 12.04. I stopped using the web-cam over a year ago and I almost forgot about it. A few days ago, I had an interview on Skype and as my phone front camera does not work well with Skype, I needed to take this one from my Desktop. So I took the web-cam and plugged it in to my computer running Ubuntu 14.04 (yes, I upgraded), launched Cheese (comes pre-installed on Ubuntu 14.04) hoping everything would work just as before. But to my surprise, even though I could take photos using Cheese, I could not see the video stream. Here's what I did to solve the problem:\nI went to Cheese -\u0026gt; Preferences -\u0026gt; Webcam tab and brought down the Photo Resolution and Video Resolution to 640 X 480 and then restarted Cheese and re-plugged in the webcam. And then it started working again!\nI thought I would share it with others so that anybody with the same problem will find it easier to fix!\n","permalink":"https://www.subhadig.net/posts/solved-cheese-webcam-booth-not-displaying-video-from-webcam-in-ubuntu/","tags":["ubuntu"],"title":"[Solved] Cheese Webcam Booth not displaying video from Webcam in Ubuntu"},{"categories":null,"contents":"Subclipse is an Eclipse Team Provider plug-in providing support for Subversion within the Eclipse IDE. Installing Subeclipse plug-in in Eclipse running on Ubuntu (or any other Linux distribution) is a little more complex than on win-32 platform. You need to install an additional package that contains the JavaHL binaries. To install Subeclipse, follow the below simple steps:\n1.Go to Ubuntu Software Center and install the below package.\nlibsvn-java\n2.Note the installed version of the above package.\nIn this case, it is 1.8.x (default for Ubuntu 14.04 LTS). It will be different for other versions and distributions. This is needed to choose the appropriate version of Subeclipse as Subclipse versions are tied to specific versions of the Subversion client API (libsvn-java in this case).\n3.Go to this link. Choose the appropriate version of Subeclipse plugin depending upon your installed libsvn-java package version. As in this case it is 1.8.x, we will choose version 1.10.x.\n4. Copy the Eclipse update site URL for the chosen version.\n5. Open Eclipse. Go to Help -\u0026gt; Install New Software. Click on Add button in the newly opened window.\n6. Paste the Eclipse update site URL as in the below screenshot. Click Ok.\n7. Select Subeclipse from the list and click next. Finish the installation.\n8.Restart Eclipse after the installation finishes. That's it. You have now Subeclipse SVN plugin installed in your Eclipse.\n","permalink":"https://www.subhadig.net/posts/install-subeclipse-subversion-plugin-in-eclipse-ubuntu/","tags":["eclipse","ubuntu"],"title":"Install Subeclipse subversion plugin in Eclipse + Ubuntu"},{"categories":null,"contents":"Users of Alliance or similar broadband services might have noticed that their network connection would sometimes get dropped while on Ubuntu or the network speed is somewhat less than what is advertised. The solution for this is that you need to change the duplex setting of your network connection. Don't freak out yet, it's not as hard as you might think. Follow the below simple steps:\n1. Get the desired duplex settings from your service provider. In this case, we will assume that it's \"10 duplex half\". Replace it with the appropriate speed in your case.\n2. Open Ubuntu Software Center, search for the following package and install. ethtool\n3.Open Gedit or any other Text editor and paste the following:\n#!/bin/sh\nETHTOOL='/sbin/ethtool'\nDEV='eth0'\nSPEED='10 duplex half'\ncase $1 in\nstart)\necho -n \"Setting eth1 speed 10 duplex half...\";\n$ETHTOOL -s $DEV autoneg off speed $SPEED;\necho \" done.\";;\nstop)\n;;\nesac\nexit 0\n4. Check the following:\nOpen Terminal. Paste \"which ethtool\" without the quotes and Enter. If it is not \"/sbin/ethtool\", copy the result and replace it with \"/sbin/ethtool\" in the second line of the Text editor. Go to the network applet (top right corner region of the screen) and click on Connection Information (assuming you are connected to the network for which you are going to change the duplex setting. If you are not, go to Network Connections -\u0026gt; Edit the connection -\u0026gt; Ethernet tab, notice the name inside braces after Device Mac Address). Check for the line \"Interface : Ethernet(eth0)\". If it is not 'eth0' in your case, copy it ('ethX') and paste it in place of 'eth0' in the third line of the Text editor. Replace '10 duplex half' with the appropriate speed for your case in the fourth line of the Text editor. 5. Save the untitled document in your home directory with any name. Lets say, we saved it with the name 10Mbps.sh (in the subsequent steps, if your file name is different, don't forget to replace '10Mbps.sh' with your file name wherever applicable).\n6. Open Terminal and paste the following one by one (if you are not using Ubuntu, then change 'nautilus' with your installed file manager in the below line) :\nsudo nautilus /etc/init.d/\n7. Copy the file (10Mbps.sh) to the newly opened window. Right click on the file, click on Properties, go to the Permission tab, check the Execute check-box and close it.\nWe are almost done now. In the next step, we check if everything we did is correct.\n8. Go the Terminal again and paste the following (one by one) :\nsudo /etc/init.d/10Mbps.sh start\nsudo ethtool eth0\nChange 'eth0' if it's different in your case (step 4). After executing the above commands, look for these lines in the result:\nSpeed: 10Mb/s\nDuplex: Half\nIf it matches with your input, then we are good to go. If you encounter any error at this stage, don't proceed before resolving those.\n9. Phew! We are at the final step of this long tutorial at last! Paste the below command in Terminal:\nsudo update-rc.d 10Mbps.sh defaults\nAgain, don't forget to replace file name '10Mbps.sh' if it's different in your case.\nWe are done now. Restart your computer for the changes to take effect. Although this tutorial assumes that you are using Ubuntu, it should work on any Ubuntu or Debian based distro with little or no modification. Let me know in the comments section if you face any issue.\n","permalink":"https://www.subhadig.net/posts/permanently-change-duplex-settings-and-network-card-speed-in-ubuntu/","tags":["ubuntu"],"title":"Permanently change Duplex settings and Network card speed in Ubuntu"},{"categories":null,"contents":"I have been brushing up my skills in Python from last week. I am a Java developer by profession and my love for Python came purely from a hobby perspective. But nevertheless, love is love. First time I learnt Python when I was still not that into Java and the Python version was 2.x. But this time, I went with the version 3.x.\nI am also learning how to make GUI application with PyGObject since PyGtk is not used in new development anymore. This is some amazing work by the developers that I don't have to work in C++ to make GTK+ applications. My next goal is to make my first application in Python and GTK+, albeit a simple one, which I might publish also.\n","permalink":"https://www.subhadig.net/posts/brushing-up-python/","tags":["python"],"title":"Brushing up Python"},{"categories":null,"contents":"I upgraded my Ubuntu from 12.04. Eclipse 3.7 with Subclipse 1.6 was installed in 12.04. Now after upgrading to 13.04, after I start Eclipse and synchronize my project with the repository, it throws the error message: \"Incompatible JavaHL library loaded. 1.6.x or later required.\"\nPossible reason: libsvn-java is needed to be installed in Ubuntu in order to make SVN work in Eclipse. The installed version in Ubuntu 12.04 was 1.6 as far as I remember. But after upgrading to 13.04, the libsvn-java version was also upgraded to 1.7. But the version of Subclipse that is compatible with libsvn-java 1.7 is Subclipse 1.8.\nSolution: Upgrade your Subeclipse to 1.8.\nSource: http://subclipse.tigris.org/servlets/ProjectProcess?pageID=p4wYuA\nHope this helps somebody. Good Luck.\n","permalink":"https://www.subhadig.net/posts/solved-svnjavahl-version-problem-in-ubuntu-13-04/","tags":["eclipse","java","ubuntu"],"title":"[SOLVED] SVN/JavaHL version problem in Ubuntu 13.04 with Eclipse Indigo"},{"categories":null,"contents":"I have been an Ubuntu user (Linux in General) for long enough time. When I was in college, I would live boot different distributions of Linux just for trying out, eager to see what new desktop effects they might have added, what the defaults applications were. But after I graduated from college and joined work, I would get little time to do all those stuffs. So I settled for just one and also I needed a stable environment. Currently I am using Ubuntu 12.04 and today after getting back from work, I felt like I got bored with Ubuntu. So I thought, what the hell, I should try out KDE and if I like then I might even replace Ubuntu. So I downloaded Kubuntu and ran it on a USB stick. I installed it in one of my spare partition also, to give it a fair chance to impress me. And it really did impress me. I liked the desktop environment, I liked the KDE default application set. They were designed very carefully. The applications launched way faster than they would in Ubuntu. But I don't know why, my eyes were still searching for the same fonts and the same look they were used to see on Ubuntu. Also I missed all those keyboard shortcuts that I enjoy using while on Ubuntu. So I rebooted back to Ubuntu. I fixed the Grub2 which was replaced by Kubuntu Grub2 with the grey screen. But I could not re-enable the auto-hiding of Grub2 while booting. I guess I will find some way to do that. But now I am feeling quite sleepy.\n","permalink":"https://www.subhadig.net/posts/not-switching-to-kubuntu/","tags":["ubuntu"],"title":"Not Switching to Kubuntu"},{"categories":null,"contents":"\u0026ldquo;I have no special talent. I am only passionately curious.\u0026rdquo; - Albert Einstein\n\u0026ndash;\nHi there!\nMy name is Subhadip Ghosh.\nI am\na) A Software Architect at Pegasystems\nb) A father to a 2-year-old girl\nc) A hobbyist blogger\nd) A curious person\nAs one of the leading architects, I make Pega Platform run better (hopefully) on cloud.\nI am passionate about Linux and open-source software.\nI occassionally write blog posts on this website to explain\na) one of my latest technological (often mis-)adventures\nb) a technical topic that I have just learnt\nViews are my personal.\nGitHub: https://github.com/subhadig\nLinkedIn: https://www.linkedin.com/in/subhadig\n","permalink":"https://www.subhadig.net/about/","tags":null,"title":"About"},{"categories":null,"contents":"This file exists solely to respond to /search URL with the related search layout template.\nNo content shown here is rendered, all content is based in the template layouts/page/search.html\nSetting a very low sitemap priority will tell search engines this is not important content.\nThis implementation uses Fusejs, jquery and mark.js\nInitial setup Search depends on additional output content type of JSON in config.toml ``` [outputs] home = [\u0026ldquo;HTML\u0026rdquo;, \u0026ldquo;JSON\u0026rdquo;] ```\nSearching additional fileds To search additional fields defined in front matter, you must add it in 2 places.\nEdit layouts/_default/index.JSON This exposes the values in /index.json i.e. add category ``` \u0026hellip; \u0026ldquo;contents\u0026rdquo;:{{ .Content | plainify | jsonify }} {{ if .Params.tags }}, \u0026ldquo;tags\u0026rdquo;:{{ .Params.tags | jsonify }}{{end}}, \u0026ldquo;categories\u0026rdquo; : {{ .Params.categories | jsonify }}, \u0026hellip; ```\nEdit fuse.js options to Search static/js/search.js ``` keys: [ \u0026ldquo;title\u0026rdquo;, \u0026ldquo;contents\u0026rdquo;, \u0026ldquo;tags\u0026rdquo;, \u0026ldquo;categories\u0026rdquo; ] ```\n","permalink":"https://www.subhadig.net/search/","tags":null,"title":"Search"}]