Sorry, Taiwan Is Closed

As of right now, every city and county government has announced that businesses and schools will be closed tomorrow. I closed my restaurants early tonight at 8pm and we will decide tomorrow when to re-open for business. It is too early to tell when it will be safe for our staff and customers to open.

Meanwhile I’ve managed to get almost complete translations up on my English version of official business and school closures. The exceptions are notes 3 and 4 at the bottom which are atrocious run-on sentences I can’t quite wrap my head around in understanding. They don’t seem to be terribly important though from what I can understand of them. 3 is about who is affected by the closure notices and 4 seems to be about whether or not the time off is paid or will require make-up work. My translator fetches a copy of the official page every ten minutes and rewrites it and posts it on my web server. Pretty neat for a quick hack.

The current forecast has the typhoon cutting across the center of Taiwan but the storm is big enough that it will probably affect all of Taiwan. The eye should cross over the east coast tomorrow morning at 8am and exit on the west coast around 5pm. So there’s a good chance that we’ll be stuck at home all of tomorrow unless the storm weakens after making landfall. Right now things are very quiet in Taipei. “The calm before the storm.”

Quick Hack

As a quick hack, I’ve whipped up something that will automatically translate the official business and school closings from Chinese to English: http://vps1.jameslick.com/cpa/

As this is a quick hack, it currently only has translations for the current contents of the main table. I will have to update the translations as new types of closings are posted, and add translations for the surrounding information.

Web application development (Part 2)

Thanks for all the great feedback on my previous post. I had previously wondered why I don’t get a lot of comments on my posts and I think I’ve discovered why. I haven’t been making postings that were nerdy enough for my readership. Well, I guess I’ve learned my lesson.

I got a lot of good advice about using Drupal, CakePHP and Rails. I also got some offline advice to look into another PHP framework called Symfony. Symfony has one good thing going for it in that it has a book out which is available locally, which isn’t something any of the other PHP frameworks have going for it. (Drupal has at least one book available locally and Rails has at least a dozen.)

Anyways, after weighing all the good suggestions, I gave a stab at learning CakePHP. I found a few good tutorials online, probably the best of which is Sitepoint’s article The CakePHP Framework: Your First Bite. I combined that with a couple of other tutorials and within a couple of hours had an application with basic user authentication working. It really was pretty easy.

Today I worked on setting up the modeling for my first web application. I want to have a system where I can enter the hourly sales breakdowns from our daily receipts to come up with a schedule predictor of how many staff should be on duty at what times. SUBWAYâ„¢ has a way to do this but it involves employees writing information on dead trees and the manager to calculate by hand this data weekly. Much easier to just enter the raw numbers from the Z-Tape receipt each day and have it calculate things for me.

So I’ve finished modeling the four database tables needed and their relationships, and have entered some basic data with scaffolding. I think the modeling is pretty much set at this point and I can start building the controllers and views.

All in all it’s been fairly easy to get to this point and already I can see all the work that’s needed to get this complete. It’s quite possible I’ll have a working application by tomorrow and can bring the results to my manager at our weekly meeting on Wednesday.

Better yet, as soon as I get the authentication framework a bit more robust I can get my manager access and have her do the weekly data entry and set the employee scheduling herself. And the eventual goal is to get everything we do now in Excel and E-mail to be done via web applications.

Web application development

I’m looking for some advice from my readers. I’m looking at developing some web applications to support my business. A lot of it will be data entry that will be saved in a database and then some simple data processing done to the data. I will also need multi user access with authentication and authorization functions.

My server is currently LAMP based: Debian 4, PHP 5, MySQL 5, Apache 2.2. So a solution built around this platform would be easiest to implement, and I also have basic PHP coding skills.

Here are some of the options I’m considering:

1) Roll my own application from scratch based in PHP. More work, but more flexibility and less learning.

2) Install Drupal or some other CMS and build modules. Will get a nice CMS too but need to learn a bunch of stuff and the type of apps I need to make will still require significant effort.

3) Use some kind of PHP Rapid Development Framework. Again, this will require more learning, but again has the flexibility of not being tied to a particular CMS’s requirements. But then the question is which one? CakePHP, Prado, Horde?

4) Switch over to Ruby on Rails which is supposedly the easiest way ever invented to code web apps. Means installing and learning a new platform and language from scratch.

5) Something else?

Any ideas or feedback?

Converting mysql InnoDB tables to MyISAM

