10 Checklist For Starting A Software Business

I am eager to write something based on my experience in the software business. Hey, it is a good reminder for me in the future as well!

1. Backup Plan

Do you have a software or script to backup both database and raw files regularly?

2. Failure Plan

What do you do when things fall apart? How do you retrieve the backups? What happens if there is a motherboard failure? What is the worst that can happen? What happens if the server is hacked?

3. Monitoring Plan

How do you monitor the cpu, disk usage? If using a software, what service do you need to monitor? How does the software alert you in times of emergency?

4. Upgrade Plan

Are you able to upgrade the existing software and hardware easily? What is the impact if you want to implement new technologies to your existing system?

5. Test Plan

Do you have a test environment? What do you need to do if you want to test new changes to the software or hardware?

6. Security Plan

Where do you store the passwords? Is there a centralised user authentication plan? Do you have different layers of defence if unauthorised user logins into the server? Restricted access to server room? Temperature control?

7. Collaboration Plan

What do you need to do in order of mulitple people to work on the same project concurrently? Do you have a centralised repository system?

8. Human Resource Plan

What happens if your lead developer leaves today? Do you have another person who can cover his/her duties temporarily? Do you have a knowledge sharing portal for other staff to pick up new skills easily? Do you leave enough room for developers to upgrade themselves? Is there a project manager? Is there enough accountability and who does what?

9. Documentation Plan

How long do you keep server logs? Does your software log what the user is doing and tells your enough when things fail? Do you write User Acceptance Testing Document? Is there enough end-user and developers documentation?

10. Budget Plan

Did you try to cost cut too much? Did you set aside enough budget for emergencies, software, hardware upgrades, social and drinks?

Command Line Blogging – WordPress

I am using command line most of the time because of the nature of my work. Normally, when I discovered new techniques to do things, solved a problem or had a cool idea, I would write them down on my exercise book. It soon became clear that I needed something more concrete as copying lines of code isn’t fun (and they were very disorganised). I was also thinking of a way to share my ideas with the world…

How about posting them in a blog! Sounds good, But I don’t want to be alt-tabbing, copying and pasting between firefox and the terminal. Most importantly, I don’t like the idea of people seeing me blogging during working hours. Looks like I have to investigate how to do it in command line then.

I know that there are some command line blogging tools out there but what I need is the ability to post articles in WordPress (because I am using it) using the command line. After some googling, I knew that that is possible using command line php and xmlrpc. WordPress supports xmlrpc. Time to rock.

This point onwards is all WordPress related. Anyone interested can download a copy of WordPress from http://www.wordpress.com. What I will be doing here is to come up with a simple php script to post articles in wordpress blogs.

Investigation

In xmlrpc.php, line 133 – 166 tells us what API WordPress supports.

133 // Blogger API
134 'blogger.getUsersBlogs' => 'this:blogger_getUsersBlogs',
135 'blogger.getUserInfo' => 'this:blogger_getUserInfo',
136 'blogger.getPost' => 'this:blogger_getPost',
137 'blogger.getRecentPosts' => 'this:blogger_getRecentPosts',
138 'blogger.getTemplate' => 'this:blogger_getTemplate',
139 'blogger.setTemplate' => 'this:blogger_setTemplate',
140 'blogger.newPost' => 'this:blogger_newPost',
141 'blogger.editPost' => 'this:blogger_editPost',
142 'blogger.deletePost' => 'this:blogger_deletePost',
143
144 // MetaWeblog API (with MT extensions to structs)
145 'metaWeblog.newPost' => 'this:mw_newPost',
146 'metaWeblog.editPost' => 'this:mw_editPost',
147 'metaWeblog.getPost' => 'this:mw_getPost',
148 'metaWeblog.getRecentPosts' => 'this:mw_getRecentPosts',
149 'metaWeblog.getCategories' => 'this:mw_getCategories',
150 'metaWeblog.newMediaObject' => 'this:mw_newMediaObject',
151
152 // MetaWeblog API aliases for Blogger API
153 // see http://www.xmlrpc.com/stories/storyReader$2460
154 'metaWeblog.deletePost' => 'this:blogger_deletePost',
155 'metaWeblog.getTemplate' => 'this:blogger_getTemplate',
156 'metaWeblog.setTemplate' => 'this:blogger_setTemplate',
157 'metaWeblog.getUsersBlogs' => 'this:blogger_getUsersBlogs',
158
159 // MovableType API
160 'mt.getCategoryList' => 'this:mt_getCategoryList',
161 'mt.getRecentPostTitles' => 'this:mt_getRecentPostTitles',
162 'mt.getPostCategories' => 'this:mt_getPostCategories',
163 'mt.setPostCategories' => 'this:mt_setPostCategories',
164 'mt.supportedMethods' => 'this:mt_supportedMethods',
165 'mt.supportedTextFilters' => 'this:mt_supportedTextFilters',
166 'mt.getTrackbackPings' => 'this:mt_getTrackbackPings',
167 'mt.publishPost' => 'this:mt_publishPost',

