if (top.location != self.location) {
	top.location = self.location;
}
var bits = unescape(location.href).match(new RegExp('twitters/([\\w _-]*)/([\\w _-]*)/([\\w _-]*)/([\\w _-]*).html', ''));
if (bits && bits.length > 4) {
	//location = 'http://localhost:8080/#!twitters/' + bits[1] + '/' + bits[2]  + '/' + bits[3]  + '/' + bits[4] + '.html';
	//location = 'http://locafollow-labs.appspot.com/#!twitters/' + bits[1] + '/' + bits[2]  + '/' + bits[3]  + '/' + bits[4] + '.html';
	//location = 'http://locafollow-beta.appspot.com/#!twitters/' + bits[1] + '/' + bits[2]  + '/' + bits[3]  + '/' + bits[4] + '.html';
	location = 'http://www.locafollow.com/#!twitters/' + bits[1] + '/' + bits[2]  + '/' + bits[3]  + '/' + bits[4] + '.html';
}
			

google.load('search', '1', {"nocss" : true, "nooldnames" : true});
google.load("language", '1');
google.load("mootools", '1.2.4');
	
google.setOnLoadCallback(function() { 
	/*
	Script: Log.js
		Provides basic logging functionality for plugins to implement.

		License:
			MIT-style license.

		Authors:
			Guillermo Rauch
	*/

	var Log = new Class({
		
		log: function(){
			Log.logger.call(this, arguments);
		}
		
	});

	Log.logged = [];

	Log.logger = function(){
		if(window.console && console.log) console.log.apply(console, arguments);
		else Log.logged.push(arguments);
	};

	/*
	Script: Class.Refactor.js
		Extends a class onto itself with new property, preserving any items attached to the class's namespace.

		License:
			MIT-style license.

		Authors:
			Aaron Newton
	*/

	Class.refactor = function(original, refactors){

		$each(refactors, function(item, name){
			var origin = original.prototype[name];
			if (origin && (origin = origin._origin) && typeof item == 'function') original.implement(name, function(){
				var old = this.previous;
				this.previous = origin;
				var value = item.apply(this, arguments);
				this.previous = old;
				return value;
			}); else original.implement(name, item);
		});

		return original;

	};


	/*
	Script: MooTools.Lang.js
		Provides methods for localization.

		License:
			MIT-style license.

		Authors:
			Aaron Newton
	*/

	(function(){

		var data = {
			language: 'en-US',
			languages: {
				'en-US': {}
			},
			cascades: ['en-US']
		};
		
		var cascaded;

		MooTools.lang = new Events();

		$extend(MooTools.lang, {

			setLanguage: function(lang){
				if (!data.languages[lang]) return this;
				data.language = lang;
				this.load();
				this.fireEvent('langChange', lang);
				return this;
			},

			load: function() {
				var langs = this.cascade(this.getCurrentLanguage());
				cascaded = {};
				$each(langs, function(set, setName){
					cascaded[setName] = this.lambda(set);
				}, this);
			},

			getCurrentLanguage: function(){
				return data.language;
			},

			addLanguage: function(lang){
				data.languages[lang] = data.languages[lang] || {};
				return this;
			},

			cascade: function(lang){
				var cascades = (data.languages[lang] || {}).cascades || [];
				cascades.combine(data.cascades);
				cascades.erase(lang).push(lang);
				var langs = cascades.map(function(lng){
					return data.languages[lng];
				}, this);
				return $merge.apply(this, langs);
			},

			lambda: function(set) {
				(set || {}).get = function(key, args){
					return $lambda(set[key]).apply(this, $splat(args));
				};
				return set;
			},

			get: function(set, key, args){
				if (cascaded && cascaded[set]) return (key ? cascaded[set].get(key, args) : cascaded[set]);
			},

			set: function(lang, set, members){
				this.addLanguage(lang);
				langData = data.languages[lang];
				if (!langData[set]) langData[set] = {};
				$extend(langData[set], members);
				if (lang == this.getCurrentLanguage()){
					this.load();
					this.fireEvent('langChange', lang);
				}
				return this;
			},

			list: function(){
				return Hash.getKeys(data.languages);
			}

		});

	})();

	/*
	Script: Date.js
		Extends the Date native object to include methods useful in managing dates.

		License:
			MIT-style license.

		Authors:
			Aaron Newton
			Nicholas Barthelemy - https://svn.nbarthelemy.com/date-js/
			Harald Kirshner - mail [at] digitarald.de; http://digitarald.de
			Scott Kyle - scott [at] appden.com; http://appden.com

	*/

	(function(){

	if (!Date.now) Date.now = $time;

	Date.Methods = {};

	['Date', 'Day', 'FullYear', 'Hours', 'Milliseconds', 'Minutes', 'Month', 'Seconds', 'Time', 'TimezoneOffset',
		'Week', 'Timezone', 'GMTOffset', 'DayOfYear', 'LastMonth', 'LastDayOfMonth', 'UTCDate', 'UTCDay', 'UTCFullYear',
		'AMPM', 'Ordinal', 'UTCHours', 'UTCMilliseconds', 'UTCMinutes', 'UTCMonth', 'UTCSeconds'].each(function(method){
		Date.Methods[method.toLowerCase()] = method;
	});

	$each({
		ms: 'Milliseconds',
		year: 'FullYear',
		min: 'Minutes',
		mo: 'Month',
		sec: 'Seconds',
		hr: 'Hours'
	}, function(value, key){
		Date.Methods[key] = value;
	});

	var zeroize = function(what, length){
		return new Array(length - what.toString().length + 1).join('0') + what;
	};

	Date.implement({

		set: function(prop, value){
			switch ($type(prop)){
				case 'object':
					for (var p in prop) this.set(p, prop[p]);
					break;
				case 'string':
					prop = prop.toLowerCase();
					var m = Date.Methods;
					if (m[prop]) this['set' + m[prop]](value);
			}
			return this;
		},

		get: function(prop){
			prop = prop.toLowerCase();
			var m = Date.Methods;
			if (m[prop]) return this['get' + m[prop]]();
			return null;
		},

		clone: function(){
			return new Date(this.get('time'));
		},

		increment: function(interval, times){
			interval = interval || 'day';
			times = $pick(times, 1);

			switch (interval){
				case 'year':
					return this.increment('month', times * 12);
				case 'month':
					var d = this.get('date');
					this.set('date', 1).set('mo', this.get('mo') + times);
					return this.set('date', d.min(this.get('lastdayofmonth')));
				case 'week':
					return this.increment('day', times * 7);
				case 'day':
					return this.set('date', this.get('date') + times);
			}

			if (!Date.units[interval]) throw new Error(interval + ' is not a supported interval');

			return this.set('time', this.get('time') + times * Date.units[interval]());
		},

		decrement: function(interval, times){
			return this.increment(interval, -1 * $pick(times, 1));
		},

		isLeapYear: function(){
			return Date.isLeapYear(this.get('year'));
		},

		clearTime: function(){
			return this.set({hr: 0, min: 0, sec: 0, ms: 0});
		},

		diff: function(d, resolution){
			resolution = resolution || 'day';
			if ($type(d) == 'string') d = Date.parse(d);

			switch (resolution){
				case 'year':
					return d.get('year') - this.get('year');
				case 'month':
					var months = (d.get('year') - this.get('year')) * 12;
					return months + d.get('mo') - this.get('mo');
				default:
					var diff = d.get('time') - this.get('time');
					if (Date.units[resolution]() > diff.abs()) return 0;
					return ((d.get('time') - this.get('time')) / Date.units[resolution]()).round();
			}

			return null;
		},

		getLastDayOfMonth: function(){
			return Date.daysInMonth(this.get('mo'), this.get('year'));
		},

		getDayOfYear: function(){
			return (Date.UTC(this.get('year'), this.get('mo'), this.get('date') + 1) 
				- Date.UTC(this.get('year'), 0, 1)) / Date.units.day();
		},

		getWeek: function(){
			return (this.get('dayofyear') / 7).ceil();
		},
		
		getOrdinal: function(day){
			return Date.getMsg('ordinal', day || this.get('date'));
		},

		getTimezone: function(){
			return this.toString()
				.replace(/^.*? ([A-Z]{3}).[0-9]{4}.*$/, '$1')
				.replace(/^.*?\(([A-Z])[a-z]+ ([A-Z])[a-z]+ ([A-Z])[a-z]+\)$/, '$1$2$3');
		},

		getGMTOffset: function(){
			var off = this.get('timezoneOffset');
			return ((off > 0) ? '-' : '+') + zeroize((off.abs() / 60).floor(), 2) + zeroize(off % 60, 2);
		},

		setAMPM: function(ampm){
			ampm = ampm.toUpperCase();
			var hr = this.get('hr');
			if (hr > 11 && ampm == 'AM') return this.decrement('hour', 12);
			else if (hr < 12 && ampm == 'PM') return this.increment('hour', 12);
			return this;
		},

		getAMPM: function(){
			return (this.get('hr') < 12) ? 'AM' : 'PM';
		},

		parse: function(str){
			this.set('time', Date.parse(str));
			return this;
		},

		isValid: function(date) {
			return !!(date || this).valueOf();
		},

		format: function(f){
			if (!this.isValid()) return 'invalid date';
			f = f || '%x %X';
			f = formats[f.toLowerCase()] || f; // replace short-hand with actual format
			var d = this;
			return f.replace(/%([a-z%])/gi,
				function($1, $2){
					switch ($2){
						case 'a': return Date.getMsg('days')[d.get('day')].substr(0, 3);
						case 'A': return Date.getMsg('days')[d.get('day')];
						case 'b': return Date.getMsg('months')[d.get('month')].substr(0, 3);
						case 'B': return Date.getMsg('months')[d.get('month')];
						case 'c': return d.toString();
						case 'd': return zeroize(d.get('date'), 2);
						case 'H': return zeroize(d.get('hr'), 2);
						case 'I': return ((d.get('hr') % 12) || 12);
						case 'j': return zeroize(d.get('dayofyear'), 3);
						case 'm': return zeroize((d.get('mo') + 1), 2);
						case 'M': return zeroize(d.get('min'), 2);
						case 'o': return d.get('ordinal');
						case 'p': return Date.getMsg(d.get('ampm'));
						case 'S': return zeroize(d.get('seconds'), 2);
						case 'U': return zeroize(d.get('week'), 2);
						case 'w': return d.get('day');
						case 'x': return d.format(Date.getMsg('shortDate'));
						case 'X': return d.format(Date.getMsg('shortTime'));
						case 'y': return d.get('year').toString().substr(2);
						case 'Y': return d.get('year');
						case 'T': return d.get('GMTOffset');
						case 'Z': return d.get('Timezone');
					}
					return $2;
				}
			);
		},

		toISOString: function(){
			return this.format('iso8601');
		}

	});

	Date.alias('diff', 'compare');
	Date.alias('format', 'strftime');

	var formats = {
		db: '%Y-%m-%d %H:%M:%S',
		compact: '%Y%m%dT%H%M%S',
		iso8601: '%Y-%m-%dT%H:%M:%S%T',
		rfc822: '%a, %d %b %Y %H:%M:%S %Z',
		'short': '%d %b %H:%M',
		'long': '%B %d, %Y %H:%M'
	};

	var nativeParse = Date.parse;

	var parseWord = function(type, word, num){
		var ret = -1;
		var translated = Date.getMsg(type + 's');

		switch ($type(word)){
			case 'object':
				ret = translated[word.get(type)];
				break;
			case 'number':
				ret = translated[month - 1];
				if (!ret) throw new Error('Invalid ' + type + ' index: ' + index);
				break;
			case 'string':
				var match = translated.filter(function(name){
					return this.test(name);
				}, new RegExp('^' + word, 'i'));
				if (!match.length)    throw new Error('Invalid ' + type + ' string');
				if (match.length > 1) throw new Error('Ambiguous ' + type);
				ret = match[0];
		}

		return (num) ? translated.indexOf(ret) : ret;
	};


	Date.extend({

		getMsg: function(key, args) {
			return MooTools.lang.get('Date', key, args);
		},

		units: {
			ms: $lambda(1),
			second: $lambda(1000),
			minute: $lambda(60000),
			hour: $lambda(3600000),
			day: $lambda(86400000),
			week: $lambda(608400000),
			month: function(month, year){
				var d = new Date;
				return Date.daysInMonth($pick(month, d.get('mo')), $pick(year, d.get('year'))) * 86400000;
			},
			year: function(year){
				year = year || new Date().get('year');
				return Date.isLeapYear(year) ? 31622400000 : 31536000000;
			}
		},

		daysInMonth: function(month, year){
			return [31, Date.isLeapYear(year) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
		},

		isLeapYear: function(year){
			return new Date(year, 1, 29).get('date') == 29;
		},

		parse: function(from){
			var t = $type(from);
			if (t == 'number') return new Date(from);
			if (t != 'string') return from;
			from = from.clean();
			if (!from.length) return null;

			var parsed;
			Date.parsePatterns.some(function(pattern){
				var r = pattern.re.exec(from);
				return (r) ? (parsed = pattern.handler(r)) : false;
			});

			return parsed || new Date(nativeParse(from));
		},

		parseDay: function(day, num){
			return parseWord('day', day, num);
		},

		parseMonth: function(month, num){
			return parseWord('month', month, num);
		},

		parseUTC: function(value){
			var localDate = new Date(value);
			var utcSeconds = Date.UTC(localDate.get('year'), 
			localDate.get('mo'),
			localDate.get('date'), 
			localDate.get('hr'), 
			localDate.get('min'), 
			localDate.get('sec'));
			return new Date(utcSeconds);
		},

		orderIndex: function(unit){
			return Date.getMsg('dateOrder').indexOf(unit) + 1;
		},

		defineFormat: function(name, format){
			formats[name] = format;
		},

		defineFormats: function(formats){
			for (var name in formats) Date.defineFormat(name, formats[f]);
		},

		parsePatterns: [],
		
		defineParser: function(pattern){
			Date.parsePatterns.push( pattern.re && pattern.handler ? pattern : build(pattern) );
		},
		
		defineParsers: function(){
			Array.flatten(arguments).each(Date.defineParser);
		},
		
		define2DigitYearStart: function(year){
			yr_start = year % 100;
			yr_base = year - yr_start;
		}

	});

	var yr_base = 1900;
	var yr_start = 70;

	var replacers = function(key){
		switch(key){
			case 'x': // iso8601 covers yyyy-mm-dd, so just check if month is first
				return (Date.orderIndex('month') == 1) ? '%m[.-/]%d([.-/]%y)?' : '%d[.-/]%m([.-/]%y)?';
			case 'X':
				return '%H([.:]%M)?([.:]%S([.:]%s)?)?\\s?%p?\\s?%T?';
			case 'o':
				return '[^\\d\\s]*';
		}
		return null;
	};

	var keys = {
		a: /[a-z]{3,}/,
		d: /[0-2]?[0-9]|3[01]/,
		H: /[01]?[0-9]|2[0-3]/,
		I: /0?[1-9]|1[0-2]/,
		M: /[0-5]?\d/,
		s: /\d+/,
		p: /[ap]\.?m\.?/,
		y: /\d{2}|\d{4}/,
		Y: /\d{4}/,
		T: /Z|[+-]\d{2}(?::?\d{2})?/
	};

	keys.B = keys.b = keys.A = keys.a;
	keys.m = keys.I;
	keys.S = keys.M;

	var lang;

	var build = function(format){
		if (!lang) return {format: format}; // wait until language is set
		
		var parsed = [null];

		var re = (format.source || format) // allow format to be regex
		 .replace(/%([a-z])/gi,
			function($1, $2){
				return replacers($2) || $1;
			}
		).replace(/\((?!\?)/g, '(?:') // make all groups non-capturing
		 .replace(/ (?!\?|\*)/g, ',? ') // be forgiving with spaces and commas
		 .replace(/%([a-z%])/gi,
			function($1, $2){
				var p = keys[$2];
				if (!p) return $2;
				parsed.push($2);
				return '(' + p.source + ')';
			}
		);

		return {
			format: format,
			re: new RegExp('^' + re + '$', 'i'),
			handler: function(bits){
				var date = new Date().clearTime();
				for (var i = 1; i < parsed.length; i++)
					date = handle.call(date, parsed[i], bits[i]);
				return date;
			}
		};
	};

	var handle = function(key, value){
		if (!value){
			if (key == 'm' || key == 'd') value = 1;
			else return this;
		}

		switch(key){
			case 'a': case 'A': return this.set('day', Date.parseDay(value, true));
			case 'b': case 'B': return this.set('mo', Date.parseMonth(value, true));
			case 'd': return this.set('date', value);
			case 'H': case 'I': return this.set('hr', value);
			case 'm': return this.set('mo', value - 1);
			case 'M': return this.set('min', value);
			case 'p': return this.set('ampm', value.replace(/\./g, ''));
			case 'S': return this.set('sec', value);
			case 's': return this.set('ms', ('0.' + value) * 1000);
			case 'w': return this.set('day', value);
			case 'Y': return this.set('year', value);
			case 'y':
				value = +value;
				if (value < 100) value += yr_base + (value < yr_start ? 100 : 0);
				return this.set('year', value);
			case 'T':
				if (value == 'Z') value = '+00';
				var offset = value.match(/([+-])(\d{2}):?(\d{2})?/);
				offset = (offset[1] + '1') * (offset[2] * 60 + (+offset[3] || 0)) + this.getTimezoneOffset();
				return this.set('time', (this * 1) - offset * 60000);
		}

		return this;
	};

	Date.defineParsers(
		'%Y([-./]%m([-./]%d((T| )%X)?)?)?', // "1999-12-31", "1999-12-31 11:59pm", "1999-12-31 23:59:59", ISO8601
		'%Y%m%d(T%H(%M%S?)?)?', // "19991231", "19991231T1159", compact
		'%x( %X)?', // "12/31", "12.31.99", "12-31-1999", "12/31/2008 11:59 PM"
		'%d%o( %b( %Y)?)?( %X)?', // "31st", "31st December", "31 Dec 1999", "31 Dec 1999 11:59pm"
		'%b %d%o?( %Y)?( %X)?', // Same as above with month and day switched
		'%b %Y' // "December 1999"
	);

	MooTools.lang.addEvent('langChange', function(language){
		if (!MooTools.lang.get('Date')) return;

		lang = language;
		Date.parsePatterns.each(function(pattern, i){
			if (pattern.format) Date.parsePatterns[i] = build(pattern.format);
		});

	}).fireEvent('langChange', MooTools.lang.getCurrentLanguage());

	})();

	/*
	Script: Date.Extras.js
		Extends the Date native object to include extra methods (on top of those in Date.js).

		License:
			MIT-style license.

		Authors:
			Aaron Newton

	*/

	Date.implement({

		timeDiffInWords: function(relative_to){
			return Date.distanceOfTimeInWords(this, relative_to || new Date);
		}

	});

	Date.alias('timeDiffInWords', 'timeAgoInWords');

	Date.extend({

		distanceOfTimeInWords: function(from, to){
			return Date.getTimePhrase(((to - from) / 1000).toInt());
		},

		getTimePhrase: function(delta){
			var suffix = (delta < 0) ? 'Until' : 'Ago';
			if (delta < 0) delta *= -1;
			
			var msg = (delta < 60) ? 'lessThanMinute' :
					  (delta < 120) ? 'minute' :
					  (delta < (45 * 60)) ? 'minutes' :
					  (delta < (90 * 60)) ? 'hour' :
					  (delta < (24 * 60 * 60)) ? 'hours' :
					  (delta < (48 * 60 * 60)) ? 'day' :
					  'days';
			
			switch(msg){
				case 'minutes': delta = (delta / 60).round(); break;
				case 'hours':   delta = (delta / 3600).round(); break;
				case 'days': 	delta = (delta / 86400).round();
			}
			
			return Date.getMsg(msg + suffix, delta).substitute({delta: delta});
		}

	});


	Date.defineParsers(

		{
			// "today", "tomorrow", "yesterday"
			re: /^tod|tom|yes/i,
			handler: function(bits){
				var d = new Date().clearTime();
				switch(bits[0]){
					case 'tom': return d.increment();
					case 'yes': return d.decrement();
					default: 	return d;
				}
			}
		},

		{
			// "next Wednesday", "last Thursday"
			re: /^(next|last) ([a-z]+)$/i,
			handler: function(bits){
				var d = new Date().clearTime();
				var day = d.getDay();
				var newDay = Date.parseDay(bits[2], true);
				var addDays = newDay - day;
				if (newDay <= day) addDays += 7;
				if (bits[1] == 'last') addDays -= 7;
				return d.set('date', d.getDate() + addDays);
			}
		}

	);


	/*
	Script: Date.English.US.js
		Date messages for US English.

		License:
			MIT-style license.

		Authors:
			Aaron Newton

	*/

	MooTools.lang.set('en-US', 'Date', {

		months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
		days: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
		//culture's date order: MM/DD/YYYY
		dateOrder: ['month', 'date', 'year'],
		shortDate: '%m/%d/%Y',
		shortTime: '%I:%M%p',
		AM: 'AM',
		PM: 'PM',

		/* Date.Extras */
		ordinal: function(dayOfMonth){
			//1st, 2nd, 3rd, etc.
			return (dayOfMonth > 3 && dayOfMonth < 21) ? 'th' : ['th', 'st', 'nd', 'rd', 'th'][Math.min(dayOfMonth % 10, 4)];
		},

		lessThanMinuteAgo: 'less than a minute ago',
		minuteAgo: 'about a minute ago',
		minutesAgo: '{delta} minutes ago',
		hourAgo: 'about an hour ago',
		hoursAgo: 'about {delta} hours ago',
		dayAgo: '1 day ago',
		daysAgo: '{delta} days ago',
		lessThanMinuteUntil: 'less than a minute from now',
		minuteUntil: 'about a minute from now',
		minutesUntil: '{delta} minutes from now',
		hourUntil: 'about an hour from now',
		hoursUntil: 'about {delta} hours from now',
		dayUntil: '1 day from now',
		daysUntil: '{delta} days from now'

	});	
	
	/*
	Script: Request.JSONP.js
		Defines Request.JSONP, a class for cross domain javascript via script injection.

		License:
			MIT-style license.

		Authors:
			Aaron Newton
			Guillermo Rauch
	*/

	Request.JSONP = new Class({

		Implements: [Chain, Events, Options, Log],

		options: {/*
			onRetry: $empty(intRetries),
			onRequest: $empty(scriptElement),
			onComplete: $empty(data),
			onSuccess: $empty(data),
			onCancel: $empty(),*/
			url: '',
			data: {},
			retries: 0,
			timeout: 0,
			link: 'ignore',
			callbackKey: 'callback',
			injectScript: document.head
		},

		initialize: function(options){
			this.setOptions(options);
			this.running = false;$
			this.requests = 0;
			this.triesRemaining = [];
		},

		check: function(){
			if (!this.running) return true;
			switch (this.options.link){
				case 'cancel': this.cancel(); return true;
				case 'chain': this.chain(this.caller.bind(this, arguments)); return false;
			}
			return false;
		},

		send: function(options){
			if (!$chk(arguments[1]) && !this.check(options)) return this;

			var type = $type(options), old = this.options, index = $chk(arguments[1]) ? arguments[1] : this.requests++;
			if (type == 'string' || type == 'element') options = {data: options};

			options = $extend({data: old.data, url: old.url}, options);

			if (!$chk(this.triesRemaining[index])) this.triesRemaining[index] = this.options.retries;
			var remaining = this.triesRemaining[index];

			(function(){
				var script = this.getScript(options);
				this.log('JSONP retrieving script with url: ' + script.get('src'));
				this.fireEvent('request', script);
				this.running = true;

				(function(){
					if (remaining){
						this.triesRemaining[index] = remaining - 1;
						if (script){
							script.destroy();
							this.send(options, index);
							this.fireEvent('retry', this.triesRemaining[index]);
						}
					} else if(script && this.options.timeout){
						script.destroy();
						this.cancel();
						this.fireEvent('failure');
					}
				}).delay(this.options.timeout, this);
			}).delay(Browser.Engine.trident ? 50 : 0, this);
			return this;
		},

		cancel: function(){
			if (!this.running) return this;
			this.running = false;
			this.fireEvent('cancel');
			return this;
		},

		getScript: function(options){
			var index = Request.JSONP.counter, data;
			Request.JSONP.counter++;

			switch ($type(options.data)){
				case 'element': data = document.id(options.data).toQueryString(); break;
				case 'object': case 'hash': data = Hash.toQueryString(options.data);
			}

			var src = options.url + 
				 (options.url.test('\\?') ? '&' :'?') + 
				 (options.callbackKey || this.options.callbackKey) + 
				 '=Request.JSONP.request_map.request_'+ index + 
				 (data ? '&' + data : '');
			if (src.length > 2083) this.log('JSONP '+ src +' will fail in Internet Explorer, which enforces a 2083 bytes length limit on URIs');

			var script = new Element('script', {type: 'text/javascript', src: src});
			Request.JSONP.request_map['request_' + index] = function(data){ this.success(data, script); }.bind(this);
			return script.inject(this.options.injectScript);
		},

		success: function(data, script){
			if (script) script.destroy();
			this.running = false;
			this.log('JSONP successfully retrieved: ', data);
			this.fireEvent('complete', [data]).fireEvent('success', [data]).callChain();
		}

	});

	Request.JSONP.counter = 0;
	Request.JSONP.request_map = {};var JsonP = Class.refactor(Request.JSONP, {
		initialize: function() {
			var params = Array.link(arguments, {url: String.type, options: Object.type});
			options = (params.options || {});
			options.url = options.url || params.url;
			if (options.callBackKey) options.callbackKey = options.callBackKey;
			this.previous(options);
		},
		getScript: function(options) {
			var queryString = options.queryString || this.options.queryString;
			if(options.url && queryString) options.url += (options.url.indexOf("?") >= 0 ? "&" : "?") + queryString;
			var script = this.previous(options);
			if ($chk(options.globalFunction)) {
				window[options.globalFunction] = function(r){
					JsonP.requestors[index].handleResults(r)
				};
			}
			return script;
		},
		request: function(url) {
			this.send({url: url||this.options.url});
		}
	});
	
	
	/**
	 * SqueezeBox - Expandable Lightbox
	 *
	 * Allows to open various content as modal,
	 * centered and animated box.
	 *
	 * Dependencies: MooTools 1.2
	 *
	 * Inspired by
	 *  ... Lokesh Dhakar	- The original Lightbox v2
	 *
	 * @version		1.1 rc4
	 *
	 * @license		MIT-style license
	 * @author		Harald Kirschner <mail [at] digitarald.de>
	 * @copyright	Author
	 */

	var SqueezeBox = {

		presets: {
			onOpen: $empty,
			onClose: $empty,
			onUpdate: $empty,
			onResize: $empty,
			onMove: $empty,
			onShow: $empty,
			onHide: $empty,
			size: {x: 600, y: 450},
			sizeLoading: {x: 200, y: 150},
			marginInner: {x: 20, y: 20},
			marginImage: {x: 50, y: 75},
			handler: false,
			target: null,
			closable: true,
			closeBtn: true,
			zIndex: 65555,
			overlayOpacity: 0.7,
			classWindow: '',
			classOverlay: '',
			overlayFx: {},
			resizeFx: {},
			contentFx: {},
			parse: false, // 'rel'
			parseSecure: false,
			shadow: true,
			document: null,
			ajaxOptions: {}
		},

		initialize: function(presets) {
			if (this.options) return this;

			this.presets = $merge(this.presets, presets);
			this.doc = this.presets.document || document;
			this.options = {};
			this.setOptions(this.presets).build();
			this.bound = {
				window: this.reposition.bind(this, [null]),
				scroll: this.checkTarget.bind(this),
				close: this.close.bind(this),
				key: this.onKey.bind(this)
			};
			this.isOpen = this.isLoading = false;
			return this;
		},

		build: function() {
			this.overlay = new Element('div', {
				id: 'sbox-overlay',
				styles: {display: 'none', zIndex: this.options.zIndex}
			});
			this.win = new Element('div', {
				id: 'sbox-window',
				styles: {display: 'none', zIndex: this.options.zIndex + 2}
			});
			if (this.options.shadow) {
				if (Browser.Engine.webkit420) {
					this.win.setStyle('-webkit-box-shadow', '0 0 10px rgba(0, 0, 0, 0.7)');
				} else if (!Browser.Engine.trident4) {
					var shadow = new Element('div', {'class': 'sbox-bg-wrap'}).inject(this.win);
					var relay = function(e) {
						this.overlay.fireEvent('click', [e]);
					}.bind(this);
					['n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw'].each(function(dir) {
						new Element('div', {'class': 'sbox-bg sbox-bg-' + dir}).inject(shadow).addEvent('click', relay);
					});
				}
			}
			this.content = new Element('div', {id: 'sbox-content'}).inject(this.win);
			this.closeBtn = new Element('a', {id: 'sbox-btn-close', href: '#'}).inject(this.win);
			this.fx = {
				overlay: new Fx.Tween(this.overlay, $merge({
					property: 'opacity',
					onStart: Events.prototype.clearChain,
					duration: 250,
					link: 'cancel'
				}, this.options.overlayFx)).set(0),
				win: new Fx.Morph(this.win, $merge({
					onStart: Events.prototype.clearChain,
					unit: 'px',
					duration: 750,
					transition: Fx.Transitions.Quint.easeOut,
					link: 'cancel',
					unit: 'px'
				}, this.options.resizeFx)),
				content: new Fx.Tween(this.content, $merge({
					property: 'opacity',
					duration: 250,
					link: 'cancel'
				}, this.options.contentFx)).set(0)
			};
			$(this.doc.body).adopt(this.overlay, this.win);
		},

		assign: function(to, options) {
			return ($(to) || $$(to)).addEvent('click', function() {
				return !SqueezeBox.fromElement(this, options);
			});
		},
		
		open: function(subject, options) {
			this.initialize();

			if (this.element != null) this.trash();
			this.element = $(subject) || false;
			
			this.setOptions($merge(this.presets, options || {}));
			
			if (this.element && this.options.parse) {
				var obj = this.element.getProperty(this.options.parse);
				if (obj && (obj = JSON.decode(obj, this.options.parseSecure))) this.setOptions(obj);
			}
			this.url = ((this.element) ? (this.element.get('href')) : subject) || this.options.url || '';

			this.assignOptions();
			
			var handler = handler || this.options.handler;
			if (handler) return this.setContent(handler, this.parsers[handler].call(this, true));
			var ret = false;
			return this.parsers.some(function(parser, key) {
				var content = parser.call(this);
				if (content) {
					ret = this.setContent(key, content);
					return true;
				}
				return false;
			}, this);
		},
		
		fromElement: function(from, options) {
			return this.open(from, options);
		},

		assignOptions: function() {
			this.overlay.set('class', this.options.classOverlay);
			this.win.set('class', this.options.classWindow);
			if (Browser.Engine.trident4) this.win.addClass('sbox-window-ie6');
		},

		close: function(e) {
			var stoppable = ($type(e) == 'event');
			if (stoppable) e.stop();
			if (!this.isOpen || (stoppable && !$lambda(this.options.closable).call(this, e))) return this;
			this.fx.overlay.start(0).chain(this.toggleOverlay.bind(this));
			this.win.setStyle('display', 'none');
			this.fireEvent('onClose', [this.content]);
			this.trash();
			this.toggleListeners();
			this.isOpen = false;
			return this;
		},

		trash: function() {
			this.element = this.asset = null;
			this.content.empty();
			this.options = {};
			this.removeEvents().setOptions(this.presets).callChain();
		},

		onError: function() {
			this.asset = null;
			this.setContent('string', this.options.errorMsg || 'An error occurred');
		},

		setContent: function(handler, content) {
			if (!this.handlers[handler]) return false;
			this.content.className = 'sbox-content-' + handler;
			this.applyTimer = this.applyContent.delay(this.fx.overlay.options.duration, this, this.handlers[handler].call(this, content));
			if (this.overlay.retrieve('opacity')) return this;
			this.toggleOverlay(true);
			this.fx.overlay.start(this.options.overlayOpacity);
			return this.reposition();
		},

		applyContent: function(content, size) {
			if (!this.isOpen && !this.applyTimer) return;
			this.applyTimer = $clear(this.applyTimer);
			this.hideContent();
			if (!content) {
				this.toggleLoading(true);
			} else {
				if (this.isLoading) this.toggleLoading(false);
				this.fireEvent('onUpdate', [this.content], 20);
			}
			if (content) {
				if (['string', 'array'].contains($type(content))) this.content.set('html', content);
				else if (!this.content.hasChild(content)) this.content.adopt(content);
			}
			this.callChain();
			if (!this.isOpen) {
				this.toggleListeners(true);
				this.resize(size, true);
				this.isOpen = true;
				this.fireEvent('onOpen', [this.content]);
			} else {
				this.resize(size);
			}
		},

		resize: function(size, instantly) {
			this.showTimer = $clear(this.showTimer || null);
			var box = this.doc.getSize(), scroll = this.doc.getScroll();
			this.size = $merge((this.isLoading) ? this.options.sizeLoading : this.options.size, size);
			var to = {
				width: this.size.x,
				height: this.size.y,
				left: (scroll.x + (box.x - this.size.x - this.options.marginInner.x) / 2).toInt(),
				top: (scroll.y + (box.y - this.size.y - this.options.marginInner.y) / 2).toInt()
			};
			this.hideContent();
			if (!instantly) {
				this.fx.win.start(to).chain(this.showContent.bind(this));
			} else {
				this.win.setStyles(to).setStyle('display', '');
				this.showTimer = this.showContent.delay(50, this);
			}
			return this.reposition();
		},

		toggleListeners: function(state) {
			var fn = (state) ? 'addEvent' : 'removeEvent';
			this.closeBtn[fn]('click', this.bound.close);
			this.overlay[fn]('click', this.bound.close);
			this.doc[fn]('keydown', this.bound.key)[fn]('mousewheel', this.bound.scroll);
			this.doc.getWindow()[fn]('resize', this.bound.window)[fn]('scroll', this.bound.window);
		},

		toggleLoading: function(state) {
			this.isLoading = state;
			this.win[(state) ? 'addClass' : 'removeClass']('sbox-loading');
			if (state) this.fireEvent('onLoading', [this.win]);
		},

		toggleOverlay: function(state) {
			var full = this.doc.getSize().x;
			this.overlay.setStyle('display', (state) ? '' : 'none');
			
			if (!Browser.Engine.webkit) {
				this.doc.body[(state) ? 'addClass' : 'removeClass']('body-overlayed');
				if (state) {
					this.scrollOffset = this.doc.getWindow().getSize().x - full;
					this.doc.body.setStyle('margin-right', this.scrollOffset);
				} else {
					this.doc.body.setStyle('margin-right', '');
				}
			}	
		},

		showContent: function() {
			if (this.content.get('opacity')) this.fireEvent('onShow', [this.win]);
			this.fx.content.start(1);
		},

		hideContent: function() {
			if (!this.content.get('opacity')) this.fireEvent('onHide', [this.win]);
			this.fx.content.cancel().set(0);
		},

		onKey: function(e) {
			switch (e.key) {
				case 'esc': this.close(e);
				case 'up': case 'down': return false;
			}
		},

		checkTarget: function(e) {
			return this.content.hasChild(e.target);
		},

		reposition: function() {
			var size = this.doc.getSize(), scroll = this.doc.getScroll(), ssize = this.doc.getScrollSize();
			this.overlay.setStyles({
				width: ssize.x + 'px',
				height: ssize.y + 'px'
			});
			this.win.setStyles({
				left: (scroll.x + (size.x - this.win.offsetWidth) / 2 - this.scrollOffset).toInt() + 'px',
				top: (scroll.y + (size.y - this.win.offsetHeight) / 2).toInt() + 'px'
			});
			return this.fireEvent('onMove', [this.overlay, this.win]);
		},

		removeEvents: function(type){
			if (!this.$events) return this;
			if (!type) this.$events = null;
			else if (this.$events[type]) this.$events[type] = null;
			return this;
		},

		extend: function(properties) {
			return $extend(this, properties);
		},

		handlers: new Hash(),

		parsers: new Hash()

	};

	SqueezeBox.extend(new Events($empty)).extend(new Options($empty)).extend(new Chain($empty));

	SqueezeBox.parsers.extend({

		image: function(preset) {
			return (preset || (/\.(?:jpg|png|gif)$/i).test(this.url)) ? this.url : false;
		},

		clone: function(preset) {
			if ($(this.options.target)) return $(this.options.target);
			if (this.element && !this.element.parentNode) return this.element;
			var bits = this.url.match(/#([\w-]+)$/);
			return (bits) ? $(bits[1]) : (preset ? this.element : false);
		},

		ajax: function(preset) {
			return (preset || (this.url && !(/^(?:javascript|#)/i).test(this.url))) ? this.url : false;
		},

		iframe: function(preset) {
			return (preset || this.url) ? this.url : false;
		},

		string: function(preset) {
			return true;
		}
	});

	SqueezeBox.handlers.extend({

		image: function(url) {
			var size, tmp = new Image();
			this.asset = null;
			tmp.onload = tmp.onabort = tmp.onerror = (function() {
				tmp.onload = tmp.onabort = tmp.onerror = null;
				if (!tmp.width) {
					this.onError.delay(10, this);
					return;
				}
				var box = this.doc.getSize();
				box.x -= this.options.marginImage.x;
				box.y -= this.options.marginImage.y;
				size = {x: tmp.width, y: tmp.height};
				for (var i = 2; i--;) {
					if (size.x > box.x) {
						size.y *= box.x / size.x;
						size.x = box.x;
					} else if (size.y > box.y) {
						size.x *= box.y / size.y;
						size.y = box.y;
					}
				}
				size.x = size.x.toInt();
				size.y = size.y.toInt();
				this.asset = $(tmp);
				tmp = null;
				this.asset.width = size.x;
				this.asset.height = size.y;
				this.applyContent(this.asset, size);
			}).bind(this);
			tmp.src = url;
			if (tmp && tmp.onload && tmp.complete) tmp.onload();
			return (this.asset) ? [this.asset, size] : null;
		},

		clone: function(el) {
			if (el) return el.clone();
			return this.onError();
		},

		adopt: function(el) {
			if (el) return el;
			return this.onError();
		},

		ajax: function(url) {
			var options = this.options.ajaxOptions || {};
			this.asset = new Request.HTML($merge({
				method: 'get',
				evalScripts: false
			}, this.options.ajaxOptions)).addEvents({
				onSuccess: function(resp) {
					this.applyContent(resp);
					if (options.evalScripts !== null && !options.evalScripts) $exec(this.asset.response.javascript);
					this.fireEvent('onAjax', [resp, this.asset]);
					this.asset = null;
				}.bind(this),
				onFailure: this.onError.bind(this)
			});
			this.asset.send.delay(10, this.asset, [{url: url}]);
		},

		iframe: function(url) {
			this.asset = new Element('iframe', $merge({
				src: url,
				frameBorder: 0,
				width: this.options.size.x,
				height: this.options.size.y
			}, this.options.iframeOptions));
			if (this.options.iframePreload) {
				this.asset.addEvent('load', function() {
					this.applyContent(this.asset.setStyle('display', ''));
				}.bind(this));
				this.asset.setStyle('display', 'none').inject(this.content);
				return false;
			}
			return this.asset;
		},

		string: function(str) {
			return str;
		}

	});

	SqueezeBox.handlers.url = SqueezeBox.handlers.ajax;
	SqueezeBox.parsers.url = SqueezeBox.parsers.ajax;
	SqueezeBox.parsers.adopt = SqueezeBox.parsers.clone;
	
	/*
	* FancyForm 0.95
	* By Vacuous Virtuoso, lipidity.com
	* ---
	* Checkbox and radio input replacement script.
	* Toggles defined class when input is selected.
	*/

	var FancyForm = {
		start: function(elements, options){
			if(FancyForm.initing != undefined) return;
			if($type(elements)!='array') elements = $$('input');
			if(!options) options = [];
			FancyForm.onclasses = ($type(options['onClasses']) == 'object') ? options['onClasses'] : {
				checkbox: 'checked',
				radio: 'selected'
			}
			FancyForm.offclasses = ($type(options['offClasses']) == 'object') ? options['offClasses'] : {
				checkbox: 'unchecked',
				radio: 'unselected'
			}
			if($type(options['extraClasses']) == 'object'){
				FancyForm.extra = options['extraClasses'];
			} else if(options['extraClasses']){
				FancyForm.extra = {
					checkbox: 'f_checkbox',
					radio: 'f_radio',
					on: 'f_on',
					off: 'f_off',
					all: 'fancy'
				}
			} else {
				FancyForm.extra = {};
			}
			FancyForm.onSelect = $pick(options['onSelect'], function(el){});
			FancyForm.onDeselect = $pick(options['onDeselect'], function(el){});
			FancyForm.chks = [];
			FancyForm.add(elements);
			$each($$('form'), function(x) {
				x.addEvent('reset', function(a) {
					window.setTimeout(function(){FancyForm.chks.each(function(x){FancyForm.update(x);x.inputElement.blur()})}, 200);
				});
			});
		},
		add: function(elements){
			if($type(elements) == 'element')
				elements = [elements];
			FancyForm.initing = 1;
			var keeps = [];
			var newChks = elements.filter(function(chk){
				if($type(chk) != 'element' || chk.inputElement || (chk.get('tag') == 'input' && chk.getParent().inputElement))
					return false;
				if(chk.get('tag') == 'input' && (FancyForm.onclasses[chk.getProperty('type')])){
					var el = chk.getParent();
					if(el.getElement('input')==chk){
						el.type = chk.getProperty('type');
						el.inputElement = chk;
						this.push(el);
					} else {
						chk.addEvent('click',function(f){
							if(f.event.stopPropagation) f.event.stopPropagation();
						});
					}
				} else if((chk.inputElement = chk.getElement('input')) && (FancyForm.onclasses[(chk.type = chk.inputElement.getProperty('type'))])){
					return true;
				}
				return false;
			}.bind(keeps));
			newChks = newChks.combine(keeps);
			newChks.each(function(chk){
				var c = chk.inputElement;
				c.setStyle('position', 'absolute');
				c.setStyle('left', '-9999px');
				chk.addEvent('selectStart', function(f){f.stop()});
				chk.name = c.getProperty('name');
				FancyForm.update(chk);
			});
			newChks.each(function(chk){
				var c = chk.inputElement;
				chk.addEvent('click', function(f){
					f.stop(); f.type = 'prop';
					c.fireEvent('click', f, 1);
				});
				chk.addEvent('mousedown', function(f){
					if($type(c.onmousedown) == 'function')
						c.onmousedown();
					f.preventDefault();
				});
				chk.addEvent('mouseup', function(f){
					if($type(c.onmouseup) == 'function')
						c.onmouseup();
				});
				c.addEvent('focus', function(f){
					if(FancyForm.focus)
						chk.setStyle('outline', '1px dotted');
				});
				c.addEvent('blur', function(f){
					chk.setStyle('outline', 0);
				});
				c.addEvent('click', function(f){
					if(f.event.stopPropagation) f.event.stopPropagation();
					if(c.getProperty('disabled')) // c.getStyle('position') != 'absolute'
						return;
					if (!chk.hasClass(FancyForm.onclasses[chk.type]))
						c.setProperty('checked', 'checked');
					else if(chk.type != 'radio')
						c.setProperty('checked', false);
					if(f.type == 'prop')
						FancyForm.focus = 0;
					FancyForm.update(chk);
					FancyForm.focus = 1;
					if(f.type == 'prop' && !FancyForm.initing && $type(c.onclick) == 'function')
						 c.onclick();
				});
				c.addEvent('mouseup', function(f){
					if(f.event.stopPropagation) f.event.stopPropagation();
				});
				c.addEvent('mousedown', function(f){
					if(f.event.stopPropagation) f.event.stopPropagation();
				});
				if(extraclass = FancyForm.extra[chk.type])
					chk.addClass(extraclass);
				if(extraclass = FancyForm.extra['all'])
					chk.addClass(extraclass);
			});
			FancyForm.chks.combine(newChks);
			FancyForm.initing = 0;
		},
		update: function(chk){
			if(chk.inputElement.getProperty('checked')) {
				chk.removeClass(FancyForm.offclasses[chk.type]);
				chk.addClass(FancyForm.onclasses[chk.type]);
				if (chk.type == 'radio'){
					FancyForm.chks.each(function(other){
						if (other.name == chk.name && other != chk) {
							other.inputElement.setProperty('checked', false);
							FancyForm.update(other);
						}
					});
				}
				if(extraclass = FancyForm.extra['on'])
					chk.addClass(extraclass);
				if(extraclass = FancyForm.extra['off'])
					chk.removeClass(extraclass);
				if(!FancyForm.initing)
					FancyForm.onSelect(chk);
			} else {
				chk.removeClass(FancyForm.onclasses[chk.type]);
				chk.addClass(FancyForm.offclasses[chk.type]);
				if(extraclass = FancyForm.extra['off'])
					chk.addClass(extraclass);
				if(extraclass = FancyForm.extra['on'])
					chk.removeClass(extraclass);
				if(!FancyForm.initing)
					FancyForm.onDeselect(chk);
			}
			//if(!FancyForm.initing)
				//chk.inputElement.focus();
		},
		all: function(){
			FancyForm.chks.each(function(chk){
				chk.inputElement.setProperty('checked', 'checked');
				FancyForm.update(chk);
			});
		},
		none: function(){
			FancyForm.chks.each(function(chk){
				chk.inputElement.setProperty('checked', false);
				FancyForm.update(chk);
			});
		}
	};
	
	
	/**
	 * HistoryManager
	 * 
	 * Observes back/forward button usage and saves states
	 * for registered modules into the hash. This allows to
	 * bookmark specific states for an application.
	 * 
	 * @version		1.0rc2
	 * 
	 * @see			Events, Options
	 * 
	 * @license		MIT License
	 * @author		Harald Kirschner <mail [at] digitarald.de>
	 * @modify		Alfredo Artiles (www.flash-free.org) Fix to make it work with mootools1.2
	 * @copyright	2007 Author
	 */
	var HistoryManagerFactory = new Class({
		Implements: [Events, Options],
		/**
		 * Default options - Can be overridden with setOptions
		 * 
		 * observeDelay: Duration for checking the state, default 100ms
		 * stateSeparator: Seperator for module-state join, default ';'
		 * iframeSrc: Scr for IE6/7 iframe, must exist on server!
		 * onStart: Fires on start
		 * onRegister: Fires on register
		 * onUnregister: Fires on unregister
		 * onUpdate: Fires when state changes from ...
		 * onStateChange: ... module changes
		 * onObserverChange: ... history change
		 */
		options: {
			observeDelay: 100,
			stateSeparator: ';',
			iframeSrc: 'blank.html',
			onStart: $empty,
			onRegister: $empty,
			onUnregister: $empty,
			onStart: $empty,
			onUpdate: $empty,
			onStateChange: $empty,
			onObserverChange: $empty
		},

		/**
		 * Default options for register
		 * 
		 * defaults: Default values array, initially empty.
		 * regexpParams: When regexp is a String, this is the second argument for new RegExp.
		 * skipDefaultMatch: default true; When true onGenerate is not called when current values are similar to the default values.
		 */
		dataOptions: {
			skipDefaultMatch: true,
			defaults: [],
			regexpParams: ''
		},

		/**
		 * Constructur - Class.initialize
		 * 
		 * Options:
		 *  - observeDelay: duration in ms, default 100 - BackBuddy observe the hash for changes periodical
		 *  - stateSeparator: char, default ';' - Separator for multiple module-states in the hash
		 *  - iframeSrc: string, default 'blank.html' - File for the iframe (IE6/7), must exist on the server!
		 *  - Events: onStart, onRegister, onStart, onUpdate, onStateChange, onObserverChange
		 * 
		 * @return	this
		 * 
		 * @param	{Object} options
		 */
		initialize: function(options) {
			if (this.modules) return this;
			this.setOptions(options);
			this.modules = $H({});
			this.count = history.length;
			this.states = [];
			this.states[this.count] = this.getHash();
			this.state = null;
			return this;
		},

		/**
		 * Start - Check hash and start observer
		 * 
		 * Call start after registering ALL modules. This start the observer,
		 * reads the state from the hash and calls onMatch for effected modules.
		 * 
		 * @return	this
		 * 
		 */
		start: function() {
			this.observe.periodical(this.options.observeDelay, this);
			this.started = true;
			this.observe();
			this.update();
			this.fireEvent('onStart', [this.state]);
			return this;
		},

		/**
		 * Registers a module
		 * 
		 * @return	{Object} Object with shortcuts for setValues, setValue, generate and unregister
		 * 
		 * @param	{String} Module key
		 * @param	{RegExp}/{String} Regular expression that matches the string updated from onGenerate
		 * @param	{Function} Will be called when the regexp matches, with the new values as argument.
		 * @param	{Function} Should return the string for the state string, values are first argument
		 * @param	{Array} default values, the input values given to onMatch and onGenerate will be complemented with these
		 * @param	{Object} (optional) options
		 */
		register: function(key, defaults, onMatch, onGenerate, regexp, options) {
			if (!this.modules) this.initialize();
			var data = $merge(this.dataOptions, options || {}, {
				defaults: defaults,
				onMatch: onMatch,
				onGenerate: onGenerate,
				regexp: regexp
			});
			data.regexp = data.regexp || key + '-([\\w_-]*)';
			if (typeof data.regexp == 'string') data.regexp = new RegExp(data.regexp, data.regexpParams);
			data.onGenerate = data.onGenerate || function(values) { return key + '-' + values[0]; };

			data.values = $A(data.defaults);
			this.modules.set(key, data);
			this.fireEvent('onUnregister', [key, data]);
			return {
				setValues: function(values) {
					return this.setValues(key, values);
				}.bind(this),
				setValue: function(index, value) {
					return this.setValue(key, index, value);
				}.bind(this),
				generate: function(values) {
					return this.generate(key, values);
				}.bind(this),
				unregister: function() {
					return this.unregister(key);
				}.bind(this)
			};
		},

		/**
		 * unregister - Removes an module from the
		 * 
		 * @param	{String} Module key
		 */
		unregister: function(key) {
			this.fireEvent('onRegister', [key]);
			this.modules.remove(key);
		},

		/**
		 * setValues - Set all values new, updates new state
		 * 
		 * @param	{String} Module key
		 * @param	{Object} Complete values
		 */
		setValues: function(key, values) {
			var data = this.modules.get(key);
			if (!data || data.values.isSimilar(values)) return this;
			data.values = values;
			this.update();
			return this;
		},

		/**
		 * setValue - Set one value, updates new state
		 * 
		 * @param	{String} Module key
		 * @param	{Number} Value index
		 * @param	{Object} Value
		 */
		setValue: function(key, index, value) {
			var data = this.modules.get(key);
			if (!data || data.values[index] == value) return this;
			data.values[index] = value;
			this.update();
			return this;
		},

		/**
		 * generate - Generates a hash from the given
		 * 
		 * @param	{String} Module key
		 * @param	{Number} Value index
		 * @param	{Object} Value
		 */
		generate: function(key, values) {
			var data = this.modules.get(key);
			var current = $A(data.values);
			data.values = values;
			var state = this.generateState();
			data.values = current;
			return '#' + state;
		},

		observe: function() {
			if (this.timeout) return;
			var state = this.getState();
			if (this.state == state) return;
			//if ((Browser.Engine.trident || Browser.Engine.webkit) && (this.state !== null)) this.setState(state, true);
			if (((Browser.Engine.trident &&(!document.querySelectorAll))) && (this.state !== null)) this.setState(state, true);
			else this.state = state;
			this.modules.each(function(data, key) {
				var bits = state.match(data.regexp);
				if (bits) {
					bits.splice(0, 1);
					bits.complement(data.defaults);
					if (!bits.isSimilar(data.defaults)) data.values = bits;
				} else data.values = $A(data.defaults);
				data.onMatch(data.values, data.defaults);
			});
			this.fireEvent('onStateChange', [state]).fireEvent('onObserverChange', [state]);
		},

		generateState: function() {
			var state = [];
			this.modules.each(function(data, key) {
				if (data.skipDefaultMatch && data.values.isSimilar(data.defaults)) return;
				state.push(data.onGenerate(data.values));
			});
			return state.join(this.options.stateSeparator);
		},

		update: function() {
			if (!this.started) return this;
			var state = this.generateState();
			if ((!this.state && !state) || (this.state == state)) return this;
			this.setState(state);
			this.fireEvent('onStateChange', [state]).fireEvent('onUpdate', [state]);
			return this;
		},

		observeTimeout: function() {
			if (this.timeout) this.timeout = $clear(this.timeout);
			else this.timeout = this.observeTimeout.delay(200, this);
		},

		getHash: function() {
			var href = unescape(top.location.href);
			var pos = href.indexOf('#') + 1;
			return (pos) ? href.substr(pos) : '';
		},

		getState: function() {
			var state = this.getHash();
			if (this.iframe) {
				var doc = this.iframe.contentWindow.document;
				if (doc && doc.body.id == 'state') {
					var istate = doc.body.innerText;
					if (this.state == state) return istate;
					this.istateOld = true;
				} else return this.istate;
			}
			/*
			if (Browser.Engine.webkit && history.length != this.count) {
				this.count = history.length;
				return $pick(this.states[this.count - 1], state);
			}
			*/
			return state;
		},

		setState: function(state, fix) {
			state = $pick(state, '');
			
			/*
			if (Browser.Engine.webkit) {
				if (!this.form) this.form = new Element('form', {method: 'get'}).inject($(document.body));
				this.count = history.length;
				this.states[this.count] = state;
				this.observeTimeout();
				this.form.setProperty('action', '#' + state).submit();
			} else */ top.location.hash = state || '#';
			
			if (Browser.Engine.trident && (!fix || this.istateOld)) {
				if (!this.iframe) {
					this.iframe = new Element('iframe', {
						'src': this.options.iframeSrc,
						'styles': 'display:none;width:1px;height:1px;',
						'width': '1px',
						'height': '1px'
					}).inject($(document.body));
					this.istate = this.state;
				}
				try {
					var doc = this.iframe.contentWindow.document;
					doc.open();
					doc.write('<html><body id="state">' + state + '</body></html>');
					doc.close();
					this.istateOld = false;
				} catch(e) {};
			}
			this.state = state;
		}
	});



	/**
	 * Extends Array with 2 helpers: isSimilar(array) and complement(array)
	 * 
	 */
	Array.implement({

		/**
		 * isSimilar - Returns true for similar arrays, type-insensitive
		 * 
		 * @example
		 *  [1].isSimilar(['1']) == true
		 *  [1, 2].isSimilar([1, false]) == false
		 *  
		 * @return	{Boolean}
		 * @param	{Object} Array
		 */
		isSimilar: function(array) {
			return (this.toString() == array.toString());
		},

		/**
		 * complement - Fills up empty array values from another array, length is the same
		 * 
		 * @example
		 *  [1, null].complement([3, 4]) == [1, 4]
		 *	[undefined, '1'].complement([2, 3, 4]) == [2, '1']

		 * @return	{Array} this
		 * @param	{Object} Array
		 */
		complement: function(array) {
			for (var i = 0, j = this.length; i < j; i++) this[i] = $pick(this[i], array[i] || null);
			return this;
		}
	});

	var HistoryManager = new HistoryManagerFactory();	
	
	/*
	Script: MainApp.js
		App Logic.

		License:

		Authors:
			Alfredo Artiles
	*/
	
	var MainApp = new Class({
		/* initialize */
		initialize: function(options) {
			this.isContent = location.href.contains('/content');

			if (Browser.Engine.trident && Browser.Engine.version <= 4 ) {
				
				var info = new Element('div', {
					'class': 'ieerror',
					'html': 
						'<h3>You are using Internet Explorer 6. Please upgrade your browser to increase safety and your browsing experience.</h3> <p>Choose one of the following links to download a modern browser: <p>' + 
						'<ul><li><a href="http://www.getfirefox.com" target="_blank"><img width="25" height="24" title="Get Firefox" alt="Get Firefox" src="img/firefox.png" /> Firefox</a></li>' + 
						'<li><a class="safari" href="http://www.apple.com/safari/download/" target="_blank"><img width="25" height="24" title="Get Safari" alt="Get Safari" src="img/safari.png" /> Safari</a></li>' + 
						'<li><a class="opera" href="http://www.opera.com/download/" target="_blank"><img width="25" height="24" title="Get Opera" alt="Get Opera" src="img/opera.png" /> Opera</a></li>' + 
						'<li><a class="internetexplorer" href="http://www.microsoft.com/windows/downloads/ie/getitnow.mspx" target="_blank"><img width="25" height="24" title="Get latest Internet Explorer" alt="Get latest Internet Explorer" src="img/ie.png" /> Internet Explorer</a></li>' + 
						'<li><a class="internetexplorer" href="http://www.google.com/chrome" target="_blank"><img width="25" height="24" title="Get Google Chrome" alt="Get Google Chrome" src="img/chrome.png" /> Google Chrome</a></li></ul>'
				});
				
				SqueezeBox.open(info, {size: {x: 450, y: 230}, handler:'adopt'});		
			} //End of Browser version checking...
		
			FancyForm.start();	
			
			this.adTemplate = 
                	'<div id="resuts_item_left"></div>' + 
                	'<div id="resuts_item_center">' + 
					
						'<div class="resuts_item_check"><label><input type="checkbox" class="checkbox" id="check_{id}" name="check_{id}" /></label></div>' +
						'<div id="avatar"><img src="{profile_image_url}" width="48" height="48" alt="{name}" /></div>' +
						'<a  href="http://twitter.com/{screen_name}"  target="blank"><div id="avatar_mask"></div></a>' +
						'<a id="follow_{id}" href="#"><div id="follow_bt"></div></a>' +
						'<div class="sponsor_item_center">' +
							'<div class="sponsor_name">You should follow <b>{name}</b> (<b>@{screen_name}</b>)</div>' +
							'<div class="sponsor_field"><b>Bio</b>: {description}</div>' +
							'<div class="sponsor_field"><b>Location</b>: {location}</div>' +
							'<div class="become_promoted">Become a <a href="http://www.followfriday.com/promotedtweeps" target="blank">Promoted Tweep</a> Today</div>' +
						'</div>' +
						
					'</div>' + 
                	'<div id="resuts_item_right"></div>';
						
					
			this.userTemplate = 
                	'<div id="resuts_item_left"></div>' + 
                	'<div id="resuts_item_center">' + 
						'<div class="resuts_item_check"><label><input type="checkbox" class="checkbox" id="check_{id}" name="check_{id}" /></label></div>' + 
						'<div id="avatar"><img src="{profile_image_url}" width="48" height="48" alt="{name}" /></div>' + 
						'<a  href="http://twitter.com/{screen_name}"  target="blank"><div id="avatar_mask"></div></a>' + 
						'<a id="follow_{id}" href="#"><div id="follow_bt"></div></a>' + 
                    	'<div id="resuts_item_center1">' + 
								'<div id="name_box">' + 
									'<div id="name_box_left"></div>' + 
									'<div id="name_box_center"><a href="http://twitter.com/{screen_name}" target="blank">{name} ({screen_name})</a></div>' + 
									'<div id="name_box_right"></div>' + 
								'</div>' + 
                            '<div class="{protected}"></div>' + 
                            '<span><b>Location:</b> {location}</span>' + 
                            '<span class="space"><b>Web:</b> <a href="{url}" target="blank">{url}</a></span>' + 
                            '<div id="text_box">' + 
                                '<p>{status_text}</p>' + 
                                '<span>{status_created_at}</span>' + 
                            '</div>' + 
                        '</div>' + 
                        '<div id="resuts_item_center2">' + 
						
                        	'<div id="rankbtn_{id}" class="my_rank"></div>' +
                            '<div id="rankwin_{id}" class="rank_window">' +
                            '        <div>' +
                            '                <textarea id="ranktxt_{id}" class="rank_window_textarea" cols="11" rows="4"></textarea>' +
                            '        </div>' +
                            '        <a id="ranksend_{id}" href="#"><div class="rank_window_send_bt"></div></a>' +
                            '</div>' +
						
                    		'<div><b class="member">Member Since:</b> {created_at}</div><br />' + 
                            '<b class="result_field">Bio: </b> ' + 
                            '<span class="bio"> {description}</span>' + 
							
							'<div id="number_box">' + 
									 	'<div id="number_box_left"></div>' + 
                            	'<div id="number_box_center"><div class="number">{friends_count}</div><span>Following</span></div>' + 
                            	'<div id="number_box_right"></div>' + 
                            '</div>' + 
							
                            '<div id="number_box">' + 
									 	'<div id="number_box_left"></div>' + 
                            	'<div id="number_box_center"><div class="number">{followers_count}</div><span>Followers</span></div>' + 
                            	'<div id="number_box_right"></div>' + 
                            '</div>' + 
									 
									 
							'<div id="number_box">' + 
									 	'<div id="number_box_left"></div>' + 
                            	'<div id="number_box_center"><div class="number">{statuses_count}</div><span>Tweets</span></div>' + 
                            	'<div id="number_box_right"></div>' + 
                            '</div>' + 
                        '</div>' + 
                    '</div>' + 
                	'<div id="resuts_item_right"></div>';
				
			this.frameTemplate = 
                	'<div id="resuts_item_left"></div>' + 
                	'<div id="resuts_item_center">' + 
					'{text}' +
                    '</div>' + 
                	'<div id="resuts_item_right"></div>';
				
			this.errorTemplate = 
                	'<div id="resuts_item_left"></div>' + 
                	'<div id="resuts_item_center">' + 
						'<div class="resuts_item_check"><label><input type="checkbox" class="checkbox"  id="check_{id}" name="check_{id}" /></label></div>' + 					
						'<div class="load_error">' +
							'<h3>{text}</h3>' +
							
							'<div id="name_box">' + 
								'<div id="name_box_left"></div>' + 
								'<div id="name_box_center"><a href="{url}" target="blank">{title}</a></div>' + 
								'<div id="name_box_right"></div>' + 
							'</div>' + 
							'<a id="follow_{id}" href="#"><div id="follow_bt2"></div></a>' + 
							
							'<p>{content}</p>' +
							'<p><a href="{url}" target="blank">{url}</a></p>' +
						'</div>' + 
                    '</div>' + 
                	'<div id="resuts_item_right"></div>';
				
			this.tweetTemplate = 
					'<div class="blue_module_avatar"><img src="{profile_image_url}" width="48" height="48" alt="{from_user}" /></div>' + 
					'<div class="blue_module_avatar_mask"></div>' + 
						'<div class="blue_module_name_box">' + 
						'<div class="blue_module_name_box_left"></div>' + 
							'<div class="blue_module_name_box_center"><a  href="http://twitter.com/{from_user}"  target="blank">{from_user}</a></div>' + 
							'<div class="blue_module_name_box_right"></div>' + 
						'</div>' + 
						'<div class="blue_module_tex">' + 
						'<p>{text}</p>' + 
						'<span>{created_at}</span>' + 
					'</div>' + 
					'<div class="blue_module_diana_check"><label><input type="checkbox" class="checkbox" rel="{from_user}" id="check_{id}" name="check_{id}" /></label></div>' + 
					'<div class="separator"></div>';
			
			this.pageSize = 10;
			this.currentPage = 1;			
			this.bioValue = '';
			this.locationValue = '';
			this.nameValue = '';
			this.keywordsValue = '';
			this.loading = false;
			this.users = [];
			this.followStack = [];
			this.following = false;
			this.listStack = [];
			this.listing = false;
			this.minutes = 0;
			this.domain = 'locafollow.com';
			this.loadedItems = 0;
			this.loadedItemsOk = 0;
			this.shortURL = '';
			this.screenName = '';
			
			this.screenNameEl = $('screenname');
			if (this.screenNameEl) {
				this.screenName = this.screenNameEl.get('html');
			}
			
			this.feedbackEl = $('feedback');
			this.bioEl = $('bio');
			this.locationEl = $('location');
			this.nameEl = $('name');
			this.keywordsEl = $('keywords');
			this.searchEl = $('search_bt');		
			this.searchformEl = $('search_form');		
			this.loadingEl = $('loading');		
			this.usersEl = $('users');		
			this.apicallsEl = $('apicalls');		
			this.pagination1El = $('pagination1');		
			this.pagination2El = $('pagination2');		
			this.total1El = $('total1');		
			this.total2El = $('total2');		
			this.selectallEl = $('selectall');		
			this.checklocafollowEl = $('check_locafollow');		
			this.sizesayhelloEl = $('size_sayhello');		
			this.checksayhelloEl = $('check_sayhello');		
			this.txtsayhelloEl = $('txt_sayhello');		
			this.bulkFollowEl = $('bulk_follow_bt');		
			this.createListEl = $('create_list_bt');		
			this.shareResultsEl = $('share_results_bt');		
			this.toppanelEl = $('left_top');		
			this.rightpanelEl = $('right_column');		
			this.txtcontentEl = $('txtcontent');		
			this.contentlistEl = $('contentlist');		
			
			this.tweetsWrapperEl = $('blue_module');		
			this.tweetsEl = $('localtweets');		
			this.tweetsLoadingEl = $('tweet_loading');		
			
			if (this.isContent) {
				//this.rightpanelEl.setStyle('display', 'block');			
			}
			else {
				this.getAPIRate.delay(10000, this);
				this.getAPIRate.periodical(60000, this);
			}

			this.searchEl.addEvent('click', function(e) { 
				e.stop(); 
				
				this.historyManager.setValues(['twitters', this.bioEl.get('value'), this.locationEl.get('value'), this.nameEl.get('value'), this.keywordsEl.get('value')]);		
				this.currentPage = 1;
				this.doSearch(); 
				return false; 
			}.bind(this));

			if (this.txtsayhelloEl) {
				this.txtsayhelloEl.addEvents({
					'keypress': this.sayHelloChange.bind(this),
					'focus': this.sayHelloChange.bind(this),
					'blur': this.sayHelloChange.bind(this)
				});
				this.sayHelloChange();
			}	

			this.feedbackEl.addEvents({
				'mouseover': function() {
					this.feedbackEl.setStyle('background-color', '#577C0B');
				}.bind(this),
				
				'mouseleave': function() {
					this.feedbackEl.setStyle('background-color', '#083B69');
				}.bind(this)
			});
			
			this.bulkFollowEl.addEvent('click', this.doBulkFollow.bind(this));
			this.createListEl.addEvent('click', this.promtCreateList.bind(this));
			this.shareResultsEl.addEvent('click', this.doShareResults.bind(this));

			this.selectallEl.setProperty('checked', '');
			FancyForm.update(this.selectallEl.getParent());
			if (this.txtsayhelloEl) {
				this.checksayhelloEl.setProperty('checked', '');
				FancyForm.update(this.checksayhelloEl.getParent());
			}	
			this.selectallEl.addEvent('click', function(e) { 
				var select = this.selectallEl.getProperty('checked');
				$$('.resuts_item_check label').each(function(el) {
					el.getFirst().setProperty('checked', select);	
					FancyForm.update(el);
				});
				this.checklocafollowEl.setProperty('checked', select);	
				FancyForm.update(this.checklocafollowEl.getParent());	
			}.bind(this));

			this.webSearch = new google.search.WebSearch();
			this.webSearch.setResultSetSize(google.search.Search.LARGE_RESULTSET);
			this.webSearch.setSearchCompleteCallback(this, this.searchCallback);
			
	
			$$('.contact').each(function(el) {
				el.addEvent('click', function(e) {
					e.stop();
					this.message('Contact us at info(at)locafollow(dot)com');
				}.bind(this));
			}, this);

			$('toplocations').addEvent('click', function(e) {
				e.stop();
				var el = $(e.target);
				if (el) {
					this.searchWrapper('', el.get('html'), '', '');
				}
			}.bind(this));

			$('topkeywords').addEvent('click', function(e) {
				e.stop();
				var el = $(e.target);
				if (el) {
					this.searchWrapper(el.get('html'), '', '', '');
				}
			}.bind(this));

			this.firstload = true;
			this.historykey = '!';			
			this.historyManager = HistoryManager.register( // arguments are (key, defaults, onMatch, onGenerate, regexp, options)
					// the unique key of the registered module
					this.historykey,
					// Array with default values, here index 0 is the current page index
					['home'],
					// onMatch, callback when the state changed
					function(values) {
						switch (values[0]) {
							case 'home':
								if (!this.isContent && this.firstload) {
									var bio = Cookie.read('bio');
									var loc = Cookie.read('loc');
									var name = Cookie.read('name');
									var keywords = Cookie.read('keywords');
									bio = bio=='null'?'':bio;
									loc = bio=='null'?'':loc;
									name = name=='null'?'':name;
									keywords = keywords=='null'?'':keywords;
									
									if (bio || loc || name || keywords) {
										
										var delayCall = function() {
											this.bioEl.set('value', bio);
											this.locationEl.set('value', loc);
											this.nameEl.set('value', name);
											this.keywordsEl.set('value', keywords);
											this.historyManager.setValues(['twitters', bio, loc, name, keywords]);		
											this.currentPage = 1;	
											this.doSearch();
										}
										delayCall.delay(2000, this);
										
									}
									else {
										this.getLocation();
									}	
								}	
							break;
							case 'twitters':
								this.bioEl.set('value', values[1]);
								this.locationEl.set('value', values[2]);
								this.nameEl.set('value', values[3]);
								this.keywordsEl.set('value', values[4]);								
								this.currentPage = 1;
								this.doSearch();								
							break;
							default:
								//this.getLocation();
							break;
						}
						this.firstload = false;
					}.bind(this),
					function(values) {
						return this.historykey + values[0] + '/' + values[1] +  '/' + values[2] + '/' + values[3] + '/' + values[4] + '.html';
					}.bind(this),
					this.historykey + '([\\w _-]*)/([\\w _-]*)/([\\w _-]*)/([\\w _-]*)/([\\w _-]*).html',
					{iframeSrc: 'content/blank'}
					
			);
			HistoryManager.start();		
			
			if (!this.isContent) {
				this.getLocalTweets();
			}
			else {
				this.tweetsWrapperEl.setStyle('display', 'none');
			}		
		},

		
		search: function(query) {
			console.log(query);
			var req = new Request.JSONP({
				url: "https://www.googleapis.com/customsearch/v1", 
				timeout: 9000,
				data: {
					'key': 'AIzaSyBaYd0vPKYg5vx4uFKPh1fs7y9fzUqdupM', 
					'cx': '013183835450476972074:dx9o8njy6ee', 
					'q': query,
					'num': this.pageSize,
					'start': (this.currentPage-1) * this.pageSize + 1
				},	
				onComplete: this.searchOk.bind(this), 
				onCancel: this.searchError.bind(this) 
			}).send();
		},
		
		searchError: function() {
			this.loading = false;
			this.loadingEl.setStyle('display', 'none');
			this.toppanelEl.setStyle('display', 'none');

			
			this.usersEl.set('html', this.frameTemplate.substitute({
				'text': '<div class="error">Bad!!... there are no results for your search</div>'
			}));;				

			//this.showSponsor();				
			this.showSponsor2();						
		},
		
		searchOk: function(res) {
			this.total = 0;
		
			if (res) {
				if (res.items && res.items.length > 0) {
					if (res.queries) {
						if (res.queries.request) {
							this.total = res.queries.request[0].totalResults;
						}
					}	
					for (var i = 0; i < res.items.length; i++) {
						var item = res.items[i];
						if (item.link.contains('http://twitter.com') || item.link.contains('https://twitter.com')) {
							var screenName = item.link.replace(/http\:\/\/twitter\.com\//, '');
							screenName = screenName.replace(/https\:\/\/twitter\.com\//, '');
							screenName = screenName.replace(/\//, '');

							var user = {
								screenName: screenName,
								loaded: false,
								show: true,
								seo: this.users.length,
								url: item.link,
								title: item.title,
								content: item.snippet,
								data: undefined
							};
							this.users[this.users.length] = user;
						}	
					}  
					
					this.doShowUsers();
					return;
				}
			}

			if (this.users.length == 0) {
				this.loading = false;
				this.loadingEl.setStyle('display', 'none');
				this.toppanelEl.setStyle('display', 'none');

				
				this.usersEl.set('html', this.frameTemplate.substitute({
					'text': '<div class="error">Bad!!... there are no results for your search</div>'
				}));;				

				//this.showSponsor();				
				this.showSponsor2();				
				
			}
		},
		
		searchCallback: function() {
			if (this.webSearch.results.length > 0) {
				for (var i = 0; i < this.webSearch.results.length; i++) {
					if (this.webSearch.results[i].url.contains('http://twitter.com') || this.webSearch.results[i].url.contains('https://twitter.com')) {
						var screenName = this.webSearch.results[i].url.replace(/http\:\/\/twitter\.com\//, '');
						screenName = screenName.replace(/https\:\/\/twitter\.com\//, '');
					    screenName = screenName.replace(/\//, '');

						var user = {
							screenName: screenName,
							loaded: false,
							show: true,
							seo: this.users.length,
							url: this.webSearch.results[i].url,
							title: this.webSearch.results[i].title,
							content: this.webSearch.results[i].content,
							data: undefined
						};
						this.users[this.users.length] = user;
					}	
				}  
				if (this.webSearch.cursor && this.webSearch.cursor.pages && this.webSearch.cursor.currentPageIndex < this.webSearch.cursor.pages.length - 1) {
					this.webSearch.gotoPage(this.webSearch.cursor.currentPageIndex + 1);
				}	
				else {
					this.doShowUsers();
				}
				
			}
			else if (this.users.length == 0) {
				this.loading = false;
				this.loadingEl.setStyle('display', 'none');
				this.toppanelEl.setStyle('display', 'none');

				
				this.usersEl.set('html', this.frameTemplate.substitute({
					'text': '<div class="error">Bad!!... there are no results for your search</div>'
				}));;				

				//this.showSponsor();				
				this.showSponsor2();				
				
			}
			else {
				this.doShowUsers();
			}	
		},
		
		sayHelloChange: function() {
			var msg = this.txtsayhelloEl.get('value');
			if (msg.length >= 134) {
				msg = msg.substr(0, 134);
				this.txtsayhelloEl.set('value', msg);
			}
			this.sizesayhelloEl.set('html', (msg.length + 6) + '/140');
			
		},
		
		doSearch: function(bio, loc, name, keywords) {
			var bio = this.bioEl.get('value');
			var loc = this.locationEl.get('value');
			var name = this.nameEl.get('value');
			var keywords = this.keywordsEl.get('value');
			
			Cookie.write('bio', bio, {domain: this.domain});
			Cookie.write('loc', loc, {domain: this.domain});
			Cookie.write('name', name, {domain: this.domain});
			Cookie.write('keywords', keywords, {domain: this.domain});
			
			this.bioValue = bio;
			this.locationValue = loc;
			this.nameValue = name;
			this.keywordsValue = keywords;
			//var query = 'site:twitter.com intitle:" on twitter" ';
			var query = 'intitle:" on twitter" ';
			if (this.bioValue) {
				query += ' "bio* * ' + this.bioValue + '" ';
			}
			if (this.locationValue) {
				query +=  ' "location ' + this.locationValue + '"';
			}
			if (this.nameValue) {
				query +=  ' intitle:" ' + this.nameValue + ' "';
			}
			if (this.keywordsValue) {
				query +=  '"' + this.keywordsValue + '"';
			}
			this.reset();
			//console.log(query);
			//this.webSearch.execute(query);	
			this.search(query);
		},

		showSponsor: function() {
			this.sponsorEl = new Element('div', {
				'class': 'resuts_item',
				'html': this.frameTemplate.substitute({
					'text': '<div class="sponsor_content"><iframe width="630" height="100" frameborder="0" scrolling="no" src="http://banner.featuredusers.com/banner?font=arial&textColor=4F4F4F&backgroundColor=f9f9f9&linkColor=006FB9&borderColor=&height=100&width=630&border=false&skipUsername=&source=' + escape(location.href) + '"></iframe></div>'
				})	
			});
			this.usersEl.grab(this.sponsorEl);
		},	
		
		loadSponsor2: function() {
			this.sponsorEl.set('html', this.frameTemplate.substitute({
					'text': '<div class="sponsor_content"><iframe width="630" height="100" frameborder="0" scrolling="no" src="http://banner.featuredusers.com/banner?font=arial&textColor=4F4F4F&backgroundColor=f9f9f9&linkColor=006FB9&borderColor=&height=100&width=630&border=false&skipUsername=&source=' + escape(location.href) + '"></iframe></div>'
			}));
		},	
		
		showSponsor2: function() {
			this.sponsorEl = new Element('div', {
				'class': 'resuts_item',
				'html': this.frameTemplate.substitute({
							'text': '<div class="item_loading"></div>'
						})
			});	
			
			this.usersEl.grab(this.sponsorEl);
			
			//Uncomment to show featuredusers.com ads
			//this.loadSponsor2();
			//return;
			
			var lang = (navigator.language || navigator.systemLanguage || navigator.userLanguage || 'en').substr(0, 2).toLowerCase();
			var country = '';
			if (google.loader.ClientLocation) {
				country = google.loader.ClientLocation.address.country_code;
			}
			
			new Request.JSON({
				url: "/ads", 
				onComplete: this.loadSponsor3.bind(this), 
				onCancel: this.loadSponsor2.bind(this)
			}).get({
				'lang': lang,
				'country': country
			});
		},	
		
		loadSponsor3: function(res) {
			if (res.success && res.users) {
				var data = res.users[0];
				this.sponsorEl.set('html', this.adTemplate.substitute({
					'id': 'ad_' + data['screenname'],
					'name': data.fullname,
					'screen_name': data['screenname'],
					'profile_image_url': data.img,
					'location': data.location,
					//'url': data.url,
					'description': data.bio
					//'followers_count': this.prettyNumber(data.followers),
					//'friends_count': this.prettyNumber(data.following),
					//'statuses_count': this.prettyNumber(data.tweets),
					//'following': user.following?'Yes':'No',
					//'protected': data.protected?'candado_close':'candado_open',
					//'created_at': (new Date(data.membersince * 1000)).timeDiffInWords()
					//'status_text': data.status?this.linkify(data.status.text):emptyText,
					//'status_created_at': data.status?Date.parse(data.status.created_at).timeDiffInWords():''
				}));			
				var checkEl = $('check_' + 'ad_' + data['screenname']);
				checkEl.store('uid', data.uid);
				checkEl.store('sname', data['screenname']);
				checkEl.store('ad', true);
				FancyForm.add(checkEl);			
			
				var followEl = $('follow_' + 'ad_' + data['screenname']);
				followEl.addEvent('click', function(e) { e.stop(); this.doFollow(data['screenname']); }.bind(this));
			}
			else {
				this.loadSponsor2();
			}	
		},	
		
		
		getAPIRate: function() {
			var req = new Request.JSONP({
				url: "http://twitter.com/account/rate_limit_status.json", 
				timeout: 9000,
				onComplete: function(res) {
						var resetTime = new Date(res.reset_time);
						var today = new Date();
						this.minutes = today.diff(resetTime, 'minute');
						this.apicallsEl.set('html', 'API Calls: ' + res.remaining_hits + '/' + res.hourly_limit + ' Reset in: ' + this.minutes + ' mins');
						$$('.minutes').each(function(el) {
							el.set('html', this.minutes);
						}, this);
					if (res) {
					}
				}.bind(this)
			}).send();
		
		},

		getShortURL: function(screenName, pos, txtEl) {
			var by = '';
			if (this.bioValue) {
				if (by) by += ', ';
				by += 'Bio:' + this.bioValue;
			}	
			if (this.locationValue) {
				if (by) by += ', ';
				by += 'Loc:' + this.locationValue;
			}	
			if (this.nameValue) {
				if (by) by += ', ';
				by += 'Name:' + this.nameValue;
			}	
			if (this.keywordsValue) {
				if (by) by += ', ';
				by += 'KeyWords:' + this.keywordsValue;
			}	
			var shareMsg = '@' + screenName + ' is ranked ' + this.cardinalNumber(pos+1) + ' at http://LocaFollow.com by ' + by + ' - ';
			var tmpshareMsg = shareMsg + (this.shortURL?this.shortURL:location.href);				
			if (txtEl) {
				txtEl.set('html', tmpshareMsg);
			}
		
			if (!this.shortURL) {
				var req = new Request.JSONP({
					//url: "http://urlal.com/?u=" + escape(location.href) + "&o=j", 
					url: "http://api.bit.ly/shorten", 
					data: {
						'version':'2.0.1',
						'longUrl': location.href,
						'login': 'aartiles',
						'apiKey':'R_fb455d5e6a4c71a3aecd1553cb9e86ac'
					},
					onComplete: function(res) {
						if (res && res.statusCode == 'OK' && res.errorCode == 0 && res.results && res.results[location.href]) {
							this.shortURL = res.results[location.href].shortUrl;
							if (shareMsg.length + this.shortURL.length <= 140) {
								shareMsg = shareMsg + this.shortURL
							}
							else {
								shareMsg = shareMsg.substr(0, 140 - this.shortURL.length) + this.shortURL;
							}	
							if (txtEl) {
								txtEl.set('html', shareMsg);
							}
						}	
					}.bind(this)
				}).send();
			}	
		},
		
		getLocalizedTweets: function(lat, lon) {			
			var req = new Request.JSONP({
				url: "http://search.twitter.com/search.json", 
				timeout: 9000,
				data: {'rpp': 10, 'show_user': true, 'geocode': lat + ',' + lon + ',25km'}, 
				onComplete: this.loadTweets.bind(this), 
				onCancel: this.loadTweetsError.bind(this) 
			}).send();
		},
		
		loadTweets: function(data) {
			this.tweetsLoadingEl.setStyle('display', 'none');
			if (data && data.results) {
				for (var i = 0; i < data.results.length; i++) {
					var tweetEl = new Element('div', {
							'class': 'blue_module_item_results',
							'html': this.tweetTemplate.substitute({
								'id': i,
								'text': this.linkify(data.results[i].text),
								'profile_image_url': data.results[i].profile_image_url,
								'created_at': Date.parse(data.results[i].created_at).timeDiffInWords(),
								'from_user': data.results[i].from_user
							})	
					});
					this.tweetsEl.grab(tweetEl);
					
					
					var checkEl = $('check_' + i);
					FancyForm.add(checkEl);			
					
				}		
			}
			else {
				this.loadTweetsError();			
			}	
		},
		
		loadTweetsError: function() {
			this.tweetsLoadingEl.setStyle('display', 'none');
			this.tweetsEl.set('html', 'Error loading tweets');
		},
		
		doShowUsers: function() {
			this.loading = false;
			this.loadingEl.setStyle('display', 'none');
			this.toppanelEl.setStyle('display', 'block');
			//this.rightpanelEl.setStyle('display', 'block');
			if (this.txtcontentEl) {
				this.txtcontentEl.setStyle('display', 'none');
			}	
			if (this.contentlistEl) {
				this.contentlistEl.setStyle('display', 'none');
			}	
			this.usersEl.empty();

			this.doPagination();

			//this.showSponsor();
			this.showSponsor2();
			
			var start = (this.currentPage - 1) * this.pageSize;
			this.loadedItems = 0;
			this.loadedItemsOk = 0;
			//for (var i = 0; i < this.users.length; i++) {
			for (var i = 0; i < this.users.length; i++) {
				if (this.users[i].show) {
					var userEl = new Element('div', {
						'id': 'user_' + this.users[i].seo,
						'class': 'resuts_item',
						'html': this.frameTemplate.substitute({
							'text': '<div class="item_loading"></div>'
						})	
					});
											
					this.usersEl.grab(userEl);
				
					if (!this.users[i].loaded) {
						var req = new Request.JSONP({
							url: "http://twitter.com/users/show.json", 
							timeout: 9000,
							data: {'screen_name': this.users[i].screenName}, 
							onComplete: this.loadUser.bindWithEvent(this, i), 
							onCancel: function(currentIndex) { 
								this.loadError(currentIndex);
							}.bind(this, i)
						}).send();
					}
					else {
						this.showUser(this.users[i]);
					}
				}
			}
		},

		loadUser: function(data, currentIndex) {
			if (this.users[currentIndex]) {
				this.users[currentIndex].data = data;
				this.users[currentIndex].loaded = true;
				this.showUser(this.users[currentIndex]);
				
				this.loadedItems++;
				this.loadedItemsOk++;
				if (this.currentPage == 1 && (this.loadedItemsOk == this.pageSize || this.loadedItemsOk == this.users.length)) {
					//this.logSeach();
				}		
			}	
		},
		
		loadError: function(currentIndex) {
			if (this.users[currentIndex]) {
				var userEl = $('user_' + this.users[currentIndex].seo);
				if (userEl) {
					var screenName = this.users[currentIndex].title.replace(/http\:\/\/twitter\.com\//, '');
					screenName = screenName.replace(/https\:\/\/twitter\.com\//, '');
					screenName = screenName.replace(/\//, '');
					
					userEl.set('html', this.errorTemplate.substitute({
						'text': 'Twitter API seems busy or maybe you reached your <a href="http://help.twitter.com/forums/10711/entries/15364" target="blank">API rate limit</a>, you can try again in <span class="minutes">'  + this.minutes + '</span> minutes. But, look what Google says:',
						'screen_name': screenName,
						'title': this.users[currentIndex].title.replace('on Twitter', ''),
						'content': this.users[currentIndex].content,
						'url': this.users[currentIndex].url,
						'id': this.users[currentIndex].seo
					}));	
					var checkEl = $('check_' + this.users[currentIndex].seo);
					checkEl.store('uid', '');
					checkEl.store('sname', screenName);
					
					
					var followEl = $('follow_' + this.users[currentIndex].seo);
					followEl.addEvent('click', function(e) { e.stop(); this.doFollow(screenName); }.bind(this));
					
					var checkEl = $('check_' + this.users[currentIndex].seo);
					FancyForm.add(checkEl);			
				}
				
				this.loadedItems++;
				this.loaded = this.loadedItems = this.pageSize;		
			}	
		},
		
		logSeach: function() {
			var log = [];
			for (var i = 0; i < this.users.length && i < this.pageSize; i++) {
				if (this.users[i].data) {
					var logItem = {
						seo: this.users[i].seo,
						data: this.users[i].data
					};
					log[log.length] = logItem;
				}	
			}
			new Request.JSON({
				url: "/log"
			}).post({
				'bio': this.bioValue,
				'loc': this.locationValue,
				'name': this.nameValue,
				'keywords': this.keywordsValue,
				'data': JSON.encode(log)
			});
		},
		
		showUser: function(user) {
			var userEl = $('user_' + user.seo);
			if (userEl) {
				userEl.empty();
				
				var emptyText = user.data.protected?'<strong>Updates protected</strong>':'';
				userEl.set('html', this.userTemplate.substitute({
					'id': user.seo,
					'name': user.data.name,
					'screen_name': user.data.screen_name,
					'profile_image_url': user.data.profile_image_url,
					'location': user.data.location,
					'url': user.data.url,
					'description': user.data.description,
					'followers_count': this.prettyNumber(user.data.followers_count),
					'friends_count': this.prettyNumber(user.data.friends_count),
					'statuses_count': this.prettyNumber(user.data.statuses_count),
					//'following': user.following?'Yes':'No',
					'protected': user.data.protected?'candado_close':'candado_open',
					'created_at': Date.parse(user.data.created_at).timeDiffInWords(),
					'status_text': user.data.status?this.linkify(user.data.status.text):emptyText,
					'status_created_at': user.data.status?Date.parse(user.data.status.created_at).timeDiffInWords():''
				}));			
				var checkEl = $('check_' + user.seo);
				checkEl.store('uid', user.data.id);
				checkEl.store('sname', user.data.screen_name);
				
				var followEl = $('follow_' + user.seo);
				followEl.addEvent('click', function(e) { e.stop(); this.doFollow(user.data.screen_name); }.bind(this));
				
				var rankbtnEl = $('rankbtn_' + user.seo);				
				var rankwinEl = $('rankwin_' + user.seo);
				var ranksendEl = $('ranksend_' + user.seo);
				var ranktxtEl = $('ranktxt_' + user.seo);
			
				rankbtnEl.addEvent('click', function(e) { 
					e.stop();
					if (rankwinEl.getStyle('display') == 'none' || rankwinEl.getStyle('opacity') == '0') {
						if (ranktxtEl.get('html') == '') {
							this.getShortURL(user.data.screen_name, user.seo, ranktxtEl);									
							if (this.bulkFollowEl.get('class') != 'logegdin') {							
								ranktxtEl.addEvent('');
							}
						}	
						rankwinEl.setStyles({'display':'block', 'opacity':0, 'width':0, 'height':0 }); 
						rankwinEl.morph({'opacity':1, 'width':258, 'height':121 })
					}
					else {
						rankwinEl.morph({'opacity':0, 'width':0, 'height':0 })
					}		
					
				}.bind(this));
				
				ranksendEl.addEvent('click', function(e) { 
					e.stop();
					if (this.bulkFollowEl.get('class') != 'logegdin') {
						window.open('http://twitter.com/home?status=' + escape(ranktxtEl.get('html')));
					}
					else {
						this.sendTweet(ranktxtEl.get('html'), true);
					}
					rankwinEl.setStyles({'display':'none', 'opacity':0, 'width':0, 'height':0 }); 
				}.bind(this));
				
				var checkEl = $('check_' + user.seo);
				FancyForm.add(checkEl);			
			}	
		},
				
		doPagination: function() {
			this.pagination1El.empty();
			this.pagination2El.empty();
			this.total1El.set('html', this.formatNumber(this.total) + ' users');
			this.total2El.set('html', this.formatNumber(this.total) + ' users');
			this.total1El.setStyle('display', 'block');
			this.total2El.setStyle('display', 'block');

			this.pagesCount = (this.total / this.pageSize).ceil();			
			if (this.pagesCount > 10) {
			   this.pagesCount = 10;
			}   
			
			if (this.pagesCount > 1 && this.currentPage > 1)  {
				var liEl = new Element('li', {'class': 'prev'});					
				var pageEl = new Element('a', {
					'href': '#',
					'title': 'prev page'
				});
				liEl.grab(pageEl);
				pageEl.addEvent('click', this.goPrevPage.bind(this));
				this.pagination1El.grab(liEl);
				
				var liEl = new Element('li', {'class': 'prev'});					
				var pageEl = new Element('a', {
					'href': '#',
					'title': 'prev page'
				});
				liEl.grab(pageEl);
				pageEl.addEvent('click', this.goPrevPage.bind(this));
				this.pagination2El.grab(liEl);
				
			}	
		
			
			var iniPage = this.currentPage - 4;
			var endPage = 10;
			if (iniPage < 1) {
				iniPage = 1;
			}
			else {
				endPage = this.currentPage + 4;
			}
			if (endPage > this.pagesCount) {
			   endPage = this.pagesCount;
			}  
		
		
			for (var i = iniPage - 1; i < endPage; i++) {
				var liEl = new Element('li', {
					'class': (this.currentPage != i+1)?'num':'num_act'
				});					
				var pageEl = new Element('a', {
					'href': '#',
					'rel': i + 1,
					'title': 'Go to page ' + (i + 1),
					'html': (i + 1)
				});
				liEl.grab(pageEl);
				pageEl.addEvent('click', this.goPage.bind(this));
				this.pagination1El.grab(liEl);
				
				var liEl = new Element('li', {
					'class': (this.currentPage != i+1)?'num':'num_act'
				});					
				var pageEl = new Element('a', {
					'href': '#',
					'rel': i + 1,
					'title': 'Go to page ' + (i + 1),
					'html': (i + 1)
				});
				liEl.grab(pageEl);
				pageEl.addEvent('click', this.goPage.bind(this));
				this.pagination2El.grab(liEl);
			}
			
			if (this.pagesCount > 1 && this.currentPage < this.pagesCount)  {
				var liEl = new Element('li', { 'class': 'next' });					
				var pageEl = new Element('a', {
					'href': '#',
					'title': 'next page'
				});
				liEl.grab(pageEl);
				pageEl.addEvent('click', this.goNextPage.bind(this));
				this.pagination1El.grab(liEl);
				
				var liEl = new Element('li', { 'class': 'next' });					
				var pageEl = new Element('a', {
					'href': '#',
					'title': 'next page'
				});
				liEl.grab(pageEl);
				pageEl.addEvent('click', this.goNextPage.bind(this));
				this.pagination2El.grab(liEl);
			}	
		},

		getLocalTweets: function() {
			if (google.loader.ClientLocation) {
				this.tweetsWrapperEl.setStyle('display', 'block');
				this.tweetsLoadingEl.setStyle('display', 'block');
				this.getLocalizedTweets(google.loader.ClientLocation.latitude, google.loader.ClientLocation.longitude);
			}
			else {
				this.tweetsWrapperEl.setStyle('display', 'none');
			}
		
		},
		
		searchWrapper: function(bio, loc, name, keywords) {
			this.bioEl.set('value', bio);
			this.nameEl.set('value', name);
			this.keywordsEl.set('value', keywords);
			this.locationEl.set('value', loc);
			this.historyManager.setValues(['twitters', bio, loc, name, keywords]);		
			this.currentPage = 1;	
			this.doSearch();
		},
		
		langAdviseDone: function() {
			//Cookie.write('lang_advise', 'true', {domain: this.domain, duration: 180});
		},
		
		
		getLocation: function() {
			if (google.loader.ClientLocation) {
				var lang = (navigator.language || navigator.systemLanguage || navigator.userLanguage || 'en').substr(0, 2).toLowerCase();
				
				/*
				if (Cookie.read('lang_advise') != 'true') {
					if (lang.test('es')) {
						this.message('<b>Existe una versión de locafollow en español. Click <a href="http://www.locafollow.es">aquí</a> si deseas visitarla.</b>');			
						this.langAdviseDone();
					} else if (lang.test('br') || lang.test('pt')) {
						this.message('<b>Existe uma versão em espanhol locafollow. Clique <a href="http://br.locafollow.com">aquí</a> se você quer visitar.</b>');			
						this.langAdviseDone();
					}
				}*/
				
				
				var city = google.loader.ClientLocation.address.city;
				if (lang != 'en') {
					google.language.translate(city, "en", lang, function(result) {
						if (result.translation) {
							this.searchWrapper('', result.translation, '', '');
						}
						else {
							this.searchWrapper('', '', '', '');
						}
					}.bind(this));
				}
				else {
					this.searchWrapper('', city, '', '');
				}			
			}
			else {
				this.searchWrapper('', '', '', '');			
			}		
		},
				
		goPage: function(e) {
			e.stop();
			this.currentPage = $(e.target).get('rel').toInt();
			this.doSearch();
		},
		
		goPrevPage: function(e) {
			e.stop();

			if (this.pagesCount > 1 && this.currentPage > 1) {
				this.currentPage--;
				this.doSearch();
			}	
		},
		
		goNextPage: function(e) {
			e.stop();

			if (this.pagesCount > 1 && this.currentPage < this.pagesCount) {			
				this.currentPage++;
				this.doSearch();
			}	
		},
		
		doBulkFollow: function() {
			if (this.bulkFollowEl.get('class') != 'logegdin') {
				this.message('You must log in before. Sign in with Twitter <a href="/oauth/twitter/login">here</a>');			
				return;
			}
			
			if (!this.following) {
				var list = $$('.resuts_item_check label[class=checked] input');
				var list2 = $$('.blue_module_diana_check label[class=checked] input');
				list.combine(list2);
				
				if (list && list.length > 0) {
					if (confirm('Are you sure to follow all the selected users?')) {
						this.following = true;
						this.followStack.empty();
						this.showFollowStatus();
						list.each(function(el) {
							if (el.getProperty('checked')) {
								var screenName = el.retrieve('sname');
								this.followStack[this.followStack.length] = {
									screenName: screenName,
									working: true,
									error: false,
									msg: ''
								};
								this.doFollow(screenName, true, this.followStack.length - 1);
							}
						}, this);

						if (this.checklocafollowEl.getProperty('checked')) {
							this.followStack[this.followStack.length] = {
								screenName: 'locafollow',
								working: true,
								error: false,
								msg: ''
							};
							this.doFollow('locafollow', true, this.followStack.length - 1);
						}
					}
				}
				else {
					this.message('Please, select a least one user to follow.');
				}	
			}
			else {
				this.message('There is already a bulk follow in progress.');
			}			
		},
		
		doShareResults: function() {
			if (this.users.length > 0) {
				var listTxt = '';
				for (var i = 0; i < this.users.length; i++)	{
					listTxt += this.users[i].screenName;
					if (i < this.users.length-1) {
						listTxt += "\n";
					}	
				}
				
				var msg = new Element('div', {
					'class': 'sharewrapper',
					'html': '<p><strong>1.- </strong>Select all and copy this list to the clipboard</p>' + 
					'<textarea>' + listTxt + '</textarea>' + 
					'<p><div class="sharewrapperdiv"><strong>2.- </strong>Go to </div> <a href="http://tweepml.org/TweepGen/" target="_blank" rel="nofollow"><div id="tweepml"></div></a> <a href="http://tweepml.org/TweepGen/" target="_blank" rel="nofollow"><div class="sharewrapperdiv">TweepML.org</div></a> <div class="sharewrapperdiv"> and paste your list</div></p>'
				});
				
				SqueezeBox.open(msg, {size: {x: 320, y: 440}, handler:'adopt'});		
			}	
			else {
				this.message('There are no results to share.');
			}			
		},
		
		promtCreateList: function() {
			if (this.bulkFollowEl.get('class') != 'logegdin') {
				this.message('You must log in before. Sign in with Twitter <a href="/oauth/twitter/login">here</a>');			
				return;
			}

			if (!this.listing) {
				var msg = new Element('div', {
					'id': 'createlistwrapper',
					'html': '<h2>Select an existing Twitter List:</h2>' + 
					'<p><strong>Your lists:</strong> <select id="listssel"></select></p>' + 
					'<p><input id="sharelist1"  type="checkbox"  /> Share this list</p>' + 					
					'<p><div id="addlist" class="ok_bt"></div><div id="canceladdlist" class="cancel_bt"></div></p>' + 					
					'<h3> - OR - </h3>' +
					'<h2>Create a new Twitter List:</h2>' + 
					'<p><strong>List Name</strong>: <input id="listname" value="" maxlength="25" /></p>' +
					'<p><strong>Privacy:</strong> <input id="listpublic" name="privacy"  value="public" type="radio" checked="checked"  />Public <input id="listprivate" name="privacy" value="private" type="radio"  />Private</p>' + 
					'<p><input id="sharelist2"  type="checkbox" checked="checked"  /> Share this list</p>' + 										
					'<p><div id="createlist" class="ok_bt"></div><div id="cancellist" class="cancel_bt"></div></p>'
				});
				$(document.body).grab(msg);	
				SqueezeBox.open(msg, {size: {x: 320, y: 330}, handler:'adopt'});														
				
				var listSelEl = $('listssel');
				var listNameEl = $('listname');
				var publicEl = $('listpublic');
				var sharelist1El = $('sharelist1');
				var sharelist2El = $('sharelist2');
				
				this.getLists(function(lists) {
					var listTxt = '';
					if (lists) {
						for (var i = 0; i < lists.length; i++) {
							listTxt += '<option value="' + lists[i].name + '">' + lists[i].name + '</option>' + "\n";
						}
						listSelEl.set('html', listTxt);
					}
					else {
					
					}
				}.bind(this));
				
				var createlistEl = $('createlist');
				createlistEl.addEvent('click', function(e) {
					e.stop();
					var listName = listNameEl.get('value');
					var listPublic = publicEl.get('checked');
					var share = sharelist2El.get('checked');
					if (listName) {
						this.doCreateNewList(listName, listPublic, share?'I just created this Twitter List: http://twitter.com/' + this.screenName + '/' + listName + ' via http://LocaFollow.com':'');
					}
					else {
						alert('Please write a valid list name');
					}	
				}.bind(this));	
				
				var addlistEl = $('addlist');
				addlistEl.addEvent('click', function(e) {
					e.stop();
					var listName = listSelEl.get('value');
					var share = sharelist1El.get('checked');
					if (listName) {
						this.doCreateList(listName, true);
						this.sendTweet(share?'Adding people to my Twitter List: http://twitter.com/' + this.screenName + '/' + listName + ' via http://LocaFollow.com':'', false);
					}
					else {
						alert('Please select a list.');
					}	
				}.bind(this));
				
				var canceladdlistEl = $('canceladdlist');
				canceladdlistEl.addEvent('click', function(e) {
					e.stop();
					SqueezeBox.close();
				}.bind(this));
				
				var cancellistEl = $('createlist');
				cancellistEl.addEvent('click', function(e) {
					e.stop();
					SqueezeBox.close();
				}.bind(this));				
				
			}
			else {
				this.message('There is already a list creation in progress.');
			}			
		},
		
		doCreateList: function(listName, verbose) {
			if (this.bulkFollowEl.get('class') != 'logegdin') {
				this.message('You must log in before. Sign in with Twitter <a href="/oauth/twitter/login">here</a>');			
				return;
			}

			if (!this.listing) {
				var list = $$('.resuts_item_check label[class=checked] input');
				var list2 = $$('.blue_module_diana_check label[class=checked] input');
				list.combine(list2);
				
				if (list && list.length > 0) {
					if (!verbose || confirm('Are you sure to add all the selected users to the selected list?')) {
						this.listing = true;
						this.listStack.empty();
						this.showListStatus();
						list.each(function(el) {
							if (el.getProperty('checked')) {
								var id = el.retrieve('uid');
								var screenName = el.retrieve('sname');
								if (id) {
									this.listStack[this.listStack.length] = {
										id: id,
										screenName: screenName,
										working: true,
										error: false,
										msg: ''
									};
									this.doAddToList(listName, id, screenName, this.listStack.length - 1);
								}
								else {
									job = this.listStack[this.listStack.length - 1];
									if (job) {
										job.error = true;
										job.working = false;
										job.msg = 'We couldn\'t get the details from this user profile <strong>' + screenName + ' </strong>.';
										this.addListStatus(this.listStack.length - 1);
									}	
								}			
							}
						}, this);

						if (this.checklocafollowEl.getProperty('checked')) {
							this.listStack[this.followStack.length] = {
								id: '79226526',
								screenName: 'locafollow',
								working: true,
								error: false,
								msg: ''
							};
							this.doAddToList(listName, '79226526', 'locafollow', this.listStack.length - 1);
						}
					}
				}
				else {
					this.message('Please, select a least one user to add.');
				}	
			}
			else {
				this.message('There is already a list creation in progress.');
			}			
			
		},
		
		addFollowStatus: function(jobIndex) {
			var job;
			var statusEl = $('follow_status');
			if (!statusEl) {
				statusEl = new Element('div', {
					'id': 'follow_status'
				});
				SqueezeBox.open(statusEl, {size: {x: 420, y: 380}, handler:'adopt'});		
			} 

			if (job = this.followStack[jobIndex]) {
				var jobEl = new Element('div', {
					'class': job.error?'joberror':'jobok',
					'html': '<div class="' + (job.error?'unchecked':'checked') + '"></div><p><strong><a href="http://twitter.com/' + job.screenName + '">' + job.screenName + '</a></strong>: ' + job.msg + '</p>'
				});
				statusEl.grab(jobEl);
			}
		
			for (var i = 0; i < this.followStack.length; i++) {
				var job = this.followStack[i];
				if (job.working) {
					return;
				}
			}
			this.following = false;
			this.showFollowStatus();
		},
		
		showFollowStatus: function() {
			var statusEl = $('follow_status');
			if (!statusEl) {
				statusEl = new Element('div', {
					'id': 'follow_status'
				});
				SqueezeBox.open(statusEl, {size: {x: 420, y: 380}, handler:'adopt'});		
				
				for (var i = 0; i < this.followStack.length; i++) {
					var job = this.followStack[i];
					if (!job.working) {
						var jobEl = new Element('div', {
							'class': job.error?'joberror':'jobok',
							'html': '<div class="' + (job.error?'unchecked':'checked') + '"></div><p><strong><a href="http://twitter.com/' + job.screenName + '">' + job.screenName + '</a></strong>: ' + job.msg + '</p>'
						});
						statusEl.grab(jobEl);
					}
				}
			}	
		},
		
		doFollow: function(screenName, bulk, jobIndex) {
			var bulk = bulk?bulk:false;
			var jobIndex = jobIndex?jobIndex:0;

			var hello = '';	
			if (this.checksayhelloEl && this.checksayhelloEl.getProperty('checked') && screenName != 'locafollow') {
				hello = this.txtsayhelloEl.getProperty('value').substitute({'username':'@' + screenName});
			}
			
			var uid = 0;
			var checkEl = $('check_' + 'ad_' + screenName);
			if (checkEl) {
				uid = checkEl.retrieve('uid');
			}	
			var lang = (navigator.language || navigator.systemLanguage || navigator.userLanguage || 'en').substr(0, 2).toLowerCase();
			var country = '';
			if (google.loader.ClientLocation) {
				country = google.loader.ClientLocation.address.country_code;
			}
			
			
			new Request.JSON({
				url: (uid?"/adsfollow/":"/follow/") + screenName, 
				onComplete: function(res, restxt) {
					if (res.success) {
						var job;
						if (res.code == 200) {
							if (!bulk) {
								this.message('You are now following <strong>' + screenName + '</strong>');
							}	
							else {
								job = this.followStack[jobIndex];
								if (job) {
									job.error = false;
									job.working = false;
									job.msg = 'You are now following <strong>' + screenName + '</strong>';
									this.addFollowStatus(jobIndex);
								}	
							}
						}
						else {
							if (!bulk) {
								this.message('Sorry: ' + res.error.error);
							}	
							else {
								job = this.followStack[jobIndex];
								if (job) {
									job.error = true;
									job.working = false;
									job.msg = 'Sorry: ' + res.error.error;
									this.addFollowStatus(jobIndex);
								}	
							}							
						}
					}	
					else {
						if (!bulk) {
							this.message('Sorry:' + res.error);
						}	
						else {
							job = this.followStack[jobIndex];
							if (job) {
								job.error = true;
								job.working = false;
								job.msg = 'Sorry: ' + res.error;
								this.addFollowStatus(jobIndex);
							}							
						}	
					}
			
				}.bind(this),
				onCancel: function() {
					var job;
					if (!bulk) {
						this.message('The Twitter API seems busy now, please try again later.');	
					}	
					else {
						job = this.followStack[jobIndex];
						if (job) {
							job.error = true;
							job.working = false;
							job.msg = 'The Twitter API seems busy now, please try again later.';
							this.addFollowStatus(jobIndex);
						}	
					}							
					
				}.bind(this)
			}).get({
				'msg': hello,
				uid: uid,
				lang: lang,
				country: country
			});
		},
		
		addListStatus: function(jobIndex) {
			var job;
			var statusEl = $('list_status');
			if (!statusEl) {
				statusEl = new Element('div', {
					'id': 'list_status'
				});
				SqueezeBox.open(statusEl, {size: {x: 420, y: 380}, handler:'adopt'});		
			} 

			if (job = this.listStack[jobIndex]) {
				var jobEl = new Element('div', {
					'class': job.error?'joberror':'jobok',
					'html': '<div class="' + (job.error?'unchecked':'checked') + '"></div><p><strong><a href="http://twitter.com/' + job.screenName + '">' + job.screenName + '</a></strong>: ' + job.msg + '</p>'
				});
				statusEl.grab(jobEl);
			}
		
			for (var i = 0; i < this.listStack.length; i++) {
				var job = this.listStack[i];
				if (job.working) {
					return;
				}
			}
			this.listing = false;
			this.showListStatus();
		},
		
		showListStatus: function() {
			var statusEl = $('list_status');
			if (!statusEl) {
				statusEl = new Element('div', {
					'id': 'list_status'
				});
				SqueezeBox.open(statusEl, {size: {x: 420, y: 380}, handler:'adopt'});		
				
				for (var i = 0; i < this.listStack.length; i++) {
					var job = this.listStack[i];
					if (!job.working) {
						var jobEl = new Element('div', {
							'class': job.error?'joberror':'jobok',
							'html': '<div class="' + (job.error?'unchecked':'checked') + '"></div><p><strong><a href="http://twitter.com/' + job.screenName + '">' + job.screenName + '</a></strong>: ' + job.msg + '</p>'
						});
						statusEl.grab(jobEl);
					}
				}
			}	
		},
		
		doAddToList: function(listName, id, screenName, jobIndex) {
			var jobIndex = jobIndex?jobIndex:0;

			new Request.JSON({
				url: "/addtolist/" + listName, 
				onComplete: function(res, restxt) {
					if (res.success) {
						var job;
						if (res.code == 200) {
							job = this.listStack[jobIndex];
							if (job) {
								job.error = false;
								job.working = false;
								job.msg = 'You have added <strong>' + screenName + '</strong> to your list <strong>' + listName + '</strong>';
								this.addListStatus(jobIndex);
							}	
						}
						else {
							job = this.listStack[jobIndex];
							if (job) {
								job.error = true;
								job.working = false;
								job.msg = 'Sorry: ' + res.error.error;
								this.addListStatus(jobIndex);
							}	
						}
					}	
					else {
						job = this.listStack[jobIndex];
						if (job) {
							job.error = true;
							job.working = false;
							job.msg = 'Sorry: ' + res.error;
							this.addListStatus(jobIndex);
						}							
					}
			
				}.bind(this),
				onCancel: function() {
					var job;
					job = this.listStack[jobIndex];
					if (job) {
						job.error = true;
						job.working = false;
						job.msg = 'The Twitter API seems busy now, please try again later.';
						this.addListStatus(jobIndex);
					}	
					
				}.bind(this)
			}).get({'id':id});
		},
		
		doCreateNewList: function(listName, listPublic, msg) {
			new Request.JSON({
				url: "/createlist", 
				onComplete: function(res) {
					if (res.success) {
						if (res.code == 200) {
							if (confirm('The list ' + listName + ' was created successfully. Do you want to add all the selected users to the new list?')) {
								this.doCreateList(listName, false);
								if (msg) {
									this.sendTweet(msg, false);
								}	
							}
						}
						else {
							this.message('Sorry: ' + res.error);
						}
					}	
					else {
						this.message('Sorry: ' + res.error);					
					}
			
				}.bind(this),
				onCancel: function() {
					this.message('The Twitter API seems busy now, please try again later.');
				}.bind(this)
			}).post({'listName': listName, 'privacy': listPublic?'public':'private'});
		},
		
		getLists: function(callback) {
			new Request.JSON({
				url: "/getlists", 
				onComplete: function(res) {
					if (res.success) {
						if (res.code == 200 && res.info) {
							callback(res.info.lists);
						}
						else {
							callback();
							this.message('Error getting your lists: ' + res.error.error);
						}
					}	
					else {
						callback();
						this.message('Error getting your lists: ' + res.error);					
					}
			
				}.bind(this),
				onCancel: function() {
					callback();
					this.message('Error getting your lists. The Twitter API seems busy now, please try again later.');
				}.bind(this)
			}).get();
		},
		
		sendTweet: function(msg, verbose) {
			new Request.JSON({
				url: "/tweet", 
				onComplete: function(res) {
					if (res.success) {
						if (res.code == 200) {
							if (vebose) {
								this.message('Your tweet was successfully sent.');
							}	
						}
						else {
							if (vebose) {
								this.message('Sorry: ' + res.error.error);
							}	
						}
					}	
					else {
						if (vebose) {
							this.message('Sorry:' + res.error);
						}	
					}
				}.bind(this),
				onCancel: function() {
					if (vebose) {
						this.message('The Twitter API seems busy now, please try again later.');	
					}	
				}.bind(this)
			}).get({'msg': msg});
		},
		
		linkify: function(text) {
			//courtesy of Jeremy Parrish (rrish.org)
			return text.replace(/(https?:\/\/\S+)/gi,'<a href="$1">$1</a>').replace(/(^|\s)@(\w+)/g,'$1<a href="http://twitter.com/$2">@$2</a>').replace(/(^|\s)#(\w+)/g,'$1#<a href="http://search.twitter.com/search?q=%23$2">$2</a>');
		},
		
		reset: function() {
			this.loading = true;
			this.shortURL = '';
			this.users.empty();
			this.usersEl.empty();
			this.pagination1El.empty();
			this.pagination2El.empty();
			this.total1El.setStyle('display', 'none');
			this.total2El.setStyle('display', 'none');
			this.loadingEl.setStyle('display', 'block');
			this.toppanelEl.setStyle('display', 'none');			
			//this.rightpanelEl.setStyle('display', 'block');			
			if (this.txtcontentEl) {
				this.txtcontentEl.setStyle('display', 'none');
			}				
			if (this.contentlistEl) {
				this.contentlistEl.setStyle('display', 'none');
			}				
		},
		
		prettyNumber: function(num) {
			if (num > 9999) {
				return (num/1000).ceil() + 'K';
			}
			return num;
		},
		
		cardinalNumber: function(num) {
			if (num == 1) {
				return '1st';
			}
			else if  (num == 2) {
				return '2nd';
			}
			else if  (num == 3) {
				return '2rd';
			}
			else  {
				return num + 'th';
			}
		},
		
		formatNumber: function (num,prefix){
		   prefix = prefix || '';
		   num += '';
		   var splitStr = num.split('.');
		   var splitLeft = splitStr[0];
		   var splitRight = splitStr.length > 1 ? '.' + splitStr[1] : '';
		   var regx = /(\d+)(\d{3})/;
		   while (regx.test(splitLeft)) {
			  splitLeft = splitLeft.replace(regx, '$1' + ',' + '$2');
		   }
		   return prefix + splitLeft + splitRight;
		},
		
		
		message: function(msg) {
			var msg = new Element('div', {
				'class': 'msg',
				'html': '<p>' + msg + '</p>'
			});
			
			SqueezeBox.open(msg, {size: {x: 300, y: 50}, handler:'adopt'});		
		}
		
	});
	
	new MainApp(); 
});	