Now that I have a VPS with limited memory available for my ‘main server’, I’ve been looking at how to optimize usage to make sure I keep well under the memory limit. I found a nice article Optimizing Apache and MySQL for Low Memory Usage, Part 2 which explains some great ways of reducing your mysql memory usage. One of their best suggestions is to disable InnoDB which can save up to 100M of memory.

I didn’t think I was using InnoDB at all but it turns out that Mediawiki by default sets up some tables using InnoDB even though most are setup as MyISAM. The Mediawiki developers note that InnoDB is better for those tables for high load wikis, but since mine doesn’t exactly qualify as high load, I thought it would be safe to convert.

But how to do it? Some sites recommended dumping the db, changing the ENGINE type for the tables in the dump and then reimport it. I’m sure that works, but it seems like a fairly crude way of going about it. Turns out there’s a better way.

First run the ‘mysql’ commend line program and connect to your database. If you have more than one database on your mysql server, you’ll need to check them each one by one:

mysql
use database;

Then get a list of databases using the InnoDB engine:

show table status where engine="innodb";

For each table change the type as follows:

alter table tablename engine="myisam";

For good measure look at the table types again to make sure you got them all:

show table status where engine="innodb";

If it doesn’t show any, then you can go ahead and put ‘skip-innodb’ in your my.cnf as outlined in the document about optimizing mysql above and you’ll suddenly have an extra 100M of memory available!

Configuring print spooling with CUPS on OpenWRT

OpenWRT software provides a way to turn certain wireless routers into general purpose Linux servers. This lets you do interesting things like install VPN software, use it as a file server, DNS server, and all the other things you can do on a basic Linux server. Of course you have to be careful as most routers have very limited memory and flash storage, so you can’t run just anything.

I use OpenWRT at my first restaurant and recently bought a printer/fax for the store so that my manager could print out necessary forms without bothering me. (I have bought an OpenWRT compatible router for my second restaurant but haven’t gotten around to installing it yet. EDIT: Installed OpenWRT with CUPS at the second restaurant and it is working fine now.) I originally followed the OpenWRT Printer Sharing HOWTO and installed the printer using the p910nd software and set up XP to be able to print to it.

p910nd provides very simple non-spooling printer sharing service. Windows XP calls these ‘Raw’ TCP/IP printers. Basically all it does is read in data from the client and then feed it out to the printer port. This has a lot of advantages in that it is simple and does not require storage space to spool the print job. (Remember what I said about limited flash storage?)

Unfortunately it doesn’t handle error conditions very well. It worked well most of the time, but all too frequently something would happen in the middle of printing a page. The printer would stop printing, the client would report an error and spoolsv.exe on XP would go nuts on the CPU usage. And then it was just about impossible to gracefully recover from the error. XP would refuse to remove the job without rebooting, and even then the next job on the printer would come out with the characters all scrambled. That sure is annoying, and wastes time and ink. (Those ink jet cartridges ain’t cheap.)

So what is the alternative? Well, the aforementioned HOWTO also mentions briefly that CUPS is an alternative, but that it isn’t necessarily a good option due to limited storage on most OpenWRT boxes. However, USB flash drives are cheap and make an excellent spooling device. And my OpenWRT box just happens to have a modest 512mb USB flash drive installed which should be plenty for print jobs.

The next frustration is that while there is a CUPS package provided for OpenWRT, I couldn’t find any comprehensive guide for installing or using it on OpenWRT. I also had no experience using this kind of print spooler either. That lead to much flailing around trying to figure out how to get it working, but I was finally able to crack that nut. This document will hopefully help others successfully implement CUPS on their OpenWRT routers.

First, let’s get the prerequisites out of the way. At the least you will need a working OpenWRT router with either a USB or parallel port, and a printer with the same. It is also highly recommended that you add a USB flash drive of 128mb or larger (512mb would be better). (EDIT: Flash drives are so cheap now you should probably get a 512mb or 1gb model.) If you use a USB flash drive and USB printer your router will either need to have two USB ports or you will also need a USB hub. (I haven’t tried it with a hub so please give me feedback if this works for you.)

Next, refer to the OpenWRT Printer Sharing HOWTO and follow step 3.1 if you have a USB printer or step 3.2 for a parallel port printer. Make sure you reboot after installing any ‘kmod’ packages. After this you should see a USB printer device in /dev/usb (e.g. /dev/usb/lp0) or a parallel port printer in /dev/printers (e.g. /dev/printers/0).

