Sunday, July 17, 2016

How to List Installed Packages in Ubuntu using Dpkg

In Ubuntu, we use apt-get to install and remove packages. To list all the packages installed on the system, one needs to run
$ dpkg --get-selections

To search for a certain package name, say python, among the list, one needs to pipe the result to grep,
$ dpkg -get-selections | grep python

Lastly, to check the details of the installed package, say python3, one needs to run
$ dpkg -s python3

That's it.

Saturday, July 16, 2016

How to Import Existing Git Repository and Upload into Git Server

Say you have a local git repository called my_project in your home folder ~ of your local machine, and you'd like upload this into your personal git server. Here is how you can do this. For more info, please refer to here.

First, make sure that your git repository folder exists in the working directory.
$ pwd
/home/your_username/
$ ls
my_project/
...

Then, create a bare git repository from the existing repository
$ git clone --bare my_project my_project.git

You should now have the cloned bare repository
$ ls
my project/
my project.git/
...

Noe that .git ending is a conventional indication of server repository.

Next, copy the cloned repository to your server, usually through scp
$ scp -r my_project.git git_server_user@your.git.server:/git/

Here, you will need to replace git_server_user, your.git.server, and /git/ with the appropriate server username, server address, and destination path in the server, respectively.

That should be it. Now, to clone from your server, simply run the following from a client system
$ git clone ssh://git_server_user@your.git.server:/git/my_project.git

Of course, you may want to delete the bare repository from the local machine (not the server).
$ rm -rf my_project.git

That should do it!

Sunday, July 10, 2016

Tab Completion with Linked Directory (Bash)

I found it very annoying that bash won't fully tab-complete a linked directory; it omits the very important character / at the end.

For example, if I type in
$ cd ~/Doc
and press [tab], it will auto-complete as below
$ cd ~/Documents/
with / character at the end, since this is a directory.

Unfortunately, however, if I create a linked directory
$ ln -s ~/Documents ~/linked_Documents
and try
$ cd ~/linked_Doc
and again press [tab], it will auto-complete to
$ cd ~/linked_Documents
without / character.

The solution for this is found here, which is reproduced below.

Simply add the following lines into ~/.inputrc and restart your terminal
$include /etc/inputrc
set mark-symlinked-directories on

That should do it!

Monday, July 4, 2016

Use Git to Version Control DOCX Files for Windows / Cygwin

Git is a wonderful tool for version control of various texts and documents, such as source code. Unfortunately however, git by default will not be able to produce diff result for Microsoft's word document format (.docx) files. In this post, I will go over how to use git diff docx files on Cygwin. This post is based on this.

Let's see what happens when we try to use git for docx files. Download Cygwin x86 for 32-bit system or Cygwin x64 for 64-bit system from the Cygwin download page.

Run the installer file to install it on the system. Just go through installation with default settings until Select Packages section. Here, search for and install unzip (Archive), git (Devel), and vim (Editors). Note that I will assume the default Cygwin installation directory to be c:\cygwin. Note that if you download 64-bit version, the default directory will be c:\cygwin64.

Let's run Cygwin. You should see bash terminal. Say you have your docx files saved in c:\Users\unixnme\Documents\docx folder. To change directory into this folder, run
$ cd /cygdrive/c/Users/unixnme/Documents/docx

Let's assume that there is a docx file called test.docx in the folder.
$ ls
test.docx

Let's initiate a git repository and commit test.docx file.
$ git init
Initialized empty Git repository in /cygdrive/c/Users/unixnme/Documents/docx.git
$ git add test.docx
$ git config --global user.name your_name
$ git config --global user.email your_email@address.com
$ git commit -m "initial commit"
[master (root-commit) 90cf9f2] initial commit
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100755 test.docx

Next, make any changes to test.docx file, save, and run git diff command:
$ git diff
diff --git a/test.docx b/test.docx
index 41c6200..ce81ceb 100755
Binary files a/test.docx and b/test.docx differ

As expected, git diff will complain that test.docx is a binary file. Now, let us enable git diff for docx files.


First, we need to install docx2txt utility. Download docx2txt-1.4.tgz file from here to your download folder, say c:\Users\unixnme\Downloads. Extract the files by running tar command
$ cd /cygdrive/c/Users/unixnme/Downloads
$ tar vxzf docx2txt-1.4.tgz

Go into the extracted directory and enable execution flag for windows installer batch file.
$ cd docx2txt-1.4
$ chmod u+x WInstall.bat

We are ready to install it. Enter the installation folder path and Perl path as follows:
$ ./WInstall.bat
Welcome to command line installer for docx2txt.

Where should the docx2txt tool be installed? Specify the location
without surrounding quotes.

Installation Folder :c:\cygwin\bin

Please specify fully qualified paths to utilities when requested.
Perl.exe is required for docx2txt tool as well as for this installation.

