Friday, November 30, 2007

Ruby, Schedule, Reoccurrence, Date, Range, Runt

Almost all of the application that I worked with has something to do with dates and time, and most of those has something to do with scheduling as well, say SoccerMap, where the user can schedule a reoccurring soccer game on google map.

But after all of the research that I have done for how to solve this problem from google, it generally comes down to 2 routes. First is to compute them, and the second is to pre-populate them in the database or file, and perform selects from it.

While the first solution seems to be efficient on the data storage, it might require more time and cpu to crank out the right occurrence dates. The second one seems to be much faster, as everything is almost a lookup away, it will hit the wall once user wants to know what happens in year 3000 ;-)

After lots of mind wrestling and discussion with other programmers, I decided to find a way to compute the occurrence either with a simple algorithm or a library that does it already.

To my surprise, even a problem as universal as this didn’t have a lot of good implementations in various languages. It’s usually provided through a module or external library, and there aren’t many good answers that surfaces google.

Luckily, I found one for the language that I prefer, runt for ruby ;-)

Following is the code to get a series of reoccurring dates from a schedule.

require 'runt'
require 'date'

include Runt
include DPrecision

last_thursday = DIMonth.new(Last_of,Thursday)
august = REYear.new(8)
expr = last_thursday & august

>> (Date.new(2004,1,1)..Date.new(2004,12,31)).select {|d| expr.include? d }
=> [Thu, 26 Aug 2004]
>> (Date.new(2004,1,1)..Date.new(2004,12,31)).select {|d| last_thursday.include? d }
=> [Thu, 29 Jan 2004, Thu, 26 Feb 2004, Thu, 25 Mar 2004, Thu, 29 Apr 2004, Thu, 27 May 2004, Thu, 24 Jun 2004, Thu, 29 Jul 2004, Thu, 26 Aug 2004, Thu, 30 Sep 2004, Thu, 28 Oct 2004, Thu, 25 Nov 2004, Thu, 30 Dec 2004]
References:

Saturday, October 20, 2007

Automatic Client Browser TimeZone Detection for Rails using Javascript and Ajax

After 2+ months of extensive development of Compliance at work, I finally had some spare time to throw into the second version of my pet project SoccerMap.

As usual, the timezone issue came up again, as soccer players can schedule games in their own time zones. After consulting with several existing solutions, TZInfo seems to be the way to go, but I didn’t quite like the fact that users have to explicitly set their own time zones. Like many other busy (or lazy) guys, I’d rather having everything just work out of the box without having me trying to customize it. Plus, what if I just traveled from west coast to east coast? All of the scheduled events will show up as west coast time in the application instead of east coast time.

My solution is actually quite simple ;-) Use javascript to notice the server as needed. This way, it doesn’t matter where you go, if the computer you are using has the local time zone set correctly, then we are good. User doesn’t have to do a thing.

1. Have the layout call a helper method get_local_time_zone, which will try to get the time zone if needed.

<%= get_local_time_zone %>
2. Implement the helper method in application_helper.rb. If we don’t see the gmtoffset stored in the session, then we would want to use a piece of javascript to get that information.

def get_local_time_zone
return '' if session[:gmtoffset].nil?
end
3. How do we get the time from javascript? We first get the client side time zone using javascript, and then use an ajax call to send it to the server.

Event.observe(window, 'load', function(e) {
var now = new Date();
var gmtoffset = now.getTimezoneOffset();
// use ajax to set the time zone here.
var set_time = new Ajax.Request('/gmtoffset/?gmtoffset='+gmtoffset, {
onSuccess: function(transport) {}
});
});
4. OK, It’s pretty obvious now that we need to implement the gmtoffset controller to take the ajax call.

def gmtoffset
session[:gmtoffset] = -params[:gmtoffset].to_i*60 if !params[:gmtoffset].nil? # notice that the javascript version of gmtoffset is in minutes ;-)
render :nothing => true # this can be improved by being able to return xml or json output to inform the client side whether the offset was successfully set on the server or not.
end
5. The rest is simple ;-) Just follow http://www.caboo.se/articles/2007/2/23/adding-timezone-to-your-rails-app, except in your application.rb, it should look like:

private
def set_timezone
TzTime.zone = TimeZone[session[:gmtoffset]] if session[:gmtoffset]
yield
TzTime.reset!
end
Reference:

Tuesday, September 11, 2007

