/* No Comments */

About a few hacks and the violin.

I am Rich (I Wish)

Well wanted to write this last week, but wanted to read more about the reactions to Apple yanking out the “I am rich” application from its store.

Apple’s reaction to the app is hardly surprising, after all the company does have a reputation for masking its dubious actions of cencorship and spoon feeding its customers under the blanket motto of “quality”.  What was surprising (may be less so given the psyche of the iStuff customers) is the customers reaction.  All I have heard all around are “kudos Steve, great work.”

Forget cencorship, are we actually planning to get rid of the words “Common Sense” out of our vocabulary and lives for ever?  What ever happened to Buyer Beware?  Let me go through the arguments Ive heard.

1. It is Apple’s store and they can do what ever they want.

Ok No argument here.  I mean if M$ can do what they want and get away with it, why shouldnt Apple?  If this is all we care about, then stop reading right here.

2. You dont find $1000 news papers in a news-stand so why should we have them in the AppStore?

Marketing and Economics 101.  A news agent, has to prioritise the shelf space to maximise his/her profits.  A good indication of this is the customer demand for a product, not ethical or moral values.  You dont find $1000 news papers in a news stand simply because the market segment looking for $1000 news papers is not the one being targetted by the news stand.  If you are looking for expensive magazines try this.

3. Dilutes the quality of the App Store

Welcome to economics again.  Ever heard of supply and demand?  Ever heard of transaction costs? It was not exactly hard to “find” the product.  The App store enables you to search by price and (I am assuming) a few other criteria.  So we have 0 transactions costs for the users OR Apple (never mind that Apple made a cool 30% of the app!).  In an open market (which is what this SHOULD be) the best would bubble to the top and crap like this sinks to the bottom (ok I suddenly have a hankering for this app and I dont even have an iPhone!).

4. People are being fooled and tricked.

How?  Was the price not clear?  Was the product description not clear?  Sure the app is useless.  But was its uselessness ever a secret and mis-communicated?  The 8 who have actually bought the app, knew exactly what they were getting into (by the way how many of them are actually complaining about it?).

5. Mockery of the store

Wow another insightful argument for masking the envy at good (well ok going a bit far there) entrepreneurship.  So suddenly we are ok with Louis Vuitton bags (known mainly for their durability?) but an attempt at brand management and positioning (towards deep-pocketed) users is wrong and unethical and evil and dodgy (and a whole lot of other equally _____ adjectives).  Perhaps it is time we (developers) start making apps targeted at user needs (refer to PG’s “make something users want” mantra for this)?

————————

All said and done fellas, the marketing hype for the AppStore and Heinrich (the app’s author) have been phenominal.  Even with a sale to 8 customers, thats a massive revenue of 80,000.  Wow.  Kudos.  This is just capitalism guys.  Get used to it.  The thing with idiots is, if you cant beat them, you just take advantage of them.  And kudos again to Heinrich for doing just that.  Dont try to beat this guy, join him!!

The other reason I am excited about Apple having been foolish in dealing with this App, is that the need for a better market place for the iPhone is becoming more pronounced.  How long can Apple’s cencorship and treatment of its customers as children help insulate (and incubate?) its customers’ stupidity?

August 11, 2008 Posted by Sri | App Store, Internet, iPhone | , , | 2 Comments

Google App Engine

Well ive been spending the last week and a bit with my first AppEngine project.  I had recieved my account on the day it was released (yes a shameless boast there :D )…  Unfortunately due to exams never got around to doing anything with it.

So as a simple project I figured Il write (yet another online) chess game – WizChess.  Note that there is already a Blitz Chess as part of the appengine samples page.  I wanted to write one just to get a feel for the engine and to largely to learn a lot of things myself.  There are a still a few things I have not implemented (eg on a castle, the server updates, but the client does not properly update UI.  en-passante-s are not implemented.  Timed game not hapening yet, chatting between players not yet happening and so on).

