Thursday, February 27, 2014

Advanced GDB tips and tricks

http://www.openlogic.com/wazi/bid/336594/advanced-gdb-tips-and-tricks


The GNU Debugger (GDB) is one of the most popular debugging tools available on Linux and Unix-like systems. Learn the advanced debugging techniques in this article to improve your development process.
To create the examples here, I used GDB 7.6.1-ubuntu and GCC 4.8.1, and compiled the C code using the -ggdb option.

Conditional breakpoints

Breakpoints are an integral part of a debugger. They let you pause program execution to do things such as examining variable values. While you probably know how to use breakpoints, you can debug your code better and faster by using conditional breakpoints.
Suppose your code crashes within a loop that runs hundreds or thousands of times. It would be impractical to put a simple breakpoint anywhere in that loop to catch a problem on some unknown iteration. With a conditional breakpoint, however, you can pause your program only when some condition is met.
Let's see how it works with the code below, which produces a floating point exception error on execution:
#include 

int main()
{
    int num = -1;
    int total = -1;
    int count = 0;
    int values[] = {10, 256, 55, 67, 43, 89, 78, 78, 89, 0};

    while(count < 10)
    {
            num = values[count];
            total = num + 0xffffffff/num;

            printf("\n result = [%d]\n", total);
            count++;
    }

    return 0;
}
You suspect that the crash happens when num is zero in line 13. You could put a breakpoint on that line, but the program would halt every time the line is executed. Instead, set a conditional breakpoint by specifying the condition subject to which the breakpoint should hit, which in this case is num==0:
$ gdb test
GNU gdb (GDB) 7.6.1-ubuntu
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later 
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-linux-gnu".
For bug reporting instructions, please see:
...
Reading symbols from /home/himanshu/practice/wazi/gdb/test...done.
(gdb) break 13 if num==0
Breakpoint 1 at 0x804849c: file test.c, line 13.
(gdb) run
Starting program: /home/himanshu/practice/wazi/gdb/test

 result = [429496739]

 result = [16777471]

 result = [78090369]

 result = [64104056]

 result = [99883003]

Breakpoint 1, main () at test.c:13
13                total = num + 0xffffffff/num;
(gdb) n

Program received signal SIGFPE, Arithmetic exception.
0x080484aa in main () at test.c:13
13                total = num + 0xffffffff/num;
(gdb)
As you can see, the conditional breakpoint made the program stop when the value of the variable num was zero. I then entered the gdb command n (for next) and confirmed that the crash happens when num is zero.
If you want to cross-check that the debugger stopped the program execution at the correct condition, you can print the value of the variable num through the p 'num' command.

Ignore breakpoints

Sometimes you don't have any clue about the problem condition, so you might want the debugger to tell you the exact number of loop iterations after which the crash occurs, to help you analyze loop conditions. GDB lets you ignore a breakpoint a specified number of times. You can then check the breakpoint information to see the number of loop iterations after which the crash occurs.
For example, the code shown below also gives a floating point exception on execution. But let's suppose that, because of the way the code was written, it is difficult for you to pinpoint a condition under which the crash occurs:
#include 

int main()
{
    int num = -1;
    int total = -1;
    int count = 50;

    while(count--)
    {
        // a lot of code here

        total = num + 0xffffffff/(count-10);
        printf("\n result = [%d]\n", total);

            // a lot of code here
    }

    return 0;
}
You can put a breakpoint at the entry of the loop and ask GDB to ignore it every time. At the end of program execution, use the info command to see how many times the program encountered the breakpoint before the crash happened.
By the way, here and in all the subsequent examples, I used GDB's -q (for quiet) command-line option to suppress introductory and copyright messages.
$ gdb -q test
Reading symbols from /home/himanshu/practice/wazi/gdb/test...done.
(gdb) break 10
Breakpoint 1 at 0x8048440: file test.c, line 10.
(gdb) info breakpoints
Num     Type           Disp Enb Address    What
1       breakpoint     keep y   0x08048440 in main at test.c:10
(gdb) ignore 1 50
Will ignore next 50 crossings of breakpoint 1.
(gdb) run
Starting program: /home/himanshu/practice/wazi/gdb/test

 result = [110127365]

 result = [113025454]

 result = [116080196]

...
...
...
 
 result = [2147483646]

 result = [-2]

Program received signal SIGFPE, Arithmetic exception.
0x08048453 in main () at test.c:13
13            total = num + 0xffffffff/(count-10);
(gdb) info break 1
Num     Type           Disp Enb Address    What
1       breakpoint     keep y   0x08048440 in main at test.c:10
    breakpoint already hit 40 times
    ignore next 10 hits
(gdb)
Note that the number 1, used in the ignore command and later in the info break 1 command, is the breakpoint number, which you can get from the info breakpoints command.
In this example the output of the info break 1 command displayed the exact number of iterations (40) after which crash occurred. You now have an idea that something went wrong after exactly 40 loop iterations, which should lead you to the problematic line total = num + 0xffffffff/(count-10);.

Use watchpoints

Sometimes a variable whose value is not supposed to be changed is passed as an argument into a series of functions, and when the code flow comes back, you observe that the variable's value was changed. To manually debug this kind of problem, you'd have to debug every function to which the variable was passed. A better approach is to use watchpoints, which help you track the value of a specified variable.
To set a watchpoint on a global variable, first set a breakpoint to stop program execution at the entry of the main() function. For a non-global variable, set a breakpoint at the entry of the function where the variable is in scope. In either case, once the breakpoint hits, set a watchpoint.
In the following code, the value of the variable ref_val is passed from the main() function to the func5() function, and when the flow comes back to the main function, we find that the value is changed from 256 to 512.
#include 

void func5(int *ptr)
{
    // a lot of code here
    *ptr = 512;
}

void func4(int *ptr)
{
    // a lot of code here
    func5(ptr);
}

void func3(int *ptr)
{
    // a lot of code here
    func4(ptr);
}

void func2(int *ptr)
{
    // a lot of code here
    func3(ptr);
}

void func1(int *ptr)
{
    // a lot of code here
    func2(ptr);
}

int main()
{
    int ref_val = 256;

    func1(&ref_val);

    printf("\n ref_val = [%d]\n", ref_val);

    return 0;
}
To debug this issue, you can put a watchpoint at the entry of each function involved in the call sequence. Here I test func5() first. I set a breakpoint at its entry, and when it is hit, I put the variable *ptr under watchlist using the watch command:
$ gdb -q test
Reading symbols from /home/himanshu/practice/wazi/gdb/test...done.
(gdb) break test.c:func5
Breakpoint 1 at 0x8048420: file test.c, line 6.
(gdb) run
Starting program: /home/himanshu/practice/wazi/gdb/test

Breakpoint 1, func5 (ptr=0xbffff0bc) at test.c:6
6        *ptr = 512;
(gdb) watch *ptr
Hardware watchpoint 2: *ptr
(gdb) c
Continuing.
Hardware watchpoint 2: *ptr

Old value = 256
New value = 512
func5 (ptr=0xbffff0bc) at test.c:7
7    }
(gdb)
When I continued program execution, GDB displayed the new and old values of the variable being watched, which in this case were different. Just like a breakpoint, a watchpoint stops program execution, but at the point at which the value changes. Once you know the culprit, which is func5() in this case, you can invest your time debugging it.

Call user-defined or system functions

Sometimes you might want to test a function by providing inputs to it. To do this, you could change the code that calls that function every time, or add extra code that makes it possible to send inputs to that function through STDIN, which is usually the command line. Alternatively, you can use GDB's call command.
Suppose you want to test the function user_defined_strlen() defined in the following code. As you can see, it essentially calculates and returns the length of a string passed to it as argument:
#include 