Model Diagram for Rails?

I have been kept busy ever since the end of August, working on soccermap.org, a place where you can find and play more pickup soccer games.

Everything went smoothly when I worked on the first version. The application was small, and things are very clear and extremely easy to find. It didn’t take long for me to receive many feature requests, a total of 16 of them from my soccer buddies just from the first use. I was darn happy about it, and before the launch day has barely passed, I was already venturing into the development of the soccermap.org v2.

Two days into the soccermap v2, I found myself with a total of 16+ different models and soon 18+ controllers. With many many-to-many relationships and polymorphic relationships, it’s getting a little over of my head ;-), and my development progress has slowed dramatically, mainly due to the re-adjustments, revisions and refactoring of the earlier work.

My note book by now, is full of scratches, omits, crosses, circles, checks, underlines, lines that fly across 3 pages, and through the back of 1 page. Oh, yeah! Believe me, I am a very creative note taker. ;-)

As the design is gradually becoming more solid and stable, I want to have something that I can visualize the skeletons of the application other than my ‘precious’ note book, so what’s out there?

I looked into the tools that are directly coming from mysql, but I didn’t get much luck there, they either cost money, or not exactly what I wanted. With a last desperate search before I had to leave for work, I hit the ‘RailRoad’:http://railroad.rubyforge.org. Haha, without dying of course ;-)

It’s a really nice tool created just for rails! So it shouldn’t matter if you are using mysql. It should support all of the db that’s supported by rails! Take that!

Within minutes, I was able to create my shining model and controller diagrams without having to bug my wife to jog them all down in a spreadsheet. That’s the last thing I want to do. ;-)

Remember to go to http://www.graphviz.org/ and find out how to install it to your OS first! Without it, you can only get metadata from Activerecord.

Enjoy!

Reference: http://railroad.rubyforge.org/

Monday, August 27, 2007

Installing RMagick on Ubuntu

Well, I ran into this when I was trying to use the attachment_fu plugin from techno-weenie.

Even though RMagick was a little more heavy on the memory comparing to the other alternatives, I still chose it, as a lot of people are using RMagick, and I can find a lot of help on the web if I just google it.

But things aren’t always as easy as it seems ;-)

I got errors like this on my first attempt to install the RMagick gem:
# gem install rmagick
Building native extensions. This could take a while...
configure: error: Can't install RMagick. Can't find Magick-config or GraphicsMagick-config program.

ERROR: While executing gem ... (RuntimeError)
ERROR: Failed to build gem native extension.
Gem files will remain installed in /usr/lib/ruby/gems/1.8/gems/rmagick-1.15.9 for inspection.

Results logged to /usr/lib/ruby/gems/1.8/gems/rmagick-1.15.9/gem_make.out

Thanks to google and ruby community ;-) I found this reference in less than 10 seconds on google!

Basically, you need to install “libmagick9-dev” package to your ubuntu first.

That’s it!

Thursday, August 23, 2007

Using Javascript to parse XML text

As I was and still am heavily involved in my company’s next major product release, I a kinda slacked off on writing valuable things down when I encounter them.

To make it up, here is something that I was trying to do yesterday.

I need to parse a complex data structure in JSON, and inside the JSON, I would have to deal with some values that are xml, So xml within JSON ;-)

First thing I thought is to create a node using document.createElement, and set the innerHTML of the element to be the value of the JSON xml, then I should be able to access the nodes inside the element that I created just like normal node traversing. (parentNode, childNodes, firstChild, etc…).

It worked with Firefox ;-), but not IE.

I remembered that the library sarissa can do the xslt transformation, so I should be able to find the code in there which handles the string to traversable xml tree conversion.

Guess what, I didn’t have enough time to look through all of the docs to see exactly how it was done, and something else hit me when I was searching through the web.

I was so glad that I don’t have to copy over the 23k lib just to turn the text into xml in IE after reading XML Parser.

So here is the code snippets:
    if (window.ActiveXObject) { // ie
xml=new ActiveXObject("Microsoft.XMLDOM");
xml.async="false";
xml.loadXML(XMLSTRING);
} else { // mozilla
var parser=new DOMParser();
xml=parser.parseFromString(XMLSTRING,"text/xml");
}

Sunday, July 29, 2007

Dynamic Date in Rails Fixture

