There are 20 previous versions of this script.

// ==UserScript==
// @name           Mafia Wars Facebook - Add Mafia Wars Links to Facebook profiles.
// @namespace      Facebook
// @description    Adds Mafia Wars specific links to the standard Facebook profile menu.
// @include        http://*.facebook.com/*
// @exclude        http://apps.facebook.com/*
// @exclude        http://www.facebook.com/*viewas*
// @date 20100522
// @time 1317
// @version 2010.05.22.1317
// ==/UserScript==
//
// Based on http://userscripts.org/scripts/show/55960 !!!
// updateScript function adapted from http://userscripts.org/scripts/show/43573 !!!
// HTML insertion of new link inspired by http://userscripts.org/scripts/show/48627 !!!
// --------------------------------------------------
//
// History
// 200909302339 - Update for FB change
// 200910011527 - More error catching
//		- Detect if on your own profile so it won't run because the send
//		  message link is not available on your own profile.
//		- Attempt to auto-update if error occurs, make it easier on users when
//		  Facebook changes things around.
// 200910032115 - Add my own menu entry instead of replacing one
//		- Display detected Facebook user ID.
//		- Not sure this is ready for prime time because I don't know why half the stuff I do actually works?!?!
// 200910140824 - Quickfix for FB changes.
// 200910201944 - Quickfix for FB changes.
// 200910232155 - Added Promote and Send Gift to menu and space at end of menu (strictly cosmetic).
// 200912092317 - Better user ID detection and fixed links.
// 200912102253 - Fix user ID detection, should cover own profile, friends and non-friends (hopefully).
// 200912111326 - Fix user ID detection on group/fan pages and fix profile link since Zynga insists on changing things on a daily basis.
// 201001222331 - Added "Add To Mafia" link to add individual users to own mob using war backdoor.
// 201003261955 - Changed the "Add To Mafia" Link so it will work even if you are not in New York.
// 201004161208 - Fix user ID detection on application pages (didn't think of that, thanks Sonar).
// 201005101634 - Disable script on "viewas" preview pages in privacy settings.
// 201005221317 - Quick fix for promote link not working.

var SCRIPT =
{
  home: "http://userscripts.org/scripts/show/58257",
  url: "http://userscripts.org/scripts/source/58257.user.js",
  date: '20100510',
  time: '1634',
  errors: 0,
  Interval: 0
}

window.addEventListener("load", function ()
{
	addMWLink();
	SCRIPT.Interval = setInterval(function (){addMWLink()}, 2500);
}	
,true);



