A Good Progammer

I found a pretty good article on the signs of a good programmer. I fit a lot of those, except maybe being in a variety of technologies. I pretty much stick to things that have good documentation (such as programming languages). I do as little hacking as possible, and by hacking I mean things that were never meant to be used. I started programming long before I learned it in a classroom setting though, and it’s never been “just a day job,” in fact, over 75% of the programming I’ve done has been unpaid.

In other news, I should be getting a new video card tomorrow… my computer will be complete, mwahaha (An evil laugh felt appropriate, I don’t know why). I also got talked into adding B-vitamins and calcium into my daily regimen by the guy at GNC, and I haven’t seen anything but positive results.


Linux: Setuid/Setgid

This is good information that all Linux developers should know: setuid/setgid.


Python: Facing the Snake

I’m starting to get back into the learning mode, and the first thing on the TODO list, Python. It’s a lot more impressive than PHP. It’s easier to learn the basics, and yet has so much power from what I’ve seen so far. Maybe I can make use of it in my new job.

I started to try to make a script to print all possible words that a phone number can make, but I found that it was harder than it seemed. I could do it, but I estimate there to be around 729 possible combinations (9 digits, 3 combinations on most keys… if my math is right, that’s 9³), I didn’t want to fool with it and any potential memory problems.

I hate to say it, but I’m ready to go back to school… Well, mainly work. I’m running out of games to take up my time.

Update: Ok, I was wrong. The possible combinations is 39, which turns out to be 19683 possibilities, where each key has 3 letters. That does not account for the letters q or z, or the number 1 or 0. I actually came up with a program that’s only 15 lines long using recursion. For anyone who cares, I’ll put the code here:

#! /usr/bin/env python

digits=['_', '.,!?', 'abc', 'def', 'ghi', 'jkl', 'mno', 'pqrs', 'tuv', 'wxyz']

def phoneLetters(phone, r=''):
  if(len(phone) == 0):
    print r
  if(phone[0] >= '0' and phone[0] <= '9'):
    for i in digits[int(phone[0])]:
      phoneLetters(phone[1:], r + i)
    phoneLetters(phone[1:], r)

import sys


An awesome game, aisleriot solitaire, is available for windows, though not as clean as it is on Linux. Not only does it have the usual klondike, freecell, spider, it has over 80 versions of solitaire total. Here’s some recommended solitaire variations:

  • Jumbo: This is a version of klondike, played with two decks. Takes a while, but it’s my current favorite.
  • Pileon: Used to be my favorite, and I also have a web version of pileon.
  • Eight Off: Similar to Freecell, but stacks do not alternate, and there are eight junk piles.

Apache Trick – Rewrite to 404 Not Found

This may be a well known trick, but I couldn’t find it anywhere. If you’re needing to hide certain files using .htaccess, the only way to do so according to the documentation is by using [G] for “410 Gone” or [F] for “403 Forbidden”. In my case, I didn’t want the user to know the file existed at all, so here’s the trick:

RewriteRule ^hidden - [R=404]

“^hidden” tells the server to look for any path on the server that starts with hidden. The “-” tells the server not to rewrite the URL, and the [R=404] tells the server to do a external redirect (making your browser go to the new location) to nowhere, and gives a 404 Not Found status.

Update: Apache 2.0 seems to only accept R=3xx, not R=404, so I think this must only work in 2.2 and up.


MySQL Searching

I’ve found that MySQL’s searching implementations don’t quite work for a smaller database. When I try to use fulltext searching on, it removes “Wolverine” because 55 of the 85 products in our database are Wolverine. So I think I’m going to have to come up with a custom search.

I’ve searched and searched, and when on a shared server (I don’t think sphinx will do it) there’s really not a lot that I found that’s very helpful. I’m probably going to have to use indexing, instead of trying to use fancy SQL queries. It’s probably going to take around three days of coding, scrapping, and more coding, until I come up with something that is both fast and effective. It probably would have helped had I stuck with a computer science major.

I think I can finish the majority of my tasks on the site within a couple of days, or at least the ones I intend to do before it goes live. If I ever get done, I’m not going to know what to do with myself. Staying busy has the upside of cutting boredom, but it also has a way of getting in the way of homework (not that I do it anyways). I may be spending a lot of time on my Wii.


The End is in Sight

I’ve been coding lots and lots for many hours, but I can finally see the end for version 2.0. I may have to come up with a new front-end to signify a change, but right now, it’s pretty similar in style. The backend is WAY more extensible though. With logging for errors and data changes, and a pretty good seperation of logic and presentation, I think it’s going to be a lot better. I hope to get some page editing in place for the admin, and better integration with Paypal and Google Checkout.

I can’t quite what I should do with data consistency. If we want to remove a product from the website, I would normally just delete it out of the database, but that creates some inconsistency, such as, if we wanted to look at selling history. I’ll probably continue to delete them, to remove the extra load on the database for indexing, etc, but I’m not sure what the rules are.

At my current job, I do a lot of reading. It’s hard to get used to, because the only jobs I’ve had before, I was expected to be, or at least look, busy. In some ways it’s nice, but it gets to be a little dull. I’ve been reading over MySQL, and even though I haven’t done much with it at work yet, I’ve implemented a lot of it into the WB‘s code. Here’s one that I came up with today:

SELECT name, COUNT(DISTINCT value) FROM variation

It’s pretty simple to most with SQL experience, but came as a revelation when trying to do different hacks in PHP. This query gets the types of variations (e.g. Size, Color) in order by the fewest distinctions. It’s useful for making a list such as (Colors are always top-level in this case):

  • Brown
    • 32
    • 34
    • 36
  • Black
    • 34
    • 38
    • 40

I then take a PHP function and sort it like this, for use in usort():

public function item_cmp(&$a, &$b) {
  $astr = $bstr = '';
  $vartns = Variation::get_variations();
  foreach($vartns as $v) {
    if(isset($a->variations[$v])) { // zero-pad with zeros to three digits
      $astr .= sprintf('%03s',$a->variations[$v]->weight);
    } else $astr .= '999'; // Make null values float to bottom
      if(isset($b->variations[$v])) {
        $bstr .= sprintf('%03s',$b->variations[$v]->weight);
      } else
        $bstr .= '999';
  return strcmp($astr, $bstr); // Compare the two as strings
  // (digits would probably work too, but strcmp was easiest)

Rather than hardcoding it, I thought it best to make it smart. I’ve implemented the site in PHP5, and I’m crossing my fingers that the shift from MySQL 5 to MySQL 4.1 won’t cause too many problems.


All About

The last month of my life has been coding a whole new site for I’ve moved everything over to PHP5, using PHP Classes, MySQLi, normalized tables, and a rough version of the Model-View-Controller system.

When dealing with footwear, you have to have shoe sizes, and other products have colors. I could have codeed different variations for products to have sizes, and others to have colors, and any other variations that would have come along, but to avoid the extra coding, I implemented them as one idea:

  • The product table contains generic information about a product, such as a brand, stock number, title, prices, category, and so forth.
  • The item table contains one instance of a product. The item is what actually gets sold and is tied to the shopping cart. Items have unique variations, which allows for a product to have multiple items.
  • The variations table has variations with a name and value. To keep the tables normalized, there is a item_variations table which join the two together, allowing an item to have multiple variations, and an item to have multiple variations (forcing a unique variation name, such as “Size” on an item).

The products have a product type, and I’ve been toying with the idea of letting variations be type specific, so that products that are footwear, can have the Size 8.5 D, 9 D, 10 D, and products that are apparel can have the size 32×32, 32×34, Medium, Large; this is kind of contaminated too, as Jeans, Shirts, and Hats have their own systems of sizing.

This method causes a few problems when trying to turn the results from the database into a web interface, but I got it to work. I may post some code later.


jQuery: Characters Remaining

I needed a counter on my input texts to say how many characters are left, so I came up with this. It creates a yellow box to the right of the input area, which is updated when the field is edited.

Counter Function

jQuery.fn.counter = function() {
  $(this).each(function() {
    var max = $(this).attr('maxlength');
    var val = $(this).attr('value');
    var cur = 0;
    if(val) // value="", or no value at all will cause an error
      cur = val.length;
    var left = max-cur;
    $(this).after("<div class='counter'>"
      + left.toString()+"</div>");
    // You can use something like this to align the
    // counter to the right of the input field.
    var c = $(this).next(".counter");

    $(this).keyup(function(i) {
      var max = $(this).attr('maxlength');
      var val = $(this).attr('value');
      var cur = 0;
        cur = val.length;
      var left = max-cur;
      return this;
  return this;

Usage Examples

You’d use it like the following. In the example, #main is the main body area, and all fields will have a class of maxlength which need the counter.

$(document).ready(function() {
  $("#main form input.maxlength").counter();

Or you could search for any fields with a maxlength attribute:

$(document).ready(function() {
  $("form input[@maxlength]").counter();