If you are using a USB flash drive as the spooling device, also see the OpenWRT USB Storage HOWTO to format and mount your USB storage. (I mount mine as /usb.)

Now you will install the CUPS package for OpenWRT: ipkg install cups

EDIT: You will either need to start cupsd by running ‘/etc/init.d/S60cupsd’ or wait until after installing the cups package to reboot to get lpinfo to work.

Next you will need to do some configuration. First, find out where your printer is by running ‘lpinfo -v’. You will get a list of possible printer ports available. For a USB printer you should see something like:

‘direct usb://HP/Officejet%204300%20series?serial=XXXXXXXXXXXX’

For a parallel printer you should see a device like:

‘direct parallel:/dev/printers/0’

Note that for USB printers you can refer to the printer by either device or by name. The listing above will show the named device if possible. In my case the device is really on /dev/usb/lp0. However, sometimes when a printer is power cycled or the cable is removed and plugged back in, it may come back as /dev/usb/lp1 or some other number. The named device should still work regardless of which USB device the system assigns it.

Now let’s go in and edit /etc/cups/printers.conf. The config that is installed by the package uses a default printer called USB on /dev/usb/lp0 and a printer called LP on /dev/printers/0. Use one of these as your template and remove the other one.

If you have a USB printer, then you’ll want to change the printer name from USB to something more descriptive. My printer is an HP OfficeJet 4355 so I set the first line of printers.conf to read ‘<DefaultPrinter HP4355>’. You can also change the ‘Info’ line to show a description of the printer and the ‘Location’ line to show where it is located. The important part is the DeviceURI. By default it is set to /dev/usb/lp0, but due to the issues described above, I changed it to the named device instead.

If you have a parallel port printer then you would make similar changes there except that your would keep the DeviceURI set to parallel:/dev/printers/0 unless your printer is on a different device.

In the end, my printers.conf looked like:

<DefaultPrinter HP4355>
Info HP OfficeJet 4355 USB Printer
Location Subway Xingtian Temple Store
DeviceURI usb://HP/Officejet%204300%20series?serial=XXXXXXXXXXXX
State Idle
Accepting Yes
JobSheets none none
QuotaPeriod 0
PageLimit 0
KLimit 0
</Printer>

CUPS is typically installed with various filter to understand various conversions of files to the printer’s native format. On OpenWRT, that’s not practical because of the memory limitations. It’s more practical to use the printers as raw printer devices and let the print client provide a formatted file. To enable this, edit /etc/cups/mime.convs and /etc/cups/mime.types. In each, find the line starting with ‘#application/octet-stream’ and uncomment it by removing the ‘#’ character and saving the files.

Now there are a couple of things to edit in /etc/cups/cupsd.conf. By default CUPS is set to require authentication of a system account to print. This essentially means setting up a user account for printing or entering the root password into clients. I didn’t find these options attractive, so instead I set it for anonymous access type and restricted access by IP address. If you do this, remember to make access to the administrative functions more restrictive, otherwise anyone will be able to modify your config. I decided to turn off remote admin functions entirely. The result is something like:

EDIT: I eventually switched back to using user account authentication which has the advantage of being able to print to the printer over the Internet reasonably securely. I added a user with a password and then opened up port 631 by editing /etc/firewall.user and copying the section for opening ssh access and changing the port number from 22 to 631. If you do this you can keep the original configuration for “Location /”. I decided to disable the admin functions even with password protection.

<Location />
AuthClass Anonymous
AuthType None
Order Deny,Allow
Deny From All
Allow From 192.168/16
</Location>

<Location /admin>
Order Deny,Allow
Deny From All
</Location>

That should work without modification when using any private network starting with 192.168.

By default, cups on OpenWRT uses /tmp/cups for storing temporary and spool files. /tmp on OpenWRT is a filesystem using free memory as storage. Many OpenWRT routers only have 16mb of memory and will have very little available for /tmp. Mine has a more robust 32m of memory but typically only has around 15m free with the software I have running.

Depending on your printer, a print job can take quite a bit more than this. For example, on my printer even just one simple page takes 8m and a multi-page document can easily grow to a 60-80m print spool. Needless to say, that’s not going to work too well if only 15m is free. That’s why I’m using a 512m USB flash drive for the print spool instead. Keep in mind that if you use the default config, you will be extremely constrained in what kind of things you can print. (EDIT: The amount of space needed will vary depending on your type of printer, the resolution, rendering engine, and the material being printed.)