function addMWLink()
{
	if(!document.getElementById("FBUserID"))
	{
                //The link to the mafia profile
		//http://apps.facebook.com/inthemafia/track.php?next_controller=stats&next_action=view&next_params=%7B%22user%22%3A%221373851008%3D%3D%22%7D
		//var MobProfile = "http://apps.facebook.com/inthemafia/remote/html_server.php?xw_controller=stats&xw_action=view&user=";
		//var MobProfile = "http://apps.facebook.com/inthemafia/track.php?next_controller=stats&next_action=view&next_params=%7B%22user%22%3A%22USER_ID%3D%3D%22%7D";
		var MobProfile = "http://apps.facebook.com/inthemafia/profile.php?id=%7B%22user%22%3A%22BASE64USER_ID%22%7D";
                //var MobPromote = "http://apps.facebook.com/inthemafia/remote/html_server.php?xw_controller=group&xw_action=view&promote=yes&uid=USER_ID";
		var MobPromote = "http://apps.facebook.com/inthemafia/track.php?next_controller=group&next_action=view&next_params=%7B%22promote%22%3A%22yes%22%2C%22pid%22%3A%22USER_ID%22%7D";
                //var MobPromote = "http://mwfb.zynga.com/mwfb/remote/html_server.php?xw_controller=group&xw_action=view&promote=yes&uid=USER_ID";
                //var MobGift =    "http://apps.facebook.com/inthemafia/remote/html_server.php?xw_controller=gift&xw_action=view&target_id=USER_ID";
                //var MobGift = "http://mwfb.zynga.com/mwfb/remote/html_server.php?xw_controller=gift&xw_action=view&target_id=USER_ID"
                var MobGift = "http://apps.facebook.com/inthemafia/track.php?next_controller=gift&next_action=view&next_params=%7B%22target_id%22%3A%22USER_ID%22%7D";
                //var MobAdd = "http://mwfb.zynga.com/mwfb/remote/html_server.php?skip_req_frame=1&xw_controller=war&xw_action=add&xw_city=1&friend_id=
		var MobAdd1 = 'http://apps.facebook.com/inthemafia/index.php?next_params=';
		var MobAdd2 = 'a:3:{i:0;s:3:"war";i:1;s:3:"add";i:2;s:CMDLEN:"';
		//var MobAdd3 = '&xw_city=1&friend_id=USER_ID";}';
		var MobAdd3 = '&friend_id=USER_ID";}'; 		
		var MobAdd4 = '&_fb_q=1&_fb_qsub=apps.facebook.com';
		var MobAdd = "";
                
		// Check to see if we are on a wall of some sort, not a feed
		if(!document.getElementById("profile_top_bar"))
		{
    			//GM_log("Not on a wall, leaving.");
    			return;
    		}

		try
                {       //Get the left column element (if it's not there, FB either changed something or we're not on a profile).
                        var leftColumn = document.getElementById("left_column");
                        if(leftColumn)
                        {
        		 	var columnHTML = leftColumn.innerHTML;
        		 	var userID = "0";

				// Check for preview page
				GM_log("Checking for preview page");
				if(columnHTML.indexOf('"Preview" mode') != -1)
				{
					GM_log("Detected preview page, outta here");
					return;
				}
				else
				{
        				// Check for fan page
        				GM_log("Checking for fan page");
        				if(columnHTML.indexOf("Remove Me from Fans") != -1 || columnHTML.indexOf("Report Page") != -1)
        				{
        					GM_log("Detected fan page, outta here");
        					return;
        				}
        				else
        				{
                				// Check for group page
                				GM_log("Checking for group page");
                				if(columnHTML.indexOf("Report Group") != -1)
                				{
                					GM_log("Detected group page, outta here");
                					return;
                				}
        					else
        					{
        						// Check for application page
                        				GM_log("Checking for application page");
                        				if(columnHTML.indexOf("Report Application") != -1)
                        				{
                        					GM_log("Detected application page, outta here");
                        					return;
                        				}
                					else
                					{
                                				// Get User ID from Facebook
                                        			// For non-friends, get user ID from report/block link
                                				GM_log("Checking non-friend");
                                        			if(columnHTML.indexOf("report.php") != -1)
                                        			{
                                        				GM_log("Retrieving non-friend");
                                        				userID = columnHTML.split('report.php?')[1].split('rid=')[1].split('&')[0];
                                				}
                                				else
                                				{
                                                			// For friends, use the remove as friend link
                                                			GM_log("Checking friend");
                                                			if(columnHTML.indexOf('removefriendconfirm.php') != -1)
                                                			{
                                						GM_log("Retrieving friend");
                                                				userID = columnHTML.split("removefriendconfirm.php?uid=")[1].split('"')[0];
                                        	        		}
                                        	        		else
                                        	        		{
                                        	        			// Check for own profile
                                	                			GM_log("Checking own");        	        			
                                        	        			if(columnHTML.indexOf('Edit My Profile') != -1)
                                        	        			{
                                                	        			GM_log("Retrieving own profile");
                                                	        			userID = columnHTML.split('album.php?profile=1&id=')[1].split('"')[0];
                                                	        		}
                                                	        		else
                                                	        		{
                                							// If we get here, either Facebook changed something or the page isn't fully loaded yet.
                                							// Either way, we need to exit.
                                
                                							GM_log("Unable to detect any page type. Possibly page is not fully loaded yet. Try again... ");
                                							
                                							// Increase error counter by 1
                                							SCRIPT.errors += 1;
                									
                									// If that error occured over 10 times, something has change, so alert user
                									if(SCRIPT.errors == 10)
                									{
                										throw "DetectionErrors";
                									}
                									
                                							return;
                                                	        		}
                                                			}
                                                		}
                                        		}
                                        	}
                                        }
                		}
        			// Should have proper ID here, if not, something changed
        			if(!isNaN(parseInt(userID)))
        			{
					// Get AddToMob URL ready
					//***********************
                              	        // Put user ID in command
                              	        MobAdd = MobAdd3.replace('USER_ID',userID);
                              	        // Add length of command
                              	        MobAdd = MobAdd2.replace('CMDLEN',(MobAdd.length - 3).toString()) + MobAdd;
                              	        // Encode the URL
                              	        MobAdd = MobAdd1 + Base64.encode(MobAdd) + MobAdd4;

        				// Add Mafia Wars menu items to Facebook menu
        				//*******************************************
        				leftColumn.innerHTML = leftColumn.innerHTML.replace("<div class="+String.fromCharCode(34)+"profile_actions"+String.fromCharCode(34)+">",
        					// Divider
        					"<div class='profile_actions'>"+			
        					// Goto Profile link
        					"<a id='mafia_wars_links' class=' profile_action actionspro_a' href=" + MobProfile.replace("BASE64USER_ID",Base64.encode(userID)) + " target='_blank'>Mafia Wars: Show Profile</a>" +
        					// Send Gift Link
        					"<a id='mafia_wars_links' class=' profile_action actionspro_a' href=" + MobGift.replace("USER_ID",userID) + " target='_blank'>Mafia Wars: Send Gift</a>" +
        					// Promote Link
						"<a class=' profile_action actionspro_a' href=" + MobPromote.replace("USER_ID",userID) + " target='_blank'>Mafia Wars: Promote</a>" +
						// Add To Mafia Link
						"<a class=' profile_action actionspro_a' href=" + MobAdd + " target='_blank'>Mafia Wars: Add To Mafia</a>" +        						
						// Put some space between me and the rest ;)
						"</div><div style='border-bottom: 1px solid #D8DFEA'></div><div class='profile_actions'>");
        				// Check if link installed properly
        				if(!document.getElementById("mafia_wars_links"))
        				{
        					throw "BadHMTL";
        				}
       
        				// Display detected Facebook user ID underneath profile picture
        				//************************************************************
        				var pageletLeftColumn = document.getElementById("pagelet_left_column")
        				if(pageletLeftColumn)
        				{
        					pageletLeftColumn.innerHTML = pageletLeftColumn.innerHTML.replace('<div class="profile_actions">',"<div id='FBUserID' style='text-align:center; padding: 3px 8px; border-bottom: 1px solid #D8DFEA'>User ID: <B>"+userID+"</B></div><div class='profile_actions'>");
						// Check if it inserter properly
                				if(!document.getElementById("FBUserID"))
                				{
                					throw "BadHMTL";
                				}
                				else
                				{
                					// Success, so reset error counter since it may just be a fluke that caused an error earlier.
                					SCRIPT.errors = 0;
                				}
        				}
        				else
        				{
        					throw "BadpageletLeftColumnTag";
        				}
                                }
                                else
                                {
                                	throw "BadUserID";
                                }
         		}
        		else
        		{
      				// If we get here, either Facebook changed something or the page isn't fully loaded yet.
      				// Either way, we need to exit.

      				GM_log("Unable to find left column. Try again... ");
      				
      				// Increase error counter by 1
      				SCRIPT.errors += 1;
      				
      				// If that error occured over 10 times, something has change, so alert user
      				if(SCRIPT.errors == 10)
      				{
      					throw "DetectionErrors";
      				}
      				
      				return;
        		}
        	}
        	// Catch if anything went wrong
                catch(err)
                {
      			// Disable timer
                        clearInterval(SCRIPT.Interval);

			// ultra lame way of preventing the script from bugging the user more than once...
			document.body.innerHTML = "<div id='FBUserID'></div>" + document.body.innerHTML;

                    	// Brief user
                    	var answer = confirm('Unable to find user ID or insert menu link.\n\nFacebook probably changed something and an updated script might fix that. Do you want to check for an update?');
                    	if(answer)
                    	{
                    		updateScript();
                    	}
                    	else
                    	{
                    		alert('Since this script will no longer work and you do not want to update, you should deactivate this script to prevent further messages!');
                    	}
      		}
        }
}