It was a very interesting experience.  The documentation was quite nice and full, but still I was not fully satisfied.  For some reason I found django a lot more satisfying as a web-app dev platform.  For the models for the game I had chosen to follow a more django style (relational) rather than harnessing the rich model extensions provided by appengine (mainly the Expando Models).  I had done this as I wasnt sure if I wanted to seal my app purely to the AppEngine platform.  And after finishing the project, I am still not sure that I do.

I had got a whole bunch of puzzle games from here.  Now I had needed a way to update the database with an initial data set.  So my way was to have a url on the webapp (something like /resetdb) that would load the initial board templates (and in the future games that are saved and so on).  However, since this loading would take some time, I had to resort to breaking this up into several parts and calling each of these individually.  eg:  Id nomally have:

class ResetDB(webapp.RequestHandler):
    def get(self):
        for board in my_boards:
            add_board_to_db(board)

Now as the number boards in my data set increased, the time to put them in the data store would naturally increase.  But there seems to a time limit on each request, which would make my request fail.  So I had to resort to writing a client side script that would call ResetDB with parameters (eg, firstboard and lastboard) and then also break em up as more saved games were restored etc.  Absolute Pain!  Its all good for appengine to be smart about things but to impose assumptions severely limits the usefulness of this platform and I hope in the future this is released.

Next thing was the model apis.  The Expando model is awesome, but once again I was not happy about the lockin.  But this was not my main concern.  The querying api is extremely poor.  Django has amazing querying facilities where one can specify pretty much arbitrary query filters (not a and c or a minus x and so on).  AppEngine does not support “not”s in its query.  Aaaaaaaaaaaaaaaaah.   Also I couldnt find an easy way of chaining queries.  Eg, to find a game, where either player0 or player1 (my way of saying white or black) was user, I had to do this:

games_with_user = []
games = models.Game.all()
games_with_user.extend([g for g in games if g['player0'] = current_user])
games_with_user.extend([g for g in games if g['player1'] = current_user])

Yuck!  Same thing in Django happens with:

games_with_user = models.Game.filter(Q(player0 = current_user) or Q(player1 = current_user))

(ok I did that syntax from memory so it may not be right, but it is something similar).

Now the final that REALLY annoyed me was lack of Comet (or any reverse ajax) support.  Essentially I poll the server every 5 seconds to get updates on whether the opponent has played.  Would have been great for the server to notify the client instead of having to keep polling and waste requests (I believe there is a limit of 6.5 million requests a day or is that 650K requests?)

But having said all this, the main (only?) advantage of the platform is the fact that we dont have to worry about scalability.  Unfortunately this is a HUGE advantage.  Normally I could write an app, and host it on my own boxes at home (if i want it to be free), but then il soon be hitting limits with 10 users and Il have to find a hoster and also handle scalability issues myself.  So migrating my own code to appengine at THAT point would be quite a nightmare.  By writing and prototyping it on appengine allows me to fail fast.  Looking at the pricing, app engine would charge about $40 per month per app (with reasonable traffic).  If my app ever got to that stage, I could always port it out of appengine (as long as I dont use Expando and stick to django style object modelling – with which I dont loose any power).

Please let me know if you would like the sources.  I am not sure how to upload files to wordpress here.

Also I would really appreciate it if you could give me feedback on my learning here.  As a python and web-app noob, Id be grateful for pointing any errors in my ways :D

June 1, 2008 Posted by Sri | Google App Engine, Internet, Python | , , | No Comments Yet

Inbreeding – The Valley Style

So Marc Andreessen joins the Board of Facebook.  (Advance note of jealousy towards Mark Zuckerberg for getting someone of Marc’s stature.  Kudos).

What I find surprising is will there be any input from Marc on FB’s technical strategy?  I am specifically concerned about Marc’s Ning using OpenSocial and FB using its own FB API.  Will we see a merging of the two?  Surely it would be stupid (a quality I possess in abundance) to think FB would abandon FB API in favour of Ning for better tapping into Ning and its countless social networks hosted within.  However one cannot help see the allure in a wrapper to FB API to be OpenSocial compatible?