That said, let’s say that you’ve mounted your USB flash drive as /usb. Make a print spool in /usb/cups: mkdir /usb/cups

This needs to have drwxrwx–T permissions which can be set with: chmod 1770 /usb/cups

Now change the RequestRoot and TempDir settings in /etc/cups/cupsd.conf to use that spool directory:

RequestRoot /usb/cups
TempDir /usb/cups

Now if you’ve set up everything correctly, you should be able to start up the cupsd server: /etc/init.d/S60cupsd

EDIT: You will need to kill the previous cupsd process before the prior command. ‘ps | grep cupsd’ then kill the process number in the first column.

For the following examples we will assume that the LAN interface of your router is IP address 192.168.1.1. If it is different or if you have set a host name for it in DNS, then change as appropriate.

Open up your browser and type in the address: http://192.168.1.1:631/

You should see the information on your CUPS server and the printers configured. Also make sure that you cannot access the admin functions, otherwise your print server is open to anyone changing your configuration.

Now let’s say that we have a Windows XP system to setup. On the above web page you should be able to browse down to your configured printer and end up with a URL which looks like this: http://192.168.1.1:631/printers/HP4355

(It will show the name you gave your printer instead of HP4355.)

Now bring up the Printers & Faxes explorer in XP and click on ‘Add a printer’. Select ‘network printer’ then ‘Connect to a printer on the Internet or on a home or office network’ and put the above URL in the box below that option. (EDIT: If you use the user account authentication method instead, it will ask for the login and password on the next screen.) Click on ‘next’ and you should be able to select the manufacturer and type of printer you have (or you may have to select ‘Have Disk’ if the printer driver is not included in XP) and the rest of the normal printer setup process.

If everything was done right then you should now be able to print to your network printer.

EDIT: In installing the printer at the second restaurant, I found that some printer drivers don’t show up in the list of available printers if installing as a network printer. The trick to get around this if you run into it is to install it as a USB printer first. Then open the printer properties and change the port to a network printer port.

I would appreciate any comments on whether this worked for you or not, or any significant changes you had to make to get your cups server working. Comments on my blog do not require any registration.

stockgrab fixed

There’s now a fixed version of stockgrab available.

The new version uses LWP::Simple to fetch web pages instead of opening a socket and manually feeding in an HTTP request (this gives you an idea how old the original script is). And instead of using the normal HTML quote page from Yahoo and parsing it, it now uses Yahoo’s quotes.csv service. That service gives you a CSV formatted response of the particular fields you want.

As a side effect, the output format of stockgrab is slightly different than previously. The format is a bit cleaner this way though. Plus it’s easy to modify things to show the data and format you want.

Also the stockbuds list has been updated for today and should work fine going forward.

stockgrab broken

For anyone using my ‘stockgrab’ script to pull stock quotes from yahoo, you may have noticed that it stopped working today. 8 years since their last format change, Yahoo has reformatted their stock quote page and broken stockgrab’s parser. If you’re on my stockbuds list, that also is temporarily broken. I’ve discovered that Yahoo has a way of requesting a comma separated values version of stock quotes, so I’ll be converting stockgrab to use that.

Stop XP’s reboot-nag

One of the most annoying things about Windows is the way it handles reboots after updates (whether a manual update or an automatic update). The way it is designed is it’ll give you a popup window every 10 minutes asking you to reboot. The only options are to reboot or wait another 10 minutes.

It gets better. If nobody is actively using the computer, it will go ahead and reboot for you. Never mind if you had important stuff running. Never mind if you hadn’t saved your files. Just go ahead and reboot.

The one user-apparent way around this is to disable Automatic Updates, and manually update when it’s safe to reboot. However, this has the effect that you will then need to remember to manually check for updates periodically, Windows Defender will not get updated, and it’ll nag you about Automatic Updates being turned off instead.

After this month’s update rebooted in the middle of running a disk recovery on a friend’s laptop drive, I finally got fed up enough to find a solution. You can find it in this blog entry: XP Automatic Update Nagging

There’s a few different solutions. I chose to use the group policy editor to disable the auto-restart option. (Though in Microsoft’s continued effort to twist logic, you have to “enable” the “no auto-restart” option.)

Now you will have to remember to reboot your box, though my experience is that you have to reboot XP every few days anyways.