unsigned int user_defined_strlen(char *ptr)
{
    int len = 0;
    printf("\n User-defined strlen() function called with string [%s]\n", ptr);

    if(NULL == ptr)
    {
        printf("\n Invalid string\n");
        return 0;
    }
     
    while(*(ptr++) != '\0')
        len++;

    printf("\n[%u]\n", len);
    return len;
}

int main()
{
    char *ptr = "some-string";
     
    user_defined_strlen(ptr);

    return 0;
}
You can put a breakpoint at the entry of the main() function. When GDB hits the breakpoint, execute the call command by passing to it a function name, along with arguments to test:
$ gdb -q test
Reading symbols from /home/himanshu/practice/wazi/gdb/test...done.
(gdb) break test.c:main
Breakpoint 1 at 0x80484bd: file test.c, line 23.
(gdb) run
Starting program: /home/himanshu/practice/wazi/gdb/test

Breakpoint 1, main () at test.c:23
23        char *ptr = "some-string";
(gdb) call user_defined_strlen("wazi")

 User-defined strlen() function called with string [wazi]

[4]
$1 = 4
(gdb)
You can also call standard library functions using the call command. For instance, at the same breakpoint, you can call the strlen() function to cross-check the output of the function:
(gdb) call strlen("wazi")
$2 = 4
(gdb)

Auto-display variable values

As a complement to a watchpoint, which stops execution whenever the value of a variable or an expression changes, you can use the display command to print the value of a variable or expression to see how it changes.
For example, in the code snippet above, if you wanted to display the value of the len variable as the while loop progresses, you could put a breakpoint at the while condition, execute the display command with len as an argument, and step through the code with the n command – or step through the code with n once, and just press Enter at every subsequent GDB prompt, because the debugger repeats the last command by default.
$ gdb -q test
Reading symbols from /home/himanshu/practice/wazi/gdb/test...done.
(gdb) break 14
Breakpoint 1 at 0x8048486: file test.c, line 14.
(gdb) run
Starting program: /home/himanshu/practice/wazi/gdb/test

 User-defined strlen() function called with string [some-string]

Breakpoint 1, user_defined_strlen (ptr=0x80485c2 "some-string") at test.c:14
14        while(*(ptr++) != '\0')
(gdb) display len
1: len = 0
(gdb) n
15            len++;
1: len = 0
(gdb) n
14        while(*(ptr++) != '\0')
1: len = 1
(gdb) n
15            len++;
1: len = 1
(gdb) n
14        while(*(ptr++) != '\0')
1: len = 2
(gdb) n
15            len++;
1: len = 2
(gdb) n
14        while(*(ptr++) != '\0')
1: len = 3
(gdb) n
15            len++;
1: len = 3
(gdb) n
14        while(*(ptr++) != '\0')
1: len = 4
(gdb) n
15            len++;
1: len = n
(gdb) n
14        while(*(ptr++) != '\0')
1: len = 5
(gdb) n
15            len++;
1: len = 5
The undisplay command removes an auto-displayed variable or expression previously set with display. It expects an expression number, which you can determine with the info command:
(gdb) info display
Auto-display expressions now in effect:
Num Enb Expression
1:   y  len
(gdb) undisplay 1
(gdb) n
15            len++;
(gdb) n
14        while(*(ptr++) != '\0')
(gdb) n
15            len++;
(gdb) n
14        while(*(ptr++) != '\0')
(gdb) n
15            len++;

In conclusion

As you can see, GDB offers several advanced tools that can help you find the flaws in your programs' code. You probably have your own favorite advanced debugging techniques – please share them in the comments below.

Tuesday, February 25, 2014

How to convert an HTML web page to PNG image on Linux

http://xmodulo.com/2014/02/convert-html-web-page-png-image-linux.html

One of the easiest way to screen capture a particular web page as a PNG image is by using CutyCapt, which is a convenient command line Linux tool for converting any HTML webpage to a variety of vector and bitmat image formats (e.g., SVG, PDF, PS, PNG, JPEG, TIFF, GIF). Internally, CutyCapt uses WebKit rendering engine to export webpage rendering output to an image file. Built with Qt, CutyCapt is actually a cross-platform application available for other platforms such as Windows as well.
In this tutorial, I will describe how to convert an HTML web page to PNG image format using CutyCapt.

Install CutyCapt on Linux

Here are distro-specific instructions to install CutyCapt on Linux.

Install CutyCapt on Debian, Ubuntu or Linux Mint

$ sudo apt-get install cutycapt

Install CutyCapt on Fedora

$ sudo yum install subversion qt-devel qtwebkit-devel gcc-c++ make
$ svn co svn://svn.code.sf.net/p/cutycapt/code/ cutycapt
$ cd cutycapt/CutyCapt
Before compilation on Fedora, you need to patch source code.
Open CutyCapt.hpp with a text editor, and add the following two lines at the beginning of the file.
#include 
#include 
Finally, compile and install CutyCapt as follows.
$ qmake-qt4
$ make
$ sudo cp CutyCapt /usr/local/bin/cutycapt

Install CutyCapt on CentOS or RHEL

First enable EPEL repository on your Linux. Then follow the same procedure as in Fedora to build and install CutyCapt.

Convert HTML to PNG with CutyCapt

To take a screenshot of an HTML page as a PNG image, simply run CutyCapt in the following format.
$ cutycapt --url=http://www.cnn.com --out=cnn.png
To save an HTML page to a different format (e.g., PDF), simply specify the output file appropriately.
$ cutycapt --url=http://www.cnn.com --out=cnn.pdf
The following shows command-line options of cutycapt.

Convert HTML to PNG with CutyCapt on a Headless Server

While CutyCapt is a CLI tool, it requires an X server running. If you attempt to run CutyCapt on a headless server, you will get the error:
cutycapt: cannot connect to X server :0
If you want to run CutyCapt on a headless server without X windows, you can set up Xvfb (lightweight "fake" X11 server) on the server, so that CutyCapt does not complain.
To install Xvfb on Debian, Ubuntu or Linux Mint:
$ sudo apt-get install xvfb
To install Xvfb on Fedora, CentOS or RHEL:
$ sudo yum install xvfb
After installing Xvfb, proceed to run CutyCapt as follows.
$ xvfb-run --server-args="-screen 0, 1280x1200x24" cutycapt --url=http://www.cnn.com --out=cnn.png
It will launch Xvfb server first, and then use CutyCapt to screen capture the webpage. So it may take longer. If you want to make multiple screenshots, you may want to start Xvfb server as a background daemon beforehand.

Monday, February 17, 2014

10 snazzy music production tools for Ubuntu/Linux

http://www.techdrivein.com/2014/02/10-music-production-tools-for-ubuntu-linux.html

Like many other niches, music production was not really a Linux forte. But that's changing now and like what happened to the video editing scene, popular music production tools are finding its way into Linux. Though I love listening to all kinds of music, I'm no music production expert. And hence I can't pass informative judgments on any of the applications you're going to read about in the article below. Consider this blogpost as a brief introduction to different music production tools available for Ubuntu and Linux, and not as a review per se. So here we go again. 10 useful music production tools for Ubuntu and Linux.

Bitwig Studio DAW for Linux

Bitwig Studio Digital Audio Workstation
  • Bitwig Studio is a multi-platform (supports Windows, Mac and Linux) music-creation tool for production, performance and DJing.
  • Bitwig Studio is made by developers that used to work on Ableton Live, a Windows only Digital Audio Workstation (DAW). And like Lightworks for video editing, Bitwig Studio will be a professional grade music production tool with support for Linux platform. 
  • Expected release date: March 26, 2014. Know more.
------------------------------------------------------------------------------------------------------------------------
Ardour audio mixing software linux

