Correction of Attitudes

Here is a question from Quora,

What are some of the most mind-blowing facts?

And two of the answers make me think.

1. Life < 900 Months

“Your lifespan is likely about 900 months. That’s a 30×30 rectangle of boxes, if you care to draw them. ”

This is a scaring fact. There’re times I imagine myself facing death, and I know deep inside, I will be totally freaked out.

And life is just about 900 months, and I have spent 1/3 of it. 600 months, that’s all I got. I’ve got to be serious about the time I have, and how I spent it. Smile

I wish the day I have to face death, I am smiling with a peaceful heart.

2. Confined Environment is Better for Great Software

“The guidance computer from the Apollo 11 mission ran at 1.024 MHz, about 1/6th of the processing power of a TI-83 calculator, and it took human beings to the moon.”

I’ve got to say, the software used at Apollo 11 must be great!

The software industry has become complicated, fancy and distractive. There’re simply too many platforms, programming languages, development tools, and APIs. We software engineers are getting used to search, copy, paste, and calling yet another set of API to develop software.

Well, we may develop software applications for years, but never know how things really work, buried in new tools, platforms, etc. That’s the success of the big companies providing platforms and tools, but we failed ourselves to become real software engineers and probably lose interest for software along the way.

The computer doesn’t have to be powerful than a modern calculator get human beings on the moon.  Great software engineers doesn’t rely on too many fancy APIs for great software.

I’ve got to learn more low level stuff! And read more, think more, code less!

Depth-First Graph Traversal using Stack — a C Implementation

There’re two common ways of visiting all nodes of a graph, depth-first search and breadth-first search. These two graph traversal approaches relate to two popular data structures, stack and queue respectively. (One can also do it in a recursive manner. It’s more intuitive but less efficient.)

This post covers depth-first search with a stack data structure. The algorithm expressed in pseudo code is as below,

DFS (Graph, root):
   create a stack S
   push root node to S
   while S is not empty:
       pop an itme v from S
       mark the item v as visited
       for each node w that is directed from v:
           if w is not visited:
               push w to S

The first step of the implementation is to implement a stack. The stack implemented below has the basic functions like push, pop, ifEmpty, etc.

1. Stack Implementation

The header file stack.h, defines the data structures used in Stack and Graph.

#include <stdio.h>
#include <stdlib.h>
typedef struct Point {
   int h;
   int w;
} Point;
typedef struct GraphNode {
   struct Point pvalue;
   struct GraphNode* left;
   struct GraphNode* right;
} GraphNode;
typedef struct StackElement {
   struct GraphNode value;
   struct StackElement *up;
   struct StackElement *down;
} StackElement;
typedef struct Stack {
   struct StackElement* topP;
   struct StackElement* bottomP;
} Stack;
void initStack(struct Stack *s);
void push(struct Stack *s, struct GraphNode _value);
void pop(struct Stack *s);
struct GraphNode top(struct Stack *s);
int ifEmpty(struct Stack *s);

The actual implementation stack.c

/**
a C stack implementation using linked list
*/
#include "stack.h"
/*initialize the stack*/
void initStack(struct Stack *s) {
   s->topP = NULL;
   s->bottomP = NULL;
}
/*add an element to the top of the stack*/
void push(struct Stack *s, struct GraphNode _value) {
   //allocate a new StackElement for _value
   StackElement *newElement;
   newElement = (StackElement*) malloc(sizeof(StackElement));
   newElement->value = _value;
   newElement->up = NULL;
   newElement->down = NULL;
   if (s->topP == NULL) {
        //first element
       s->topP = newElement;
        s->bottomP = newElement;
   } else {
        //push it to the top
        newElement->down = s->topP;
        s->topP = newElement;
   }
}
/*delete the top element from the stack*/
void pop(struct Stack *s) {
   StackElement *element;
   if (s->topP == NULL) {
        //empty stack
        return;
   } else {
        element = s->topP;
        s->topP = element->down;
        if (s->topP != NULL)
             s->topP->up = NULL;
        free(element);
   }
}
/*get the top value of the stack, but don't delete it*/
struct GraphNode top(struct Stack *s) {
   return s->topP->value;
}
/*check if the stack is empty*/
int ifEmpty(struct Stack *s) {
   return (s->topP == NULL ? 1:0);
}

Note that the top() function above returns the top element of the stack and the pop() function deletes the top element from the stack. Some stack implementations has the pop() function does both return and delete. But I personally think separating them is more convenient as sometimes you just want to take a look at the stack but not delete anything from it.

