lime icon

Phosphorus and Lime

A Developer's Broadsheet

This blog has been deprecated. Please visit my new blog at klenwell.com/press.
Slashdot on Earthlink Wi-Fi
More news on the failings of Earthlink wi-fi. I found this comment insightful:
Earthlink badly overreached themselves here with two major mistakes - first, deciding to use Tropos equipment to paint an entire city. Most of the money you burn in setting up a wifi installation is in the install and then trying to get everything to work when your planning tools are out of sync with reality (which is almost always). Tropos's mesh equipment is crap, so they've wasted months and burned untold money trying to nail jello to a wall.

Second, trying to blanket an entire city at once is doable, but it's far more practical to grow the network from little seed areas (while keeping future growth in mind) - blanket a six block area of downtown, for instance, and then expand from that. This lets you get everything right for a small area before you apply that to larger areas - it's the way almost all WISP (wireless ISPs) operate and it works fairly well.

I think Earthlink finally realized it wasn't gonna work, which of course makes all the assumptions under which they signed contracts not so great for them.
Greqo Licensing
A few weeks ago, I noted a reference to Greqo in what looked like a Russian forum for spammers:

Greqo: The Russian Blog-Spammer's Class of Choice?


A couple days ago I received an email from a Russian PHP developer drawing my attention to the Blogoferma site. The Russian developer pointed out that this product appears to be marketed in violation of Greqo's GPL license and he said that the marketer claims that he is selling it with my endorsement.

On the first point: as I noted in my previous post, my understanding of the GPL is that the marketer is free to use my code in his product just so long as he extends the GPL to his source (which I believe requires him including a GPL notice with his product) and makes his source code available upon request. As long as he does that, he is not under any obligation to me and can charge whatever he whatever he wants for it.

Of course, if it is true, as the PHP developer claims, that this product is little more than my code repackaged, anyone interested in the product would probably be better served just grabbing my code themselves for free at the project site. Also, I still look on Greqo as a beta release at best, so I'd be hesitant to trust anything too critical to it at this point.

On the second point: although I believe the marketer of Blogoferma has contacted me and even commented on my previous point, we have never discussed his product. If he claims I have endorsed or approved of it in any way, that's not true. As noted above, he can use it under the terms of the GPL, so my permission is not really necessary. The license is the authority with which he needs to reconcile himself.

And while I don't really like the idea of Greqo being used solely for the purposes of blogspam (or SEO if you will, which is often little more than a bagful of spamming tricks), that's a matter for which Blogger ultimately takes responsibility – and does a pretty good job of it.
Earthlink Layoffs
Just came across this in NY Times this morning:

EarthLink to Trim Work Force and Close Offices
The company is struggling to attract dial-up customers who are turning to high-speed alternatives and is studying the performance of its municipal wireless Internet networks in four cities before deciding how to move forward with similar networks elsewhere.


Looks like I got out just in time. I get the feeling their muni services are a bust. I know they were for me. Too bad, because it would have been a pretty good deal if it performed like advertised.