Or is this issue too puny and insignificant to deserve a mention?

May 7, 2008 Posted by Sri | Entrepreneurship, Internet, Startups | | No Comments Yet

gDay Mate

Well, no exception. Google dazzles us all with their supreme Mate technology – short for Machine Assisted Temporal Extraction.  Its the beginning of Future searches!!!  Just put in the keywords and search for items that may appear tomorrow!!

I was a bit skeptical to see how it actually works but man its amazing!  Looks like I wont have to be working ever again!!

Here’s the link!!

http://www.google.com.au/intl/en/gday/index.html

March 31, 2008 Posted by Sri | Internet | | No Comments Yet

gprobe – Json Parser

Here is the code for the json parser I had described in an earlier post.  It is still to be fully tested (works for our purpose right now).

Essentially data is fed into the parser continuosly (as there are no blocked reads in flex from the socket).

Usage is:


var parser:GPJsonParser = new GPJsonParser()
parser.processBytes(byteArray)
var nextObj:* = parser.next();
while (nextObj != null)
{
// do something with nextObj
nextObj = parser.next();
}

nextObj will only be non-null if there were no syntax errors and if enough bytes were consumed to produced a complete json fragment.

package gprobe.utils
{

import flash.utils.ByteArray;/*
* On-demand parser for parsing json from a stream
*/
public class GPJsonParser
{
private static var STATE_EOF:int                  = -1;
private static var STATE_START:int                = 0;
private static var STATE_READING_IDENTIFIER:int    = 1;
private static var STATE_READING_NUMBER:int       = 2;
private static var STATE_READING_STRING:int       = 3;

private static var OBJ_NULL:int         = 0;
private static var OBJ_BOOL:int         = 1;
private static var OBJ_NUMBER:int       = 2;
private static var OBJ_STRING:int       = 3;
private static var OBJ_LIST:int         = 4;
private static var OBJ_STRUCT:int       = 5;
private static var OBJ_COMA:int         = 6;
private static var OBJ_COLON:int        = 7;
private static var OBJ_OPEN_BRACE:int   = 8;
private static var OBJ_OPEN_SQUARE:int  = 9;
private static var OBJ_CLOSE_BRACE:int  = 10;
private static var OBJ_CLOSE_SQUARE:int = 11;

/*
* Current string delimiter only valid if we are
* currently reading a string
*/
private var currDelim:int;

/*
* Current string - only if we are reading a string
*/
private var currString:String;

/*
* State in reading current string
*/
private var currStringState:int;

/*
* The byte buffer
*/
private var byteBuffers: Array = new Array();

/*
*
*/
private var currBuffer: ByteArray;

/*
* Number of bytes read since start of object
*/
private var bytesRead: int;

/*
* Current parser state
*/
private var currState: int;

/*
* How many unmatched open square brackets have we encountered?
*/
private var squareCount: int = 0;

/*
* How many unmatched open braces have we encountered?
*/
private var braceCount: int = 0;

/*
* Current parent object
*/
private var objStack: Array = null;

private static const CHAR_BSLASH:int = '\/'.charCodeAt(0);
private static const CHAR_DQUOTE:int = '"'.charCodeAt(0);
private static const CHAR_SQUOTE:int = '\''.charCodeAt(0);
private static const CHAR_PLUS:int = '+'.charCodeAt(0);
private static const CHAR_DOT:int = '.'.charCodeAt(0);
private static const CHAR_a:int = 'a'.charCodeAt(0);
private static const CHAR_A:int = 'A'.charCodeAt(0);
private static const CHAR_e:int = 'e'.charCodeAt(0);
private static const CHAR_E:int = 'E'.charCodeAt(0);
private static const CHAR_t:int = 't'.charCodeAt(0);
private static const CHAR_v:int = 'v'.charCodeAt(0);
private static const CHAR_b:int = 'b'.charCodeAt(0);
private static const CHAR_f:int = 'f'.charCodeAt(0);
private static const CHAR_r:int = 'r'.charCodeAt(0);
private static const CHAR_n:int = 'n'.charCodeAt(0);
private static const CHAR_z:int = 'z'.charCodeAt(0);
private static const CHAR_Z:int = 'Z'.charCodeAt(0);
private static const CHAR_0:int = '0'.charCodeAt(0);
private static const CHAR_9:int = '9'.charCodeAt(0);
private static const CHAR_SLASH:int = '\\'.charCodeAt(0);
private static const CHAR_SPACE:int = ' '.charCodeAt(0);
private static const CHAR_MINUS:int = '-'.charCodeAt(0);
private static const CHAR_UND:int = '_'.charCodeAt(0);
private static const CHAR_TAB:int = '\t'.charCodeAt(0);
private static const CHAR_CR:int = '\r'.charCodeAt(0);
private static const CHAR_LF:int = '\n'.charCodeAt(0);
private static const CHAR_COMA:int = ','.charCodeAt(0);
private static const CHAR_COLON:int = ':'.charCodeAt(0);
private static const CHAR_OSQ:int = '['.charCodeAt(0);
private static const CHAR_CSQ:int = ']'.charCodeAt(0);
private static const CHAR_OBRACE:int = '{'.charCodeAt(0);
private static const CHAR_CBRACE:int = '}'.charCodeAt(0);

/*
* Constructor
*/
public function GPJsonParser()
{
reset();
}

/*
* Resets the parser
*/
public function reset(resetBytes:Boolean = true): void
{
objStack        = [];
currState       = STATE_START;
bytesRead       = 0;
currString      = "";
currStringState = 0;
squareCount     = 0;
braceCount      = 0;
if (resetBytes)
{
byteBuffers = new Array();
currBuffer  = null;
}
}

/*
* Process more bytes.
*
* Returns nothing.  Call next() to retrieve the next object
* from the stream (if any).
*/
public function processBytes(data:ByteArray): void
{
byteBuffers.push(data);
}

/*
* Return the next object from the stream.
* null if none (this is not necessarily an error, just means we do
* not have enough bytes given to us to extract the next object).
*/
public function next(): *
{
var currCh:*;
var readChar:Boolean = true;

while ( ! (objStack.length == 1 && squareCount == 0 && braceCount == 0))
{
if (currBuffer == null || currBuffer.bytesAvailable == 0)
{
if (byteBuffers.length == 0)
{
return null;
}
currBuffer = byteBuffers.pop();
}
if (readChar)
{
if (currBuffer.bytesAvailable == 0)
return null;
bytesRead++;
currCh = currBuffer.readByte();
}
else
{
readChar = true;
}

if (currState == STATE_READING_STRING)
{
processStringBytes(currCh);
}
else if (currState == STATE_READING_IDENTIFIER)
{
if ((currCh >= CHAR_a && currCh <= CHAR_z)         ||
(currCh >= CHAR_A && currCh <= CHAR_Z)     ||
(currCh >= CHAR_0 && currCh <= CHAR_9)     ||
currCh == CHAR_UND)
{
currString += String.fromCharCode(currCh);
}
else
{
if (currString == "true")
{
shift(OBJ_BOOL, true);
}
else if (currString == "false")
{
shift(OBJ_BOOL, false);
}
else if (currString == "null")
{
shift(OBJ_NULL, null);
}
else
{
shift(OBJ_STRING, currString);
//throw new Error("Invalid identifier: " + currString);
}

currState = STATE_START;
readChar = false;
}
}
else if (currState == STATE_READING_NUMBER)
{
if ( ! processNumberBytes(currCh))
{
readChar = false;
}
}
else if (currState == STATE_START)
{
if (currCh == CHAR_SPACE || currCh == CHAR_TAB ||
currCh == CHAR_CR || currCh == CHAR_LF)
{
// ignore white spaces
}
else if ((currCh >= CHAR_a && currCh <= CHAR_z)         ||
(currCh >= CHAR_A && currCh <= CHAR_Z)     ||
currCh == CHAR_UND)
{
currState = STATE_READING_IDENTIFIER;
currString = String.fromCharCode(currCh);
}
else if (currCh == CHAR_MINUS || (currCh >= CHAR_0 && currCh <= CHAR_9))
{
currState = STATE_READING_NUMBER;
currStringState = 0;
processNumberBytes(currCh);
}
else if (currCh == CHAR_SQUOTE || currCh == CHAR_DQUOTE)
{
currDelim = currCh;
currString = "";
currState = STATE_READING_STRING;
}
else if (currCh == CHAR_COMA)
{
shift(OBJ_COMA);
}
else if (currCh == CHAR_COLON)
{
shift(OBJ_COLON);
}
else if (currCh == CHAR_OSQ)
{
squareCount++;
shift(OBJ_OPEN_SQUARE);
}
else if (currCh == CHAR_OBRACE)
{
braceCount++;
// shift(OBJ_STRUCT, new Object());
shift(OBJ_OPEN_BRACE);
}
else if (currCh == CHAR_CSQ)
{
squareCount--;
shift(OBJ_CLOSE_SQUARE);
}
else if (currCh == CHAR_CBRACE)
{
braceCount--;
shift(OBJ_CLOSE_BRACE);
}
}
}

if (objStack.length == 1)
{
var obj:Object = objStack.pop();
reset(false);
return obj['value'];
}

return null;
}

/*
* Shifts a token onto the stack and immediately reduces it (the
* stack)
*/
private function shift(tok:int, value: * = null): void
{
if (tok == OBJ_CLOSE_SQUARE || tok == OBJ_CLOSE_BRACE)
{
reduce(tok);
}
else
{
objStack.push({'type': tok, 'value': value});
}
}

/*
* Reduces the parse stackby utilising the next token.
* Reduction can happen more than once.
*/
private function reduce(topType:int): void
{
var t1: *;
var t2: *;

if (topType == OBJ_CLOSE_SQUARE)
{
// we are building a list
var newArray: Array = new Array();
while (objStack.length > 0 &&
objStack[objStack.length - 1]['type'] != OBJ_OPEN_SQUARE)
{
t1 = objStack.pop();
if (t1['type'] == OBJ_COMA)
t1 = objStack.pop();
newArray.push(t1['value']);
}
if (objStack.length == 0 || objStack[objStack.length - 1]['type'] != OBJ_OPEN_SQUARE)
{
throw new Error("Could not find '['");
}
objStack.pop();
newArray.reverse();
objStack.push({'type': OBJ_LIST, 'value': newArray});
}
else
{
// we are building a map
var newObj: Object = new Object();
while (objStack.length > 0 &&
objStack[objStack.length - 1]['type'] != OBJ_OPEN_BRACE)
{
t1 = objStack.pop();
if (t1['type'] == OBJ_COMA)
{
t1 = objStack.pop();
}

t2 = objStack.pop();
if (t2['type'] != OBJ_COLON)
{
throw new Error("':' expected but not found");
}
t2 = objStack.pop();

newObj[t2['value']] = t1['value'];
}
if (objStack.length == 0 || objStack[objStack.length - 1]['type'] != OBJ_OPEN_BRACE)
{
throw new Error("Could not find '{'");
}
objStack.pop();
objStack.push({'type': OBJ_STRUCT, 'value': newObj});
}
}

private function processNumberBytes(currCh: *): Boolean
{
var NUM_START:int               = 0;
var NUM_READING_INT:int         = 1;
var NUM_READING_DOT:int         = 2;
var NUM_READING_FRAC:int        = 3;
var NUM_READING_EXP:int         = 4;
var NUM_READING_EXP_DIGITS:int  = 5;

if (currStringState == NUM_START)
{
currString         = "";
currStringState = NUM_READING_INT;
if (currCh == CHAR_MINUS)
{
currString     = '-';
return true;
}
}

if (currStringState == NUM_READING_INT)
{
if (currCh >= CHAR_0 && currCh <= CHAR_9)
{
currString += String.fromCharCode(currCh);
return true;
}
else
{
currStringState = NUM_READING_DOT;
}
}

if (currStringState == NUM_READING_DOT)
{
if (currCh == CHAR_DOT)
{
currString += '.';
return true;
}
else if (currCh == CHAR_e || currCh == CHAR_E)
{
currString += 'e';
currStringState = NUM_READING_EXP;
return true;
}

currStringState = NUM_READING_FRAC;
}

if (currStringState == NUM_READING_FRAC)
{
if (currCh >= CHAR_0 && currCh <= CHAR_9)
{
currString += String.fromCharCode(currCh);
return true;
}
else if (currCh == CHAR_e || currCh == CHAR_E)
{
currString += 'e';
currStringState = NUM_READING_EXP;
return true;
}
}

if (currStringState == NUM_READING_EXP)
{
currStringState = NUM_READING_EXP_DIGITS;
if (currCh == CHAR_PLUS)
{
currString += '+';
return true;
}
else if (currCh == CHAR_MINUS)
{
currString += '-';
return true;
}
}

if (currStringState == NUM_READING_EXP_DIGITS)
{
if (currCh >= CHAR_0 && currCh <= CHAR_9)
{
currString += String.fromCharCode(currCh);
return true;
}
}

currState = STATE_START;
shift(OBJ_NUMBER, Number(currString));

// invalid char, must be end of numeric
// value so let the caller take care of the
// rest by not consuming the character
return false;
}
private function processStringBytes(currCh: *): void
{
var STR_NORMAL:int = 0;
var STR_SLASH:int  = 1;

if (currStringState == STR_SLASH)
{
currStringState = STR_NORMAL
if (currCh == CHAR_SLASH)
{
currString += '\\';
}
else if (currCh == CHAR_t)
{
currString += '\t';
}
else if (currCh == CHAR_n)
{
currString += '\n';
}
else if (currCh == CHAR_r)
{
currString += '\r';
}
else if (currCh == CHAR_b)
{
currString += '\b';
}
else if (currCh == CHAR_f)
{
currString += '\f';
}
else if (currCh == CHAR_BSLASH)
{
currString += '\/';
}
else if (currCh == CHAR_DQUOTE)
{
currString += '"';
}
else if (currCh == CHAR_SQUOTE)
{
currString += '\'';
}
else
{
currString += ("\\" + currCh);
}
}
else if (currCh == currDelim)
{
currState = STATE_START;
shift(OBJ_STRING, currString);
}
else
{
currString += String.fromCharCode(currCh);
}
}
}

}
Essentially, since data is read asynchronously, it needs to be "fed" data as it is recieved by calling