The name of the function tells a lot. I had a quick look at the functions and MetaWeblog API seems to be quite promising as it supports a wide range of options. The part that I am interested is the function mw_newPost.

1365 /* MetaWeblog API functions
1366 * specs on wherever Dave Winer wants them to be
1367 */
1368
1369 /* metaweblog.newPost creates a post */
1370 function mw_newPost($args) {
1371 $this->escape($args);
1372
1373 $blog_ID = (int) $args[0]; // we will support this in the near future
1374 $user_login = $args[1];
1375 $user_pass = $args[2];
1376 $content_struct = $args[3];
1377 $publish = $args[4];
1378
1379 if (!$this->login_pass_ok($user_login, $user_pass)) {
1380 return $this->error;
1381 }
1382 $user = set_current_user(0, $user_login);
1383
1384 do_action('xmlrpc_call', 'metaWeblog.newPost');

So we need to pass an array containing 5 elements to the function, namely $blog_ID (not implemented yet), $user_login, $user_pass, $content_struct and $publish. Looking at the code further, I know that $content_struct contains another array and there are a few elements within $content_struct that I am interested for now: title, categories, mt_keywords. With all these information at hand, I can start building my script.

Check Requirements

I am going to use php built-in xml-rpc function. So my php has to support xml-rpc.


[username@web ~]$ cd /etc/php.d
[username@web php.d]$ ls
dbase.ini  mysqli.ini  pdo.ini        pdo_sqlite.ini
gd.ini     mysql.ini   pdo_mysql.ini  
[username@web php]$ cd /usr/lib/php/modules/
[username@web modules]$ ls
dbase.so  mysqli.so  pdo_mysql.so  pdo_sqlite.so
gd.so     mysql.so   pdo.so        phpcups.so

ok, looks like xmlrpc is not installed. I need to install it.

[username@web modules]$ yum install php-xmlrpc

Actual PHP Code

Now we have what we need. Time to code:

#!/usr/bin/php -q
$v) {
echo "[$k. $v] ";
}
echo "\n\neg. ".basename($_SERVER['argv'][0])." -t \"blog title\" -c 1,3,4 -k \"php,linux\" -p 0\n";
exit(1);
}
$options = getopt("c:k:t:p:");
if (empty($options)) {
displayHelp();
}
// convert categories to array
$cat = explode(',',$options['c']);
$catList = getCategories();
$categories = array();
foreach ($cat as $v) {
$categories[] = $catList[$v];
}
// convert tags to array
$tag = explode(',',$options['k']);
$title = $options['t'];
$publish = ($options['p']) ? $options['p'] : 1;
$stdin = file_get_contents("php://stdin", "r");
// posting blog
$params = array();
$contruct_params = array(
'title'=>$title,
'description'=>"$stdin",
'mt_allow_comments'=>1,
'mt_allow_pings'=>1,
'mt_keywords'=> $tag,
'categories'=> $categories
);
$request_params = array(
'1',
$username,
$passwd,
$contruct_params,
$publish
);
$request = xmlrpc_encode_request("metaWeblog.newPost", $request_params);
$context = stream_context_create(array('http' => array(
'method' => "POST",
'header' => "Content-Type: text/xml",
'content' => $request
)));
$file = file_get_contents($url, false, $context);
$response = xmlrpc_decode($file);
if (xmlrpc_is_fault($response)) {
echo $response['faultString'];
exit(1);
}
else {
echo "article posted successfully";
exit(0);
}
?>

anyone interested in the code can get it here