The Stack above will take input element of GraphNode type, but you’re free to modify it to fit your needs.

2. The Depth-First Graph Traversal

For simplicity, an example of visiting all nodes of a binary tree is given below. The tree structure is included in the comment of the source code file dfs.c,

#include <stdio.h>
#include <stdlib.h>
#include "stack.h"
/* a simple graph (binary tree)
         (0,    3)   <– root node
          /     
      (1, 2)    (1,4)
       /       /   
   (2,1) (2,2) (2,3) (2,5)
*/
typedef struct Graph {
   struct GraphNode* root;
} Graph;
struct GraphNode initNode(int _h, int _w) {
   struct GraphNode node;
   node.pvalue.h = _h;
   node.pvalue.w = _w;
   node.left = NULL;
   node.right = NULL;
   return node;
}
int main() {
   struct Graph g;
   struct GraphNode currentNode;
   /*read in the graph from top to bottom*/
   g.root = (GraphNode*) malloc(sizeof(GraphNode));
   *g.root = initNode(0, 3);
   //level 2 nodes
   g.root->left = (GraphNode*) malloc(sizeof(GraphNode));
   *g.root->left = initNode(1, 2);
   g.root->right = (GraphNode*) malloc(sizeof(GraphNode));
   *g.root->right = initNode(1, 4);
   //level 3 nodes
   (*g.root->left).left = (GraphNode*) malloc(sizeof(GraphNode));
   *(*g.root->left).left = initNode(2, 1);
   (*g.root->left).right = (GraphNode*) malloc(sizeof(GraphNode));
   *(*g.root->left).right = initNode(2, 2);
   (*g.root->right).left = (GraphNode*) malloc(sizeof(GraphNode));
   *(*g.root->right).left = initNode(2, 3);
   (*g.root->right).right = (GraphNode*) malloc(sizeof(GraphNode));
   *(*g.root->right).right = initNode(2, 5);
   /*DFS traversal*/
   Stack s;
   initStack(&s);
   push(&s, *g.root);
   while (!ifEmpty(&s)) {
       currentNode = top(&s);
        pop(&s);
        //mark as visited, here we simply print the graph node value out
       printf("(%d, %d)n", currentNode.pvalue.h, currentNode.pvalue.w);
        //at most two children, left and right. As the binary tree is acyclic,
        // both nodes should not be visited yet, for cyclic graphs, 
        //one need additional methods to check if the nodes is visited or not before push
       if (currentNode.left != NULL) {
           push(&s, *currentNode.left);
       } 
       if (currentNode.right != NULL) {
           push(&s, *currentNode.right);
        } 
   }
   return 0;
}

3. Output

To compile the code in Linux, type the following command,

gcc stack.c dfs.c -o dfs

Then run the binary dfs,

        ./dfs

The output we’ll get is,

(0, 3)

(1, 4)

(2, 5)

(2, 3)

(1, 2)

(2, 2)

(2, 1)

which corresponds to the expected nodes visiting order in depth-first search. As we push the left node first, the traversal is from right to left.

Breadth-First Graph Traversal using Queue – a C Implementation

There’re two common ways of visiting all nodes of a graph, depth-first search and breadth-first search. These two graph traversal approaches relate to two popular data structures, stack and queue respectively. (One can also do it in a recursive manner. It’s more intuitive but less efficient.)

This post covers breadth-first search with a queue data structure. The algorithm expressed in pseudo code is as below,

BFS (Graph, root):
    create a queue Q
    enqueue root node to Q
    while Q is not empty:
        dequeue an itme v from Q
        mark the item v as visited
        for each node w that is directed from v:
            if w is not visited:
                enqueue w to Q

The first step of the implementation is to implement a queue. The queue implemented below has the basic functions like enqueue, dequeue, ifEmpty, etc.

1. A Queue Implementation

The header file queue.h, defines the data structures used in Queue and Graph.

#include <stdio.h>
#include <stdlib.h>
typedef struct Point {
   int h;
   int w;
} Point;
typedef struct GraphNode {
   struct Point pvalue;
   struct GraphNode* left;
   struct GraphNode* right;
} GraphNode;
typedef struct QueueElement {
   struct GraphNode value;
   struct QueueElement *next;
} QueueElement;
typedef struct Queue {
   struct QueueElement* head;
   struct QueueElement* tail;
} Queue;
void initQueue(struct Queue *q);
void enqueue(struct Queue *q, struct GraphNode _value);
void dequeue(struct Queue *q);
struct GraphNode front(struct Queue *q);
int ifEmpty(struct Queue *q);