February 7, 2008 Posted by Sri | Internet | | No Comments Yet

gprobe – Part 1 – Message Formats

Message transport (between the gprobe, the game server I had written for my work in my spare time and the front end client) was using json or  Action Message Format, AMF.  Reason for the duality, was that for quick testing, I could login into the server with simple telnet and send (textual) commands and recieve data in json format – Simple.  However, I could not find a built in JSON parser for Flex and writing one (again, as I had already written one in C++ for the server side) – didnt just seem too appealing.  Luckily, Flex is capable of serializing and deserializing objects in binary format over a stream – yep – the Action Message Format or AMF.  Adding the AMF serializer to the server was fairly simple (did take few hints on the integer encoding from pyamf – thanks guys).

Now the problem was that I could not find a way of debugging the decoding (on the flex side) of the AMF stream I had generated from my server.  Why do I need debugging you ask?  Well, I was having random errors in the AMF stream (no doubt due to my encoding) while encoding strings.  Due to time-constraints I had decided to switch to JSON.  This meant I had to write a json parser for flex (as I could not find one at the time).  Not too bad as it gave me a lot of insight into what was being sent and so on.  One day when I earn more free time at work I may decided to debug my AMF encoder.

February 4, 2008 Posted by Sri | C++, Internet | | No Comments Yet