As you can see, the script is a quick draft. There are a few things that I can improve on it. First of all, I can do more work on validating the input arguments or making getopt work better. Then, instead of hardcoding the categories, I can retreive all categories using the function ‘metaWeblog.getCategories’. I can also ping technorati after every post. There is a good possibility of expanding the script and create a class that make use of other API functions, like ‘metaWeblog.getPost’ and ‘metaWeblog.deletePost’… and lastly, the command line can be more user friendly with more interactive prompts. The possibilities are limitless.

Time to test

I call the script ‘postblog’ and put in under my bin directory, ie ~/bin. Then display the help to see the category options.


[user@web ~]# postblog
Usage: postblog -t [title] -c [categoriesNo] -k [tags] -p [publish]
category choice: [0. Blog] [1. Think Linux] [2. Think Network Monitoring] [3. Think Networking] [4. Think Technology] [5. Think PHP] [6. Think Regular Expression] [7. Think SEO] [8. Think Software] [9. Think SQL] [10. Other Interest]
eg. postblog -t "blog title" -c 1,3,4 -k "php,linux" -p 0

I wrote my blog in vim and save the file as ‘myblog’. To publish the article in wordpress under the ‘Blog ‘, ‘Think Linux’ category with blogging and technology tags,


[user@web ~]# cat myblog | postblog -t "Command Line Blogging" -c 0,1 -k blogging,technology
[user@web ~]# article posted successfully

Yay, it works!

What’s Next

Perhaps a bash version of the script or further improvements on the php current script.

Linux Network Printing

I installed a linux network printer for a friend and thought I post the steps here. First of all, find out the ip address of the printer. Go to http://localhost:631 to add a printer. You might need root access.

Under device, choose ipp and in Device URI, type ipp://hostname/ipp/. Then add the model and follow through the rest of the prompts. When you have finished, go to http://localhost:631/printers/ and you should see your printer listed there. do a test print. If it works, congrats. If not, click on modify printer and under Device URI try using socket://address:9100 instead of ipp. The later seems to work quite well with alot of printers. if in doubt, always telnet host 9000 to see if the port is accessible.

If you do not have access to cups via http://localhost:631, just edit the printers.conf file

vi /etc/cups/printers.conf

the config will be something like this:


Info HP laserjet 4100
Location myhouse
DeviceURI socket://your-ip:9100
State Idle
StateTime 1189572516
Accepting Yes
Shared Yes
JobSheets none none
QuotaPeriod 0
PageLimit 0
KLimit 0
OpPolicy default
ErrorPolicy stop-printer

when done, do a “sudo /etc/init.d/cupsys restart”

hopefully, everything should be working.

Create New Debian Package From Scratch (Extra Tips for PHP Pear Modules)

Pear often has alot of packages that are not yet in the debian repository… It make sense to create new pear-debian packages just to follow the protocol.

Firstly, you will have to make sure that the package that you are trying to create is not yet available in the repository else you will be re-inventing the wheel. Next, decide a name for the package. The name must be unique and you can check it easily using

dpkg -S ${pkgName}

Rename the source directory containing the installation files as ${PackageName}-${PackageVersion}. Next, tar and compress the source directory and name it ${PackageName}-${PackageVersion}.tar.gz

Create a ‘deb’ dir under your home directory. Then, transfer the entire source directory and .gz file over.

If you are trying to create a pear module, you need to download and extract the source files from http://pear.php.net/packages.php. Do a fresh tar following the naming convention ${PackageName}-${PackageVersion}.tar.gz. For example, the original downloaded pear package is HTML_AJAX-0.5.2.tgz but I want my new package to be named pear-html-ajax-0.5.2, I would do this:

cd ~/deb
cp ../HTML_AJAX-0.5.2.tgz ./
tar -xzvf HTML_AJAX-0.5.2.tgz
rm HTML_AJAX-0.5.2.tgz
mv HTML_AJAX-0.5.2 pear-html-ajax-0.5.2
tar -czvf pear-html-ajax-0.5.2.tar.gz pear-html-ajax-0.5.2

If everything seems ok, your directory structure should be something like this:

- deb
- pear-html-ajax-0.5.2
+ AJAX
+ docs
+ examples
+ js
+ tests
AJAX.php
package.xml
pear-html-ajax-0.5.2.tar.gz

