I’m moving the WURFL Capability Browser to its own domain with a slightly different name (and look): http://www.mobiledevicebrowser.com
So there it is.
I’m moving the WURFL Capability Browser to its own domain with a slightly different name (and look): http://www.mobiledevicebrowser.com
So there it is.
Recently I was tasked with making an internal “link shortener”, a la Bit.ly’s. For those that are unfamiliar with the concept, if you have an exceedingly long url that’s difficult to remember i.e.
You can use a shortener to make it more manageable. Bitly compressed the example URL above to: http://bit.ly/g25djH much easier to remember, much easier to distribute.
So I wanted similar functionality. I want to be able to generate a short, unique key to represent a long url. Most relational databases already use some form of base-ten integers (i.e. 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13… so forth) for keys on their tables. This is pretty well established, there are either auto increment support or sequences depending on the database that will keep track of these values for you. I could use these keys for shortening, but in the offshoot chance this feature took off it wouldn’t be too long before the integer numbers would get pretty long themselves, plus its generally advisable to mask the real table ids from the public eye.
So back to that url that bit.ly generated for me: http://bit.ly/g25djH. “g25djH” is obviously a key that translates to a row in a database somewhere that holds the original long url. Given that databases prefer numeric keys, what’s to make of bit.ly’s alpha numeric version? By using upper and lower case letters in their keys, they save a ton of space.
To wit: with a decimal representation of a number, each digit represents 10^x. If you add lowercase letters (a-z), each digit represents 36^x. Much larger values can be represented with fewer digits. So the standard ASCII character set provides for a couple hundred or so characters with which to construct an alpha numeric key, but the ten digits and twenty six lower-case letters are enough for my needs, and this example.
But still, how should you leverage a database to store these keys? You could make a varchar column a primary key and store these alpha-numeric values, but that wouldn’t be practical as the dataset grew not to mention if you wanted to use this value as a foreign key elsewhere. You could have a standard int-type primary key and a second key for the alpha-numeric representation, this is closer to ideal but the extra column is wasted space.
The best solution, in my opinion, is to make a function that will convert the standard base 10 integer into a base 36 value. This is essentially the same process as converting a decimal to hexidecimal value, but with a whole slew of characters. Therefore you get your condensed alpha-numeric keys while only using the standard int-type primary key.
This is functionality I’d like the db to have so I can translate keys directly in the sql. To accomplish this I’ve written two functions, one to convert an int to an alpha numeric key, and the other to convert an alpha numeric key to an int:
DELIMITER $$
DROP FUNCTION IF EXISTS ConvertIntToKey$$
CREATE FUNCTION ConvertIntToKey(intval INT )
RETURNS VARCHAR(100)
DETERMINISTIC
BEGIN
DECLARE i INT;
DECLARE d INT;
DECLARE r INT;
DECLARE dMoinsR INT;
DECLARE ch CHAR(1);
DECLARE result VARCHAR(200);
SET result = '';
SET d = intval;
REPEAT
SET r = MOD(d, 36);
SET ch = SUBSTR("0123456789abcdefghijklmnopqrstuvwxyz", (r+1), 1);
SET result = CONCAT( ch, result);
SET dMoinsR = d - r;
SET d = (dMoinsR / 36);
UNTIL (dMoinsR = 0)
END REPEAT;
RETURN result;
END$$
DELIMITER ;
DELIMITER $$
DROP FUNCTION IF EXISTS ConvertKeyToInt$$
CREATE FUNCTION ConvertKeyToInt( keyval VARCHAR(100) )
RETURNS INT
DETERMINISTIC
BEGIN
DECLARE backwards VARCHAR(100);
DECLARE keylen INT;
DECLARE intval INT;
DECLARE i INT;
DECLARE rootval INT;
SET backwards = REVERSE(keyval);
SET keylen = CHAR_LENGTH(keyval);
SET i = 0;
SET intval = 0;
SET rootval = 0;
WHILE i < keylen DO
SET rootval = POW(36, i) * (LOCATE(SUBSTR(backwards, (i+1), 1), "0123456789abcdefghijklmnopqrstuvwxyz") - 1);
SET intval = intval + rootval;
SET i = i + 1;
END WHILE;
RETURN intval;
END$$
DELIMITER ;
Because these are functions–not procedures–you can slot these right into a SQL query.
So the user types in http://your.bitly.clone/aba1
“aba1” is the key.
Your SQL query would look like:
SELECT su.id, ConvertIntToKey(su.id), su.full_url FROM stored_urls su WHERE su.id = ConvertKeyToInt(“aba1”);
Also, credit where credit’s due, I basically modified the hex to decimal conversion up on wikipedia: http://en.wikipedia.org/wiki/Hexadecimal#Converting_from_other_bases
Recently I’ve been catching up on all the games I missed back in the late eighties and nineties. Thanks to Steam, the Mac Games Store (http://www.macgamestore.com/), Good Old Games (http://gog.com), iTunes, and of course the random altruistic blog poster. So I’ve finally started on the 7th guest. I won’t lie, I’ve never been very good at pure puzzlers, but the main difference between myself today and fifteen odd years ago is that I’m more comfortable with letting computers solve these damn things for me. I’ve also been looking for excuses to practice python, so its two bird with one stone…
The puzzle in question is the queens problem: arrange eight queens on a chessboard such that none would “attack” each other in chess rules. That’s to say that one queen cannot be on the same vertical, horizontal, or diagonal path as another.
So first off what are a few rules:
So those rules being determined, there’s a matter of how to feed in the various board configurations to test. I could nest eight loops and run through each, but that’d take forever.
Since I’m using a one dimensional array to track this, a sample line would look like:
[0,1,2,3,4,5,6,7] or [0,2,1,3,5,4,6,7]
Every index could only hold a value from zero to seven. The starting array would look like [0,0,0,0,0,0,0,0] and the ending array would look like [7,7,7,7,7,7,7,7]. Well I want this to be in a single loop, I thought what if I just looped through a set number from 0 to the final value. My math’s a bit shaky, and statistics were never a strong suit, but looking at these numbers again, the question became very simple. Finding the maximum number of loops is pretty tricky in decimal (base ten) logic, but all these indexes could only go up to eight. Fortunately Python supports base eight (aka octal) arithmetic right out of the box. If counted in octal, converted the counter to a string and then sliced the resulting characters into an array, I could find all possible combinations in one loop and then process accordingly.
def printBoard( board ):
for row in range(0, 8):
rowstring = ''
for col in range(0, 8):
if(board[row] == col):
rowstring += 'q'
else :
rowstring += '_'
rowstring += ' '
print rowstring
print '\n\n'
return
success_count = 0
for i in range (0, 0100000000):
octa = int( oct(i) )
mask = '%(#)09d' % { "#" : octa }
board = [ int(mask[1]), int(mask[2]), int(mask[3]), int(mask[4]), int(mask[5]), int(mask[6]), int(mask[7]), int(mask[8]) ];
works = 1
for rowindex in range(0, 8):
for testindex in range(0, 8):
if(testindex != rowindex):
#check for horizontal
if( board[testindex] == board[rowindex] ):
works = 0
break
# check for diagonal
if( abs(testindex - rowindex) == abs(board[testindex] - board[rowindex]) ):
works = 0
break
if(works == 0):
break
if(works == 1) :
success_count = success_count + 1
print "Board ", success_count
printBoard( board )
As it turns out, there’s ninety two solutions to this puzzle, meaning I probably would’ve guessed the answer faster than coding had I stuck with it but c’est la vie.
And not to keep you in suspense, here’s one of the valid solutions to the puzzle:
_ _ _ _ _ q _ _ _ _ _ q _ _ _ _ q _ _ _ _ _ _ _ _ _ _ _ q _ _ _ _ _ _ _ _ _ _ q _ q _ _ _ _ _ _ _ _ _ _ _ _ q _ _ _ q _ _ _ _ _
So today marks the release of the newest version of the Wurfl browser (http://wurfl.ditherandbicker.com). In brief the changes encapsulate:
As before, I haven’t put much focus on IE compatibility, given that I don’t have easy access to a Windows computer outside of the workplace. IE fixes will probably be forthcoming.
This will probably be the last “major” revision to the tool. Here on out I’ll try to update the underlying db a few times a year and may play with the styling some more.
A previous employer entrusted the redesign of a major product to an Indian offshore firm. After about seven months, they lost total confidence in this team and severed all ties. It quickly fell on me to salvage the project and I believe it took about three months to getting it working “passably”. Nevertheless I still got constant questions about why it was taking so long. Rather than try to explain all of the issues with the offshore code to management and the business owners of the product, I printed out a before and after of a single function in a single file (of which there were hundreds of others in a similar state).
So important to note here: my revised code was about two pages long when spaced for readability. The original code was about eight pages long, basically single-spaced, and didn’t work at all.
I taped this over my workstation and whenever someone asked me about the delays I just pointed. It always did the trick.