Flex

At work I write games.  No not the cool ones like Xbox or PS3 or Wii, but pokie machines ones.  Enough said.  Anyway, each build of the game takes about 5-10 minutes and each start takes upto 3 minutes.  Needless to say, the bug-fixing and configuration is quite the pain in the posterior.

An obvious realisation was, why not write a server that could listen to commands from “somewhere” and make changes to the game (objects) at run time.  This would mean a build is only necessary on a critical improvent.  And a restart (of the the game) would only be required on a rebuild!  This would be useful for modifying Sprite locations and properties and just about anything which the custom server can get hold off.  Now such a tool did exist.  Unfortunatly it was a custom written http server, which printed out the entire Sprite tree on each request.  Worse still, each request opened a new connection and then closed it.  Did I mention that this server only allowed querying, not modifying or creation of sprites (or other game objects)?

So I embarked on a new probing utility for doing just that.  The server was written in C++ using pthreads for multi-threading.  No big deal.  That is not what I am going to talk about – better people have written and preached about the art of server writing.  Thing that got me tickled was I used this opportunity to learn flash, so I begain writing the gui in flash/flex.  Main reason was that I wanted a web based UI for the client-side.  The experience was amazing.  The API is fantastic and intuitive, the IDE (well painful was having to move from VIM to Flex Builder/Linux on Eclipse due to intellisense).  Conversely without intellisense, the experience is tortuous.