Install the dh-make package. Then, in the package dir (in this case, pear-html-ajax-0.5.2), run

dh_make -e yourname@infoxchange.net.au -f ../${pkgName.tar.gz}

* note the extra debian dir and orig.tar.gz file created
* consult man dh-make and man debhelper if necessary

- deb
- pear-html-ajax-0.5.2
+ AJAX
+ debian
+ docs
+ examples
+ js
+ tests
AJAX.php
package.xml
pear-html-ajax_0.5.2.orig.tar.gz
pear-html-ajax-0.5.2.tar.gz

The debian dir contains important information about the installation process. cd debian and you will see many files. The .ex files are sample templates and can usually be ignored.

* changelog – As the name implies.
* copyright – As the name implies.
* compat – Set the rules under which debhelper scripts (dh_*) operates. (no modification needed)
* control – Contains important installation parameters. Change the following fields: section, depends and description.
* dirs – directory where the files will be installed.
* rules – Rules for the installation procedure. This is the hardcore part. Major changes needed.

If you are creating a pear package, you need to move package.xml into the package dir (in this case, pear-html-ajax-0.5.2). I have created a sample pear rule and you can copy and paste it into your rule file just to save time (see below).

So when you’re ready to try creating a package, do:

cd ~/deb/$your_new_directory
dpkg-buildpackage -rfakeroot (or sudo dpkg-buildpackage)

The dpkg-buildpackage command will try to create a .deb package in the directory above your current directory, using the files in the ‘debian’ directory inside your current directory.

A proper install will include some other files other than the .deb file.

- deb
+ pear-html-ajax-0.5.2
pear-html-ajax_0.5.2.orig.tar.gz
pear-html-ajax_0.5.2-1.diff.gz
pear-html-ajax_0.5.2-1.dsc
pear-html-ajax_0.5.2-1_i386.changes
pear-html-ajax_0.5.2-1_i386.deb
pear-html-ajax-0.5.2.tar.gz

* see http://www.debian.org/doc/maint-guide/ch-build.en.html

If that seems to complete properly, you should be able to try installing it on your own machine with:

cd ~/deb
dpkg -i ${your_new_package}.deb

Check that all the files have been installed in the right place. Eg, all pear files should go to /usr/share/php.

Also note that there are other ways of creating debian packages… this is the standard way.

——- SAMPLE RULES FILE FOR PEAR —–

#!/usr/bin/make -f

# IX custom script for making pear modules into debian package. you need to have php-pear installed first.

PEAR ?= /usr/bin/pear

# Your package name. Make sure it is consistent with other files.
package = pear-sample
configure: configure-stamp
configure-stamp:
dh_testdir
touch configure-stamp
build: build-stamp
build-stamp: configure-stamp
dh_testdir
touch build-stamp

clean:
dh_clean build-stamp configure-stamp

install: build
dh_testdir
dh_testroot
dh_clean -k
dh_installdirs

# Add here commands to install the package into debian/package.
# if the script does not work test with this line and see error
$(PEAR) install -n -R debian/$(package) package.xml;
# remove unwanted pear files left by installation
rm -f debian/$(package)/usr/share/php/.filemap;
rm -f debian/$(package)/usr/share/php/.lock;
rm -rf debian/$(package)/usr/share/php/.channels;
rm -rf debian/$(package)/usr/share/php/.depdblock;
rm -rf debian/$(package)/usr/share/php/.depdb;
rm -rf debian/$(package)/usr/share/php/.registry/.channel.pecl.php.net;
rm -rf debian/$(package)/usr/share/php/.registry/.channel.__uri;

# remove duplicated files, these files are in /usr/share/doc/package
rm -rf debian/$(package)/usr/share/php/tests;
rm -rf debian/$(package)/usr/share/php/docs;

# remove created tmp dir
rm -rf debian/$(package)/tmp

# Build architecture-independent files here.

binary-indep: build install
# We have nothing to do by default.

# Build architecture-dependent files here.
binary-arch: build install
dh_testdir
dh_testroot
dh_installdocs
dh_installexamples
dh_installchangelogs
dh_compress
dh_fixperms
dh_installdeb
dh_gencontrol
dh_md5sums
dh_builddeb
binary: binary-indep binary-arch
.PHONY: build clean binary-indep binary-arch binary install configure