Path to Perl.exe : c:\cygwin\bin\perl.exe

Continuing with simple installation ....

Copying script files to "c:\cygwin\bin" ....

Please adjust perl, unzip and cakecmd paths (as needed) in
"c:\cygwin\bin\docx2txt.bat" and "c:\cygwin\bin\docx2txt.config"

Note that I simply installed docx2txt in c:\cygwin\bin, but you may want to change it as desired. The default perl executable is installed in the cygwin/bin directory, which in this case is c:\cygwin\bin\perl.exe. Note that if you have installed the 64-bit version of cygwin, then you will need to replace cygwin with cygwin64 for paths. If it asks for unzip and cakecmd paths, simply leave them blank as they are not necessary.

Next, we need to create /usr/bin/docx2txt file by
$ vim /usr/bin/docx2txt

with the following content.
#!/bin/bash
docx2txt.pl $1 -

Make sure to set the executable flag
$ chmod u+x /usr/bin/docx2txt

Finally, go back to the git repository folder and create .gitattributes file to apply filter for docx files
$ cd /cygdrive/c/Users/unixnme/Documents/docx
$ echo "*.docx diff=word" > .gitattributes

Finally, edit git config file to run /usr/bin/docx2txt script file for word filter
$ git config diff.word.textconv docx2txt

When everything is successful, you should see diff result for the modified docx file like a regular plain text file
$ git diff
diff --git a/test.docx b/test.docx
index 41c6200..ce81ceb 100755
--- a/test.docx
+++ b/test.docx
@@ -1 +1 @@
-This is a test file
+This is a test file, which I have modified after commit.

Enjoy git on your Microsoft Word documents!

Saturday, July 2, 2016

How to Setup Git Server on Mac OS X

In this tutorial, I will go over the instructions to setup a git server on Mac OS X. Here, I will assume that the server IP address is 12.34.56.78.

First, you will need to add a user named git, into which client machines will ssh into. To do so,
1. Open up System Preferences -> Users & Groups
2. You may need to click the Lock image to make any changes. 
3. Click on the + button to add a user.
4. Add a standard user whose full name and account name is git. Enter password.
5. Click on Create User button.

Next, you will need to allow ssh login for user git from client machines. To do so,
1. Open up System Preferences -> Sharing
2. Check Remote Login box.
3. Add the user git in the Allow access for field by clicking on the + button.

From your client system, make sure that you can remote log into the server's git account.
$ ssh git@12.34.56.78 -p 22

Note that here I am assuming that you are using the port 22 to access the server. Depending on your router or firewall configuration, the port number may differ.

If you can successfully log into the account, then you are pretty much done. Let's assume that you will want to create a repository named Project. From the git account from the server or through ssh, run
$ pwd
/Users/git
$ git init --bare Project.git

This will create a bare Project repository on the server, which clients can clone, push to, and pull from. The location of this repository in this case is /Users/git/Project.git, as you can see from pwd command above. To clone this repository from a client, you will need to run the following from the client
$ git clone ssh://git@12.34.56.78:22/Users/git/Project.git

You will need to enter the password for the server's git account, as if you are remote logging into it through ssh. You should now have a personal git server.

Note: If you are concerned with safety, you may want to disable password login and instead only allow public key authentication. I will cover how to do so in the future post.

Sunday, June 26, 2016

Android Development - Access Activity Instances from Other Classes

Each page on Android app is defined by an activity instance or an object. Sometimes, you may want to edit the instance externally, i.e., from other objects or classes. The following code shows how to do access the instance of MainActivity class externally:

...
public class MainActivity extends Activity {
  private static MainActivity instance;
  private static void setInstance (MainActivity instance) {
    MainActivity.instance = instance;
  }
  public static MainActivity getInstance () {
    return instance;
  }
  public void somePublicMethod () {
  ...
  }
  public void onCreate (Bundle savedInstanceState) {
    super.onCreate (savedInstanceState);
    setContentView (R.layout.activity_main);
    setInstance (this);
    ...
  }
  ...
}

As you can see from the code above, static variable instance is to be assigned in the onCreate method. Now, this instance can be accessed externally by calling the public getInstance method, as shown below:

...
public class SomeClass {
  public void someMethod () {
    MainActivity.getInstance().somePublicMethod();
  }
}

This method is called singleton design, as there is only one instance of the Activity class, which we want to access externally.

Thursday, June 23, 2016

Android Development - Schedule a Task at Certain Time

First, you will need to edit the manifest xml file and add the following:

...
<manifest ... >
    <uses-permission android:name="android.permission.WAKE_LOCK"/>
    ...
    <application ... >
       <receiver android:name=".AlarmReceiver" />
    </application>
</manifest>

The permission will enable the Android system to wake up at the specified time. The receiver field declares BroadcastReceiver element to be used. Here, I will be using the name AlarmReceiver.

Next, create AlarmReceiver.java file with something similar to below:

...
public class AlarmReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
        PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "");
        wl.acquire();

        // Put here YOUR code.
        Toast.makeText(context, "Alarm !!!!!!!!!!", Toast.LENGTH_LONG).show(); // For example

        wl.release();
    }

    public void setAlarm(Context context) {
        AlarmManager alarmManager;
        PendingIntent pi;

        alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        Intent intent = new Intent (context, AlarmReceiver.class);
        pi = PendingIntent.getBroadcast(context, 0, intent, 0);

        alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()+5000, pi);
    }
}

Here, setAlarm method is specifying the scheduled time to be 5 secs after the current time. At that time, onReceive method will be invoked, so you will need to place your tasks there.

Finally, edit your activity java file to add the following code to schedule:

Context context = this.getApplicationContext();
AlarmReceiver alarm = new AlarmReceiver();
alarm.setAlarm(context);

That's it!

Android Development - How to Make Buttons Respond

In the series of Android Development posts, I will go over the very basics of Android programming intended for complete beginners. I won't be able to explain every singe details of the code, so one will need to refer here for general details.

Say you have a button that you would like to respond when a user tabs on it. In the layout xml file in the res folder, you will need to have your button element defined similar to below:

    <Button
        android:id="@+id/buttonSend"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/send"
        android:onClick="buttonAction" />

The necessary field for assigning any actions to "clicks" on the button is the last field, android:onClick="buttonAction". What it says is that when the user pushes on the button, the program will execute buttonAction function. Of course, we will need to define such function in the activity java file.

...
public class MainActivity extends Activity {
...
    public void buttonAction(View v) {
        // insert code for action
    }
...
}

That's it!

Saturday, June 11, 2016

C/C++ #define Directive Not-So-Obvious Mistake

Consider the following code below:
#include <stdio.h>
#define ABS(x) (x>=0 ? x : -x)
int abs (int x) {
   return x >= 0 ? x : -x;
}
int main () {
   printf ("ABS(1) = %d\n", ABS(1));
   printf ("ABS(-1) = %d\n", ABS(-1));
   printf ("ABS(2-1) = %d\n", ABS(2-1));
   printf ("ABS(1-2) = %d\n", ABS(1-2));
   printf ("abs(1) = %d\n", abs(1));
   printf ("abs(-1) = %d\n", abs(-1));
   printf ("abs(2-1) = %d\n", abs(2-1));
   printf ("abs(1-2) = %d\n", abs(1-2));
   return 0;
}

The code defines the absolute value evaluation procedure using both the C directive and a regular subroutine. In the main function, we are printing out four example values to verify if both methods work correct. What do you think the expected output would be?

Guess the answer first, and copy the code run it.
$ gcc ABS_test.c
$ ./a.out

Does your guess agree with the output? If so, then you must be an experienced C/C++ programmer! If not, do not worry. I did not get it the first time either. Both the C directive ABS(x) and C subroutine abs(x) are defined by the same expression, but one is erroneous while the other is fine. 

It turns out that the ABS(x) directive definition is incorrect and requires an extra parenthesis pair around last x:
#define ABS(x) (x>=0 ? x : -(x))

This is because the C directive is simply literal, replacing whatever expression in the parenthesis of ABS(...) into the definition. Below is actual code that is being compiled by the compiler:
ABS(1) ---> 1 >= 0 ? 1 : -1
ABS(-1) ---> -1 >= 0 ? -1 : --1
ABS(2-1) ---> 2-1 >= 0 ? 2-1 : -2-1
ABS(1-2) ---> 1-2 >= 0 ? 1-2 : -2-1

So, it should now be clear to you why the last expression's output was -3! By the way, the subroutine abs(x) is fine because the compiler will evaluate the value of whatever in the parenthesis of abs(...) before actually calling the function.

Friday, June 3, 2016

How to Setup SSH Login Email Alert for Mac OS X

This tutorial will discuss how to setup email alert for ssh login to your Mac OS X system. In particular, this has been tested on El Capitan only, but I am pretty sure that it should work with other versions as well. This is based on this post with slight modification.

First, create /etc/ssh/sshrc file with the following content
#!/bin/bash
ADDRESS="your_email@example.com"
IP=`echo $SSH_CONNECTION | cut -d " " -f 1`
DATE=`date`
echo "User $USER just logged in from $IP at $DATE" | mail -s "ssh login alert" "$ADDRESS"

Make sure to enter your own email address above to receive the alert mails. Set the owner of the file as root and set the execution flag.
$ sudo chown root /etc/ssh/sshrc && sudo chmod u+x /etc/ssh/sshrc

By the way, make sure there is no ~/.ssh/rc file, because the above script file won't be executed if ~/.ssh/rc file exists. To see more details on this, read sshd manual and search for sshrc
$ man sshd
/sshrc

This should do it. Make sure to check your spam folder for the alert mails.