Il talk more about the features in future posts each dealing with a subchallenge in the project.

December 18, 2007 Posted by Sri | C++, Internet | | No Comments Yet

OpenSocial

Google’s announcement of OpenSocial is fairly old news (atleast by blog time-lines anyway).  It was amazing how many companies had been  briefed earlier on, while Facebook had been kept in the dark.  If it was intended as fair platforms for all social network sites out there, why had Google decided to work with MySpace “secretly” over the past year?

And am I the only one finding it odd (or just finding) that it is merely a glorified version of the Google Gadget API?

November 5, 2007 Posted by Sri | Internet | | No Comments Yet

OmniFS

Today marks the release of omnifs. I had started trying omnidrive – a storage drive on the web in mid April. I am still on the free service (which comes with 1Gb of Storage and 5Gb of transfers/month). It is still in beta mind you, but not bad at all. They even have a client for windows and mac. The windows client lets you mount omnidrive as a special folder which can be accessed from windows explorer.

However, for Linux, I had to install a Java client. Now I am not against Java, but wondered why couldnt this just be a mountable drive? So being the fidder (or is it twiddler?) that I am, I thought, “if you cant find it, make it”. I set about making a mountable drive for omnidrive. Luckily I had come across the omnidrive developer API. It is not bad but could really be better by being clearer. The result of this work is omnifs. This is small program that uses the Fuse (Filesystem over User Space) library to mount your omnidrive account as a directory in Linux! By doing so, normal file operations can be performed (eg cp, mv, ls and also developer functionility like fXXX functions in the C library). Please do try it out. Would love to here what you think about it and ofcourse to fix it up more.