function updateScript()
{
	try
	{
		if (!GM_getValue)
		{
			return;
		}

		GM_xmlhttpRequest(
		{
        		method: 'GET',
        		url: SCRIPT.url + '?source',
        		onload: function(result)
        		{
        			if (result.status != 200 || !result.responseText.match(/@time\s+([\d.]+)/))        			
        			{
        				alert('Unknown answer received while checking for update!\n\nTaking you to ' + SCRIPT.home + ' so you can download the newer script.');
        				window.location.href = SCRIPT.home;
        				return;
        			}
        		        var theOtherTime = parseInt(RegExp.$1);
        		        var runningTime = parseInt(SCRIPT.time);
        		        var theOtherDate = parseInt(result.responseText.match(/@date\s+([\d.]+)/)? RegExp.$1 : '');
        		        if (theOtherTime > runningTime && theOtherDate >= parseInt(SCRIPT.date))
        		        {
        				if (window.confirm('Version ' + theOtherDate + ' build ' + theOtherTime + ' is available!\n\n' + 'Do you want to upgrade?' + '\n'))
        				{
        					window.location.href = SCRIPT.url;
        				}
        			}
        			else
        			{
        				alert('You already have the latest version.');
        				return;
        		        }
        		}
		}
		);
	}
	catch (err)
	{
        	alert('Unknown problem occured while checking for update!\n\nTaking you to ' + SCRIPT.home + ' so you can download the newer script.');
		window.location.href = SCRIPT.home;
	} 
}