While I was happily creating a fixture to test my newly created Article model, I found out that the <%= Time.now %> that I used in the fixture was dumping nil’s into the db. ;-(

That was suppose to work, at least long time ago… I still recall reading the first Rails book… The rails api didn’t say much about the dates in dynamic fixtures…

Well, let’s be a little skeptical, and say… Time.now.strftime(“%Y-%m-%d %H:%M:%S”).

Ha! It worked!

But it’s a kinda too long…

Hum… what else does google has to offer?

There was a ticket open with the same issue: Time.now in a fixture return nil. Guess I am not the first ;-)

<%= Time.now.to_s(:db) %>

There, this is much prettier ;-)

Oh, here is a bonus link for more Dynamic Fixture stuff!

Saturday, July 28, 2007

Turning off Activerecord timestamp

Context: I was trying to increment an article’s views column every time when a reader has viewed the article.

Problem: Whenever I increment the article.views, article.updated_at will be updated by the rails through magic column. That’s not what I want, since updated_at should mean it was last updated by the author of the article, not the reader?!

I could stay with the new meaning of the updated_at, really last_viewed_at, but being a little stubborn, I decided to try out my luck on google.

Ref 1: hacking activerecord’s automatic timestamps

A lot of good stuff, but a lot of errors, too… didn’t work for me.

Ref 2: Turning off Magic Columns

Ahh… But it’s not so thread safe, is it? ;-) The good thing that I learned from Ref 1.

Ref 3: Database Conventions

A lot of good info, but doesn’t totally solve my problem. At least I know that meta class is very useful in this threading scenario. ;-)

Ref 4: Seeing Metaclasses Clearly

Aha… That’s really tricky ;-)

Ref 5: So how do I use remove_method?

Ref 6: This one is coming from me ;-)
  def increment_views
class << self
def record_timestamps; false; end
end

self.increment! :views

class << self
remove_method :record_timestamps
end
end

Javascript get the local file path in Mozilla

This function gives you the local file path of the file (nsIFile).

function getLocalFilePath(file) {
// file is nsIFile
var ios = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService);
var fileHandler = ios.getProtocolHandler("file")
.QueryInterface(Components.interfaces.nsIFileProtocolHandler);
var URL = fileHandler.getURLSpecFromFile(file);
return URL;
}

Thursday, July 19, 2007

svn ignore files and directories

Ignore files and directories
The svn:ignore property can be set on filename patterns and directories.

svn propset svn:ignore PATTERN directory PATH
svn propset svn:ignore directory PATH

Edit property setting
Subversion properties can be edited using svn’s propedit function.

svn propedit svn:ignore PATH
svn propget svn:ignore PATH

PATH is assumed current working directory if not specified. If PATTERN is not specified, an editor window will open and let you edit patterns.

Wednesday, July 18, 2007

ActiveRecord Session for Rails

I know that this is probably all over the Internet, this is just an entry for my own convenience.

  • Uncomment the ‘config.action_controller.session_store = :active_record_store’ from the app/config/environment.rb
  • rake db:sessions:create
  • rake migrate

Restart your server, and you are done!

Tuesday, June 26, 2007

svn external

svn:external is a very useful feature, it allows you to link other repositories into yours.


svn propedit svn:externals .

Sunday, June 24, 2007

XPCOM to store your data

Here are some more links after my research.

If you are using Javascript to write an XPCOM Component to store your data, you can store objects of any kind, and it’s better to make it a service rather than an instance.

References:

Saturday, June 23, 2007

XPIDL - Defining your XPCOM Component Interface

It didn’t take long before I arrived at a point where I need to define an interface that has a lot more to do than just returning Strings. To find out more, here are some very good resources:

How to use an XPCOM Component?

In the last post, I created an article on How to create a Javascript XPCOM component in 5 minutes”. To make it a little more complete, I will provide the details on how to use the XPCOM Component that you created in this post.

It turns out to be pretty simple once you have followed the instructions from the previous post. The code snippets is shown below.

try {
// this is needed to generally allow usage of components in javascript
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");

var fc = Components.classes['@hungryfools.com/helloworld;1']
.createInstance(Components.interfaces.nsIHelloWorld);

} catch (anError) {
LOG("ERROR: " + anError);
}

Reference: http://developer.mozilla.org/en/docs/How_to_Build_an_XPCOM_Component_in_Javascript

Tuesday, May 22, 2007

Make a Javascript XPCOM component in five minutes!