Ardour: Audio mixing software for Linux
  • Record, edit and mix audio using Ardour. Supports Linux and Mac. 
  • Ardour is open source and is released under GPLv2/GPLv3 license.
  • Ardour is a great example of commercial free-libre software. Users who download from ardour.org are asked to pay at least $1 for downloading prebuilt binaries of Ardour; those users then have the right to obtain minor updates until the next major release. 
  • Another option is to subscribe by paying $1, $4 or $10 per month. Subscribers can download prebuilt binaries of all updates during the subscription period.
  • Without paying anything, users can download the full source code for all platforms.
------------------------------------------------------------------------------------------------------------------------
Renoise DAW for linux

Renoise Digital Audio Workstation
  • Renoise is a Digital Audio Workstation (DAW) with a unique top-down approach to music composition known as a tracker interface.
  • Features include full MIDI and MIDI sync support, VST 2.0 plugin support, ASIO multi I/O cards support, integrated sampler and sample editor, internal real-time DSP effects with unlimited number of effects per track, master and send tracks, full automation of all commands, hi-fi .WAV rendering (up to 32 bit 96 kHz), Rewire support, etc.
  • A full version of Renoise cost USD 78.00, which is noticeably cheaper than competing digital audio workstations (DAWs) such as Ableton Live and even the upcoming Bitwig Studio which costs around USD 749 and USD 400 (rumored) respectively. 
------------------------------------------------------------------------------------------------------------------------
top DAW on linux
Tracktion Music Production Software for Linux
  • Tracktion is yet another high-profile entrant into the Linux music production scene.
  • Tracktion is a digital audio workstation for recording and editing audio and MIDI. The project was started with the intention of creating the most easy-to-use music production tool out there. Tracktion is proprietary though.
  • Support for a wide range of audio formats including  WAV, AIFF and Ogg-Vorbis.
  • Tracktion beta version for Linux is free now. Get it here
------------------------------------------------------------------------------------------------------------------------

top music production tools on Linux

Rosegarden Digital Audio Workstation (Linux exclusive)
  • Rosegarden is an open source digital audio workstation for Linux, based around a MIDI sequencer that features a rich understanding of music notation and includes basic support for digital audio.
  • Ideal for composers, musicians, and students working from a small studio or home recording environments. Quite easy to learn and runs exclusively on Linux.
------------------------------------------------------------------------------------------------------------------------
10 best music production tools for linux
Hydrogen: Advanced drum machine for Linux
  • Hydrogen is an advanced drum machine for Linux, an electronic musical instrument designed to imitate the sound of drums or similar percussion instruments.  
  • Hydrogen's interface uses Qt library and the entire code-base is released to the public under the GNU General Public License. 
------------------------------------------------------------------------------------------------------------------------

MIXXX professional DJing software for Linux

Mixxx: Linux's very own professional DJing software
  • Mixxx is a free and open source digital DJing software that allows mixing music in your Linux system with ease. 
  • Mixxx started off as a humble project for a doctoral thesis way back in 2001. Today it is a full-fledged application that is downloaded over one million times annually.
  • It is licensed under the GPL (v2.0 or later) and runs on all major desktop operating systems.
  • More download options here.
------------------------------------------------------------------------------------------------------------------------

edit mp3 in ubuntu using audacity

Audacity: Record and edit music in Linux with ease
  • Audacity is the most well-known application here, and perhaps the most basic too.
  • Audacity is a free and open source, cross-platform software for recording and editing all kinds of music and audio. It is one of the most downloaded software in SourceForge, with nearly 100 million downloads. 
  • More download options for Audacity can be found here
------------------------------------------------------------------------------------------------------------------------
best music production tools linux
LMMS: Linux MultiMedia Studio
  • LMMS is yet another free and open-source, cross-platform software that allows you to produce music with your computer. This include creating of melodies and beats, synthesizing and mixing of sounds and arranging samples.
  • LMMS is available for Linux and Windows. Download here
------------------------------------------------------------------------------------------------------------------------

top 10 music production tools on linux and Ubuntu

JACK: Jack Audio Connection Kit
  • Jack Audio Connection Kit (JACK) is perhaps the most important tool as far as music production on Linux is concerned. It is a professional sound server daemon that provides real-time, low latency connections for both audio and MIDI data between applications that implement its API.
  • It can connect a number of different applications to an audio device, as well as allowing them to share audio between themselves.
  • Most of the open-source applications listed above and plenty more out there does use its API. See this exhaustive list for yourself. 
  • The server is free software, licensed under the GNU GPL, while the library is licensed under the more permissive GNU LGPL.
  • Download options here.

Tuesday, February 11, 2014

SSH from a web browser tutorial

http://www.linuxuser.co.uk/tutorials/ssh-from-a-web-browser-tutorial

There are times when you are stuck using a locked-down machine. As long as you have a browser, though, you can still connect to your remote machines. Here’s how…


SSH is the de facto way of securely connecting to remote machines where you need to get work done. Normally, this is achieved through an SSH client application installed on your desktop. Unfortunately, there are situations where this is just not feasible, for any number of reasons. In this tutorial we will look at a few different options for how to regain a command- line connection to your remote machines.
No matter how locked down a machine may be, you will almost always have a web browser available. We can leverage this and get an SSH connection established through this browser. There are several different technologies that can be used to give us this connection. The first option we will look at is a purely browser-based application that requires nothing extra on either the client side or the server side. Naturally, the available options are limited, but it is one of the leanest options. The issue is that you need to use a supported browser. The second option is a Java-based one. A Java applet is loaded into your browser to handle the actual SSH connection management. Unfortunately, this is only an option if you have Java installed and are allowed to run Java applets in the browser. The third option is even leaner on the client side than the first option, and has the added advantage of running in almost any browser. The downside is that it requires you to install a piece of server-side code to facilitate the actual SSH connection management.
Hopefully, by the end of this tutorial, you will have found an option that fits your situation and helps you manage your remote machines no matter where you are.

There is an URL always available pointing you to a goo.gl URL containing an FAQ for Secure Shell
There is an URL always available pointing you to a goo.gl URL containing an FAQ for Secure Shell

Resources

Secure Shell
Shellinabox
MindTerm
DropPages
Pancake
Step 01 Finding an SSH client plug-in
Both Chrome and Firefox have SSH clients in their respective app stores. In this tutorial, we will be looking at Secure Shell from the Chrome store and FireSSH from the Firefox store.
Step 02 Installation
In the case of both browsers, installation should be straightforward. All you need to do is find the relevant app in the browser store and click on the Install button. Most browsers also require a restart before the SSH client is ready to use.
Step 03 Open a new connection
For the rest of this tutorial, we will use the Chrome version. To open a new connection, simply click on the ‘Secure Shell’ icon on the browser homepage. This will open up a connection window where you can enter the host, username and password.
Step 04 Terminal Options
‘Secure Shell’ in Chrome does not have a terminal preferences window yet, so you need to open a JavaScript console (by clicking the menu item View>Developer>JavaScript Console) and entering the changes you want to make. For example, you can set the background colour with the following: term_.prefs_.set(’background-color’, ’wheat’)
Step 05 Working in SSH
You can do almost everything with ‘Secure Shell’ that you would normally do with a regular client. You can do port forwarding by including the relevant options when you make the original connection. You place these types of options in the SSH Arguments box.

