<?xml version="1.0" encoding="UTF-8"?> <rss
version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:wfw="http://wellformedweb.org/CommentAPI/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
><channel><title>GeekLad &#187; Programming</title> <atom:link href="http://geeklad.com/category/programming/feed" rel="self" type="application/rss+xml" /><link>http://geeklad.com</link> <description></description> <lastBuildDate>Thu, 03 May 2012 19:52:06 +0000</lastBuildDate> <language>en</language> <sy:updatePeriod>hourly</sy:updatePeriod> <sy:updateFrequency>1</sy:updateFrequency> <generator>http://wordpress.org/?v=3.3.1</generator> <item><title>Modifying the JavaScript String Prototype</title><link>http://geeklad.com/html-entities-in-js-and-modifying-string-prototype</link> <comments>http://geeklad.com/html-entities-in-js-and-modifying-string-prototype#comments</comments> <pubDate>Wed, 22 Feb 2012 00:54:00 +0000</pubDate> <dc:creator>GeekLad</dc:creator> <category><![CDATA[Programming]]></category> <category><![CDATA[JavaScript]]></category><guid
isPermaLink="false">http://geeklad.com/?p=3081</guid> <description><![CDATA[When manipulating strings in JavaScript, it is often necessary to perform certain functions to escape characters, decode them, and perform other string manipulations.  JavaScript makes it easy to modify the String prototype, making it possible to create new methods on String types.  As of late, I&#8217;ve preferred this [...]]]></description> <content:encoded><![CDATA[<p><img
src="http://geeklad.com/wp-content/uploads/2012/02/script.png?cda6c1" alt="" title="script" width="200" height="160" class="alignleft size-full wp-image-2813" style="border: 0 none;"/>When manipulating strings in JavaScript, it is often necessary to perform certain functions to escape characters, decode them, and perform other string manipulations.  JavaScript makes it easy to modify the String prototype, making it possible to create new methods on String types.  As of late, I&#8217;ve preferred this method (pun intended) over creating custom functions.</p><p><span
id="more-3081"></span>I was recently working on a project in which I was using JavaScript to output HTML (my <a
href="http://geeklad.com/updated-script-to-download-google-history">Google History download tool</a>).  I needed to escape special HTML characters in the string, in order to prevent problems with the output being mangled by any &lt; followed by &gt; characters in the strings I was outputting.  I created a simple String method that emulates <a
href="http://php.net/manual/en/function.htmlentities.php">PHP&#8217;s htmlentities function</a>:</p><pre class="brush: js">

String.prototype.htmlEntities = function() {
	return this.valueOf().replace(/&amp;/g, '&amp;amp;').replace(/&lt;/g, '&amp;lt;').replace(/&gt;/g, '&amp;gt;').replace(/&quot;/g, '&amp;quot;');
}
foo = "&lt;pre&gt;This string has HTML tags&lt;pre&gt;";
bar = foo.htmlEntities(); // bar contains: &amp;lt;pre&amp;gt;This string has HTML tags&amp;lt;pre&amp;gt;
</pre><p>It&#8217;s quite rudimentary, and simply chains together a few replace calls to search/replace <b>&amp;, &lt;, &gt;, and &quot;</b> characters with the appropriate HTML escape characters.  Unfortunately JavaScript provides no htmlentities equivalent, but it is easy enough to recreate via a simple String method.</p><p>If you are encoding strings to be used in URLs, you&#8217;ll want to use the escape(), encodeURI(), and encodeURIComponent() JavaScript functions.  Each function varies slightly in the characters it converts.  If you want, you can convert them into String methods rather than use them as functions:</p><pre class="brush: js">

String.prototype.escape = function() {return escape(this.valueOf());}
String.prototype.encodeURI = function() {return encodeURI(this.valueOf());}
String.prototype.encodeURIComponent = function() {return encodeURIComponent(this.valueOf());}

special_chars = '~!@#$%^&#038;*(){}[]=:/,;?+\'"\\';
str1 = special_chars.escape(); // str1 contains: %7E%21@%23%24%25%5E%26*%28%29%7B%7D%5B%5D%3D%3A/%2C%3B%3F+%27%22%5C
str2 = special_chars.encodeURI(); // str2 contains: ~!@#$%25%5E&#038;*()%7B%7D%5B%5D=:/,;?+'%22%5C
str3 = special_chars.encodeURIComponent(); // str3 contains: ~!%40%23%24%25%5E%26*()%7B%7D%5B%5D%3D%3A%2F%2C%3B%3F%2B'%22%5C
</pre><p>Writing methods for built-in JavaScript may be a bit of overkill, but it&#8217;s a nice way to demonstrate how easy it is to create new JavaScript methods for the String object.  To learn more about these URL escaping functions, be sure to visit: <a
href="http://xkr.us/articles/javascript/encode-compare/">http://xkr.us/articles/javascript/encode-compare/</a>.</p><p>Perhaps a better example for another String manipulation method you may want, is a method to remove tags:</p><pre class="brush: js">

String.prototype.stripTags = function() {
	return this.valueOf().replace(/&lt;[^&gt;]+&gt;/g, "");
}
foo = "&lt;pre&gt;This string has HTML tags&lt;pre&gt;";
bar = foo.stripTags(); // bar contains: This string has HTML tags
</pre><p>A couple of more tips when creating String methods in JavaScript:</p><ul><li>When you&#8217;re writing new methods for strings, be sure to refer to this.valueOf() to obtain the value of the string object itself<li>If you create any variables within your new methods, be sure to use the var directive to declare/assign the variables.  If you do not use the var directive, the internal variables will have a global scope, which can wreak havoc on your code!</ul><p>The last tip really applies to any object methods and custom JavaScript functions you create.  Although it can be convenient that JavaScript does not require explicit declaration of variables and types, it can be problematic to debug if you do not declare variables within object methods and global functions.</p><p>Any variables declared in an object method or function without the var directive will be global.  If you reuse variable names in multiple methods/functions (such as &#8220;x&#8221; or &#8220;i&#8221; for loop variables, for example), you may experience very unexpected results if you do not explicitly declare them with the var directive.</p> ]]></content:encoded> <wfw:commentRss>http://geeklad.com/html-entities-in-js-and-modifying-string-prototype/feed</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>SQL First Function Equivalent in SQL Server and Oracle</title><link>http://geeklad.com/sql-first-function</link> <comments>http://geeklad.com/sql-first-function#comments</comments> <pubDate>Sat, 18 Feb 2012 21:01:47 +0000</pubDate> <dc:creator>GeekLad</dc:creator> <category><![CDATA[Programming]]></category> <category><![CDATA[SQL]]></category><guid
isPermaLink="false">http://geeklad.com/?p=3008</guid> <description><![CDATA[Microsoft Access is nice for quick and dirty manipulation of data and merging data sets.  It also has a lot of nice functions you won&#8217;t find in other versions of SQL.  One of these functions is the First() function.  Although not available in Microsoft SQL Server or [...]]]></description> <content:encoded><![CDATA[<p><img
src="http://geeklad.com/wp-content/uploads/2012/02/sql.png?cda6c1" alt="" title="SQL Logo" width="200" height="111" class="alignleft size-full wp-image-3009" border="0 none;" />Microsoft Access is nice for quick and dirty manipulation of data and merging data sets.  It also has a lot of nice functions you won&#8217;t find in other versions of SQL.  One of these functions is the <b>First()</b> function.  Although not available in Microsoft SQL Server or Oracle, it can be emulated by other means.</p><p><span
id="more-3008"></span>The trick is to use the <b>RANK()</b> and <b>OVER</b> clauses.  When combined together, RANK() and OVER can perform aggregation in a query without having to use the GROUP BY clause.  This allows you to obtain aggregation information for individual rows in a result.  Unfortunately, this does not work in MySQL, but it does work in both Oracle and T-SQL (transact SQL, which is what MS SQL Server uses).</p><p>For example, let&#8217;s say you have the following table called <i>employees</i>:</p><table><tr><th>Row</th><th>Department</th><th>Employee_Name</th><th>Salary</th></tr><tr><td>1</td><td>HR</td><td>John Smith</td><td>32500</td></tr><tr><td>2</td><td>HR</td><td>Jane Doe</td><td>18350</td></tr><tr><td>3</td><td>HR</td><td>Mike Smith</td><td>42730</td></tr><tr><td>4</td><td>IT</td><td>Ben Dover</td><td>50370</td></tr><tr><td>5</td><td>IT</td><td>Anita Mann</td><td>90450</td></tr><tr><td>6</td><td>IT</td><td>Joe King</td><td>30920</td></tr><tr><td>7</td><td>Operations</td><td>Justin Case</td><td>18350</td></tr><tr><td>8</td><td>Operations</td><td>Kandi Barr</td><td>43290</td></tr><tr><td>9</td><td>Operations</td><td>Hugo First</td><td>80500</td></tr></table><p>You want to select only those individuals that have the highest salary, by department.  In MS Access, you could do this with the <b>First()</b> function:</p><pre class="brush: sql">