You don’t really have to make XPCOM components if you prefer not to when you are developing a Firefox extension, but there are times when it’s the right way of doing things, and I just happen to be a guy who really love to do the things right. ;-)

Again, even though XPCOM is not necessary, and might be evil in some cases such as causing memory leaks if used without care, it does provide a lot of benefits, such as providing a clean way to store temporary data, sepating the development concerns between multiple developers by making a clear contract, also enabling developers to use different languages(C, C++, Java, Python, Javascript) to program the underlying implementations!

Since reading XPCOM document isn’t the easist thing for me, I am going to give you an even quicker and dirtier kick start:

  • Go to http://developer.mozilla.org/en/docs/Gecko_SDK and download the right version of gecko sdk, for me, I am downloading the linux one on the bottom right side, since I am using ubuntu.
  • Unzip it using “tar -xjf gecko-sdk-i686-pc-linux-gnu-1.8.0.4.tar.bz2”, and move it into your home directory “move gecko-sdk ~/”
  • Go to your XOCOM component development dir and “touch HelloWorld.idl”
  • Inside “HelloWorld.idl”, paste

#include "nsISupports.idl"

[scriptable, uuid(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)]
interface nsIHelloWorld : nsISupports
{
string hello();
};
  • Go to http://www.famkruithof.net/uuid/uuidgen, generate a bunch of UUID, and replace the xxx’s of “[scriptable, uuid(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)]” with your favorite UUID that you want to use for your component.
  • Compile the typelib interface

~/gecko-sdk/bin/xpidl -m typelib -w -v -I ~/gecko-sdk/idl -e nsIFireCruncher.xpt nsIFireCruncher.idl
  • Paste the following code into “HelloWorld.js”.

/***********************************************************
constants
***********************************************************/


// reference to the interface defined in nsIHelloWorld.idl
const nsIHelloWorld = Components.interfaces.nsIHelloWorld;

// reference to the required base interface that all components must support
const nsISupports = Components.interfaces.nsISupports;

// UUID uniquely identifying our component
// You can get from: http://kruithof.xs4all.nl/uuid/uuidgen here
const CLASS_ID = Components.ID("{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx}");

// description
const CLASS_NAME = "My Hello World Javascript XPCOM Component";

// textual unique identifier
const CONTRACT_ID = "@hungryfools.com/helloworld;1";

/***********************************************************
class definition
***********************************************************/


//class constructor
function HelloWorld() {
};

// class definition
HelloWorld.prototype = {

// define the function we want to expose in our interface
hello: function() {
return "Hello World!";
},

QueryInterface: function(aIID)
{
if (!aIID.equals(nsIHelloWorld) &&
!aIID.equals(nsISupports))
throw Components.results.NS_ERROR_NO_INTERFACE;
return this;
}
};

/***********************************************************
class factory

This object is a member of the global-scope Components.classes.
It is keyed off of the contract ID. Eg:

myHelloWorld = Components.classes["@dietrich.ganx4.com/helloworld;1"].
createInstance(Components.interfaces.nsIHelloWorld);

***********************************************************/

var HelloWorldFactory = {
createInstance: function (aOuter, aIID)
{
if (aOuter != null)
throw Components.results.NS_ERROR_NO_AGGREGATION;
return (new HelloWorld()).QueryInterface(aIID);
}
};

/***********************************************************
module definition (xpcom registration)
***********************************************************/

var HelloWorldModule = {
registerSelf: function(aCompMgr, aFileSpec, aLocation, aType)
{
aCompMgr = aCompMgr.
QueryInterface(Components.interfaces.nsIComponentRegistrar);
aCompMgr.registerFactoryLocation(CLASS_ID, CLASS_NAME,
CONTRACT_ID, aFileSpec, aLocation, aType);
},

unregisterSelf: function(aCompMgr, aLocation, aType)
{
aCompMgr = aCompMgr.
QueryInterface(Components.interfaces.nsIComponentRegistrar);
aCompMgr.unregisterFactoryLocation(CLASS_ID, aLocation);
},

getClassObject: function(aCompMgr, aCID, aIID)
{
if (!aIID.equals(Components.interfaces.nsIFactory))
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;

if (aCID.equals(CLASS_ID))
return HelloWorldFactory;

throw Components.results.NS_ERROR_NO_INTERFACE;
},

canUnload: function(aCompMgr) { return true; }
};