shellinabox
Working in SSH
Step 06 Closing connections
You close your connection the same way you would with any other SSH client, by typing in exit. When the connection closes, ‘Secure Shell’ offers you the option to reconnect (R), choose another connection (C), or simply finish and exit (x). If you choose ‘x’, the current browser window will stay open but will be inactive.
Step 07 Saving connections
All of your previous connections get stored as a list that becomes available at the top of the connection screen. Clicking on one of these stored connections lets you edit the SSH options before firing off and connecting to the remote machine.
Step 08 Finding a Java plug-in client
There is a Java applet that you can use called MindTerm. In this case, you need to wrap MindTerm in a simple webpage in order to get the browser to load it for you and host it somewhere visible. You can also run it directly as a Java app.
Step 09 Installation
If you need to host MindTerm somewhere non-local, you can place it on a hosting service if you have one. If not, you can get a Dropbox account and host it there as a static webpage. There are services like DropPages or Pancake.io that will help you here.
Step 10 Open a new connection
The screenshot above is made using the MindTerm jar file standalone. The behaviour is the same in the browser. When it starts up, it asks you to enter either a server alias or a server hostname. If this is a new machine, it will ask you whether you want to save it as an alias.
Step 11 Connection options
The advantage of a Java applet is that you have more tools available to you. Clicking on the menu item Settings>Terminal… will pop up a full preferences window where you can set the terminal type, font type and size, and colours, among other items.

Connection options
Connection options
Step 12 Working in SSH
With MindTerm, you also have easy access to all of the SSH connection options. Clicking on the menu item Settings>Connection… will pop up a new window where you can set port forwarding, as well as more esoteric items such as the type of cipher or the type of compression to use.
Step 13 Closing connections
You close your session with the exit command, just like with a regular SSH client. Once the connection is shut down, MindTerm resets itself and is ready for a new connection to a new host.
Step 14 Saving connections
Whenever you connect to a new host, MindTerm asks you whether you want to save it in the list of hosts under an optional alias. To get access to these saved connections, you will need to click on the menu item File>Connect…. This will pop up a connection window where you can select the server from a drop-down box.
Step 15 Client/server browser-based SSH
The previous two methods have an advantage where all of the SSH connections are essentially only through the client and the server. This also means that the machine you are working on also needs to allow network connections on the ports that you need, most often port 22. But what can you do if your desktop is locked down to only allowing HTTP traffic? In this case, you need to move the workhorse part of your SSH connection off to another machine, and connect to it over HTTP with your browser. The most common choice for this is shellinabox.
Step 16 Installation
Once you download the source, you need to install it with the usual ./configure; ./make; ./make install step that should be in most Linux users’ repertoire of skills. You do this on the remote host that you want to connect to.
Step 17 Starting the server
Once shellinabox is installed, starting it is done by simply starting up shellinaboxd on the remote host. There are tons of options available as command-line parameters. The most common ones are options like –port=x, and –verbose.
Step 18 Starting the client
To start the client, you simply need to open your browser and enter the URL to the remote machine. It will look like http://mymachine.com:4200, where you might have changed the port being used. This will open up a terminal where you can enter your username and password.
Step 19 Connecting to a different machine
Once you log in, you can always just SSH to another machine. But if this is something that you always do, you can get shellinabox to do this for you by using the option -s /:SSH:mynewhost.com. This means you could have connection tunnels to multiple different machines, each with its own port.
Step 20 Connection options
Because this is the leanest of the web- based SSH clients available, you simply don’t have the same level of configuration options.
Right-clicking in the terminal window will bring up a set of options that get saved in a web cookie that survives over sessions.
Step 21 Working with SSH
Unlike the other methods, you do not have the option to set up more complicated options, like SSH tunnelling. All you get on the client side is pure HTML, with nothing else. If you need more, you will need to use one of the other methods.
Step 22 Closing connections
Like every other SSH client, you shut down your connection with the exit command. This leaves your browser window open with a button popping up in the centre labelled Connect. Clicking on this button will refresh the screen and reopen the connection to your remote host.

Closing connections
Closing connections
Step 23 Saving connections
Unfortunately, there is no real way to ‘store’ a set of connection strings to different machines within shellinabox. The best option open to you is to configure a series of daemons on different ports tunnelling to different machines, and then you can save the URLs to these servers as bookmarks in your browser.
Step 24 Where to now?
Hopefully this tutorial will have shown you some options that are available when you get stuck with an overly locked down machine. If these don’t fit your exact situation, don’t be afraid to look for some of the other options available out in the wild.

How to set password policy on Linux

http://xmodulo.com/2013/12/set-password-policy-linux.html

User account management is one of the most critical jobs of system admins. In particular, password security should be considered the top concern for any secure Linux system. In this tutorial, I will describe how to set password policy on Linux.
I assume that you are using PAM (Pluggable Authentication Modules) on your Linux system, which is the case on all recent Linux distros.

Preparation

Install a PAM module to enable cracklib support, which can provide additional password checking capabilities.
On Debian, Ubuntu or Linux Mint:
$ sudo apt-get install libpam-cracklib
The cracklib PAM module is installed by default on CentOS, Fedora, or RHEL. So no further installation is necessary on those systems.
To enforce password policy, we need to modify an authentication-related PAM configuration file located at /etc/pam.d. Policy change will take effect immediately after change.
Note that the password rules presented in this tutorial will be enforced only when non-root users change passwords, but not the root.

Prevent Reusing Old Passwords

Look for a line that contains both "password" and "pam_unix.so", and append "remember=5" to that line. It will prevent five most recently used passwords (by storing them in /etc/security/opasswd).
On Debian, Ubuntu or Linux Mint:
$ sudo vi /etc/pam.d/common-password
password     [success=1 default=ignore]    pam_unix.so obscure sha512 remember=5
On Fedora, CentOS or RHEL:
$ sudo vi /etc/pam.d/system-auth
password   sufficient   pam_unix.so sha512 shadow nullok try_first_pass use_authtok remember=5

Set Minimum Password Length