I just hope they really canceled my service. (Waiting for next invoice to show up in inbox...)
PHP: Get Base Domain
The problem: take a url (in this case, we'll specify an absolute url, http and all) and return only the base domain. For instance, given 'www.domain.com' or 'sub.subdomain.domain.com', it should return 'domain.com'.

Simple enough, but now consider: 'http://www.example_site.com.pk' or 'http://damnlimies.co.uk' or 'http://username:password@this.is.a.worst.shortly.subdomain.thisIsMyMainWebsite.com.cl'

It is an anvil upon which many a hammer has been broken:

http://lists.evolt.org/archive/Week-of-Mon-20031201/152316.html
http://www.webmasterworld.com/forum88/10656.htm

Anyway, I think I have a solution. I won't bother with the details of how I arrived at it. Suffice to say, you just need to break down your own url parsing process. It passed the battery of tests at the end:

// get base domain (domain.tld)
/*____________________________________________________________________________*/
function get_base_domain($url)
{
$debug = 0;
$base_domain = '';

// generic tlds (source: http://en.wikipedia.org/wiki/Generic_top-level_domain)
$G_TLD = array(
'biz','com','edu','gov','info','int','mil','name','net','org',
'aero','asia','cat','coop','jobs','mobi','museum','pro','tel','travel',
'arpa','root',
'berlin','bzh','cym','gal','geo','kid','kids','lat','mail','nyc','post','sco','web','xxx',
'nato',
'example','invalid','localhost','test',
'bitnet','csnet','ip','local','onion','uucp',
'co' // note: not technically, but used in things like co.uk
);

// country tlds (source: http://en.wikipedia.org/wiki/Country_code_top-level_domain)
$C_TLD = array(
// active
'ac','ad','ae','af','ag','ai','al','am','an','ao','aq','ar','as','at','au','aw','ax','az',
'ba','bb','bd','be','bf','bg','bh','bi','bj','bm','bn','bo','br','bs','bt','bw','by','bz',
'ca','cc','cd','cf','cg','ch','ci','ck','cl','cm','cn','co','cr','cu','cv','cx','cy','cz',
'de','dj','dk','dm','do','dz','ec','ee','eg','er','es','et','eu','fi','fj','fk','fm','fo',
'fr','ga','gd','ge','gf','gg','gh','gi','gl','gm','gn','gp','gq','gr','gs','gt','gu','gw',
'gy','hk','hm','hn','hr','ht','hu','id','ie','il','im','in','io','iq','ir','is','it','je',
'jm','jo','jp','ke','kg','kh','ki','km','kn','kr','kw','ky','kz','la','lb','lc','li','lk',
'lr','ls','lt','lu','lv','ly','ma','mc','md','mg','mh','mk','ml','mm','mn','mo','mp','mq',
'mr','ms','mt','mu','mv','mw','mx','my','mz','na','nc','ne','nf','ng','ni','nl','no','np',
'nr','nu','nz','om','pa','pe','pf','pg','ph','pk','pl','pn','pr','ps','pt','pw','py','qa',
're','ro','ru','rw','sa','sb','sc','sd','se','sg','sh','si','sk','sl','sm','sn','sr','st',
'sv','sy','sz','tc','td','tf','tg','th','tj','tk','tl','tm','tn','to','tr','tt','tv','tw',
'tz','ua','ug','uk','us','uy','uz','va','vc','ve','vg','vi','vn','vu','wf','ws','ye','yu',
'za','zm','zw',
// inactive
'eh','kp','me','rs','um','bv','gb','pm','sj','so','yt','su','tp','bu','cs','dd','zr'
);


// get domain
if ( !$full_domain = get_url_domain($url) )
{
return $base_domain;
}

// now the fun

// break up domain, reverse
$DOMAIN = explode('.', $full_domain);
if ( $debug ) print_r($DOMAIN);
$DOMAIN = array_reverse($DOMAIN);
if ( $debug ) print_r($DOMAIN);

// first check for ip address
if ( count($DOMAIN) == 4 && is_numeric($DOMAIN[0]) && is_numeric($DOMAIN[3]) )
{
return $full_domain;
}

// if only 2 domain parts, that must be our domain
if ( count($DOMAIN) <= 2 ) return $full_domain;

/*
finally, with 3+ domain parts: obviously D0 is tld
now, if D0 = ctld and D1 = gtld, we might have something like com.uk
so, if D0 = ctld && D1 = gtld && D2 != 'www', domain = D2.D1.D0
else if D0 = ctld && D1 = gtld && D2 == 'www', domain = D1.D0
else domain = D1.D0
these rules are simplified below
*/
if ( in_array($DOMAIN[0], $C_TLD) && in_array($DOMAIN[1], $G_TLD) && $DOMAIN[2] != 'www' )
{
$full_domain = $DOMAIN[2] . '.' . $DOMAIN[1] . '.' . $DOMAIN[0];
}
else
{
$full_domain = $DOMAIN[1] . '.' . $DOMAIN[0];;
}

// did we succeed?
return $full_domain;
}
/*____________________________________________________________________________*/


// get domain from url
/*____________________________________________________________________________*/
function get_url_domain($url)
{
$domain = '';

$_URL = parse_url($url);

// sanity check
if ( empty($_URL) || empty($_URL['host']) )
{
$domain = '';
}
else
{
$domain = $_URL['host'];
}

return $domain;
}
/*____________________________________________________________________________*/


// Testbed
/*____________________________________________________________________________*/

if ( 1 )
{
// test code here
$TESTURL[] = 'http://127.0.0.1';
$TESTURL[] = 'http://www.examplesite.com.pk';
$TESTURL[] = 'http://domain.tv.com';
$TESTURL[] = 'http://domain.com.tv';
$TESTURL[] = 'http://domain.tv';
$TESTURL[] = 'http://domain.com';
$TESTURL[] = 'http://secure.email.website.co.uk';
$TESTURL[] = 'http://username:password@this.is.a.worst.shortly.subdomain.thisIsMyMainWebsite.com.cl';

foreach ( $TESTURL as $url )
{
echo $url . ' -> ' . get_base_domain($url) . '
';
}
}

/*____________________________________________________________________________*/


results:
http://127.0.0.1 -> 127.0.0.1
http://www.examplesite.com.pk -> examplesite.com.pk
http://domain.tv.com -> tv.com
http://domain.com.tv -> domain.com.tv
http://domain.tv -> domain.tv
http://domain.com -> domain.com
http://secure.email.website.co.uk -> website.co.uk
http://username:password@this.is.a.worst.shortly.subdomain.thisIsMyMainWebsite.com.cl -> thisIsMyMainWebsite.com.cl


The source will eventually end up in the bafflegate repository.
New York Times on Micropayments
Micropayments – currency in general – has always been a fascination of mine. The New York Times has a brief report this morning on the state of online micropayments:

In Online World, Pocket Change Is Not Easily Spent

From the article:
But the problems proved insurmountable. Many micropayments companies have shut down, been acquired or changed their business models over the years. Among them: DigiCash, CyberCash, First Virtual Holdings and Peppercoin.

They used various systems, but in general users paid into accounts with their credit cards and then drew from those accounts. In the mid- to late ’90s, electronic cash had become such a popular concept that some politicians worried that it might threaten the stability of the nation’s currency.

But the economic and technical challenges were enormous. Consumers were reluctant to pay even a tenth of a cent for something they believed should be free. “There is a certain amount of anxiety involved in any decision to buy, no matter how small,” Mr. Shirky wrote in 2000.
PHP: Drupal Theme "abstruct"
This is a revision of the wtfm theme I posted last week. I posted a brief overview in the drupal forums.

Some links:

demo
download
source

Also, I discovered this page which I found very helpful:

http://drupal.org/node/11812

It lists all the page.tpl.php variables

Labels: ,

CSS: The Rounded Corner Fairy
Technically, it's a sprite. A single image used to round all four corners of a div block. The idea was inspired by this ALA article.

Previously, I've used the clever nifty corners javascript package. It's more elegant on the development side. But in operation, it's a bit clunky and results in a noticeable bounce as the tweaks are applied to the output.

Css-defined background images fill in more smoothly, but require additional sweat in putting together the page. First, you must create the appropriate image(s) (the background and foreground colors must match the css settings.) You only need one 16x16 round image like this:



But you must add four additional empty divs:

<div id="col1" class="column"><div class="tl"></div><div class="tr"></div><div class="child">

<!-- content -->

<div class="clear"></div>
</div><div class="bl"></div><div class="br"></div></div>


You must include the css settings:

/* note: parent block must have position setting of relative or absolute */
.column { position:relative; }
.tl { top:0px; left:0px; }
.tr { top:0px; right:0px; background-position:8px 0px; }
.bl { bottom:0px; left:0px; background-position:0px 8px; }
.br { bottom:0px; right:0px; background-position:8px 8px; }
.tl, .tr, .bl, .br { background-image:url('c16.ccddcc.png'); position:absolute; height:8px; width:8px; overflow:hidden }


And, as noted above, you have to make sure you give the parent block the proper position setting.

Also, while it works in Firefox and IE7, it doesn't quite work in IE6 and I haven't tested it any other browsers.

You can see the technique in action here: klenwell google page

Not perfect. But it has it virtues.
Earthlink Cancelled
At last. I haven't even used it for the last 3 months. My year-long contract didn't expire until last month so wasn't much I could do in the meantime, except pay my $20/mo subscription.

It took me three phone calls and about a half-hour waiting on hold to finally find someone who could help me. The call-center agent offered me 2 months free to stay, a sign that things as fucked up now as when I last used it.

Earthlink was my first ISP ever (over 10 years ago!) and I always kinda rooted for them as the underdog. No more. I would have been patient with the crappy muni wifi service if only their technical support wasn't so totally ineffective. No email support, maddening phone trees (where there isn't even a wifi option!) and interminable wait times.