SELECT
	Department,
	First(Employee_Name) as Employee_Name,
	First(Salary) as Salary
FROM
	(SELECT
		*
	FROM
		employees
	ORDER BY
		Department,
		Salary DESC
	) AS [Ordered Salaries]
GROUP BY
	Department
</pre><p>This will create an inner query that sorts by department and then descending salary.  The outer query groups by department and selects the first salary and name.  Because the inner query is sorted, the <b>First()</b> function returns the employee with the highest salary for each department.</p><p>You can simulate the First() function in SQL Server and Oracle, with RANK() OVER.  Here is what the inner query would look like in SQL Server (T-SQL):</p><pre class="brush: sql">

SELECT
	employees.Department,
	employees.Employee_Name,
	employees.Salary,
	RANK() OVER(PARTITION BY Department ORDER BY Salary DESC) AS Ranking
FROM
	employees
</pre><p>This query would return:</p><table><tr><th>Department</th><th>Employee_Name</th><th>Salary</th><th>Ranking</th></tr><tr><td>HR</td><td>John Smith</td><td>32500</td><td>2</td></tr><tr><td>HR</td><td>Jane Doe</td><td>18350</td><td>3</td></tr><tr><td>HR</td><td>Mike Smith</td><td>42730</td><td>1</td></tr><tr><td>IT</td><td>Ben Dover</td><td>50370</td><td>2</td></tr><tr><td>IT</td><td>Anita Mann</td><td>90450</td><td>1</td></tr><tr><td>IT</td><td>Joe King</td><td>30920</td><td>3</td></tr><tr><td>Operations</td><td>Justin Case</td><td>18350</td><td>3</td></tr><tr><td>Operations</td><td>Kandi Barr</td><td>43290</td><td>2</td></tr><tr><td>Operations</td><td>Hugo First</td><td>80500</td><td>1</td></tr></table><p>Notice how the RANK() OVER(PARTITION BY) clause provides aggregated information for rows in the result, without having to use the GROUP BY clause.  This can be a very powerful tool, especially considering that other aggregation functions such as MIN(), MAX(), SUM(), etc. can be used with OVER(PARTITION BY).</p><p>You can probably already see where this is going.  The <b>PARTITION BY Department</b> portion of the query aggregates the table by department, and the results are then ordered descending by salary.</p><p>To get the final result we desire, all we need to do is select the rows of the inner query where the Ranking is 1.  Here&#8217;s what the final query looks like:</p><pre class="brush: sql">

SELECT
	Department, Name, Salary
FROM
	(SELECT
		employees.Department,
		employees.Name,
		employees.Salary,
		RANK() OVER(PARTITION BY Department ORDER BY Salary Desc) AS Ranking
	FROM
		employees
	) AS [Ranked Salaries]
WHERE
	Ranking = 1
GROUP BY
	Department
</pre><p>And the final result:</p><table><tr><th>Department</th><th>Employee_Name</th><th>Salary</th></tr><tr><td>HR</td><td>Mike Smith</td><td>42730</td></tr><tr><td>IT</td><td>Anita Mann</td><td>90450</td></tr><tr><td>Operations</td><td>Hugo First</td><td>80500</td></tr></table><p>Although the First() function may be a bit more intuitive in Access, emulating it with RANK() OVER(PARTITION BY) works just as well.  The syntax for Oracle PL/SQL is exactly the same:</p><pre class="brush: sql">