The source file queue.c,

/**
a C queue implementation using linked list
*/
#include "queue.h"
/*initialize the queue*/
void initQueue(struct Queue *q) {
   q->head = NULL;
   q->tail = NULL;
}
/*insert an element to the end of the queue*/
void enqueue(struct Queue *q, struct GraphNode _value) {
   //allocate a new QeueuElement for _value
   QueueElement *newElement;
   newElement = (QueueElement*) malloc(sizeof(QueueElement));
   newElement->value = _value;
   newElement->next = NULL;
   if (q->head == NULL) {
        //first element
       q->head = newElement;
       q->tail = newElement;
   } else {
        //put it to the tail
        q->tail->next = newElement;
        q->tail = newElement;
   }
}
/*delete the first element from the queue*/
void dequeue(struct Queue *q) {
   QueueElement *element;
   if (q->head == NULL) {
        //empty queue
        return;
   } else {
        element = q->head;
        q->head = q->head->next;
        free(element);
   }
}
/*get the front value of the queue, but don't delete it*/
struct GraphNode front(struct Queue *q) {
   return q->head->value;
}
/*check if the queue is empty*/
int ifEmpty(struct Queue *q) {
   return (q->head == NULL ? 1:0);
}

Note that the front() function above returns the first element of the queue and the dequeue() function deletes the first element from the queue. Some queue implementations has the dequeue() function does both return and delete. But I personally think separating them is more convenient as sometimes you just want to take a look at the queue but not delete anything from it.

The Queue above will take input element of GraphNode type, but you’re free to modify it to fit your needs.

2. The Breadth-First Graph Traversal

For simplicity, an example of visiting all nodes of a binary tree is given below. The tree structure is included in the comment of the source code file bfs.c,

#include <stdio.h>
#include <stdlib.h>
#include "queue.h"
/* a simple graph (binary tree)
         (0,    3)   <– root node
          /     
      (1, 2)    (1,4)
       /       /   
   (2,1) (2,2) (2,3) (2,5)
*/
typedef struct Graph {
   struct GraphNode* root;
} Graph;
struct GraphNode initNode(int _h, int _w) {
   struct GraphNode node;
   node.pvalue.h = _h;
   node.pvalue.w = _w;
   node.left = NULL;
   node.right = NULL;
   return node;
}
int main() {
   struct Graph g;
   struct GraphNode currentNode;
   /*read in the graph from top to bottom*/
   g.root = (GraphNode*) malloc(sizeof(GraphNode));
   *g.root = initNode(0, 3);
   //level 2 nodes
   g.root->left = (GraphNode*) malloc(sizeof(GraphNode));
   *g.root->left = initNode(1, 2);
   g.root->right = (GraphNode*) malloc(sizeof(GraphNode));
   *g.root->right = initNode(1, 4);
   //level 3 nodes
   (*g.root->left).left = (GraphNode*) malloc(sizeof(GraphNode));
   *(*g.root->left).left = initNode(2, 1);
   (*g.root->left).right = (GraphNode*) malloc(sizeof(GraphNode));
   *(*g.root->left).right = initNode(2, 2);
   (*g.root->right).left = (GraphNode*) malloc(sizeof(GraphNode));
   *(*g.root->right).left = initNode(2, 3);
   (*g.root->right).right = (GraphNode*) malloc(sizeof(GraphNode));
   *(*g.root->right).right = initNode(2, 5);
   /*BFS traversal*/
   Queue q;
   initQueue(&q);
   enqueue(&q, *g.root);
   while (!ifEmpty(&q)) {
       currentNode = front(&q);
       //dequeue(&q); //you can either put dequeue here or at the end of while
        //mark as visited, here we simply print the graph node value out
       printf("(%d, %d)n", currentNode.pvalue.h, currentNode.pvalue.w);
        //at most two children, left and right. As the binary tree is acyclic,
        // both nodes should not be visited yet, for cyclic graphs, 
        //one need additional methods to check if the nodes is visited or not before enqueue
       if (currentNode.left != NULL) {
           enqueue(&q, *currentNode.left);
       } 
       if (currentNode.right != NULL) {
           enqueue(&q, *currentNode.right);
        } 
        dequeue(&q);
   }
   return 0;
}

3. Output

To compile the code in Linux, type the following command,

gcc queue.c bfs.c -o bfs

Then run the binary bfs,

        ./bfs

The output we’ll get is,

(0, 3)

(1, 2)

(1, 4)