Look for a line that contains both "password" and "pam_cracklib.so", and append "minlen=10" to that line. This will enforce a password of length (10 - <# of types>), where <# of types> indicates how many different types of characters are used in the password. There are four types (upper-case, lower-case, numeric, and symbol) of characters. So if you use a combination of all four types, and minlen is set to 10, the shorted password allowed would be 6.
On Debian, Ubuntu or Linux Mint:
$ sudo vi /etc/pam.d/common-password
password   requisite    pam_cracklib.so retry=3 minlen=10 difok=3
On Fedora, CentOS or RHEL:
$ sudo vi /etc/pam.d/system-auth
password   requisite   pam_cracklib.so retry=3 difok=3 minlen=10

Set Password Complexity

Look for a line that contains "password" and "pam_cracklib.so", and append "ucredit=-1 lcredit=-2 dcredit=-1 ocredit=-1" to that line. This will force you to include at least one upper-case letter (ucredit), two lower-case letters (lcredit), one digit (dcredit) and one symbol (ocredit).
On Debian, Ubuntu or Linux Mint:
$ sudo vi /etc/pam.d/common-password
password   requisite    pam_cracklib.so retry=3 minlen=10 difok=3 ucredit=-1 lcredit=-2 dcredit=-1 ocredit=-1
On Fedora, CentOS or RHEL:
$ sudo vi /etc/pam.d/system-auth
password   requisite   pam_cracklib.so retry=3 difok=3 minlen=10 ucredit=-1 lcredit=-2 dcredit=-1 ocredit=-1

Set Password Expiration Period

To set the maximum period of time the current password is valid, edit the following variables in /etc/login.defs.
$ sudo vi /etc/login.defs
PASS_MAX_DAYS   150
PASS_MIN_DAYS   0
PASS_WARN_AGE   7
This will force every user to change their password once every six months, and send out a warning message seven days prior to password expiration.
If you want to set password expiration on per-user basis, use chage command instead. To view password expiration policy for a specific user:
$ sudo chage -l xmodulo
Last password change                                    : Dec 30, 2013
Password expires                                        : never
Password inactive                                       : never
Account expires                                         : never
Minimum number of days between password change          : 0
Maximum number of days between password change          : 99999
Number of days of warning before password expires       : 7
By default, a user's password is set to never expire.
To change the password expiration period for user xmodulo:
$ sudo chage -E 6/30/2014 -m 5 -M 90 -I 30 -W 14 xmodulo
The above command will set the password to expire on 6/30/2014. In addition, the minimum/maximum number of days between password changes is set to 5 and 90 respectively. The account will be locked 30 days after a password expires, and a warning message will be sent out 14 days before password expiration.

Get better Apache load balancing with mod_cluster

http://www.openlogic.com/wazi/bid/330406/get-better-apache-load-balancing-with-mod_cluster


Mod_cluster is an innovative Apache module for HTTP load balancing and proxying. It implements a communication channel between the load balancer and back-end nodes to make better load-balancing decisions and redistribute loads more evenly.
Why use mod_cluster instead of a traditional load balancer such as Apache's mod_balancer and mod_proxy or even a high-performance hardware balancer? Thanks to its unique back-end communication channel, mod_cluster takes into account back-end servers' loads, and thus provides better and more precise load balancing tailored for JBoss and Tomcat servers. Mod_cluster also knows when an application is undeployed, and does not forward requests for its context (URL path) until its redeployment. And mod_cluster is easy to implement, use, and configure, requiring minimal configuration on the front-end Apache server and on the back-end servers.

How to install mod_cluster

You can use mod_cluster either with JBoss or Tomcat back-end servers. We'll install and configure mod_cluster with Tomcat under CentOS; using it with JBoss or on other Linux distributions is a similar process. I'll assume you already have at least one front-end Apache server and a few back-end Tomcat servers installed.
To install mod_cluster, first download the latest mod_cluster httpd binaries. Make sure to select the correct package for your hardware architecture – 32- or 64-bit.
Unpack the archive to create four new Apache module files: mod_advertise.so, mod_manager.so, mod_proxy_cluster.so, and mod_slotmem.so. We won't need mod_advertise.so; it advertises the location of the load balancer through multicast packets, but we will use a static address on each back-end server. Copy the other three .so files to the default Apache modules directory (/etc/httpd/modules/ for CentOS).
Before loading the new modules in Apache you have to remove the default proxy balancer module (mod_proxy_balancer.so) because it is not compatible with mod_cluster. Edit the Apache configuration file (/etc/httpd/conf/httpd.conf) and remove the line LoadModule proxy_balancer_module modules/mod_proxy_balancer.so. Create a new configuration file and give it a name such as /etc/httpd/conf.d/mod_cluster.conf. Use it to load mod_cluster's modules:
LoadModule slotmem_module modules/mod_slotmem.so
LoadModule manager_module modules/mod_manager.so
LoadModule proxy_cluster_module modules/mod_proxy_cluster.so
In the same file add the rest of the settings you'll need for mod_cluster. For example:
Listen 192.168.204.203:9999



    
        Order deny,allow
        Allow from all 192.168
    

    ManagerBalancerName mymodcluster
    EnableMCPMReceive


ProxyPass / balancer://mymodcluster/
The above directives create a new virtual host listening on port 9999 on the Apache server you want to use for load balancing, on which the load balancer will receive information from the back-end application servers. In this example, the virtual host is listening on IP address 192.168.204.203, and for security reasons it allows connections only from the 192.168.0.0/16 network.
The directive ManagerBalancerName defines the name of the cluster – mymodcluster in this example. The directive EnableMCPMReceive allows the back-end servers to send updates to the load balancer. The standard ProxyPass and ProxyPassReverse directives instruct Apache to proxy all requests to the mymodcluster balancer.
That's all you need for a minimal configuration of mod_cluster on the Apache load balancer. At next server restart Apache will automatically load the file mod_cluster.conf from the /etc/httpd/conf.d directory. To learn about more options that might be useful in specific scenarios, check mod_cluster's documentation.
While you're changing Apache configuration, you should probably set the log level in Apache to debug when you're getting started with mod_cluster, so that you can trace the communication between the front- and the back-end servers and troubleshoot problems more easily. To do so, edit Apache's configuration file and add the line LogLevel debug, then restart Apache.

How to set up Tomcat for mod_cluster

Mod_cluster works with Tomcat version 6 and 7. To set up the Tomcat back ends you have to deploy a few JAR files and make a change in Tomcat's server.xml configuration file.
The necessary JAR files extend Tomcat's default functionality so that it can communicate with the proxy load balancer. You can download the JAR file archive by clicking on "Java bundles" on the mod_cluster download page. It will be saved under the name mod_cluster-parent-1.2.6.Final-bin.tar.gz.
Create a new directory such as /root/java_bundles and extract the files from mod_cluster-parent-1.2.6.Final-bin.tar.gz there. Inside the directory /root/java_bundlesJBossWeb-Tomcat/lib/*.jar you will find all the necessary JAR files for Tomcat, including two Tomcat version-specific JAR files – mod_cluster-container-tomcat6-1.2.6.Final.jar for Tomcat 6 and mod_cluster-container-tomcat7-1.2.6.Final.jar for Tomcat 7. Delete the one that does not correspond to your Tomcat version.
Copy all the files from /root/java_bundlesJBossWeb-Tomcat/lib/ to your Tomcat lib directory – thus if you have installed Tomcat in /srv/tomcat, run the command cp /root/java_bundles/JBossWeb-Tomcat/lib/* /srv/tomcat/lib/.
Next, edit your Tomcat's server.xml file (/srv/tomcat/conf/server.xml). After the default listeners add the following line:

This instructs Tomcat to send its mod_cluster-related information to IP 192.168.204.203 on TCP port 9999, which is what we set up as Apache's dedicated vhost for mod_cluster.
While that's enough for a basic mod_cluster setup, you should also configure a unique, intuitive JVM route value on each Tomcat instance so that you can easily differentiate the nodes later. To do so, edit the server.xml file and extend the Engine property to contain a jvmRoute, like this: . Assign a different value, such as node2, to each Tomcat instance. Then restart Tomcat so that these settings take effect.
To confirm that everything is working as expected and that the Tomcat instance connects to the load balancer, grep Tomcat's log for the string "modcluster" (case-insensitive). You should see output similar to:
Dec 23, 2013 8:34:00 AM org.jboss.modcluster.ModClusterService init
INFO: MODCLUSTER000001: Initializing mod_cluster ${project.version}
Dec 23, 2013 8:34:11 AM org.jboss.modcluster.ModClusterService connectionEstablished
INFO: MODCLUSTER000012: Catalina connector will use /192.168.204.204
This shows that mod_cluster has been successfully initialized and that it will use the connector for 192.168.204.204, the configured IP address for the main listener.
Also check Apache's error log. You should see confirmation about the properly working back-end server:
[Mon Dec 23 08:36:22 2013] [debug] proxy_util.c(2026): proxy: ajp: has acquired connection for (192.168.204.204)
[Mon Dec 23 08:36:22 2013] [debug] proxy_util.c(2082): proxy: connecting ajp://192.168.204.204:8009/ to 192.168.204.204:8009
[Mon Dec 23 08:36:22 2013] [debug] proxy_util.c(2209): proxy: connected / to 192.168.204.204:8009
[Mon Dec 23 08:36:22 2013] [debug] mod_proxy_cluster.c(1366): proxy_cluster_try_pingpong: connected to backend
[Mon Dec 23 08:36:22 2013] [debug] mod_proxy_cluster.c(1089): ajp_cping_cpong: Done
[Mon Dec 23 08:36:22 2013] [debug] proxy_util.c(2044): proxy: ajp: has released connection for (192.168.204.204)
This Apache error log shows that an AJP connection with 192.168.204.204 was successfully established and confirms the working state of the node, then shows that the load balancer closed the connection after the successful attempt.
You can start testing by opening in a browser the example servlet SessionExample, which is available in a default installation of Tomcat. Access this servlet through a browser at the URL http://balancer_address/examples/servlets/servlet/SessionExample. In your browser you should see first a session ID that contains the name of the back-end node that is serving your request – for example, Session ID: 5D90CB2C0AA05CB5FE13111E4B23E630.node2. Next, through the servlet's web form, create different session attributes. If you have a properly working load balancer with sticky sessions you should always (that is, until your current browser session expires) access the same node, with the previously created session attributes still available. To test further to confirm load balancing is in place, at the same time open the same servlet from another browser. You should be redirected to another back-end server where you can conduct a similar session test.
As you can see, mod_cluster is easy to use and configure. Give it a try to address sporadic single-back-end overloads that cause overall application slowdowns.

Will DuckDuckGo eventually destroy Google in search?

http://www.itworld.com/open-source/400624/will-duckduckgo-destroy-google-search

Today in Open Source: DuckDuckGo gains more users as privacy concerns mount. Plus: An exhaustive list of Open Source software, and the Ubuntu phone may be delayed until 2015

By , ITworld |  Open Source, Google, open source 8
DuckDuckGo gains larger user base
Fierce Content Management is reporting that DuckDuckGo grew quite a bit over the last year, probably due to privacy concerns on the part of users.
DuckDuckGo reported phenomenal growth last year, and it's no wonder.
In a time when our privacy is continually being eroded, and every day there seems to be a new revelation about government surveillance, many people are looking away from major search engines like Google and Bing and moving to DuckDuckGo, a service that guarantees it doesn't save your search information.

Image credit: Fierce Content Management
More at Fierce Content Management

Image credit: DuckDuckGo
I'm very glad to see DuckDuckGo doing so well recently. I highly recommend using it when you want your searches to be private. It's a much better option than Google, Bing, Yahoo or some of the other better known search engines.
This report makes me wonder how long Google will be king of the search engines. More and more people are disturbed at the tracking and bubbling that happens when you use Google. Privacy is becoming a major issue for people on the web, particularly while searching for information.
I actually had a friend of mine who is not very tech-savvy ask me about this. He was worried that Google was tracking his searches and sharing it with the government. I was surprised to hear this from him as it's the sort of thing that he doesn't usually pay attention to in the media.
Sure enough though it had gotten through to him and he was worried. So I gave him the URL for DuckDuckGo and told him to use that instead of Google if privacy mattered to him.
I also showed him the DuckDuckGo site, and let him scan the DuckDuckGo pages that explain the differences between DuckDuckGo and Google:
Don't Track Us
Don't Bubble Us
He was impressed and also somewhat shocked at the mechanics of Google's search experience.
It might seem very early for me to ponder this, but I can't help but think that Google's days are numbered as the number one search engine. It might or might not be DuckDuckGo that dethrones Google, but the issue of privacy is beginning to matter to even non-tech-savvy users.
I suspect that a quiet tidal wave of anger about privacy is forming out there, and I wonder if it will someday sweep Google and the other large search engines away. I doubt any of those companies are worried about this in the short term, but it's something they had better pay attention to over the long haul.
What's your take on this? Will DuckDuckGo or some other privacy protecting search engine eventually destroy Google? Tell me your thoughts in the comments.
A guide to Open Source software
Datamation has a very long (12 pages!) guide to Open Source software.
For the fifth year in a row, Datamation is closing out the year with a big, big list of all the software we've featured on our monthly open source software guides. This year's list is the longest ever with 1,180 projects in 143 different categories from Accessibility to Wine and Beer.
We refreshed the list with all the new applications we've highlighted this year, and we dropped those that hadn't been updated in a while. Please note that the list is organized by category and alphabetically within each category — the numbers don't indicate rank or quality.
More at Datamation
Kudos to Datamation for the exhaustive list, but twelve pages is a bit much to expect people to click through. It would be nice if there was a single page alternative for folks who don't want to keep clicking over and over to see the list.
Anyway, check out the list if you're looking for more Open Source applications. There's bound to be something on there that you'll find useful, if you can manage to click all the way to the end.
Ubuntu phone may be delayed until 2015
The Register is reporting that the Ubuntu phone may be delayed until 2015.
When Canonical CEO Jane Silber first announced plans to port Ubuntu to phones last year, she said the goal was to ship the first handsets with the OS preloaded by the end of 2013.
That didn't happen, and from the sound of it, Ubuntu fans probably shouldn't hold their breath for a dedicated Ubuntu phone this year, either. Even if one does appear, it will likely be a limited-run device targeting niche use cases.
"Longer-term we would love to see the major OEM/Carriers shipping Ubuntu handsets," Ubuntu community manager Jono Bacon wrote in a recent Reddit AMA session. "This is a long road though with many components, and I would be surprised if we see anything like this before 2015."
More at The Register
It sounds like Firefox OS will be the most prominent alternative to Android and iOS phones for the immediate future. It's a shame that Canonical has not been able to launch an Ubuntu phone. Piggybacking off of a limited selection of Android phones just isn't going to cut it.

How to develop an Android app using Apache Cordova and jQuery Mobile

http://www.openlogic.com/wazi/bid/332279/how-to-develop-an-android-app-using-apache-cordova-and-jquery-mobile


Apache Cordova is a platform for building native mobile applications using common web technologies, including HTML, CSS, and JavaScript. It offers a set of APIs that allow mobile application developers to access native mobile functions such as audio, camera, and filesystem using JavaScript. Another developer tool, jQuery Mobile, is one of the best mobile web application frameworks. It allows developers to create rich web applications that are mobile-friendly. You can use Apache Cordova with jQuery Mobile to create a complete Android application.
To create, develop, build, and test a Cordova application, you can use the Cordova command-line interface. From the Cordova CLI you can create new Cordova projects, build them on mobile platforms, and run them on real devices or within emulators.
Before you install the Cordova CLI, install the Android SDK and Node.js, and be sure you have Apache Ant installed, then use the Node.js command sudo npm install -g cordova to install Cordova. The latest Cordova version is 3.3.0.
Create a Cordova project by running the command cordova create voicememo com.xyz.voicememo VoiceMemo. The first parameter tells Cordova to generate a voicememo directory for the project. The directory will contain a www subdirectory that includes the application's home page (index.html), along with various resources under css, js, and img directories. The command also creates a config.xml file that contains important metadata Cordova needs to generate and distribute the application.
The second and the third parameters are optional. The second parameter, com.xyz.voicememo, provides a project namespace. For an Android project, such as the one we are building, the project namespace maps to a Java package with the same name. The last parameter, VoiceMemo, provides the application's display text. You can edit both of these values later in the config.xml file.
Now you have a Cordova project that you can use as a base for generating platform-specific code. Before you generate Android code, run the commands
cd voicememo
cordova platform add android
The cordova platform command depends on Apache Ant. After you run it, you will find a new platforms/android subdirectory under the voicememo directory.
To generate Android-specific code under platforms/android, build the project using the cordova build command under the voicememo directory. You can then run and test the generated Android project in the Cordova emulator by executing the command cordova emulate android.
Note: The Cordova project recommends you make your code changes in the root www directory, and not in the platforms/android/assets/www directory, because the platforms directory is overwritten every time you execute a cordova build command after you use Cordova CLI to initialize the project.
Figure 1
The home page of the VoiceMemo application, which represents the list of voice memos.
From the Voice Listing page, users can click on three buttons: New, to create a new recording; About, to open the application's About page; and Remove All Memos, to remove the saved voice memos.
When users click the New button, they are forwarded to the voice recording page:
Figure 2
Here users can enter the title and description of a voice memo, then click the Record button to invoke the voice recording application of the Android mobile device. When a recording is completed, users are returned to the voice recording page and can play back the recording or save it. To work with voice recording and playback in Cordova, you can install several plugins; the first two below are mandatory. Run the following commands from the voicememo directory:
  • Media Capture plugin, for media capture:
    cordova plugin add https://git-wip-us.apache.org/repos/asf/cordova-plugin-media-capture.git
  • Media plugin, for working with media:
    cordova plugin add https://git-wip-us.apache.org/repos/asf/cordova-plugin-media.git
  • Device plugin, for accessing device information:
    cordova plugin add https://git-wip-us.apache.org/repos/asf/cordova-plugin-device.git
  • Dialog plugin, for displaying native-looking messages:
    cordova plugin add https://git-wip-us.apache.org/repos/asf/cordova-plugin-dialogs.git
  • File plugin, for accessing the mobile filesystem:
    cordova plugin add https://git-wip-us.apache.org/repos/asf/cordova-plugin-file.git
Apply these plugins to your Cordova project by running the cordova build command.
At this point you're done with the preparation of the application. You can now start writing the application custom code.
Let's look at the VoiceMemo application directory hierarchy. The www directory contains the following subdirectories:
Figure3
  • css contains the custom application Cascading Style Sheet.
  • jqueryMobile contains the jQuery Mobile framework and plugins JStorage and Page Params.
  • js contains all the custom application JavaScript code. It has three subdirectories:
    • api contains the application managers (VoiceManager and CacheManager) and utility files.
    • model contains the application model. In this application we have a single object that represents a Voice item called VoiceItem.
    • vc contains the application view controllers, which include the application action handlers. Action handlers usually create model objects and populate them with UI data, pass them to the application APIs, and display the results on the application view or page.
Finally, also under www, index.html contains all of the application pages, which for this project comprise three jQuery pages:
  • Voice Listing (home page)
  • Voice Recording
  • About
The following code snippet shows the Voice Listing jQuery page code in the index.html file.

Let's walk through the code. The page has a header (the div whose data-role="header") that contains two navigation buttons to the About page and to the Voice Recording page. It has content (the div whose data-role="content") that contains the list of the voice recordings that are populated when the page is shown. Finally, it has a footer (the div whose data-role="footer") that contains a button to remove all of the voice memos from the list.
Now let's look at the page view controller JavaScript object, which includes the action handlers of the page (voiceList.js). voiceList.js is included in the index.html page, so when it is loaded by the browser the script is automatically executed to register the JavaScript event handlers for this jQuery page.
(function() {
 
    var voiceManager = VoiceManager.getInstance();
 
    $(document).on("pageinit", "#voiceList", function(e) {
     
     $("#removeAllVoices").on("tap", function() {
      e.preventDefault();
      
      voiceManager.removeAllVoices();
      
      updateVoiceList();
     });      
    });
    
    $(document).on("pageshow", "#voiceList", function(e) {
        e.preventDefault();
        
        updateVoiceList();
    });
    
    function updateVoiceList() {
        var voices = voiceManager.getVoices();

        $("#voiceListView").empty();
                
        if (jQuery.isEmptyObject(voices)) {
            $("
  • No Memos Available
  • ").appendTo("#voiceListView"); } else { for (var voice in voices) { $("
  • " + voices[voice].title + "
  • ").appendTo("#voiceListView"); } } $("#voiceListView").listview('refresh'); } })();
    The "pageinit" event handler, which is called once in the page initialization, registers the voice recordings removal tap event handler. The voice recordings removal tap event handler removes the list of voice recordings by calling the removeAllVoices() method of the VoiceManager object, then updates the voice listview.
    The "pageshow" event handler, which is called every time the page is shown – it is triggered on the "to" transition page, after the transition animation completes – updates the voice list view with the current saved voice recordings. To do this it retrieves the current saved voice recordings by calling the getVoices() method of VoiceManager, then adds the voice items to the list view so that if any voice item in the list is clicked, its ID will be passed to the voice recording page to display the voice item details.
    Note: In a jQuery Mobile list view you must call listview('refresh') to see list view updates.
    The next code snippet shows the Voice Recording page code in the index.html file:
    Home

    Record Voice

    Back

    The Voice Recording page has header and content sections. The content div contains the voice recording elements (title, description, and the voice recording file) and a Save button. Let's see the page view controller JavaScript object, which includes the action handlers of the page (recordVoice.js). Like the event handler JavaScript we just looked at, recordVoice.js is included in the index.html page and is automatically executed when it is loaded by the browser.
    (function() {
        
        var voiceManager = VoiceManager.getInstance();
        
        $(document).on("pageinit", "#voiceRecording", function(e) {
            e.preventDefault();
            
            $("#saveVoice").on("tap", function() {
                e.preventDefault();
    
                var voiceItem = new VoiceItem($("#title").val() || "Untitled", 
                                              $("#desc").val() || "", 
                                              $("#location").val() || "",
                                              $("#vid").val() || null);
                
                voiceManager.saveVoice(voiceItem);
                
                $.mobile.changePage("#voiceList");
            });        
            
            $("#recordVoice").on("tap", function() {
                e.preventDefault();
            
                var recordingCallback = {};
                
                recordingCallback.captureSuccess = handleCaptureSuccess;
                recordingCallback.captureError = handleCaptureError;
                
                voiceManager.recordVoice(recordingCallback);
             }); 
            
            $("#playVoice").on("tap", function() {
                e.preventDefault();
            
                var playCallback = {};
                
                playCallback.playSuccess = handlePlaySuccess;
                playCallback.playError = handlePlayError;
                
                voiceManager.playVoice($("#location").val(), playCallback);
            });           
            
        });
        
        $(document).on("pageshow", "#voiceRecording", function(e) {
            e.preventDefault();
            
            var voiceID = ($.mobile.pageData && $.mobile.pageData.voiceID) ? $.mobile.pageData.voiceID : null;
            var voiceItem = new VoiceItem("", "", "");
            
            if (voiceID) {
                
                //Update an existing voice
                voiceItem = voiceManager.getVoiceDetails(voiceID);
            } 
            
            populateRecordingFields(voiceItem);
            
            if (voiceItem.location.length > 0) {
                $("#playVoice").closest('.ui-btn').show();
            } else {
                $("#playVoice").closest('.ui-btn').hide();    
            }        
        });
        
        $(document).on("pagebeforehide", "#voiceRecording", function(e) {
            voiceManager.cleanUpResources();
        });
        
        function populateRecordingFields(voiceItem) {
            $("#vid").val(voiceItem.id);
            $("#title").val(voiceItem.title);
            $("#desc").val(voiceItem.desc);
            $("#location").val(voiceItem.location);
        }
        
        function handleCaptureSuccess(mediaFiles) {
            if (mediaFiles && mediaFiles[0]) {        
                currentFilePath = mediaFiles[0].fullPath;
                
                $("#location").val(currentFilePath);
                
                $("#playVoice").closest('.ui-btn').show();  
            }
        }
        
        function handleCaptureError(error) {
         displayMediaError(error);
        }  
        
        function handlePlaySuccess() {
            console.log("Voice file is played successfully ...");
        }
        
        function handlePlayError(error) {
         displayMediaError(error);
        }        
        
        function displayMediaError(error) {
            if (error.code == MediaError.MEDIA_ERR_ABORTED) {
                AppUtil.showMessage("Media aborted error");
            } else if (error.code == MediaError.MEDIA_ERR_NETWORK) {
                AppUtil.showMessage("Network error");
            } else if (error.code == MediaError.MEDIA_ERR_DECODE) {
                AppUtil.showMessage("Decode error");
            } else if (error.code ==  MediaError.MEDIA_ERR_NONE_SUPPORTED) {
                AppUtil.showMessage("Media is not supported error");
            } else {
             console.log("General Error: code = " + error.code);
            }        
        }
    })();
    
    The "pageinit" event handler registers the voice save, record, and play tap event handlers. The voice saving tap event handler saves a voice recording by calling the saveVoice() method of the VoiceManager object. The user is then forwarded to the voice listing page using $.mobile.changePage("#voiceList"). This page can be used either to create a new voice recording or update an existing one. In the second case, the voice ID is passed from the list view of the Voice Listing page and is saved in a hidden field "vid" to be used by VoiceManager for updating the existing voice recording. In the first case, the "vid" hidden field value is empty, which signals VoiceManager that this is a new voice recording and not an update to an existing one.
    The voice ID is retrieved on the "pageshow" event of the voice recording page. If there is a passed voice ID from the Voice Listing page then the code retrieves the full voice recording information using voiceManager.getVoiceDetails(voiceID) and populates the form elements using the retrieved information. Finally, in the "pageshow" handler, if there is an existing voice recording (that is, voiceItem.location.length > 0) then the program displays the Play button to allow users to play the voice recording.
    Note that the application automatically passes parameters between the two pages thanks to the jQuery Mobile Page parameters plugin, which is included on the index.html page.
    In the voice recording tap event handler, the code starts voice recording by calling voiceManager.recordVoice(recordingCallback). The recording callback contains two attributes: VoiceManager calls captureSuccess if the voice capture process succeeds, and captureError it fails. With the captureSuccess callback (handleCaptureSuccess), the full voice recording path is stored in a hidden field to be used later to play the voice. With the captureError callback (handleCaptureError), an error message is displayed.
    The voice playing tap event handler starts voice playback by calling voiceManager.playVoice(voiceLocation, playCallback). The playing callback contains two attributes: playSuccess and playError. VoiceManager calls playSuccess if voice play succeeds, and playError if it fails. The handlePlaySuccess callback prints a statement in the console log to indicate that voice play succeeded, while the handlePlayError callback displays an error message to the user.
    The jQuery Mobile framework calls the "pagebeforehide" event before a page is hidden. This event handler calls voiceManager.cleanUpResources() to stop any recording that is currently playing and to clean up the media object.
    So much for the two main pages of the application. Here's the complete code of the index.html file:
    
        
            
            
            
            
            
                  
              
                           
                                                 
                  
                              
                        
                         
            Voice Memo
        
                
               
    
    Home

    Record Voice

    Back
    Home

    About

    Back
    This sample is developed for education purposes
    Let's look at the application APIs – that is, the scripts listed at the end of index.html, which are placed before the view controller objects so they can be used by them. The following code snippet shows the VoiceManager object, which is the main API object used by the view controller objects (voiceList and recordVoice):
    var VoiceManager = (function () {     
      var instance;
     
      function createObject() {
          var cacheManager = CacheManager.getInstance();
          var VOICES_KEY = "voices";
          var voiceMap;
          var audioMedia;
          
          return {
              getVoices: function () {
                  voiceMap = cacheManager.get(VOICES_KEY) || {};
                  
                  return voiceMap;
              }, 
              getVoiceDetails: function (voiceID) {
                  voiceMap = cacheManager.get(VOICES_KEY) || {};
                  
                  return voiceMap[voiceID];
              },
              saveVoice: function (voiceItem) {  
                  voiceMap = cacheManager.get(VOICES_KEY) || {};
                  
                  voiceMap[voiceItem.id] = voiceItem;
                  
                  cacheManager.put(VOICES_KEY, voiceMap);
              }, 
              removeAllVoices: function() {
                  cacheManager.remove(VOICES_KEY);
              },
              recordVoice: function (recordingCallback) {
                  navigator.device.capture.captureAudio(recordingCallback.captureSuccess, 
                                                        recordingCallback.captureError, 
                                                        {limit: 1});
              }, 
              playVoice: function (filePath, playCallback) {
                  if (filePath) {
                   
                   //You have to make this in order to make this working on Android ...
                      filePath = filePath.replace("file:/","file://");
                      
                   this.cleanUpResources();
                      
                   audioMedia = new Media(filePath, playCallback.playSuccess, playCallback.playError);
                 
                   // Play audio
                   audioMedia.play();
                  }            
              }, 
              cleanUpResources: function() {
                  if (audioMedia) {
                   audioMedia.stop();
                      audioMedia.release();
                      audioMedia = null;
                  } 
              }
        };
      };
     
      return {
        getInstance: function () {
          if (!instance) {
              instance = createObject();
          }
     
          return instance;
        }
      }; 
    })();
    
    As you can see, VoiceManager is a singleton object that has seven methods:
    Method NameDescription
    getVoices() Get all of the saved voices from the mobile local storage using the CacheManager object.
    getVoiceDetails(voiceID) Get the voice details using the voice ID from the mobile local storage using the CacheManager object.
    saveVoice(voiceItem) Save the voice item object in the mobile local storage using the CacheManager object.
    RemoveAllVoices() Remove all the voice items from the mobile local storage using CacheManager object.
    recordVoice(recordingCallback) Use Cordova navigator.device.capture.captureAudio to capture the voice recording. Call recordingCallback.captureSuccess if the operation succeeds and recordingCallback.captureError if it fails.
    playVoice(filePath, playCallback) Uses Cordova Media object to play the voice recording, whose full location is specified in the filePath parameter. Call playCallback.playSuccess if the operation succeeds and playCallback.playError if it fails.
    CleanUpResources() Stop any playing recording and clean up media resources.
    VoiceManager uses CacheManager to persist, update, delete, and retrieve the voice items. The next code snippet shows the CacheManager object.
    var CacheManager = (function () {     
      var instance;
     
      function createObject() {   
        return {
            put: function (key, value) {
                $.jStorage.set(key, value);
            },
            get: function (key) {
             return $.jStorage.get(key);
            },
            remove: function (key) {
             return $.jStorage.deleteKey(key);
            }
        };
      };
     
      return {
        getInstance: function () {
     
          if (!instance) {
            instance = createObject();
          }
     
          return instance;
        }
      }; 
    })();
    

    CacheManager is a singleton object that uses jStorage to access local storage. CacheManager has three methods:
    Method NameDescription
    put(key, value) Add an entry in the local storage with (key, value) pairs.
    get(key) Get the entry value whose key is specified as a parameter.
    remove(key) Remove the entry whose key is specified as a parameter.
    The final code snippet shows the VoiceItem object, which represents the voice item with the attributes of title, description, location, and ID.
    var VoiceItem = function(title, desc, location, id) {
     this.title = title || "";
     this.desc = desc || "";
     this.location = location || "";
     this.id = id || "Voice_" + (new Date()).getTime();
    };
    
    VoiceItem.prototype.toString = function () {
     return "Title = " + this.title + ", " +
         "Description = " + this.desc + ", " +
         "Location = " + this.location + ", " +
         "ID = " + this.id;
    };
    
    At this point I've walked you through the application logic and what happens when users interact with each screen. Now let's see how it works. You can run the application from the command line under the voicememo directory with the command cordova emulate android. If you want to try it yourself you can download the complete code.
    After you've run the cordova build command, you should find the generated Android APK file under the platforms/android/bin directory, and you can deploy it on your Android phone or tablet.

    Conclusion

    At this point I hope you can see how to design and implement a complete native Android mobile application that uses Apache Cordova as a platform for accessing mobile native features and jQuery Mobile as a powerful mobile application framework. Armed with this knowledge, you can start developing your own native Android applications using your HTML, CSS, and JavaScript skills.