/***********************************************************
module initialization

When the application registers the component, this function
is called.
***********************************************************/

function NSGetModule(aCompMgr, aFileSpec) { return HelloWorldModule; }
  • To install the Component that you’ve just created into your extension,
    • Copy HelloWorld.js and HelloWorld.xpt to {extensiondir}/components/
    • Delete compreg.dat and xpti.dat from your profile directory.
    • Restart application

Original Reference: http://developer.mozilla.org/en/docs/How_to_Build_an_XPCOM_Component_in_Javascript

UUID Generator

If you want to make an XPCOM component, the first thing that comes to do is to get a UUID for your component.

Here are the two online ones that would just do this job for you free of charge ;-)

  1. http://www.famkruithof.net/uuid/uuidgen
  2. http://www.somacon.com/p113.php

I like the first one better, as it allows you to make a whole bunch of UUIDs, and let you pick the number that you think is right for your dream component!

Oh, one more freebie ;-)

If you are in a really good mood and have a couple of minutes to spare, why not try to generate a UUID from Firefox itself? It’s got an XPCOM component to do this! How fun would that be? ;-)

Firefox Extension: XPCOMViewer

After many attempts to kick start my XPCOM adventure, here is one of the many useful plugins that you don’t want to miss in your Firefox extension development environment, XPCOMViewer.

With XPCOMViewer, you wouldn’t have to search all over the xulplanet.com or developer.mozilla.org for the XPCOM interfaces any more. Just type in the keywords or key phrases into the filter on the top, and you will find all about the available interfaces just by a couple of clicks!

Another wonderful addition to my tools collection. ;-)

Monday, May 21, 2007

Firefox extension in sidebar

To date, other than the first “Hello World” extension I created for Firefox, almost all of my other works makes use of the Sidebar. After trying to search for the instruction of building the extension overlay into the Firefox sidebar for countless times, I am now deciding to add the original article link into my collection.

Three ways to log errors and messages in firefox

After making a couple of simple firefox plugins, I decided to write a really good Javascript logger. With the previous experience and a little more dig around, I am thinking about providing three primary logging target implementations which firefox supports out of the box.

  1. Dump
  2. Components.utils.reportError
  3. nsIConsoleService

To use dump() function, you have to make sure that your firefox application is started with the command line option ‘-console’ after you set the setting ‘browser.dom.window.dump.enabled’ to true. This is good for really any logging, but it’s limited to command line logging.

‘Components.utils.reportError’ on the other hand, is really great for reporting errors, and it’s usually used as the exception catching block like below:

try {
this.could.raise.an.exception;
} catch(e) {
Components.utils.reportError(e); // report the error and continue execution
}
My favorite one would be the ‘nsIConsoleService’, as it is logging directly into the console, and you can easily create a wrapper into it to make it really powerful.

function LOG(msg) {
var consoleService = Components.classes["@mozilla.org/consoleservice;1"]
.getService(Components.interfaces.nsIConsoleService);
consoleService.logStringMessage(msg);
}
You can even specify line numbers, flags and category ;-) through scripterror component class that comes with the firefox!

var scriptError = Components.classes["@mozilla.org/scripterror;1"]
.createInstance(Components.interfaces.nsIScriptError);
scriptError.init(aMessage, aSourceName, aSourceLine, aLineNumber,
aColumnNumber, aFlags, aCategory);
consoleService.logMessage(scriptError);

Monday, May 14, 2007

A thought on Firefox extension development

ust for fun, I started my own firefox extension project some time ago, and as the code base grows, I found out that the current extension architecture is very easy to get smaller extensions to work, but once you hit 5k to 10k lines of code, you need to really do something about the refactoring of the javascript. As my extension goes, it has a base command set, and a base execution environment. The key would be to enable the other developers to develop the extension of my extension, so it will have an ever richer command set! ;-) Organization and loading of the code without restarting firefox or reloading the chrome is crucial at this stage!

I am currently looking for advice. If you have an idea, please post a comment or email me. (You can find my email address at the end of the about page.) I will also post any updates as I receive them.

Wednesday, May 2, 2007

A good tutorial site for web development

I came across many sites that gives tutorials for web development. The sad thing is, not many of them are actually good for real programming tasks.

Here is one that I found recently that’s pretty good: http://www.howtocreate.co.uk from Mark Wilton-Jones – usually known as “Tarquin”.