The general goal of omnifs is to transition into a “webfs” so that it would eventually support WebDAV and other online storage accounts!

June 1, 2007 Posted by Sri | All, Internet | | No Comments Yet

KabookiWater

STIRR Sydney was hosted again last night (Thu 29/03/2007) at the Ivory Restaurant 620 Harris St, by Tangler, Atlassian, Omnidrive and TVP. This was my first time at this event (well I had been to BarCamp earlier so I knew some of the gang here) and the event stood upto its reputation. Smaller than BC, it was again teeming with loads of entrepreneurs and VCs alike.

As usual, the game HalfBaked was played here. The idea is something like this:

  1. Come up with a whole bunch of words in random: Kabooki, bungy, vodka, lemon, wave, sequins, sheik, water, etc
  2. Split crowd into 5 groups (around 8-12 in people each).
  3. Each group comes with a two-letter word dot com name drawn from the words above (in step 1).
  4. Each team now has 10-15 mins to make a pitch to the VCs out there.

SO the fun begins. Our team came upon the company name KabookiWater like a pack of bums on Sydney’s Liverpool St upon a juicy steak. We had initially thought this was something to do with japanese beer, but soon Michael had pointed out that Kabooki actually stood for Japanese theatre (D’oh). After a bit of hair pulling (lucky for me), we decided it should be User-Generated Interactive Drama – aka Theatre On Tap (TOT).