RANK() OVER(PARTITION BY Some_Column ORDER BY Some_Other_Column)
</pre><p>You just need to put the column(s) you want to group after the PARTITION BY and then sort the data accordingly.  After you use it a few times, you&#8217;ll get the hang of it.  You can also use this method to obtain the top results for a category.  You would simply just select records with a ranking greater than or equal to the top number of results you want to see.  Perhaps that will be another tutorial for another time.</p> ]]></content:encoded> <wfw:commentRss>http://geeklad.com/sql-first-function/feed</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Remove Stop Words in JavaScript</title><link>http://geeklad.com/remove-stop-words-in-javascript</link> <comments>http://geeklad.com/remove-stop-words-in-javascript#comments</comments> <pubDate>Fri, 10 Feb 2012 02:34:27 +0000</pubDate> <dc:creator>GeekLad</dc:creator> <category><![CDATA[Programming]]></category> <category><![CDATA[JavaScript]]></category><guid
isPermaLink="false">http://geeklad.com/?p=2810</guid> <description><![CDATA[Sometimes it may be useful to remove stop words from strings, when parsing data in JavaScript.  I found myself in that situation with a recent project.  I looked around for a String method to do this, but didn&#8217;t have much luck, so I wrote my own.
Stop words are [...]]]></description> <content:encoded><![CDATA[<p><img
src="http://geeklad.com/wp-content/uploads/2012/02/script.png?cda6c1" alt="" title="script" width="200" height="160" class="alignleft size-full wp-image-2813" style="border: 0 none;" />Sometimes it may be useful to remove stop words from strings, when parsing data in JavaScript.  I found myself in that situation with a recent project.  I looked around for a String method to do this, but didn&#8217;t have much luck, so I wrote my own.</p><p><span
id="more-2810"></span>Stop words are typically things like conjunctions, prepositions, etc.  Typically, a developer would want to remove stop words from a string, in order to extract keywords from it.  I found a <a
href="http://www.lextek.com/manuals/onix/stopwords1.html">stop word list</a> after a quick search, and used it in my method.  The method I wrote actually extends the JavaScript String data type, so it can be applied to any string.  You just have to be sure to define the prototype method before calling it.</p><p>Once you&#8217;ve defined it, you just call the method like this:</p><pre class="brush: javascript; gutter: false;">
foo = "here is a string that has some stop words in it";
bar = foo.removeStopWords();
// The value of bar will be "string stop words"
</pre><p>The method works by first defining a very large array with stop words in it.  The string itself is split by whitespaces within the string, creating an array of contiguous non-whitespace characters.  There are then two loops for processing the words.</p><p>The outer loop cycles through all of the words in the string, and the inner loop cycles through all of the stop words.  The inner loop performs a comparison between the current word and current stopword.  If the word matches the stop word, all instances of it are removed from the main string.</p><p>Here&#8217;s the code:</p><pre class="brush: javascript; gutter: false;">
/*
 * String method to remove stop words
 * Written by GeekLad http://geeklad.com
 * Stop words obtained from http://www.lextek.com/manuals/onix/stopwords1.html
 *   Usage: string_variable.removeStopWords();
 *   Output: The original String with stop words removed
 */
String.prototype.removeStopWords = function() {
	var x;
	var y;
	var word;
	var stop_word;
	var regex_str;
	var regex;
	var cleansed_string = this.valueOf();
	var stop_words = new Array(
		'a',
		'about',
		'above',
		'across',
		'after',
		'again',
		'against',
		'all',
		'almost',
		'alone',
		'along',
		'already',
		'also',
		'although',
		'always',
		'among',
		'an',
		'and',
		'another',
		'any',
		'anybody',
		'anyone',
		'anything',
		'anywhere',
		'are',
		'area',
		'areas',
		'around',
		'as',
		'ask',
		'asked',
		'asking',
		'asks',
		'at',
		'away',
		'b',
		'back',
		'backed',
		'backing',
		'backs',
		'be',
		'became',
		'because',
		'become',
		'becomes',
		'been',
		'before',
		'began',
		'behind',
		'being',
		'beings',
		'best',
		'better',
		'between',
		'big',
		'both',
		'but',
		'by',
		'c',
		'came',
		'can',
		'cannot',
		'case',
		'cases',
		'certain',
		'certainly',
		'clear',
		'clearly',
		'come',
		'could',
		'd',
		'did',
		'differ',
		'different',
		'differently',
		'do',
		'does',
		'done',
		'down',
		'down',
		'downed',
		'downing',
		'downs',
		'during',
		'e',
		'each',
		'early',
		'either',
		'end',
		'ended',
		'ending',
		'ends',
		'enough',
		'even',
		'evenly',
		'ever',
		'every',
		'everybody',
		'everyone',
		'everything',
		'everywhere',
		'f',
		'face',
		'faces',
		'fact',
		'facts',
		'far',
		'felt',
		'few',
		'find',
		'finds',
		'first',
		'for',
		'four',
		'from',
		'full',
		'fully',
		'further',
		'furthered',
		'furthering',
		'furthers',
		'g',
		'gave',
		'general',
		'generally',
		'get',
		'gets',
		'give',
		'given',
		'gives',
		'go',
		'going',
		'good',
		'goods',
		'got',
		'great',
		'greater',
		'greatest',
		'group',
		'grouped',
		'grouping',
		'groups',
		'h',
		'had',
		'has',
		'have',
		'having',
		'he',
		'her',
		'here',
		'herself',
		'high',
		'high',
		'high',
		'higher',
		'highest',
		'him',
		'himself',
		'his',
		'how',
		'however',
		'i',
		'if',
		'important',
		'in',
		'interest',
		'interested',
		'interesting',
		'interests',
		'into',
		'is',
		'it',
		'its',
		'itself',
		'j',
		'just',
		'k',
		'keep',
		'keeps',
		'kind',
		'knew',
		'know',
		'known',
		'knows',
		'l',
		'large',
		'largely',
		'last',
		'later',
		'latest',
		'least',
		'less',
		'let',
		'lets',
		'like',
		'likely',
		'long',
		'longer',
		'longest',
		'm',
		'made',
		'make',
		'making',
		'man',
		'many',
		'may',
		'me',
		'member',
		'members',
		'men',
		'might',
		'more',
		'most',
		'mostly',
		'mr',
		'mrs',
		'much',
		'must',
		'my',
		'myself',
		'n',
		'necessary',
		'need',
		'needed',
		'needing',
		'needs',
		'never',
		'new',
		'new',
		'newer',
		'newest',
		'next',
		'no',
		'nobody',
		'non',
		'noone',
		'not',
		'nothing',
		'now',
		'nowhere',
		'number',
		'numbers',
		'o',
		'of',
		'off',
		'often',
		'old',
		'older',
		'oldest',
		'on',
		'once',
		'one',
		'only',
		'open',
		'opened',
		'opening',
		'opens',
		'or',
		'order',
		'ordered',
		'ordering',
		'orders',
		'other',
		'others',
		'our',
		'out',
		'over',
		'p',
		'part',
		'parted',
		'parting',
		'parts',
		'per',
		'perhaps',
		'place',
		'places',
		'point',
		'pointed',
		'pointing',
		'points',
		'possible',
		'present',
		'presented',
		'presenting',
		'presents',
		'problem',
		'problems',
		'put',
		'puts',
		'q',
		'quite',
		'r',
		'rather',
		'really',
		'right',
		'right',
		'room',
		'rooms',
		's',
		'said',
		'same',
		'saw',
		'say',
		'says',
		'second',
		'seconds',
		'see',
		'seem',
		'seemed',
		'seeming',
		'seems',
		'sees',
		'several',
		'shall',
		'she',
		'should',
		'show',
		'showed',
		'showing',
		'shows',
		'side',
		'sides',
		'since',
		'small',
		'smaller',
		'smallest',
		'so',
		'some',
		'somebody',
		'someone',
		'something',
		'somewhere',
		'state',
		'states',
		'still',
		'still',
		'such',
		'sure',
		't',
		'take',
		'taken',
		'than',
		'that',
		'the',
		'their',
		'them',
		'then',
		'there',
		'therefore',
		'these',
		'they',
		'thing',
		'things',
		'think',
		'thinks',
		'this',
		'those',
		'though',
		'thought',
		'thoughts',
		'three',
		'through',
		'thus',
		'to',
		'today',
		'together',
		'too',
		'took',
		'toward',
		'turn',
		'turned',
		'turning',
		'turns',
		'two',
		'u',
		'under',
		'until',
		'up',
		'upon',
		'us',
		'use',
		'used',
		'uses',
		'v',
		'very',
		'w',
		'want',
		'wanted',
		'wanting',
		'wants',
		'was',
		'way',
		'ways',
		'we',
		'well',
		'wells',
		'went',
		'were',
		'what',
		'when',
		'where',
		'whether',
		'which',
		'while',
		'who',
		'whole',
		'whose',
		'why',
		'will',
		'with',
		'within',
		'without',
		'work',
		'worked',
		'working',
		'works',
		'would',
		'x',
		'y',
		'year',
		'years',
		'yet',
		'you',
		'young',
		'younger',
		'youngest',
		'your',
		'yours',
		'z'
	)

	// Split out all the individual words in the phrase
	words = cleansed_string.match(/[^\s]+|\s+[^\s+]$/g)

	// Review all the words
	for(x=0; x &lt; words.length; x++) {
		// For each word, check all the stop words
		for(y=0; y &lt; stop_words.length; y++) {
			// Get the current word
			word = words[x].replace(/\s+|[^a-z]+/ig, "");	// Trim the word and remove non-alpha

			// Get the stop word
			stop_word = stop_words[y];

			// If the word matches the stop word, remove it from the keywords
			if(word.toLowerCase() == stop_word) {
				// Build the regex
				regex_str = "^\\s*"+stop_word+"\\s*$";		// Only word
				regex_str += "|^\\s*"+stop_word+"\\s+";		// First word
				regex_str += "|\\s+"+stop_word+"\\s*$";		// Last word
				regex_str += "|\\s+"+stop_word+"\\s+";		// Word somewhere in the middle
				regex = new RegExp(regex_str, "ig");

				// Remove the word from the keywords
				cleansed_string = cleansed_string.replace(regex, " ");
			}
		}
	}
	return cleansed_string.replace(/^\s+|\s+$/g, "");
}
</pre>]]></content:encoded> <wfw:commentRss>http://geeklad.com/remove-stop-words-in-javascript/feed</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Playing the Empire Avenue Social Media Exchange</title><link>http://geeklad.com/playing-empire-avenue</link> <comments>http://geeklad.com/playing-empire-avenue#comments</comments> <pubDate>Tue, 10 May 2011 02:00:56 +0000</pubDate> <dc:creator>GeekLad</dc:creator> <category><![CDATA[Gaming]]></category> <category><![CDATA[Programming]]></category><guid
isPermaLink="false">http://geeklad.com/?p=2442</guid> <description><![CDATA[ Update: e(RINGLE) has incorporated my algorithm into his P3 for Empire Avenue Chrome extension.  Use his extension instead of mine, because it includes what I built and much more!  If you already installed mine, be sure to uninstall it before installing P3, or some weird things can [...]]]></description> <content:encoded><![CDATA[<p><a
href="http://empireavenue.com/?t=zb6nzta0"><img
src="http://geeklad.com/wp-content/uploads/2011/05/empire-avenue-logo.png?cda6c1" alt="" title="empire-avenue-logo" width="300" height="43" class="alignleft size-full wp-image-2443" style="border: 0 none;" /></a> <em><strong>Update</strong>: <a
href="http://www.empireavenue.com/RINGLE?t=zb6nzta0">e(RINGLE)</a> has incorporated my algorithm into his <a
href="https://chrome.google.com/webstore/detail/nicoicbaoinjgpcclfjdkfimngkgogdl">P<sup>3</sup> for Empire Avenue</a> Chrome extension.  Use his extension instead of mine, because it includes what I built and much more!  If you already installed mine, be sure to uninstall it before installing P<sup>3</sup>, or some weird things can happen.</em></p><p>Recently, I started playing in a fantasy social media stock exchange, called <a
href="http://empireavenue.com/?t=zb6nzta0">Empire Avenue</a>. It took me a while to get a handle on what moves the prices, and I&#8217;m still learning.  With some help from <a
href="http://chris.pirillo.com/">Chris Pirillo</a>, I think I&#8217;ve finally got a good handle on it and he&#8217;s helped me start a tool that can help you build a sound Empire Avenue portfolio too.</p><p><span
id="more-2442"></span>I first came to learn about Empire Avenue when Jesse Stay made a few blog posts about it where he writes about Empire Avenue as <a
href="http://www.staynalive.com/2011/04/empire-avenue-is-catalyst-for-new.html">a catalyst for the new economy</a> and <a
href="http://www.staynalive.com/2011/05/new-frontier-of-capitalism.html">the new frontier of capitalism</a>.  Both articles were excellent, but my interest hadn&#8217;t quite piqued until my good friend Bwana posted his <a
href="http://www.bwana.org/2011/05/07/empire-avenue-just-plain-fun/">thoughts on Empire Avenue</a> and he referred me to <a
href="http://chris.pirillo.com/my-empire-avenue-strategy-and-tips/">Chris Pirillo&#8217;s tips on Empire Avenue</a>.</p><h3>Two Ways to Make Eaves</h3><p>Eaves are the Empire Avenue (virtual) currency.  Being a numbers guy and with data analysis being my day job, I wanted to learn how to play the Empire Avenue exchange.  I figured I could probably put together some tools to earn some virtual money, just as I did in <a
href="http://geeklad.com/urban-rivals-market-bot">Urban Rivals</a>.</p><p>When it comes down to it, there are two ways to make Eaves in Empire Avenue with your investments:</p><ul><li>By earning dividends from what I will henceforth refer to as stocks (which are actually people or companies &#8211; i.e. entities with social networking accounts)</li><li>By buying stocks for a low price and selling at a higher price</li></ul><p>Fundamentally speaking it&#8217;s pretty simple, but in order to determine what constitutes a good investment, you need to learn what drives both dividends and stock prices.  It became very clear to me when Chris Pirillo told me:</p><blockquote><ul><li>Stock price = buying interest from others</li><li>Dividends = your (social networking) activity (both on and off-site)</li></ul></blockquote><h3>Dividend Yield</h3><p>Chris Pirillo&#8217;s strategy is to identify stocks that provide a high dividend, relative to the stock price.  I like this strategy very much, because it is quite conservative.  If you find a good dividend producer, the stock price could remain stagnant or even drop, and you still make money.  While you own the stock, you will continue to earn daily dividends, which come from the daily social networking activities of the person/company.</p><p>This strategy also applies to real stock exchanges, where investors might purchase a stock that has an attractive <strong>dividend yield</strong>.  Dividend yield is calculated by dividing the dividends paid per share by the stock price.  It&#8217;s a good measure to use to decide whether or not a stock might be a good investment, in terms of the dividends it will provide relative to the purchase price of the stock.</p><p>Because I was attracted to Chris&#8217; strategy of focusing on high dividend yielding stocks, I started developing my own Chrome Extension to provide some investment analysis on Empire Avenue stocks.  Chris provided a great deal of help in developing the tool, with suggestions on what to add.  In addition to providing dividend yields, it also provides break even information (which I will explain in a bit) as well as current profitability info for the stocks you currently own.</p><h3>Capital Appreciation</h3><p>Just as one might buy real life stocks low and sell high, that same concept applies to Empire Avenue.  In real life stock markets, this is referred to as <b>capital appreciation</b>.  You can certainly use dividend yield to decide whether or not a stock is still relatively inexpensive compared to the dividends it provides.  Chris also uses this as an indicator for whether or not a stock has room to grow in price.</p><p>I think this is a decent strategy as well, however, I would not rely on it alone.  The price of a stock is driven by the demand to buy it.  If a lot of people want to buy it, the stock price will move up.  By the same token, if the stock has appeared to plateau, it may drive individuals to sell it which in turn would drive the stock price down.  The speculative nature of these ups and downs can make investing based on price alone somewhat risky.</p><p>Until more tools such as mine and <a
href="https://chrome.google.com/webstore/detail/nicoicbaoinjgpcclfjdkfimngkgogdl">Eddie Ringle&#8217;s</a> (I will likely incorporate my calculations into his extension eventually, as he has his open sourced and <a
href="https://github.com/eddieringle/p3_eav">posted to Git</a>) come out and provide additional valuation metrics and analysis, there is also the human nature of thinking because the share price is high the stock is expensive, which is mistake many would-be investors make.  One cannot value a stock as inexpensive or expensive based on share price alone.  It must be placed into context with valuation metrics such as dividend yield.</p><p>For example, my stock <a
href="http://www.empireavenue.com/GEEKLAD?t=zb6nzta0">e(GEEKLAD)</a> is currently trading for 13.620 and Chris&#8217; stock <a
href="http://www.empireavenue.com/PIRILLO?t=zb6nzta0">e(PIRILLO)</a> is trading for 156.32.  If you were to value our stocks on share price alone, you would say mine is cheap and Chris&#8217; is expensive.  However, if you used dividend yield to valuate our stocks, Chris&#8217; could be considered much cheaper.  His provides more than a 1% dividend yield, whereas mine does not even provide 0.50% dividend yield.</p><p>On the other hand, there is still that human factor where most individuals would have the tendency to say Chris&#8217; stock is more expensive than mine, and I would suspect that at his current price his stock probably won&#8217;t appreciate as fast as mine.  Also, because he has many more outstanding shares, it would take much more volume for his stock to move rapidly than it would take for my stock to move.  As the outstanding shares increase, the relative volume will probably decrease, so you&#8217;ll see slower acceleration in the stock price.</p><h3>My Chrome Extension</h3><p>My plugin provides you with the following information when you either view a stock&#8217;s profile page (when you are logged into Empire Avenue):</p><ul><li><b><u>Daily Dividend Yield</u></b>: This the calculation of the daily dividend per share divided by the share price.  In Chris&#8217; experience, 1% is a good yield, 2% is extremely good, and 3% is nearly unheard of.</li><li><b><u>Approximate Dividend Pay Back (Days)</u></b>This is how long it would take you to earn back the money you paid to buy the stock, and cover (an assumed) 5% commission as well as the 5% commission you would need to pay when you sell it.</li><li><b><u>Current Break Even</u></b>: This is the share price the stock would have to increase to, in order to cover the 5% purchase commission and 5% sale commission if the stock were purchased at the current price.</li></ul><p>In addition, for stocks you already own you will also see:</p><ul><li><b><u>Your Average Purchase Price</u></b>: This is your average purchase price, excluding commissions.</li><li><b><u>Your Breakeven Price</u></b>: This is where the stock price has to be for you to recoup your purchase price, purchase commission (assumed at 5%) and sale commission as well.</li><li><b><u>Your Real Gain per Share</u></b>: This is how much you&#8217;ve actually made per share, taking account your purchase commission and your sale commission if you were to sell at the current share price.</li><li><b><u>Your Real Total Gain</u></b>: This is how much you&#8217;ve actually made in total, taking into account commissions for the purchase and sale and your average purchase price, were you to sell the price at the current share price.</li></ul><p>Here&#8217;s a screenshot of my investment in <a
href="http://www.empireavenue.com/BWANA?t=zb6nzta0">e(BWANA)</a>:</p><p><img
src="http://geeklad.com/wp-content/uploads/2011/05/empire-avenue-investment-analyzer-screenshot.png?cda6c1" alt="" title="empire-avenue-investment-analyzer-screenshot" class="aligncenter size-full" /></p><p>To see this in action, visit your portfolio/lists at <a
href="http://www.empireavenue.com/influencer/portfolio">http://www.empireavenue.com/influencer/portfolio</a>, then click on any stock to view the stats as you see them in the screenshot above.  You can also see those stats if you visit a stock profile page.  For profile pages of stocks you own, you&#8217;ll see your profitability stats.</p><p>It is very important to make sure you cover your purchase/sale commissions when you trade, otherwise you could very well sell a stock you think you&#8217;ve made money on, but you won&#8217;t be able to cover the 10.5% or so you&#8217;ll pay in commissions.  Say what?  Why 10.5%???  To calculate the gain, you can take 105% and divide it by 95%, which gives you a little over 110.5%.  That 10.5% represents the gain from your purchase price that you need to cover your purchase and sale commissions.</p><p>If you make a hot buy that has a higher purchase commission, your break even is even higher.  Unfortunately, neither the website or API (from what I can tell) provide any info on commissions you&#8217;ve paid in your transactions, so I have to assume you paid 5%.  If you paid 30% commission and pay 5% on the sale, your pay back would be 36.8% above your purchase price (130% divided by 95%).</p><p>So do not be alarmed when you view a stock in your portfolio and my plugin says you currently have a loss.  It&#8217;s because the stock hasn&#8217;t moved high enough to cover your commissions.  However, if you have a stock that yields 1% dividends, your dividends will have covered your commissions in 11 days or so.  In a future version of the extension, I want to account for accumulated dividends to get a true ROI calculation, which would be:</p><p><i>Sale Price &#8211; Sale Commissions &#8211; Purchase Price &#8211; Purchase Commissions <b> + Accumulated Dividends</b></i></p><p>What Chris previously referred to as ROI (previous to the discussions I had with him), is actually dividend yield.  ROI would be calculated as I have stated in my formula above, for investments currently being held.  If I can get to a true ROI calculation that includes accumulated dividends, my extension will be that much better.</p><p>So, give it a shot and <strike><a
href="#">download the Empire Avenue Investment Analyzer Chrome extension</a></strike> <a
href="https://chrome.google.com/webstore/detail/nicoicbaoinjgpcclfjdkfimngkgogdl">download the P<sup>3</sup> for Empire Avenue Chrome extension</a>.  Let me know what suggestions you may have by leaving comments here, or if you run into any bugs.  Feel free to ask me any questions about investing on Empire Avenue as well, and I&#8217;ll be glad to try to answer them.  Good luck and happy investing!</p><p>If you like my extension, feel free to show your appreciation and pick up a few shares of <a
href="http://www.empireavenue.com/GEEKLAD?t=zb6nzta0">e(GEEKLAD)</a>.</p> ]]></content:encoded> <wfw:commentRss>http://geeklad.com/playing-empire-avenue/feed</wfw:commentRss> <slash:comments>20</slash:comments> </item> <item><title>Urban Rivals Market Bot</title><link>http://geeklad.com/urban-rivals-market-bot</link> <comments>http://geeklad.com/urban-rivals-market-bot#comments</comments> <pubDate>Wed, 23 Mar 2011 02:43:25 +0000</pubDate> <dc:creator>GeekLad</dc:creator> <category><![CDATA[Gaming]]></category> <category><![CDATA[Internet]]></category> <category><![CDATA[Programming]]></category> <category><![CDATA[Google Chrome]]></category><guid
isPermaLink="false">http://geeklad.com/?p=2260</guid> <description><![CDATA[Update: Shortly after I posted this, the good folks of Urban Rivals politely asked me to remove the post and I politely declined.  About a week later, someone informed me changes were made to the market, and the first few sales for each card are now displayed as images [...]]]></description> <content:encoded><![CDATA[<p><img
src="http://geeklad.com/wp-content/uploads/2011/03/urban-rivals-logo.png?cda6c1" alt="urban-rivals-logo" title="urban-rivals-logo" width="204" height="103" class="alignleft size-full wp-image-2261" style="border: 0 none;" /><i><b><u>Update</u></b>: Shortly after I posted this, the good folks of Urban Rivals politely asked me to remove the post and I politely declined.  About a week later, someone informed me changes were made to the market, and the first few sales for each card are now displayed as images rather than HTML.  He said up until then, the bot was working great for him, but the changes to the market have caused the bot to stop working.  Unless someone is able to fix it with some sort of image to text JavaScript library (I think there are some libraries that do this w/ captchas), the script is effectively dead.  I will leave the source posted, in case someone is able to repair it.</i></p><p>Some time ago, a friend got me into an online card game called <a
href="http://www.urban-rivals.com/">Urban Rivals</a>.  It is similar to other card games such as Magic the Gathering, but played online either via iPhone/iPad app or in your browser.  One aspect of the game that quickly got my attention (other than the game itself), was the card marketplace where you can buy and sell playing cards.</p><p>It didn&#8217;t take long for me to realize that it was an inefficient market.  Profitable trades presented themselves quite regularly, and with a bit of automation it would be easy to take advantage of the market.  I proceeded with developing a Google Chrome extension that would allow me to do so, and it worked quite well.</p><p><span
id="more-2260"></span>Over the course of a few days, I had it up and running, automating both buying and selling of cards.  Essentially, it continually scans the marketplace until a profitable buy appears, buys the card (or cards), and immediately posts them for sale at one clintz (the in-game currency) below the lowest price.  I told a friend of mine about it, and with some trepidation at first, he decided to try it out and helped me test and tweak it.  Eventually, he realized it worked great and used it extensively as I did.</p><p>When it was all said and done, I had accumulated probably over 6 million worth of clintz and cards, having started with just a few thousand.  My friend had probably accumulated on the order of about 5 million.  Ultimately, my friend and I were both banned.  I told him if ever I did get banned, I would likely release the extension into the wild to see what sort of havoc it might wreak on the marketplace.  Well, I did get banned, so here we are.  Even before I was banned, I had a morbid curiosity to learn what might happen if I were to give it to more than just one or two other players.  Having been banned was just the excuse I was looking for, as I (and my friends) no longer have a vested interest in keeping it a secret.</p><h3>Words of Wisdom in Using the Urban Rivals Market Bot</h3><p>First and foremost, <strong><em>Use at Your Own Risk.</em></strong><br
/> If the good folks of Urban Rivals find out you&#8217;re using a bot, they will ban you.  If you use it in moderation, you may not get caught.  Of course, I can make no guarantees.  If you get banned for using this, don&#8217;t blame me as you&#8217;ve been warned!</p><p><strong><em>Be very careful if you set up a separate account.</em></strong><br
/> My friend set up an account for using the bot, in case if he got banned, so he would still have the original account.  Unfortunately this plan backfired on him, as he was banned not for the bot but both accounts were banned for having duplicate accounts.</p><p>If you do use decide to set up an additional account, do not ever connect to them from the same internet connection.  You could try using <a
href="https://www.torproject.org/">Tor</a> to connect from an anonymous internet connection for the bot account, and use your regular internet connection for your regular account.  I haven&#8217;t tried this, but this method of using multiple accounts would probably work without a problem.  You just have to be very careful you never connect via the same method/connection.</p><p><strong><em>It may not work for long, or at all at this point.</em></strong><br
/> Since I no longer have a valid Urban Rivals account, I have no mechanism to see if it even still works.  The last time I used it, it worked without issue so it&#8217;s likely it still works, but I make no guarantees.  So that my &#8220;legacy&#8221; may still live on, I&#8217;ll include the source code as well.</p><p>If you&#8217;re good with JavaScript, you can probably figure out my mess of code and fix things if they&#8217;ve broken.  If you do fix any bugs you see, feel free to send me the new code and I&#8217;ll post it here.</p><p><strong><em>Be prepared for personal attacks.</em></strong><br
/> Because the bot works by looking for good deals, occasionally it picks up deals that were posted in error.  Sometimes people forget a 0, and end up posting a card worth thousands for hundreds, or even hundreds of thousands for tens of thousands.  The bot will pick these up for a song and repost them for sale and make 10x profit.  Of course, when this happens it sometimes solicits inflammatory language from those that posted the price in error.</p><p>I would gladly exchange the card back to players that asked politely and patiently.  Either I would tell them to sell me a cheap card for slightly less than the value of the card so I could still make a profit, or sell the card back to them (if I still had it) for a profit.  I would recommend you do the same, if you do not wish to draw the attention of the UR gods.  If you want to remain even more transparent, you may even wish to throw the impolite requestors a bone as well.</p><p>I would also recommend disabling your online presence for your UR login.  I think in many cases, the players I pissed off thought I was online, when in fact it was simply that my browser window was open conducting market transactions on my behalf.  In some cases, I was receiving many messages from incensed players within minutes of each other, but I did not see the messages for many hours later and sometimes even days.</p><p>When I finally realized my online presence was the reason I was receiving so many messages so quickly from the same angry players, I disabled my online presence.  This helped quite a bit to quell the angry messages coming in rapid succession, but they did still happen.  Be nice to those who make mistakes in their market transactions and ask you to sell their card back to them.</p><h3>Instructions</h3><ol><li>If you don&#8217;t have it, <a
href="http://www.google.com/chrome">download Google Chrome</a>, the best web browser known to man</p><li>Download and install the <a
href="http://geeklad.com/tools/Urban%20Rivals%20Market%20Bot.crx">Urban Rivals Market Bot</a> Extension for Google Chrome</li><li>Configure the bot however you like:<ul><li><strong>Enable Profitability Filter</strong>: This enables/disables the filtering of the market to only show profitable trades, according to the profitability settings.</p><li><strong>Enable Stars Filter</strong>: You can filter the market to only show cards with a certain number of stars<li><strong>Min and Max Price</strong>: The minimum and max price to filter on.  Cards less than the minimum or more than the maximum will be removed from the market list.<li><strong>Min Profit</strong>: The minimum amount of profit to make on the purchase and sale of a card, if sold for 1 clintz less than the lowest listed card.  Any cards that do not meet this criteria will not be displayed in the market.<li><strong>Min Percent Profit</strong>: The minimum percent profit to make on the purchase/sale.  Cards must meet both the min profit and min percent profit criteria to be displayed.<li><strong>Autobuy</strong>: Buy cards that meet the profit filter criteria.  Without the profitability filter enabled, this does nothing.<li><strong>Autosell</strong>: Sell cards that are autobought.  Without autobuy enabled, this won&#8217;t do anything.  If disabled while autobuy runs, cards will be accumulated in a profitable manner, but not sold.<li><strong>Refresh Delay</strong>: How many seconds to wait before refreshing the market page to try autobuying again.  You can set it to 0.  If you set it too fast, you&#8217;ll probably get a captcha, at which point the bot will stop working until you manually clear the captcha.<li><strong>Max # of Cards to Buy</strong>: Sometimes there are profitable trades where there is a big breakpoint in the price of cards.  You can buy perhaps the two or three cheapest cards, and sell at the price of the remaining cheapest card.  If you want to be conservative, just leave it at 1.<li><strong>Max Premium on Sale</strong>: Sometimes players buy up a lot of cards to raise the lowest price so they can sell the cards they buy at a higher price.  This is a safeguard to avoid buying/selling a card when this has happened, otherwise you could fall victim to this market manipulation tactic.  This is how far you are willing to resell a card marked up above the lowest price of the day, week, and month.  If you set it too high, you could end up paying too much for a card and you won&#8217;t be able to sell it profitably.  I typically ran it at 10 percent, which served me well.</ul><li>Visit the first page of the UR market.  Be sure to sort the market by date, with the most recent listings first (this is the default, so you really shouldn&#8217;t have to change anything).  The page will continually refresh according to the refresh delay setting, and as profitable listings are found it will attempt to buy them and resell them 1 clintz lower than the cheapest.  Please note, that it will only deal with cards with maxed experience.</ol><p><strong>The Autosale of Doubles Feature</strong><br
/> One last note on using the plugin.  If your sales expire, you may end up with many doubles in your collection.  I eventually grew tired of manually selling all of my doubles, so I also added functionality to autosell doubles when visiting my collection page.  When you visit your collection page, if you have doubles you&#8217;ll be prompted if you want to sell them.</p><p>If you use this feature to sell a lot of doubles at once (perhaps 50 or more), it could result in a temporary ban from using the market.  This is a bit more severe than being captchad, as you can&#8217;t do anything but wait on the order of about 7-8 hours to access the marketplace again.  Don&#8217;t panic if it does happen, but you won&#8217;t be able to access ANY market pages (even your pending sales, sold cards, etc.) until enough time has passed.  I ultimately wanted to make this a feature that could be enabled/disabled in the settings popup, but I never got around to implementing that.</p><h3>A Small Request</h3><p>If someone could do me a favor, please contact <a
href="http://www.urban-rivals.com/player/?id_player=13219177">mrdisco</a> and tell him about my bot.  He went on a rant in the forums to tell everyone what an asshole I am (scroll to the bottom of <a
href="http://www.urban-rivals.com/community/forum/?mode=viewsubject&#038;id_subject=1488133&#038;language=2#37389312">this post</a> to read it).  Someone please send him the link to this post.  At least he can recoup his clintz using my bot, and even make a good bit more.</p><p>I attempted to contact him via UR messaging to tell him I would have gladly refunded him, if he had given me a chance to respond.  He sent me a barrage of messages in a span of maybe an hour, probably while I was sleeping or at work, so I never got to respond.  By the time I was able to respond, he added me to is ignore list so I couldn&#8217;t message him on UR although I wanted to.</p><p>At the time, I decided it best I not even try to explain myself in the forum.  He obviously had no interest in hearing what I had to say since he never even gave me the chance to explain.  At this point, I think this post is sufficient explanation and perhaps he may even no longer feel ill will.</p><h3>Final Thoughts</h3><p>Unfortunately, I was banned from UR (I&#8217;m sure mrdisco will be happy about that) so I am not able to post this in the UR forums, so here it is on my blog.  If any discussion does take place in the UR forums about it, please feel free to repost it here.  I&#8217;m very curious to know what people might say about it, if anything at all.</p><p>Oh, I almost forgot the source code!</p><p><a
href="http://geeklad.com/tools/Urban%20Rivals%20Market%20Bot.zip?cda6c1">Download the Urban Rivals Market Bot Source Code</a></p><p>The code is ugly but it works (at least it did, when I last used it).  It&#8217;s all screen scraping with regular expressions in JavaScript.  If you know JavaScript, you can probably figure it out for the most part.  If you know regular expressions as well, then you can easily bend it to your will.  If you do, feel free to reach out to me if you keep the code working and up-to-date.</p><p>Enjoy!  Let me know if you have any questions about the plugin.  Unfortunately, without a UR account I really can&#8217;t do anything about fixing bugs if there are any, but perhaps there&#8217;s a JavaScript/regular expression guru out there that can take hold of the Urban Rivals Market Bot torch.</p> ]]></content:encoded> <wfw:commentRss>http://geeklad.com/urban-rivals-market-bot/feed</wfw:commentRss> <slash:comments>21</slash:comments> </item> <item><title>goo.gl URL Shortener Bookmarklet via YQL</title><link>http://geeklad.com/goo-gl-url-shortener-bookmarklet-via-yql</link> <comments>http://geeklad.com/goo-gl-url-shortener-bookmarklet-via-yql#comments</comments> <pubDate>Sat, 16 Jan 2010 15:40:54 +0000</pubDate> <dc:creator>GeekLad</dc:creator> <category><![CDATA[Programming]]></category> <category><![CDATA[goo.gl]]></category> <category><![CDATA[Google]]></category> <category><![CDATA[YQL]]></category><guid
isPermaLink="false">http://geeklad.com/?p=2087</guid> <description><![CDATA[Last month we saw a new Google URL shortening service that will be used for Feedburner and the Google Toolbar.  It wasn&#8217;t long before the URL shortening code in the toolbar was dissected, and subsequent APIs developed.  I managed to put together my own by using YQL.
YQL is [...]]]></description> <content:encoded><![CDATA[<p><img
class="alignleft size-full wp-image-2088" title="goo.gl_yql" src="http://geeklad.com/wp-content/uploads/2010/01/goo.gl_yql.png?cda6c1" alt="goo.gl_yql" width="247" height="243" style="border: 0 none;" />Last month we saw a new <a
href="http://googleblog.blogspot.com/2009/12/making-urls-shorter-for-google-toolbar.html">Google URL shortening service</a> that will be used for Feedburner and the Google Toolbar.  It wasn&#8217;t long before the <a
href="http://www.kix.in/blog/2009/12/goo-gl/">URL shortening code in the toolbar was dissected</a>, and subsequent APIs developed.  I managed to put together my own by using <a
href="http://developer.yahoo.com/yql/">YQL</a>.</p><p><span
id="more-2087"></span>YQL is a truly amazing web API.  With its <a
href="http://developer.yahoo.com/yql/guide/yql-execute-chapter.html">server-side JavaScript</a> and the ability to quickly scour the web for information, there is very little it cannot do.  I decided it was the perfect platform for putting together a simple API for goo.gl.</p><p>Because the Google Toolbar was already written in JavaScript, implementing it in YQL was quite easy with the server-side JavaScript.  It wasn&#8217;t long, before I put together my own <a
href="http://www.datatables.org/">open data table</a> for <a
href="http://goo.gl">goo.gl</a>.</p><p>I submitted my open table to the <a
href="http://github.com/yql/yql-tables">git repository for open data tables</a>, and shortly after my <a
href="http://github.com/yql/yql-tables/blob/master/google/google.goo.gl.xml">goo.gl open data table</a> was included.  It&#8217;s really pretty simple.  The YQL you would use to get the short URL for my blog would be:</p><pre class="brush: sql">SELECT * FROM google.goo.gl WHERE url="http://geeklad.com"</pre><p>The great thing about YQL is that you can obtain the data as XML or JSON, and specify a JSON callback function.  So that means it&#8217;s very easy to use in JavaScript and develop <a
href="http://geeklad.com/make-cross-domain-ajax-requests-with-xdrequest">cross-domain JavaScript</a>.  I put together a simple bookmarklet that uses my public YQL table and provides a goo.gl URL for the current page.  To try it out, just drag and drop the link below to your browser&#8217;s shortcut bar:</p><p><p
style="text-align: center;"><a
style="border: 1px solid #888888; padding: 4px 8px; font-weight: bold;" href="javascript:var YQL_url='https://query.yahooapis.com/v1/public/yql?format=json&env=store://datatables.org/alltableswithkeys&q=';var YQL_statement='SELECT * FROM google.goo.gl WHERE url=\''+document.location.href+'\'';var YQL_script_url=YQL_url+encodeURIComponent(YQL_statement)+'&callback=yql_cb';function yql_cb(response){short_url=response.query.results.result;prompt('Here is your short URL:  (be sure to copy to your clipboard)', short_url);}var yql_script=document.createElement('script');yql_script.src=YQL_script_url;document.getElementsByTagName('head')[0].appendChild(yql_script);void(0);">goo.gl page</a></p></p><p>Here&#8217;s the JavaScript code from the bookmarklet:<br
/><pre class="brush: js">var YQL_url='https://query.yahooapis.com/v1/public/yql?format=json&env=store://datatables.org/alltableswithkeys&q=';
var YQL_statement='SELECT * FROM google.goo.gl WHERE url=\''+document.location.href+'\'';
var YQL_script_url=YQL_url+encodeURIComponent(YQL_statement)+'&callback=yql_cb';
function yql_cb(response){
	short_url=response.query.results.result;
	prompt('Here is your short URL (be sure to copy to your clipboard): ', short_url);
}
var yql_script=document.createElement('script');
yql_script.src=YQL_script_url;
document.getElementsByTagName('head')[0].appendChild(yql_script);</pre></p><p>Pretty simple.  Basically it works by putting together the YQL statement w/ the URL of the current page, builds the proper YQL API URL for it, and finally inserts a JavaScript script with the call to the callback function that displays the URL of the current page in a prompt.  You&#8217;ll have to manually copy it to your clipboard.  Enjoy!</p> ]]></content:encoded> <wfw:commentRss>http://geeklad.com/goo-gl-url-shortener-bookmarklet-via-yql/feed</wfw:commentRss> <slash:comments>4</slash:comments> </item> <item><title>Google Fusion Tables Could be a Game Changer</title><link>http://geeklad.com/google-fusion-tables-could-be-a-game-changer</link> <comments>http://geeklad.com/google-fusion-tables-could-be-a-game-changer#comments</comments> <pubDate>Tue, 15 Dec 2009 23:56:16 +0000</pubDate> <dc:creator>GeekLad</dc:creator> <category><![CDATA[Programming]]></category> <category><![CDATA[Google]]></category> <category><![CDATA[Google Chrome]]></category> <category><![CDATA[Google Fusion Tables]]></category><guid
isPermaLink="false">http://geeklad.com/?p=2028</guid> <description><![CDATA[ Google has been very busy lately with many new products recently.  Many of them, such as Google Public DNS, Google Chrome OS, and real-time search have received the lion&#8217;s share of publicity.  I&#8217;d like to talk about a little jewel sitting in Google Labs you may not [...]]]></description> <content:encoded><![CDATA[<p><img
src="http://geeklad.com/wp-content/uploads/2009/12/fusiontables_logo.png?cda6c1" alt="fusiontables_logo" title="fusiontables_logo" width="251" height="43" class="alignleft size-full wp-image-2029" style="border: 0 none;" /> Google has been very busy lately with many new products recently.  Many of them, such as <a
href="http://googleblog.blogspot.com/2009/12/introducing-google-public-dns.html">Google Public DNS</a>, <a
href="http://googleblog.blogspot.com/2009/11/releasing-chromium-os-open-source.html">Google Chrome OS</a>, and <a
href="http://googleblog.blogspot.com/2009/12/relevance-meets-real-time-web.html">real-time search</a> have received the lion&#8217;s share of publicity.  I&#8217;d like to talk about a little jewel sitting in <a
href="http://www.googlelabs.com">Google Labs</a> you may not heard of.   It&#8217;s a shiny little jewel that could become a real game changer and not many people are talking about it yet: <a
href="http://tables.googlelabs.com">Google Fusion Tables</a>.</p><p><span
id="more-2028"></span>Google Fusion Tables is a web application that allows you to import, manipulate, and generate reports from large data sets.  It is designed to handle much more data than you can put into <a
href="http://docs.google.com/support/bin/topic.py?hl=en&#038;topic=15115">Google Spreadsheets</a> or versions of Excel earlier than Excel 2007.  Some time ago, I started fooling around with it and I managed to import a relatively large data set with nearly 150,000 records without any issues whatsoever.  The interface also provides some nice ways to visualize the data.</p><p><img
src="http://geeklad.com/wp-content/uploads/2009/12/fusiontables_visualizations.png?cda6c1" alt="fusiontables_visualizations" title="fusiontables_visualizations" width="240" height="275" class="alignnone size-full wp-image-2034" style="border: 0 none;"/></p><p>In addition to providing some nifty visualizations, there are also many data tables that have been published for public use.  For example, the 2010 Quality of Life Index:</p><p><img
src="http://geeklad.com/wp-content/uploads/2009/12/fusiontables_screenshot.png?cda6c1" alt="fusiontables_screenshot" title="fusiontables_screenshot" width="500" height="240" class="alignnone size-full wp-image-2033" style="border: 0 none;" /></p><p>So why do I think this could be a game changer?  Yesterday, the Google Code Blog <a
href="http://googlecode.blogspot.com/2009/12/google-fusion-tables-api.html">announced the Fusion Tables API</a>.  With the API it is no longer necessary to use the Fusion Tables web interface to upload, manipulate, and visualize data.  Now it can be done programatically, and Fusion Tables can be used to store large data sets in the cloud.  The data can be extracted using <a
href="http://en.wikipedia.org/wiki/SQL">SQL</a>, which is the gold standard for handling the data stored within databases.</p><p>Not long ago, <a
href="http://staynalive.com/">Jesse Stay</a> wrote about <a
href="http://staynalive.com/articles/2009/10/15/web-3-0-the-building-block-web/">the building block web</a>.  The Fusion Tables API is a perfect example of a new set of blocks that will integrate very well (and easily) with the building block web.  Persistent data storage is an essential component for the building block web, and that is just what Fusion Tables provides.</p><p>Of course, it doesn&#8217;t come without its limitations.  According to the <a
href="http://code.google.com/apis/fusiontables/docs/developers_guide.html">Google Fusion Tables API developer&#8217;s guide</a>, the API can send a maximum of 5 requests per second to the Fusion Tables server.  Hopefully Google will lift that constraint or increase it at some point.  5 requests per second won&#8217;t be enough for the enterprise applications that could potentially be built on top of Fusion Tables.</p><p>If you&#8217;re a PHP programmer, here&#8217;s some PHP code I&#8217;ve put together to help get you started:</p><link
href="http://geeklad.com/syntax-highlighter/style.css?cda6c1" rel="stylesheet" type="text/css"/><script src="http://geeklad.com/syntax-highlighter/script.js?cda6c1" type="text/javascript"></script></p><p><script  type="syntaxhighlighter" class="brush: php">/*<![CDATA[*/function GoogleClientLogin($username,$password,$service){if(!$username||!$password||!$service){throw new Exception("You must provide a username, password, and service when creating a new GoogleClientLogin.");}
$body="accountType=GOOGLE &Email=$username&Passwd=$password&service=$service";$c=curl_init("https://www.google.com/accounts/ClientLogin");curl_setopt($c,CURLOPT_POST,true);curl_setopt($c,CURLOPT_POSTFIELDS,$body);curl_setopt($c,CURLOPT_RETURNTRANSFER,true);$response=curl_exec($c);return preg_replace("/[\s\S]*Auth=/","",$response);}
class FusionTable{var $token;function FusionTable($token){if(!$token){throw new Exception("You must provide a token when creating a new FusionTable.");}
$this-&gt;token=$token;}
function query($query){if(!$query){throw new Exception("query method requires a query.");}
if(preg_match("/^select|^show tables|^describe/i",$query)){$request_url="http://tables.googlelabs.com/api/query?sql=".urlencode($query);$c=curl_init($request_url);curl_setopt($c,CURLOPT_HTTPHEADER,array("Authorization: GoogleLogin auth=".$this-&gt;token));curl_setopt($c,CURLOPT_RETURNTRANSFER,true);$results=preg_split("/\n/",curl_exec($c));if(curl_getinfo($c,CURLINFO_HTTP_CODE)!=200){return $this-&gt;output_error($results);}
array_pop($results);return $this-&gt;parse_output($results);}
else if(preg_match("/^update|^delete|^insert/i",$query)){$body="sql=".urlencode($query);$c=curl_init("http://tables.googlelabs.com/api/query");curl_setopt($c,CURLOPT_POST,true);curl_setopt($c,CURLOPT_RETURNTRANSFER,true);curl_setopt($c,CURLOPT_HTTPHEADER,array("Content-length: ".strlen($body),"Content-type: application/x-www-form-urlencoded","Authorization: GoogleLogin auth=".$this-&gt;token." "));curl_setopt($c,CURLOPT_POSTFIELDS,$body);$results=preg_split("/\n/",curl_exec($c));if(curl_getinfo($c,CURLINFO_HTTP_CODE)!=200){return $this-&gt;output_error($results);}
array_pop($results);return $this-&gt;parse_output($results);}
else{throw new Exception("Unknown SQL query submitted.");}}
private function parse_output($results){$headers=false;$output=array();foreach($results as $row){if(!$headers){$headers=$this-&gt;parse_row($row);}
else{$newrow=array();$values=$this-&gt;parse_row($row);foreach($headers as $index=&gt;$header){$newrow[$header]=$values[$index];}
array_push($output,$newrow);}}
return $output;}
private function parse_row($row){$cells=preg_split("/,/",$row);foreach($cells as $index=&gt;$value){if(preg_match("/^\"/",$value)){$cells[$index]=preg_replace("/^\"|\"$/","",$cells[$index].$cells[$index+1]);array_splice($cells,$index+1,1);}}
return $cells;}
private function output_error($err){$err=implode("",$err);$err=preg_replace("/[\s\S]*&lt;H1&gt;|&lt;\/H1&gt;[\s\S]*/i","",$err);return $err;throw new Exception($err);}}
$token=GoogleClientLogin("mygm...@gmail.com","mygoogleaccountpassword","fusiontables");$ft=new FusionTable($token);$output=$ft-&gt;query("SELECT * FROM FOOTABLE WHERE FOO=1");$ft-&gt;query("INSERT INTO FOOTABLE (FOO,BAR) VALUES (1,2)");]]&gt;/*]]>*/</script></p> ]]></content:encoded> <wfw:commentRss>http://geeklad.com/google-fusion-tables-could-be-a-game-changer/feed</wfw:commentRss> <slash:comments>9</slash:comments> </item> <item><title>Make Cross-Domain AJAX Requests with xdRequest</title><link>http://geeklad.com/make-cross-domain-ajax-requests-with-xdrequest</link> <comments>http://geeklad.com/make-cross-domain-ajax-requests-with-xdrequest#comments</comments> <pubDate>Thu, 15 Oct 2009 19:03:25 +0000</pubDate> <dc:creator>GeekLad</dc:creator> <category><![CDATA[Programming]]></category> <category><![CDATA[AJAX]]></category> <category><![CDATA[JavaScript]]></category> <category><![CDATA[YQL]]></category><guid
isPermaLink="false">http://geeklad.com/?p=1843</guid> <description><![CDATA[xdRequest is an open-source JavaScript library that I&#8217;ve developed for making cross-domain AJAX requests. In this day and age, with web browsers becoming very fast and powerful, it has become quite possible to build web applications with much of the work performed by the client. xdRequest makes it possible to [...]]]></description> <content:encoded><![CDATA[<p><a
href="http://code.google.com/p/xdrequest/">xdRequest</a> is an open-source JavaScript library that I&#8217;ve developed for making cross-domain <a
href="http://en.wikipedia.org/wiki/Ajax_(programming)">AJAX</a> requests. In this day and age, with web browsers becoming very fast and powerful, it has become quite possible to build web applications with much of the work performed by the client. xdRequest makes it possible to easily pull data from other sources and manipulate it all on the client-side. With xdRequest, you will no longer need to perform data extractions/manipulations from other sources on a server. It can all happen right in the browser.</p><p><span
id="more-1843"></span></p><p><a
href="http://geeklad.com/wp-content/uploads/2009/10/YQL-html-data-table.png?cda6c1" rel="lightbox"><img
src="http://geeklad.com/wp-content/uploads/2009/10/YQL-html-data-table_thumb.png?cda6c1" alt="Screenshot of the YQL html data table" width="160" height="240" align="right" style="border: 0 none;" /></a> I had recently been fooling around quite a bit with <a
href="http://developer.yahoo.com/yql/">YQL</a>, which does provide some built-in features to make cross-domain http requests. It can be done with the html <a
href="http://www.datatables.org/">open data table</a>. You can try it out from the <a
href="http://developer.yahoo.com/yql/console/">YQL Console</a>.  Just go to the data tables section on the right side and select <strong>Data &gt; html</strong>. Unfortunately, the built-in html table is somewhat limited.  You can only make requests using the GET method, and it does not provide any mechanism for sending/receiving HTTP headers.</p><p>Someone in the <a
href="http://developer.yahoo.net/forum/index.php?showforum=41">YQL forums</a> posted a <a
href="http://developer.yahoo.net/forum/index.php?showtopic=1930">YQL feature request to add POST</a> and other HTTP request methods to the html table. Someone responded with the suggestion of building an open data table to do just that. I then started reading the <a
href="http://developer.yahoo.com/yql/guide/yql-opentables-chapter.html">open data table documentation</a>, and came to realize that what you can do with YQL and open data tables is nothing short of astounding.  You can use <a
href="http://developer.yahoo.com/yql/guide/yql-execute-chapter.html">server-side JavaScript</a> to request data from multiple sources and manipulate it in any way you see fit.</p><p>I started developing my own custom open data table for the particular project I was working on at the time, and eventually the project morphed into xdRequest. Because I needed to track cookies and redirects in my little project, I realized that it would be great to develop a generic library that could handle such requests.  Eventually, I more or less abandoned the previous project to develop xdRequest.  Here are some of the features, as highlighted on the project page:</p><ul><li>Make cross-domain requests using the GET and POST methods</li><li>Add request headers along with the requests</li><li>Automatically collect cookies sent by the remote web server</li><li>Automatically follow redirects and collect cookies along the way</li><li>Properly store/transmit cookies, much like the popular server-side library, <a
href="http://curl.haxx.se">cURL</a></li><li>Automatically submits hidden fields detected within forms on webpages</li></ul><p>I also put together a relatively simple <a
href="http://geeklad.com/tools/xdRequest/xdRequest-example.html">xdRequest demo</a>. It brings in data from espn.go.com. When the page loads, it makes an xdRequest to ESPN for the <a
href="http://www.gatorzone.com/football/">University of Florida Football</a> schedule. I&#8217;m a die-hard Gator and UF alumnus, so that&#8217;s why I decided to start the demo with the UF football schedule. When you can click the hyperlinks in the demo, xdRequests are made to ESPN to load schedules for other teams, as well as the box scores for games. It&#8217;s a simple example, but the sky is the limit as to what you can do with xdRequest.</p><p>If you&#8217;re interested in learning more about the project, be sure to check out the <a
href="http://code.google.com/p/xdrequest/">xdRequest project</a> page. If you&#8217;re a JavaScript geek and would like to join, just drop me a line and I&#8217;ll gladly add you to the project. I&#8217;m kind of a n00b when it comes to object-oriented programming with JavaScript, so I could definitely use some help to clean up the code, make enhancements, find bugs, and fix bugs. This is the first &#8220;official&#8221; Open Source project I&#8217;ve ever worked on, so I&#8217;m a n00b when it comes to working on OSS as well.</p><p>If you like xdRequest and build any cool web applications with it, let me know and I&#8217;ll link to it from the project page. If you have any feature suggestions or encounter any bugs, please report them in the <a
href="http://code.google.com/p/xdrequest/issues/list">xdRequest issue tracker</a>.</p> ]]></content:encoded> <wfw:commentRss>http://geeklad.com/make-cross-domain-ajax-requests-with-xdrequest/feed</wfw:commentRss> <slash:comments>25</slash:comments> </item> <item><title>Display Your iGoogle Gadget User Count</title><link>http://geeklad.com/display-your-igoogle-gadget-user-count</link> <comments>http://geeklad.com/display-your-igoogle-gadget-user-count#comments</comments> <pubDate>Tue, 07 Oct 2008 01:38:56 +0000</pubDate> <dc:creator>GeekLad</dc:creator> <category><![CDATA[Programming]]></category> <category><![CDATA[iGoogle gadgets]]></category><guid
isPermaLink="false">http://geeklad.com/?p=456</guid> <description><![CDATA[Most of you probably won&#8217;t use this ever, but if you are an iGoogle gadget developer then this is definitely for you!  I put together a simple little tool that will display how many users my gadgets currently have, and I&#8217;ve set it up so that anyone can use [...]]]></description> <content:encoded><![CDATA[<p>Most of you probably won&#8217;t use this ever, but if you are an iGoogle gadget developer then this is definitely for you!  I put together a simple little tool that will display how many users <a
href="http://geeklad.com/projects/gadgets">my gadgets</a> currently have, and I&#8217;ve set it up so that anyone can use it. <span
id="more-456"></span>If you&#8217;d like to display the number of users your iGoogle gadget has, simply add this HTML code snippet to any webpage or even within your gadget:</p><p><code>&lt;script type="text/javascript" src="http://geeklad.com/tools/gadgetusers.js?url=www.somewebsite.com/somepath/yourgadgetfile.xml&amp;cda6c1"&gt;&lt;/script&gt;</code></p><p>Just be sure to replace the <code>www.somewebsite.com</code> and <code>/somepath/yourgadgetfile.xml</code> accordingly.  My gadget user counter works by performing a <code>document.write</code> to output the number of users that are currently using your gadget, according to the <a
href="http://www.google.com/ig/directory">iGoogle gadget directory</a>.  I have a feeling that these figures are understated or not updated very often, because according to <a
href="http://www.google.com/analytics/">Google Analytics</a> I have many more users than the iGoogle gadget directory states.  At least the directory figures are conservative and they do get updated with some frequency.  Now you can easily inform people as to how many users are using your gadgets too!  Check out <a
href="http://geeklad.com/projects/gadgets/web-definitions">my web definitions gadget</a> page to see it in action.</p><p> ]]></content:encoded> <wfw:commentRss>http://geeklad.com/display-your-igoogle-gadget-user-count/feed</wfw:commentRss> <slash:comments>2</slash:comments> </item> </channel> </rss>
<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Minified using disk: basic
Page Caching using disk: enhanced
Database Caching 96/166 queries in 0.050 seconds using disk: basic
Object Caching 1476/1637 objects using disk: basic

Served from: geeklad.com @ 2012-05-23 19:30:40 -->