Mark’s got a lot of good materials on Javascript, CSS, Design and cross browser compatibility stuff. A lot of examples and code that you can see in action and download, too!

Consider his site the UK version of http://www.quirksmode.com/.

Javascript Closure

Even though there are alternative technologies such as Flash and Flex, Javascript is still being considered as the mainstream. I started my interested in Javascript by working with one of my early mentors, who worked for Netscape back in the first browser war. ;-) He uses Javascript to create prototypes of the code piece, and created many everyday programmer’s utilities by writing a small piece of Javascript. It was one of the most fascinating thing I’ve seen then. Now I am pretty much as in love of Javascript as my mentor does.

There are many shortcomings in the language itself, but Prototypal inheritance, Closure and many other built-in features makes Javascript one of the most flexible and powerful computer language.

Here is the reference to one of my favorite Javascript Closure documentation: http://www.jibbering.com/faq/faq_notes/closures.html

Monday, April 30, 2007

The dollar-dollar ($$) function in prototype.

Since I am going to be working with the dollar-dollar ($$) function from prototype pretty soon, might as well do some research and write about it.

It turns out that the newest versions of prototype 1.5.0 and 1.5.1_rc4 include a lot of cool features for the $$ css selector function. Some of the very useful ones include Attribute selectors (~= $= *=).

For details, please refer to http://prototypejs.org/api/utility/dollar-dollar and w3c css selector reference.

Friday, April 27, 2007

New things in Javascript 1.7

As the Javascript is becoming more than more mature, it is starting to show some really neat features that you can find in programming other scripting language, such as Ruby and Python. Here, I will just pick a couple of them to do some neat tricks that we would probably find useful.

Destructuring assignment makes it possible to extract data from arrays or objects using a syntax that mirrors the construction of array and object literals.

The object and array literal expressions provide an easy way to create ad-hoc packages of data. Once you’ve created these packages of data, you can use them any way you want to. You can even return them from functions.

One particularly useful thing you can do with destructuring assignment is to read an entire structure in a single statement, although there are a number of interesting things you can do with them, as shown in the section full of examples that follows.

This capability is similar to features present in languages such as Perl and Python.

Trick 1: Swapping values between two variables without using the temporary variable.

I still remember when I was learning assembly language programming, one of my friend was so proud of showing off the XOR Swap Trick. It was indeed the coolest thing I saw then, since it saves 1 register. ;-)

Now, how can you do it in Javascript? Use Destructing Assignment.


var a = 1;
var b = 3;

[a, b] = [b, a];

Ha! One line does it all, and it is quite readable!

Trick 2: Parse a URL and get the parts from it using as few lines of code as possible.


var url = 'http://hungryfools.com/2007/4/27/new-things-in-javascript-1-7';
var parsedURL = /^(\w+)\:\/\/([^\/]+)\/(.*)$/.exec(url);
var [, protocol, fullhost, fullpath] = parsedURL;
alert(protocol);
alert(fullhost);
alert(fullpath);

Notices that we ignored the first value from the result, and we are able to extract and assign all of the parts of the URL in one line!

For detailed explanation of what’s new in Javascript 1.7, please visit http://developer.mozilla.org/en/docs/New_in_JavaScript_1.7.

Thursday, April 26, 2007

Cheat Sheets for programmers

My cheat sheet discovery didn’t just end with regular expression. ;-) I went on and found a great cheat sheet collection for programmers like me!

More help on regular expressions ;-)

Even though you’ve got the Awesome Free Regular Expression Generator, there are times that you will still trying to scratch your head for some of the regex syntax details. Here is the link to the Regular Expression Cheatsheet! Oh, did I forget to say~ “It’s really awesome, too!”

Reference: http://www.ilovejackdaniels.com/cheat-sheets/regular-expressions-cheat-sheet

Wednesday, April 25, 2007

Awesome Free Regular Expression Generator