/**
*
*  Base64 encode / decode
*  http://www.webtoolkit.info/
*
**/
 
var Base64 = {
 
	// private property
	_keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
 
	// public method for encoding
	encode : function (input) {
		var output = "";
		var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
		var i = 0;
 
		input = Base64._utf8_encode(input);
 
		while (i < input.length) {
 
			chr1 = input.charCodeAt(i++);
			chr2 = input.charCodeAt(i++);
			chr3 = input.charCodeAt(i++);
 
			enc1 = chr1 >> 2;
			enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
			enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
			enc4 = chr3 & 63;
 
			if (isNaN(chr2)) {
				enc3 = enc4 = 64;
			} else if (isNaN(chr3)) {
				enc4 = 64;
			}
 
			output = output +
			this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
			this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);
 
		}
 
		return output;
	},
 
	// public method for decoding
	decode : function (input) {
		var output = "";
		var chr1, chr2, chr3;
		var enc1, enc2, enc3, enc4;
		var i = 0;
 
		input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
 
		while (i < input.length) {
 
			enc1 = this._keyStr.indexOf(input.charAt(i++));
			enc2 = this._keyStr.indexOf(input.charAt(i++));
			enc3 = this._keyStr.indexOf(input.charAt(i++));
			enc4 = this._keyStr.indexOf(input.charAt(i++));
 
			chr1 = (enc1 << 2) | (enc2 >> 4);
			chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
			chr3 = ((enc3 & 3) << 6) | enc4;
 
			output = output + String.fromCharCode(chr1);
 
			if (enc3 != 64) {
				output = output + String.fromCharCode(chr2);
			}
			if (enc4 != 64) {
				output = output + String.fromCharCode(chr3);
			}
 
		}
 
		output = Base64._utf8_decode(output);
 
		return output;
 
	},
 
	// private method for UTF-8 encoding
	_utf8_encode : function (string) {
		string = string.replace(/\r\n/g,"\n");
		var utftext = "";
 
		for (var n = 0; n < string.length; n++) {
 
			var c = string.charCodeAt(n);
 
			if (c < 128) {
				utftext += String.fromCharCode(c);
			}
			else if((c > 127) && (c < 2048)) {
				utftext += String.fromCharCode((c >> 6) | 192);
				utftext += String.fromCharCode((c & 63) | 128);
			}
			else {
				utftext += String.fromCharCode((c >> 12) | 224);
				utftext += String.fromCharCode(((c >> 6) & 63) | 128);
				utftext += String.fromCharCode((c & 63) | 128);
			}
 
		}
 
		return utftext;
	},
 
	// private method for UTF-8 decoding
	_utf8_decode : function (utftext) {
		var string = "";
		var i = 0;
		var c = c1 = c2 = 0;
 
		while ( i < utftext.length ) {
 
			c = utftext.charCodeAt(i);
 
			if (c < 128) {
				string += String.fromCharCode(c);
				i++;
			}
			else if((c > 191) && (c < 224)) {
				c2 = utftext.charCodeAt(i+1);
				string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
				i += 2;
			}
			else {
				c2 = utftext.charCodeAt(i+1);
				c3 = utftext.charCodeAt(i+2);
				string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
				i += 3;
			}
 
		}
 
		return string;
	}
 
}