Exams :’( :’( :’(

Test in dream

Semester exams starting tomorrow. Do i need to say more?

:’(
:’( :’(
:’( :’( :’(
:’( :’( :’( :’(
:’( :’( :’( :’( :’(
:’( :’( :’( :’( :’( :’(
:’( :’( :’( :’( :’( :’( :’(
:’( :’( :’( :’( :’( :’( :’( :’(
:’( :’( :’( :’( :’( :’( :’( :’( :’(

No, that’s not enough. I guess this code should do.


#include <stdio.h>
int main() {
    while ('/'/'/') printf (":'( :'( :'(\n");
}

SSH Client…

I guess every GNU/Linux user must have sshed from one comp to another sometime or the other. We have different servers for various purposes in our college and ssh is a common thing. Most of the time, we end up typing some thing like

ssh -XCYP hari@spider.nitt.edu

Though not many knows what these options stands for, life will become very simple if you try to understand the command and create a configuration file for ssh and use it when you ssh from one box to another.

The ssh client takes the parameters from three places in the following order.

  • Command line options
  • User-specific configuration file
  • System-wide configuration file

The command line options are the one you specify when connect to other system using the ssh command. For example ssh -X specifies that X11 forwarding should be enabled.

The User specific configuration file is ~/.ssh/config.

The System wide configuration file is /etc/ssh/ssh_config. Note that the configuration file for ssh server (sshd_server) is also found in this folder. The file ssh_config is the configuration file for the ssh client while sshd_config is the configuration file for the server.

Any configuration value is only changed the first time it is set. So if you run the ssh command with X option, X11 will be forwarded no matter what values ~/.ssh/config and /etc/ssh/ssh_config file has. The values are parsed in the order mentioned above.

The User config file gives users the choices to configure ssh client when you ssh often. A config file is explained with an example below.

Host codelabs
    hostname codelabs.nitt.edu
    user hari
    ForwardX11 yes
    port 22

In the above example, very few options were added to make the config file simple. I guess that will be enough for everyone.

The config file has Host blocks. The properties which come under a host are set when you connect to the given to any host. In this example i have used the host machine called codelabs.nitt.edu. You can also specify * to apply to any host or 10.1.39.* to apply to all machines which comes under 10.1.39. series. Remember that the configuration values are set only once. So if * appears in the beginning of your config file, then the configurations which come below that may not be used by the ssh client. For example consider the following configuration file.
Host *.edu
    ForwardX11 yes

Now in the above case when you connect to any server which ends with .edu (spider.nitt.edu, codelabs.nitt.edu …) then the X is forwarded. But if you want to diasable X11 forwarding for spider.nitt.edu, then the following won’ t work

Host *.edu
    ForwardX11 yes
Host spider
    hostname spider.nitt.edu
    ForwardX11 no

This is because in the first block, ForwardX11 is set to yes for all hosts ending with .edu and then it can’t be changed. The correct way to block X11 forwarding for spider is to have a config file as shown below.
Host spider
    hostname spider.nitt.edu
    ForwardX11 no
Host *.edu
    ForwardX11 yes

You can tweak almost everything you need from the public key file, port, number of passwords prompts, compression, ciphers, compression level, user, tunnel, tunnel device and lots more. :) Happy sshing :-)

LDTP Editor

Want to use LDTP to test your application? Or do you want to automate the actions you do often? Or are you a GNU/Linux user who want to show “magic” to your friends by recording your actions and playing them back? You can use LDTP for this. But one small issue with LDTP is that you should know the LDTP Python API to write any test suite. But with the new LDTP Editor, this makes your job really simple. A screenshot of the LDTP Editor is shown below.

 

LDTP Editor

 

This is a simple HOWTO for recording and playing back the recorded script.

Installing LDTP.

  • Download the lastest LDTP source code from http://people.freedesktop.org/~nagappan/ldtp-0.9.2.tar.gz.
  • Uncompress the file.
  • Compile the code using ./configure and make
  • If you don’t have the access to install softwares, run the ldtpeditor file in the python folder
  • If you have access to install softwares, then run “make install”

Note:: After installing LDTP Editor, i when i tried to run ldtpeditor, got an error saying

hari@hari-laptop:~/ldtp/ldtp-0.9.2$ ldtpeditor
(ldtpeditor:11130): libglade-WARNING **: could not find glade file '/usr/share/local/ldtp/glade/ldtpeditor.glade'
Glade file not found

The ldtpeditor.glade file is present in the python folder. I got this error because i compiled the code as ./configure. If i had done it as ‘./configure –prefix=/usr’, then i wouldn’t have got this error. Anyway i copied the file manually to that folder.

hari@hari-laptop:~/ldtp/ldtp-0.9.2$ sudo mkdir -p /usr/share/local/ldtp/glade/
hari@hari-laptop:~/ldtp/ldtp-0.9.2$ sudo cp python/ldtpeditor.glade /usr/share/local/ldtp/glade/
hari@hari-laptop:~/ldtp/ldtp-0.9.2$ ldtpeditor

After that when i ran ldtpeditor, it ran without any issues.

Recording using LDTP Editor

For this let us consider recording the actions performed in gcalctool.

  • First make sure Assistive Technology is enabled in your desktop. If you are not sure about this, open gnome-control-center and in that open Assistive Technology Preferences. You should have Enable Assistive Technologies checked to use LDTP.
  • If you are enabling Assistive Technology only now, logout and login again.
  • Run ldtpeditor and gcalctool.
  • Make sure both you have enabled ‘Always on Top’ or both the applications and both the window doesn’t overlap with each other.
  • Click the Start button the LDTP Editor. All actions performed after this are recorded.
  • Perform actions in the gcalctool. Check out this video to see the actions i recored in my computer .
  • After you’re done with the actions in the gcalctool, click the Stop button in the LDTP Editor.
  • You can see that the ‘Recorded Code’ tab is updated with code as when you perform actions in gcalctool.
  • Click the convert button in the LDTP Editor. You’ll see that the Generated LDTP Code and Generated LDTP XML tabs are filled with generated code.
  • The Play button is not working now. I wrote the patch for that yesterday night ;-).
  • Save the contents of the ‘Generated LDTP Code’ into a python file (for ex frisco.py) . Note that if the file name you specify already exists, then it OVERWRITES the filename without any warning.
  • Then run hari@hari-laptop:~$ python frisco.py
  • The actions you performed while recording will be played back again :-)

Currently the Play button in the LDTP Editor is not enabled. But you can make it work by applying the patch mentioned below. I guess this patch will be added to LDTP Editor in a week or so. So check the ChangeLog file before applying the patch.

LDTP Editor Preferences

Using the LDTP Prefereces, you can control what all actions you can control. A brief summary about the options given in the Preferences window.

  • Listen key events
    This option is not yet implemented. Checking/Unchecking this doesn’t make any difference now.
  • Listen mouse events
    This option is not yet implemented. Checking/Unchecking this doesn’t make any difference now.
  • Generate LDTP Code
    Only when if this option is enabled, Convert will generated to LDTP code in the ‘Generated LDTP Code’ tab. This is enabled by default when you run LDTP Editor.
  • Generate Data XML
    If this option is enabled, the LDTP Editor will generate data XML for the actions you perform.
  • Generate keyboard events code
    Generates code for the keyboard events you performed during the recording session.
  • Generate wait time code
    Calculates the delay one takes between each action during the recording session and generates code so that similar time delay is generated while play back.
  • Generate Memory / CPU statistics.
    The code to generate Memory and CPU statistics will be generated. You need to install pystatgrab and libstatgrab packages.

Patching to make the Run button work

  • Copy this patch file to your ldtp folder.
  • Runhari@hari-laptop:~/ldtp/ldtp-0.9.2$ cd ldtp-0.9.2
    hari@hari-laptop:~/ldtp/ldtp-0.9.2$ patch -p0 < ldtpeditor_runbutton.patch
  • Compile the code again and run ldtpeditor. This time after you Convert the Code, you can Run the code from the LDTP Editor. :-)

Note:: The generated code had many unwanted waittillguiexist. I saw waittillguiexist(“dlg0″) in many places. If your playback is stopped because of this, remove that before running the scripts.
Sometime the resource will go high as the application map info is collected from the application, so no need to worry.

If you find any issues regarding LDTP Editor, report it to ldtp-dev@lists.freedesktop.org or nagappan@gmail.com or sp2hari@gmail.com

All patches are welcome. :-)

Gedit Plugin

In this article, we’ll see how to write plugins for Gedit. Since plugin development is easy in Python, I’m planning to explain this using Python.

When the first caveman programmer chiseled the first program on the walls of the first cave computer, it was program to paint the string “Hello, world” in Antelope pictures. Roman programming textbooks began with the “Salut, Mundi” program. I don’t know what happens to people who break with this tradition, but I think it’s safer not to find out. So we’ll also deal only with HelloWorld in our first plugin.

This plugin is going to do two things. One is to add the string “HelloWorld ” at the cursor position. The next is to convert all “Hello” in the program to “World”. A neat tutorial to write python plugins is can be found at live.gnome.org. Though you can skip that tutorial for now since I’ve explained most of the things one need to know to write this plugin. But i suggest you read that tutorial soon.

Some of the paths you need to know for writing a plugin.

Path Details
/usr/lib/gedit-2/plugins/ System-wide plugins directory
~/.gnome2/gedit/plugins/ User Plugins directory
/usr/share/gedit-2/ Data needed for system-wide plugins.
~/.gconf/apps/gedit-2/ Gedit configuration.
Can be modified using gconf-editor.
/usr/share/gtk-doc/html/gedit gedit Reference Manual

Every python plugin needs at least two files. Let us name our plugin as “frisco”. So we should have two files namely, frisco.gedit-plugin and frisco.py

Let’s start with the contents of frisco.gedit-plugin.
[Gedit Plugin]
Loader=python
Module=frisco
IAge=2
Name=HelloWord
Description=A HelloWorld plugin for Gedit.
Authors=Harishankaran K <sp2hari@gmail.com>
Copyright=Copyright © sp2hari
Website=http://www.sp2hari.com

The contents of this file is almost same for all the plugins. The module, name and description will change for different plugins. If your plugin has the python file frisco.py, then the modulde is frisco.

Note :: We don’t specify the extension in the module name.

The .gedit-plugin file is done now. Next let’s move on to frisco.py.

#!/usr/bin/python

import gedit

class HelloWorldPlugin(gedit.Plugin):
    def __init__(self):
        print "Plugin loaded"

    def activate(self, window):
        print "Plugin activated"

    def deactivate(self, window):
        print "Plugin deactivated"

    def update_ui(self, window):
        pass

This file, frisco.py derives one class from the Gedit.plugin and defines activate, deactivate and update_ui. activate() is called when the plugin is activated. Similarly deactivate() is called when the plugin is deactivated. We will check how our plugin works now.

Run gedit from terminal and check whether your plugin is listed in the plugins list.

You can see that the details you provided in frisco.gedit-plugin can be viewed in the About Plugin and the Credits.

Now enable the plugin and look at shell prompt. You will see the print statements being execute when we activate and deactivate the plugin. :). Wow, our first plugin is ready to add more spice. :-)

Note:: If you get an error saying

WARNING **: Cannot load Python plugin ‘HelloWord’ since file ‘frisco’ cannot be read.

WARNING **: Error activating plugin ‘HelloWord’

Then the file frisco.py is not present in your plugins directory or the python file has an error. Fix the code and try again. You will get the output as shown below.

Frisco Plugin

 

The output for the above plugin in the shell when the plugin is activated and deactivated for a few times will be like


hari@hari-laptop:~$ gedit
Plugin loaded
Plugin activated
Plugin deactivated
Plugin activated
Plugin deactivated
Plugin activated
Plugin deactivated
Plugin activated

Now we have to add functionality to this plugin. A good practice while coding plugin is the create a separate ‘Helper’ Class which will control the window and do all useful actions. It’ll be called once in the main class.

So we will modify the HelloWorldPlugin class as follows

#!/usr/bin/python

import gedit

class HelloWorld(gedit.Plugin):
    def __init__(self):
        gedit.Plugin.__init__(self)
        self._instances = {}

    def activate(self, window):
        self._instances[window] = HelloWorldHelper(self, window)

    def deactivate(self, window):
        self._instances[window].deactivate()
        del self._instances[window]

    def update_ui(self, window):
        self._instances[window].update_ui()

The code for the HelloWorldHelper class will be



class HelloWorldHelper:
    def __init__(self, plugin, window):
        print "Plugin created for", window
        self._window = window
        self._plugin = plugin

    def deactivate(self):
        print "Plugin stopped for", self._window
        self._window = None
        self._plugin = None

    def update_ui(self):
        # Called whenever the window has been updated (active tab
        # changed, etc.)
        print "Plugin update for", self._window

When you run gedit from terminal, now, it will print more details like the Gedit window object. A sample run for the above code is given below

hari@hari-laptop:~$ gedit
Plugin created for <gedit.Window object at 0x8521504 (GeditWindow at 0x816e000)>
Plugin update for <gedit.Window object at 0x8521504 (GeditWindow at 0x816e000)>
Plugin update for <gedit.Window object at 0x8521504 (GeditWindow at 0x816e000)>
Plugin stopped for <gedit.Window object at 0x8521504 (GeditWindow at 0x816e000)>
Plugin created for <gedit.Window object at 0x8521504 (GeditWindow at 0x816e000)>
Plugin stopped for <gedit.Window object at 0x8521504 (GeditWindow at 0x816e000)>
Plugin created for <gedit.Window object at 0x8521504 (GeditWindow at 0x816e000)>
Plugin stopped for <gedit.Window object at 0x8521504 (GeditWindow at 0x816e000)>
Plugin created for <gedit.Window object at 0x8521504 (GeditWindow at 0x816e000)>

Hereafter there is no need to change the HelloWorldPlugin class. So we’ll work only on the HelloWorldHelper class. We will define a ui_str which will enable us to add a menuitem in the Tools menu.

We will define the ui_str as follows

import gtk 

ui_str = """<ui>
  <menubar name="MenuBar">
    <menu name="ToolsMenu" action="Tools">
      <placeholder name="ToolsOps_2">
        <menuitem name="Insert HelloWorld" action="InsertHelloWorld"/>
        <menuitem name="Change Hello to World" action="ChangeHellotoWorld"/>
      </placeholder>
    </menu>
  </menubar>
</ui>
"""

The activate, deactivate and update ui functions for the HelloWorldHelper Class are modified as follows

    def __init__(self, plugin, window):
        self._window = window
        self._plugin = plugin

        # Insert menu items
        self._insert_menu()

    def deactivate(self):
        self._window = None
        self._plugin = None

        self._remove_menu()
    def update_ui(self):
        # Called whenever the window has been updated (active tab
        # changed, etc.)
        self._action_group.set_sensitive(self._window.get_active_document() != None)

Now we need to write the method insert_menu which will register the callbacks for the actions like inserting hello world and changing hello to world.
The insert_menu function is defined as followed. If you know gtk or pygtk then it’ll be easy for you to understand that code. I’ll advise you to read the basics of pygtk if you plan to write your own plugin.

    def _insert_menu(self):
        # Get the GtkUIManager
        manager = self._window.get_ui_manager()

        # Create a new action group
        self._action_group = gtk.ActionGroup("ExamplePyPluginActions")
        self._action_group.add_actions([("InsertHelloWorld", None, _("Insert HelloWorld"),
                                         None, _("Insert HelloWorld"),
                                         self._inserthelloworld)])
        self._action_group.add_actions([("ChangeHellotoWorld", None, _("Change Hello to World"),
                                         None, _("Change Hello to World"),
                                         self._hellotoworld)])

        # Insert the action group
        manager.insert_action_group(self._action_group, -1)

        # Merge the UI
        self._ui_id = manager.add_ui_from_string(ui_str)

    def _remove_menu(self):
        # Get the GtkUIManager
        manager = self._window.get_ui_manager()

        # Remove the ui
        manager.remove_ui(self._ui_id)

        # Remove the action group
        manager.remove_action_group(self._action_group)

        # Make sure the manager updates
        manager.ensure_update()

Now we are all set the two final functions which will do the required actions. These are defined in the helper class as follows

    def _hellotoworld(self, action):
        doc = self._window.get_active_document();
        if not doc:
            return
        doc.replace_all("Hello", "World", 0);

    def _inserthelloworld(self, action):
        doc = self._window.get_active_document();
        if not doc:
            print "Noe";
            return;
        doc.insert_at_cursor("HelloWorld")

Well, that’s all. Your first plugin is up and running now :-) :-)

The python files used in this example can be downloaded here.