Ever had “Not again~!” time with regular expression coming in your way? I had a lot of them recently. Fortunately, someone has already wrote regex generator for it. While there are tons of them out there, not a lot of them do what I want, or as easy to use and free. After a while, I found text2re.com. The regex generator provided by text2re is really simple to use; it’s works from the browser, so you don’t have to install anything, and virtually use it anywhere; it even gives you the generated regular expression code in 15 computer languages (ruby, perl, python, php, javascript, c, c++, c#, etc.), ;-) and most important of all, it is FREE!

Reference: http://www.txt2re.com

Use Javascript to detect Vista?

I encountered a strange bug today, where the same piece of javascript code works perfectly on ie 7 (7.0.6000.16386) on xp, but fails randomly on the same version of ie7 on vista. I know how to use object detection technique to figure out which version of browser it is and what kind of functionality it supports, but how am I gonna use that to tell the two supposedly the same browser from 2 different OS?

Object detection is not an option now, and the best I can find online is to check User Agent, which is not very reliable.

You can try the following code on your browser address bar:

javascript:alert(navigator.userAgent);

Notices the IE versions:

2K is version 5
XP is version 5.1
vista is version 6
[1] Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.0.4) Gecko/20060508 Firefox/1.5.0.4
[2] Opera/9.00 (Windows NT 6.0; U; en)
[3] Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 6.0)

Reference: http://www.webmasterworld.com/javascript/3179395.htm

Textile

Just for the heck of it, I am adding the link of textile reference to my collection ;-)

Tuesday, April 24, 2007

ie6 and ie7 on the same machine

As the firefox went nuts on my windows workstation, it seems that there isn’t much I can do to fix it even after numerous reinstalls and clearing of the left over files. Even worse, after my workstation was reinstalled with a new image, my working ie6 was gone, and I got ie7 instead ;-(.

How am I gonna fix the ie6 specific bugs now.

Here is what I found out:

Thank God! At least Microsoft has a blogging place for its developers.

Friday, April 20, 2007

Mephisto liquid references

During the process of creating my own Mephisto theme, I found it very difficult not to copy from the other existing themes. Yet, not all of them have the functions that I need. After digging into the code and spend hours to figure out what I can do with the liquid in mephisto with out much efficiency, I finally come across these 2 links on Slash7.

Hope these will help you a lot in creating a custom mephisto theme! ;-)

Wednesday, April 18, 2007

How to remove the default background in Mediawiki?

Assuming that you are going to make changes to the monobook skin, go to skins/monobook/main.css, and comment out the background line in body like following.


body {
font: x-small sans-serif;
/*background: #f9f9f9 url(headbg.jpg) 0 0 no-repeat;*/
color: black;
margin: 0;
padding: 0;
}

Sunday, April 15, 2007

Helpful notes on administrative tasks on Mediawiki.

After playing around with Mediawiki, I came through some of the good documents for administrative tasks.

Tuesday, April 10, 2007

How do I delete a page from mediawiki?

As recent playing with Mediawiki, I had a hard time finding the page deletion option just from the user interface. It turns out that there isn’t one! ;-) Here is how you delete a page in Mediawiki.

  1. Go to the page that you want to delete.
  2. Append “&action=delete” to the end of the url, and press enter.

For more detailed description, see Deleting a page.

Monday, April 9, 2007

How to clean up the change history of the mediawiki?

From time to time, I make lots of changes into the mediawiki. How can I delete the unwanted history of a page?

Start the command line, and go to the maintenance directory of the mediawiki installation. Finally, enter the following command:

# php deleteOldRevisions.php --delete

Note: You have to have php5 installed, in order to execute this command. Depending on your system configuration, on Dreamhost, it is /usr/local/dh/cgi-system/php5.cgi instead.

Sunday, April 8, 2007

How to get rid of the caching problem in Mediawiki?

Sometimes you will find that the Mediawiki is not updating its content. This is sometimes due to client side caching. To disable this, edit LocalSettings.php as following:


# Client-side caching:
$wgCachePages = false; # Allow client-side caching of pages

How to change the content of Navigation Bar in Mediawiki?

Ref: http://www.mediawiki.org/wiki/Manual:Navigation_bar

How to set the timezone for mediawiki?

There are times when the physical server and the mediawiki users are in different timezones. Here is how to adjust the timezone in mediawiki. Add the following lines to your LocalSettings.php


$wgLocaltimezone="America/Los_Angeles";
putenv("TZ=$wgLocaltimezone");
$wgLocalTZoffset = date("Z") / 60;

Note: You can find your local time zone text here.

How to enable file upload in Mediawiki?

In LocalSettings.php, Change


$wgEnableUploads = true;

Once you have done that, you can find the “Upload file” link in your “Toolbox” section.

How to make mediawiki not editable by public?

In LocalSettings.php, add the following