Kaching!! Folks, this is big money. Imagine a soap, that is actually controlled by what users want on any particular day, instead of the usual Birth-Marriage-Death cycles their writers have to churn out till time immemorial? Audience demands drama, KabookiTheatre gives them crying and moaning. Audience demands sex, instead of crying and moaning, KT gives them, moaning and THEN crying. So possibilities are limitless. I dont want to spoil your fun by revealing all the possibilities to you.

So where is the money coming from? Simple, folks. Product Placement! Users are telling you what they want from the drama, and that should give an indication of what the kind of audience is. So bingo. Google, with your Ad-Sense, eat your corporate hearts out! Not to mention Spin-off markup languages including UGIDML and TOTML for representing and distributed user theatrical preferences. Here come those courses on Tafe’s and those TOTML and UGIDML for Dummies books – Kaching Kaching.

So if any of you out there (especially VCs with lots of money) are interested in the next best/super-duper thing since sliced-bread and Google combined, here it is. Il be waiting. I have nothing better to do :D .

March 30, 2007 Posted by Sri | All, Internet, Startups | | 3 Comments

Cybersquatting

I am sure many of you read the article last week about M$ going on a crusade against cyber squatters. Great finally someone doing something about all those useless (albeit rich) rodents of the society trying to make a quick buck (or a lot of it) by getting a free ride on hard work (and not to mention trademarks) of others. But as much of a problem as this is, ie these folks trying to peddle spam and all other garbage, should Microsoft’s reaction become the defacto standard in the industry?

First of all, the money generated on such bogus sites (eg micrsoft.com or microsof.com) can be monitored and as a result the loss to MicrOsoft can be clearly evaluated. However, if you are stupid enough to end up falling for material on a squat-site, may be you are not the kind of material to be visiting MS? (wait a minute, I may be wrong about that).  If cybersquatters are making money from typo-ed sites, then surely Microsof and Microsoft are completely different entities, so while this is unethical, clearly this is not legal (isnt that what we are all about these days?).  Ofcourse, the easiest and most obvious solution is allow rich companies decide on what constitutes as law and in which situations these laws are applicable.

A more serious argument could be that a typo-ed site could be “sponsored” into redirecting a visitor to a competitor’s site. But how is this different from internet explorer redirecting invalid addresses to MSN.com? This is just free-enterprise. The legal boundary is crossed, when the typo-ed site is actually being used for slander and misrepresentation. But is this what the cybersquatters were doing?

An argument in favour of cybersquatting is that of free-enterprise and capitalism. The argument of free-enterprise goes something like “well they got there and bought it first so they should do with it what they can”.  And to extend the argument, being a free market MS should have got in there first and bought out the typo domains as well. Surely microsof and micrsoft could not have existed before the real deal.  However, the argument does not hold for common words. In this situation, the counter argument that unlike in a free market, the domains were improperly priced initially actually makes sense. But if common words had been used for company names, then companies registering these words SHOULD have gotten there first. If they couldnt, then why rely on common english words for a company name?  How about being a bit creative about it for a change instead of opting for a easy hack?  Besides how cool would “www.cool.com” really be?1.

What determines a trademark infringement? How would MikeRowSoft and MyCrowSoft be treated? With speech recognition becoming common, a browser could direct a search to one of these sites rather than MS. Should MS have the authority to deem these as evil and try to get them closed (after extracting all compensation ofcourse).  At the end of the day, such battles will be one by the sides with the more expensive lawyers rather than being based on any sense of legal or ethical fairness.

Notes

1. Example taken from Paul Graham’s essay – “Why Smart people have bad ideas?

March 20, 2007 Posted by Sri | All, Internet | | No Comments Yet