(2, 1)

(2, 2)

(2, 3)

(2, 5)

which corresponds to the expected nodes visiting order in breadth-first search, level 0 node, follows by level 1 nodes, and finally level 2 nodes.

 

Is this really a Problem needs to be Solved?

I’m in a rush to a project deadline, and encountered a problem. I thought it would be easy to solve, and started to work on it without a second thought.

It turns out the problem is not so simple. It’s difficult, in fact. I spent over 10 hours trying to figure out the problem. At last, I got a workaround and started to program it. In the middle of it, I took a rest, and after I came back, I suddenly realized that this problem needs not to be solved. It won’t cause any difference in later part of the processing.

I am a little pissed off and also want to laugh at myself. I’ve spent over 10 hours to solve a problem that doesn’t need to be solved? Certainly a good way to let time pass away. Winking smile

So, lesson learned. Alwasy ask yourself: is this problem really needs to be solved, before you start to work on it.

Work Time is Still My Time

Well, most of us work to get paid. As a software developer who is interested in software development and programming, it’s not bad that my work has lots of programming stuff. But work is not all fun, often I’m requested to work on something that I’m not so keen on. Frankly speaking, even programming are not all fun.

So sometimes I just get lazy at work, and I tends to act slow. And the idea inside my mind tells me, “hey, get some rest at work, and save the energy for after-work time”. But the ironic thing is I have everything I need to do several things I do after work. I read stuff online after-work, I study for my master degree after work, I think some stuff after work. Actually, all I need to do these things are Internet connection, en, ya, that’s all I need.

If I think this again, this is not logical. I am free to arrange my time at work, I can finish the task assigned to me fast, and I have everything I need to do things I do after-work, so why not make use of the time more efficiently? I can finish the work well and do some stuff I do after-work.

Well, I need to change the mindset, I am not working to get paid. I am working to practice my development skills and write good software solution. Work time is still my time, and I should be getting the same value from work time as the time I spend on improving my skills after work.

Ubuntu Package Management – Usage of a Few Cases

Ubuntu Linux comes with a good package management system, apt. Once you familiar with it, it is really easy to use.

There’re several front-end interface to this package management system, including aptitude, the command line interface, synaptic, the GUI application for X Window System and apt-get, the command line package handling utility.

Update/Upgrade:

  1. Install All Latest Updates
    apt-get update     //refresh available updates
    apt-get upgrade   //upgrade all packages
  2. Install a New Version of Ubuntu
    apt-get update
    apt-get dist-upgrade

Install/Uninstall New Software Packages

  1. If you know the package nameFor installation, enter the following command,
    sudo apt-get install  <pkg>

    For uninstallation, enter the following command,

    sudo apt-get purge  <pkg>

    or

    sudo apt-get remove <pkg>
  2. If you don’t know the package name exactly, use the aptitude search function,
    sudo aptitude search <whatever-what-know>

    The system will return a list of packages, then you can use commands mentioned above to install the package you want.

  3. If there’re broken packages in your system, fix the broken packages by entering the command,
    sudo apt-get -f install

 

Get the Source Code for Compiling the Software Package

  1. Get the package source code by entering the following command,
    sudo apt-get source <pkg>
  2. Get other packages needed to build this package
    sudo apt-get build-dep <pkg>
  3. If you haven’t installed the build tools yet, install them by entering the command,
    sudo apt-get build-essential
  4. follow the compilation guideline of the package to compile the package. Normally what you’ll need to do is, (in case you don’t have permission for any steps below, add sudo in front)
    cd <pkg-directory>
    ./configure
    make
    make install

 

Download without Installing Software Package

  1. Sometimes you might just want to download the package and pass it to your friend who doesn’t have a Internet connection,
    sudo aptitude download <pkg>

The .deb installation package will be downloaded to your current directory.

 

How to Set Programs Starting Automatically–Part 2. After System Initialization

This is the second part of the setting programs starting automatically. Part 1 start programs at system initialization is here.

Method 2: Add your Program to Profiles and bashrc

1. Profiles

Right before user is logged into the system, there’re certain settings configured. The system wide configuration is done through the script /ect/profile.

And there is also a profile for each user at home directory. There’re several possible names for it. The system will search for .bash_profile first, if not found, it will look for .bash_login, if not found also, it will finally use .profile.

If you want to execute some programs/scripts right before user is logged in, these are the files you should edit.

2. Bashrc

After user is logged in, if your system doesn’t have a UI environment, the text terminal should have been started already. The script /etc/bash.bashrc (for all users) and ~/.bashrc (for a specific user) are executed.

If you want to execute some programs/scripts every time you start up a text terminal, you can put them into these files.

Method 3: Add your Program to Gnome Start Up Programs

In Ubuntu (I guess the same in other gnome desktop system), you can set Startup Applications under System=>Preferences=>Startup Applications.

You can add your program by specifying the name and command.screenshot1

Once you add a program, a configuration is created under ~/.config/autostart/ directory. For example, my Ubuntu system has Dropbox installed and it’s configured to start up when Gnome starts up. The configuration file is located at ~/.config/autostart/dropbox.desktop

Method 4: Use cron to Start your Program

cron is utility to execute scheduled commands, like task scheduler in Windows. Although it’s mainly used to execute scheduled task, you can also make use of it to auto start up your programs/scripts.

The idea is simple. Add a cron entry to run a wrapper script every minute. In the wrapper script, check if the program/scripts is already started. If not, start the program/script, otherwise, do nothing.

1. To configure a cron task, use

sudo crontab -e

Add the line to the configuration file,

* * * * * /home/xxx/xxx/autostart.sh

You can check your configuraiton by entering

sudo crontab -l

2. Write the autostart.sh script similar to the sample below,

#!/bin/bash

if [ -z "$(pgrep myprogram)" ]

then

/home/xx/xx/myprogram &

fi

The & is added to run the program at background.

If you want to learn more details about cron, you can refer to here.

How to Set Programs Starting Automatically–Part 1 System Initialization

There’re lots of ways to start up a program or script when a Linux system boots up. Not all of them work for all types of applications. This article covers several methods you can configure your program to start up automatically at system boot up. It’s based on Ubuntu Linux, but I think they should apply to many other Linux distributions too.

Method 1: Add your Program in the System Initialization

When a Linux system is powered on, it will first run the program in BIOS. The BIOS locates the boot device and then the Linux kernel starts to boot up.

The kernel will mount the root file system, and run /sbin/init program, which normally has a process ID of 1. You can use ps -ax command to check.

1. /etc/init.d/rcS

The /sbin/init program will run script /etc/init.d/rcS, which in turn calls all S??* scripts in /etc/rcS.d/ directory in numerical/alphabetical order. Using ls -l command shows the content of my Ubuntu system as below,

-rw-r--r-- 1 root root 447 2009-09-08 02:58 README

lrwxrwxrwx 1 root root 24 2010-11-24 18:16 S06keyboard-setup -> ../init.d/keyboard-setup

lrwxrwxrwx 1 root root 21 2010-11-24 18:16 S13pcmciautils -> ../init.d/pcmciautils

lrwxrwxrwx 1 root root 16 2010-11-24 18:16 S25brltty -> ../init.d/brltty

lrwxrwxrwx 1 root root 18 2010-11-24 18:16 S37apparmor -> ../init.d/apparmor

lrwxrwxrwx 1 root root 23 2010-11-24 18:16 S49console-setup -> ../init.d/console-setup

lrwxrwxrwx 1 root root 17 2010-11-24 18:16 S55urandom -> ../init.d/urandom

lrwxrwxrwx 1 root root 21 2010-12-02 10:47 S65firestarter -> ../init.d/firestarter

lrwxrwxrwx 1 root root 24 2010-11-24 18:16 S70screen-cleanup -> ../init.d/screen-cleanup

lrwxrwxrwx 1 root root 20 2010-11-24 18:16 S70x11-common -> ../init.d/x11-common

lrwxrwxrwx 1 root root 19 2011-04-05 10:50 S75policykit -> ../init.d/policykit

2. /etc/rc2.d

After rcS, the system will switch to default run level. The default run level is defined in /etc/inittab. If not found, it will refer to /etc/init/rc-sysinit.conf file.

Run levels refers to a mode of operation, it’s used to configure a selected group of process to run. There’re 7 of them, from 0 to 6. A very brief summary is given below,

0 halt

1 single user

2-4 user defined

5 X11

6 Reboot

Once the default run level is found, the initialization will execute all the scripts under /etc/rc*.d, where * is the default run level.

In my Ubuntu system, there is no /etc/inittab file and the default level is set to 2 in /etc/init/rc-sysinit.conf file, so the initialization will execute the scripts under /etc/rc2.d/ directory. Use ls -l shows the following in my /etc/rc2.d/ directory,

lrwxrwxrwx 1 root root 13 2011-02-21 15:45 K50ntp -> ../init.d/ntp

-rw-r--r-- 1 root root 677 2009-11-10 17:44 README

lrwxrwxrwx 1 root root 15 2011-03-01 18:09 S00kdump -> ../init.d/kdump

lrwxrwxrwx 1 root root 18 2011-03-11 12:36 S10sysklogd -> ../init.d/sysklogd

lrwxrwxrwx 1 root root 15 2011-03-11 12:36 S11klogd -> ../init.d/klogd

lrwxrwxrwx 1 root root 14 2011-04-28 10:23 S12dbus -> ../init.d/dbus

…...

lrwxrwxrwx 1 root root 18 2010-11-24 18:16 S99ondemand -> ../init.d/ondemand

lrwxrwxrwx 1 root root 18 2010-11-24 18:16 S99rc.local -> ../init.d/rc.local

 

Note that there’s README file. It actually contains quite useful information. It’s worth reading it if you want to change something in this directory.

Also note that a the end of the list, there is rc.local, which is execute at the end of rc*.d directory.

3./etc/init.d/rc.local

The /etc/init.d/rc.local script will run all the programs/scripts in the /etc/rc.local script.

All the above actions are carried out in the boot up process and before a specific user is logged in. So if you want to start up your program using super user privilege, you can add your program here. The step-by-step instruction is as below,

1. put scripts/programs to /etc/init.d/

sudo cp /home/my_script /etc/init.d/

2. sudo chown root scriptname.sh

3. sudo chmod 4755 scriptname.sh

4. sudo update-rc.d scriptname.sh defaults

How to Reset USB Device in Linux

USB devices are anywhere nowadays, even many embedded devices replace the traditional serial devices with usb devices. However, I experienced that USB devices hang from time to time. In most cases, a manual unplug and replug will solve the issue. Actually, usb reset can simulate the unplug and replug operation.

First, get the device path for your usb device. Enter the command lsusb will give you something similar as below,

Bus 008 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 007 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 006 Device 002: ID 04b3:310c IBM Corp. Wheel Mouse
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 004 Device 002: ID 0a5c:2145 Broadcom Corp.
Bus 005 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub

Use the IBM Wheel Mouse as an example, the device node for it is /dev/bus/usb/006/002, where 006 is the bus number, and 002 is the device number.

Second, apply ioctl operation to reset the device. This is done in C code,

#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <linux/usbdevice_fs.h>

void main(int argc, char **argv)
{
	const char *filename;
	int fd;

	filename = argv[1];
	fd = open(filename, O_WRONLY);
	ioctl(fd, USBDEVFS_RESET, 0);
	close(fd);
	return;
}

Save the code above as reset.c, then compile the code using

gcc -o reset reset.c

This will produce the a binary named reset. Again, using the wheel mouse as an example, execute the following commands,

sudo ./reset /dev/bus/usb/006/002

You can take a look at the message by,

tail -f /var/log/messages

On my Ubuntu desktop, the last line reads,

May 4 16:09:17 roman10 kernel: [ 1663.013118] usb 6-2:
reset low speed USB device using uhci_hcd and address 2

This reset operation is effectively the same as you unplug and replug a usb device.

For another method of reset usb using libusb, please refer here

Reference: http://forums.x-plane.org/index.php?app=downloads&showfile=9485.

Long Pending TS II Released

Finally, TS II is released to Android Market. It has been almost half a year when I initialized rewriting of TSP/TSV. I was busy with school stuff and work, that’s why it’s pending for so long. But anway, I’m happy it’s finally out there.

This release has almost all features in the old TSP,

1. Encryption of photos

2. Decryption of photos on the fly

3. built-in viewer to view, slideshow, share, zoom, pan, rotate photos.

4. secondary account to hide your real account.

5. undo deletion, data recovery.

It also has some new features,

1. Secure share: share your photos with password.

2. Secure shot: take photo within TS, and it’s protected by default.

More information can be found here.

So why a complete rewrite? Well, mainly because of people complains about several bugs. These bugs are difficult to fix in the original design, so I decided to rewrite the app from scratch. Another reason is to merge TSP/TSV together. Although this first release only supports photos, video support will be coming soon in the next 1~3 releases.

I’ve also built a small website for TS II, you can find it here. It’s mainly for helping people better use the app. Users of TSP/TSV have asked me a lot of questions about how to use the app, so FAQ is there. I also added a TODOs so people knows what to expect in future releases.

I also created two pages for user request features/bug fixes and ask questions.

Top Secret II – Question List

Top Secret II – Request a Feature or Report a Bug

Hope some people will like the app.