/* Disable anonymous user from creating account and editing
pages */
$wgGroupPermissions['*' ]['createaccount'] = false;
$wgGroupPermissions['*' ]['read'] = true;
$wgGroupPermissions['*' ]['edit'] = false;
$wgGroupPermissions['*' ]['createpage'] = false;
$wgGroupPermissions['*' ]['createtalk'] = false;

/* Allow user to login */
$wgWhitelistRead = array ("Special:Userlogin");

/* Make sure that user have to have a valid email address
before edit */
$wgEmailConfirmToEdit = true;

How to make Mediawiki readonly?

This is usually very useful when you want to freeze the database changes to do migrations, upgrades, etc.

  1. make sure the /image directory is writable
  2. go to /image directory and write whatever reason for a readonly wiki in lock_yBgMBwiR.

OR

  1. Change $wgReadOnly in LocalSettings.php to the reason for a readonly wiki.

Sunday, April 1, 2007

Why this? Why now?

I have actually started blogging back in 2001. Had a lot more time back then. I started with hard coding html, copying layouts from rinoa.nu and the Final Fantasy gamers blog rings. Later, I moved on with simple php mysql stuff when I started to help people with their dynamic websites.

After that, I started to blog when ever there is a new blogging software or blogging engine. Really just to try them out, but the sad thing is, the blog entries were never kept together and archived. Now, they are scattered all over the place.

So far, there hasn’t been any blogging solution that really fits my needs. The need to have a place to dump all of my daily info, thoughts, files, schedules, emails, contacts in, and being able to search whatever I want with absolute ease and clarity.

So why this? and why now?

As the information that I would like to record grew over the years, I just decided to have a place to dump them first. Hopefully, after a short while, migrating them wouldn’t be such a big pain. ;-)

About me

As you have probably guessed from the tag line, Steve Jobs is one of my greatest inspirations. ;-)

I was one of the luckiest few Shanghai kid, who got to spend my 17th birthday as a high school exchange student in Kissimmee, Florida with my foreign host family. My American high school, Osceola High School, had the finest football team in the entire Florida, and tons of funny stories from me, the 6’2” skinny teen ‘Borat’ from China.

After trying out Mechanical Polymer Engineering, Electrical Engineering and Computer Engineering, I finally settled with Computer Science, as I found it teaching me the things that I am mostly interested in. While enduring the coldest winters of my life in (Akron, Ohio), where I finished my Bachelors in University of Akron, I drove across the country three times exploring my dream place – Silicon Valley.

Being an evangelist of web and the technologies around it, I shortly started my career as a software engineer in Bay Area. I found my first real job after college in Manhattan Associates through one of my former mentors I worked for. While I was there, I helped the R&D of the company wide next generation user interface framework with the architect. Then, I got into Visa, where I worked on the then "next generation" credit card message gateway as a system engineer, and developed a multiple products build and release automation process and tools.

After a brief period of Sms.ac (now Fanbox) as a member of their infrastructure and performance team in San Diego, I came back to Bay Area for a great internet security company Qualys Inc, where I became one of the core developers of QualysGard. While working along side with the security veterans, I became more involved with enterprise UI and cross browser support for our award winning On Demand Vulnerability Management System.

I became a Yahoo! several months before the summer Olympics of 2008, and has been a member of the Yahoo Frontpage group ever since. There, I learned and relearned a whole bunch of things that I thought I learned well before. Never knew that aggregation of the even smallest mistakes, tinyist performance enhancement could make such a big difference. I am so grateful that my team as well as the teams I worked with have taught me so much about the web, and I was given lots of opportunities to work on so many parts of the product. It has truly been an eye opening experience on how one of the most visited pages was made. At the same time, I found out how important data is, and fell in love with it.

My interest in data soon got me into Netflix. As a member of the subscriber acquisition team, we helped optimizing their customer conversion from various marketing channels. I would have to say that Netflix has one of the best marketing teams in the world, and one of the best user funnel management systems ever.

I am currently working for a startup called Outright, where I actually got to design and build their entire data stack. We are trying to make accounting and tax preparation painless for all of the small businesses around the country.

I usually like to keep my brains busy, or having them entertained by the web feeds. Whenever I get a break, I love playing volley ball, soccer, basket ball, and now foosball and table tennis ;-)

Oh, the last but not the least, my latest contributions to open source communities can be found on the right side of this page, or in my linkedin profile.

Thanks for reading!

You can always reach me at lei [dot] sun [at] gmail [dot] com.