Need to cancel (or just get a couple months of service for free)?

888-327-8454

Good riddance!

Labels:

PHP: Drupal Theme "wtfm"
wtfm is my first full drupal theme. It's primary goal is to function as a basic template for other themes, but I have made it the theme of my new drupal site, wtfm.

More info:
features
demo
source code

Labels: ,

Games: boomshine
Not much of a gamer. Not anymore. My favorite game? Probably Texas hold 'em. Or Monopoly. On the computer, it's Sim City or good old Free Cell.

Anyway, came across boomshine today on bored.com via digg. The original home page seems to be here (though it did not load for me here):

http://www.k2xl.com/games/boomshine/

Can't say much for the creator's web design sense, but I think the game is beautiful and elegant in its simplicity. And fun to play. A little masterpiece.
New Yorker: Damn Spam
A well-written article from The New Yorker this week on the state of spam. Old news to anyone who casually follows the issue. And not at all encouraging. But an intelligent summary for technical and non-technical readers:

Damn Spam: The losing war on junk e-mail

slashdot commentary
OneKeyAway
Before parties, guests register online and complete questionnaires. The answers are then transferred to digital memory devices -- red, plastic squares slightly larger than a matchbox -- that the guests wear like necklaces.

During a party, people point their devices at one another to check how compatible they are. The devices flash red, yellow or green, depending on their level of compatibility.

