Online Marketing

I’ve started doing some online marketing through Google Adwords. Those of you in Taiwan may see ads for my restaurants show up on Google searches for various keywords. I’m not really sure how effective this will be at getting customers in the doors, but it’s not terribly expensive.

Google Adwords is pretty nifty in the amount of control you can get over your ads. You can restrict things to a particular geographic area. Over here the most I can narrow things down to is all of Taiwan, though I’d prefer to limit it to just Taipei City. They don’t have that option here, but in the US and some other countries you can narrow down the advertising to as small an area as a city block.

The system works via a bid system where you tell how much you are willing to pay and then it will show your ad or not depending on who else is bidding on the keywords you want. There don’t seem to be a lot of other people advertising in Taiwan, at least not for the keywords I’m using, so bid rates are quite low to get even top placement.

You can even do nifty things like display different ad versions depending on which language the browser is set to use, so I can target different ads to Chinese or English speakers, which I do. And they even have a tool that will suggest based on your current keywords what other keywords might be appropriate. This is great for me for the Chinese keywords since I would have to struggle to come up with other things besides the basics.

Anyways, it’s still unknown what effect this will have, but so far 329,874 people have seen my ads, 318 have clicked through, and traffic on my web site has gone up by a factor of 10.

There’s still a lot of work to do. I really need to reorganize my web site to make it easier to navigate and better organize the information. I should also work on building an email list of customers who want to get updated on new promotions, exclusive discounts, and new product news, as well as offer some kind of online coupon system. If anyone else has some ideas, I’d love to hear about it.

Flash is insanely cheap!

I mentioned in my previous blog entry “Configuring print spooling with CUPS on OpenWRT”, that USB flash drives work as a good spool device and are quite cheap. When I wrote that, I didn’t realize exactly how cheap they were. The last one I bought was a 512m model which I believe was around US$25 after a pretty substantial rebate. I thought that was pretty good, but that was a while ago and I assumed things had gone down in price a bit.

I went down to one of the large electronics retailers in Taiwan, 燦坤3C (Cankun Electronics), to get one for the router that will go in my second restaurant so that it can be configured for print spooling too. I was intending to get a 512m model again since that’s a pretty generous size for a print spool device. Instead I ended up with a Transcend 1GB JetFlash V30 for TWD449 (USD13.60). 2GB drives were going for TWD699 (USD21.18) and up. They even had models up to 8gb in size for fairly reasonable prices. (They had 512m models still but they weren’t significantly cheaper than the 1gb models.)

This is a higher end brand at a bigger (more expensive) retailer, so it’s a bit more expensive than elsewhere (for example, the same drive is available for USD7.75 on Amazon), but it’s still a very inexpensive price. I saw that there are 16gb and 32gb models on the market, but those are still quite expensive. No wonder laptop makers are talking about replacing disk drives with flash! 16gb of storage on a laptop is plenty of room for most purposes. And a 16gb or 32gb iPod Nano would be pretty nifty.

I feel old.

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.

SUBWAYâ„¢ Taiwan $99 Daily Special

Sub of the Day and Small Drink $99 Special

Available March 16, 2007 through May 31, 2007 at all participating SUBWAYâ„¢ Taiwan restaurants:

Sub of the Day and Small Drink $99 Special
(Click for larger version)

Daily savings of up to $36.

Monday: 6″ Seafood Sensation and Small Drink
Tuesday: 6″ Turkey Breast and Small Drink
Wednesday: 6″ Double Cheese Smoked Chicken and Small Drink
Thursday: 6″ Italian BMT and Small Drink
Friday: 6″ Roast Beef and Small Drink
Saturday: 6″ BLT and Small Drink
Sunday: 6″ Turkey, Ham & Roast Beef and Small Drink

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.

Optimus Maximus Keyboard nears reality

The Optimus Maximus keyboard is emerging from the vaporware. This is the full size keyboard where every key contains a full color display so that the mapping of keys and what is shown on them can be redone at whim. They are now saying the should have it around year end.

The bad part… $1490 for a keyboard. And yes, that’s US DOLLARS.

Still, looks sweet.