New way for singles to meet -- the digital zap (Yahoo! News)


The bad news for me is that I had an idea for an "icebreaker" device very similar to this a couple years ago.

The good news is, OneKeyAway over-complicated their device to the point that it will never be more than a novelty gadget "for professionals who want to meet other professionals" in a speed-dating environment.

The bad news is that a better marketer will simply copy this, figure out how to mainstream it, and make a social networking gadget that's more popular than the iPod -- and it won't be me.

The other good news is that the article notes that the inventor of this started working on it in 2004, which was before I had my idea. So I don't feel so bad after all.
JS: balancing columns
A common problem: set two html blocks to the same height using only css and without tables. I've usually solved this in the past by using tables. But I figured it was time to grow up and figure out the "modern" div-based method for setting two side-by-side blocks to the same height.

Here's a javascript function that returns the max height for two html blocks:

function get_max_div_height(id1, id2)
{
var Dom1 = document.getElementById(id1);
var Dom2 = document.getElementById(id2);
var h1 = Dom1.offsetHeight;
var h2 = Dom2.offsetHeight;
max_ht = Math.max(h1, h2);

// debug
// alert("compare " + id1 + " & " + id2 + " heights: " + h1 + " / " + h2 + " -> max: " + max_ht);

return max_ht;
}


From here, it's just a matter of setting each block to the max height:

document.getElementById(dom_id).style.height = max_ht + "px";


I'm working on a version of this that can take n elements and equalize the height. I'll post that to the klenwell repository when complete and tested.

Labels: