Unfollow non-followers on Twitter (or unfollow everyone)

Here is a JavaScript code to stop following those ones who are not following you back (of unfollow everyone, if you want to) on Twitter and keeping those you want: https://gist.github.com/jalbam/d7678c32b6f029c602c0bfb2a72e0c26

This will work for new Twitter web site code structure (it was changed from July 2019, causing other unfollow-scripts to stop working).

Instructions:

  1. The code may need to be modified depending on the language of your Twitter web site:
    • For English language web site, no modification needed.
    • For Spanish language web site, remember to set the ‘LANGUAGE’ variable to “ES”.
    • For another language, remember to set the ‘LANGUAGE’ variable to that language and modify the ‘WORDS’ object to add the words in that language.
  2. Optionally, you can edit the ‘SKIP_USERS’ array to insert those users that you do not want to unfollow (even if they are not following you back).
  3. If you want to follow everyone (except the users in ‘SKIP_USERS‘), including those who are following you, just set the ‘UNFOLLOW_FOLLOWERS‘ variable to true.
  4. You can set the milliseconds per cycle (each call to the ‘performUnfollow‘ function) by modifying the ‘MS_PER_CYCLE‘ variable.
  5. If desired, set a number to the ‘MAXIMUM_UNFOLLOW_ACTIONS_PER_CYCLE‘ variable to establish a maximum of unfollow actions to perform for each cycle (each call to the ‘performUnfollow’ function). Set to null to have no limit.
  6. If desired, set a number to the ‘MAXIMUM_UNFOLLOW_ACTIONS_TOTAL‘ variable to establish a maximum of unfollow actions to perform in total for all cycles (all calls to the ‘performUnfollow’ function). Set to null to have no limit.
  7. When the code is fine, on Twitter web site, go to the section where it shows all the people you are following (https://twitter.com/YOUR_USERNAME_HERE/following).
  8. Once there, open the JavaScript console (F12 key, normally), paste all the code there and press enter.
  9. If something goes wrong or some users were not unfollowed, reload the page and repeat from the step 8 again.

NOTE: STILL NOT SURE ABOUT THE TEXT IN THE CONFIRMATION BUTTON FOR ENGLISH LANGUAGE. LET ME KNOW OR MODIFY IT BY YOURSELF TO THE CORRECT ONE IF NEEDED!

Gist by Joan Alba Maldonado: https://gist.github.com/jalbam/d7678c32b6f029c602c0bfb2a72e0c26

Code:

/*
	Unfollow (stop following) those people who are not following you back on Twitter (or unfollow everyone if desired).
	
	This will work for new Twitter web site code structure (it was changed from July 2019, causing other unfollow-scripts to stop working).
	
	Instructions:
	1) The code may need to be modified depending on the language of your Twitter web site:
		* For English language web site, no modification needed.
		* For Spanish language web site, remember to set the 'LANGUAGE' variable to "ES".
		* For another language, remember to set the 'LANGUAGE' variable to that language and modify the 'WORDS' object to add the words in that language.
	2) Optionally, you can edit the 'SKIP_USERS' array to insert those users that you do not want to unfollow (even if they are not following you back).
	3) If you want to follow everyone (except the users in 'SKIP_USERS'), including those who are following you, just set the 'UNFOLLOW_FOLLOWERS' variable to 'true'.
	4) You can set the milliseconds per cycle (each call to the 'performUnfollow' function) by modifying the 'MS_PER_CYCLE' variable.
	5) If desired, set a number to the 'MAXIMUM_UNFOLLOW_ACTIONS_PER_CYCLE' variable to establish a maximum of unfollow actions to perform for each cycle (each call to the 'performUnfollow' function). Set to null to have no limit.
	6) If desired, set a number to the 'MAXIMUM_UNFOLLOW_ACTIONS_TOTAL' variable to establish a maximum of unfollow actions to perform in total for all cycles (all calls to the 'performUnfollow' function). Set to null to have no limit.
	7) When the code is fine, on Twitter web site, go to the section where it shows all the people you are following (https://twitter.com/YOUR_USERNAME_HERE/following).
	8) Once there, open the JavaScript console (F12 key, normally), paste all the code there and press enter.
	9) Wait until you see it has finished. If something goes wrong or some users were not unfollowed, reload the page and repeat from the step 8 again.
	
	* Gist by Joan Alba Maldonado: https://gist.github.com/jalbam/d7678c32b6f029c602c0bfb2a72e0c26
*/


var LANGUAGE = "EN"; //NOTE: change it to use your language!
var WORDS =
{
	//English language:
	EN:
	{
		followsYouText: "Follows you", //Text that informs that follows you.
		followingButtonText: "Following", //Text of the "Following" button.
		confirmationButtonText: "Unfollow" //Text of the confirmation button. I am not totally sure.
	},
	//Spanish language:
	ES:
	{
		followsYouText: "Te sigue", //Text that informs that follows you.
		followingButtonText: "Siguiendo", //Text of the "Following" button.
		confirmationButtonText: "Dejar de seguir" //Text of the confirmation button. I am not totally sure.
	}
	//NOTE: if needed, add your language here...
}
var UNFOLLOW_FOLLOWERS = false; //If set to true, it will also remove followers (unless they are skipped).
var MS_PER_CYCLE = 10; //Milliseconds per cycle (each call to 'performUnfollow').
var MAXIMUM_UNFOLLOW_ACTIONS_PER_CYCLE = null; //Maximum of unfollow actions to perform, per cycle (each call to 'performUnfollow'). Set to 'null' to have no limit.
var MAXIMUM_UNFOLLOW_ACTIONS_TOTAL = null; //Maximum of unfollow actions to perform, in total (among all calls to 'performUnfollow'). Set to 'null' to have no limit.
var SKIP_USERS = //Users that we do not want to unfollow (even if they are not following you back):
[
	//Place the user names that you want to skip here (they will not be unfollowed):
	"user_name_to_skip_example_1",
	"user_name_to_skip_example_2",
	"user_name_to_skip_example_3"
];
SKIP_USERS.forEach(function(value, index) { SKIP_USERS[index] = value.toLowerCase(); }); //Transforms all the user names to lower case as it will be case insensitive.

var _UNFOLLOWED_TOTAL = 0; //Keeps the number of total unfollow actions performed. Read-only (do not modify).

//Function that unfollows non-followers on Twitter:
var performUnfollow = function(followsYouText, followingButtonText, confirmationButtonText, unfollowFollowers, maximumUnfollowActionsPerCycle, maximumUnfollowActionsTotal)
{
	var unfollowed = 0;
	followsYouText = followsYouText || WORDS.EN.followsYouText; //Text that informs that follows you.
	followingButtonText = followingButtonText || WORDS.EN.followingButtonText; //Text of the "Following" button.
	confirmationButtonText = confirmationButtonText || WORDS.EN.confirmationButtonText; //Text of the confirmation button.
	unfollowFollowers = typeof(unfollowFollowers) === "undefined" || unfollowFollowers === null ? UNFOLLOW_FOLLOWERS : unfollowFollowers;
	maximumUnfollowActionsTotal = maximumUnfollowActionsTotal === null || !isNaN(parseInt(maximumUnfollowActionsTotal)) ? maximumUnfollowActionsTotal : MAXIMUM_UNFOLLOW_ACTIONS_TOTAL || null;
	maximumUnfollowActionsTotal = !isNaN(parseInt(maximumUnfollowActionsTotal)) ? parseInt(maximumUnfollowActionsTotal) : null;
	maximumUnfollowActionsPerCycle = maximumUnfollowActionsPerCycle === null || !isNaN(parseInt(maximumUnfollowActionsPerCycle)) ? maximumUnfollowActionsPerCycle : MAXIMUM_UNFOLLOW_ACTIONS_PER_CYCLE || null;
	maximumUnfollowActionsPerCycle = !isNaN(parseInt(maximumUnfollowActionsPerCycle)) ? parseInt(maximumUnfollowActionsPerCycle) : null;
	
	//Looks through all the containers of each user:
	var totalLimitReached = false;
	var localLimitReached = false;
	var userContainers = document.querySelectorAll('[data-testid=UserCell]');
	Array.prototype.filter.call
	(
		userContainers,
		function(userContainer)
		{
			//If we have reached a limit previously, exits silently:
			if (totalLimitReached || localLimitReached) { return; }
			//If we have reached the maximum desired number of total unfollow actions, exits:
			else if (maximumUnfollowActionsTotal !== null && _UNFOLLOWED_TOTAL >= maximumUnfollowActionsTotal) { console.log("Exiting! Limit of unfollow actions in total reached: " + maximumUnfollowActionsTotal); totalLimitReached = true; return;  }
			//...otherwise, if we have reached the maximum desired number of local unfollow actions, exits:
			else if (maximumUnfollowActionsPerCycle !== null && unfollowed >= maximumUnfollowActionsPerCycle) { console.log("Exiting! Limit of unfollow actions per cycle reached: " + maximumUnfollowActionsPerCycle); localLimitReached = true; return;  }
			
			//Checks whether the user is following you:
			if (!unfollowFollowers)
			{
				var followsYou = false;
				Array.from(userContainer.querySelectorAll("*")).find
				(
					function(element)
					{
						if (element.textContent === followsYouText) { followsYou = true; }
					}
				);
			}
			else { followsYou = false; } //If we want to also unfollow followers, we consider it is not a follower.

			//If the user is not following you (or we also want to unfollow followers):
			if (!followsYou)
			{
				//Finds the user name and checks whether we want to skip this user or not:
				var skipUser = false;
				var userName = "";
				Array.from(userContainer.querySelectorAll("[href^='/']")).find
				(
					function (element)
					{
						if (element.href.indexOf("search?q=") !== -1 || element.href.indexOf("/") === -1) { return; }
						userName = element.href.substring(element.href.lastIndexOf("/") + 1).toLowerCase();
						Array.from(element.querySelectorAll("*")).find
						(
							function (subElement)
							{
								if (subElement.textContent.toLowerCase() === "@" + userName)
								{
									if (SKIP_USERS.indexOf(userName) !== -1)
									{
										console.log("We want to skip: " + userName);
										skipUser = true;
									}
								}
							}
						);
						if (skipUser) { return; }
					}
				);
				
				//If we do not want to skip the user:
				if (!skipUser)
				{
					//Finds the unfollow button:
					Array.from(userContainer.querySelectorAll('[role=button]')).find
					(
						function(element)
						{
							//If the unfollow button is found, clicks it:
							if (element.textContent === followingButtonText)
							{
								console.log("* Unfollowing: " + userName);
								element.click();
								unfollowed++;
								_UNFOLLOWED_TOTAL++;
							}
						}
					);
				}
			}
		}
	);
	
	//If there is a confirmation dialog, press it automatically:
	Array.from(document.querySelectorAll('[role=button]')).find //Finds the confirmation button.
	(
		function(element)
		{
			//If the confirmation button is found, clicks it:
			if (element.textContent === confirmationButtonText)
			{
				element.click();
			}
		}
	);
	
	return totalLimitReached ? null : unfollowed; //If the total limit has been reached, returns null. Otherwise, returns the number of unfollowed people.
}


//Scrolls and unfollows non-followers, constantly:
var scrollAndUnfollow = function()
{
	window.scrollTo(0, document.body.scrollHeight);
	var unfollowed = performUnfollow(WORDS[LANGUAGE].followsYouText, WORDS[LANGUAGE].followingButtonText, WORDS[LANGUAGE].confirmationButtonText, UNFOLLOW_FOLLOWERS, MAXIMUM_UNFOLLOW_ACTIONS_PER_CYCLE, MAXIMUM_UNFOLLOW_ACTIONS_TOTAL); //For English, you can try to call it without parameters.
	if (unfollowed !== null) { setTimeout(scrollAndUnfollow, MS_PER_CYCLE); }
	else { console.log("Total desire of unfollow actions performed!"); }
};
scrollAndUnfollow();

Thank you very much. Any comments are welcome.

AutoHotkey mouse scripts – Play games without a keyboard (on a tablet, for example)

Here you have simple AutoHotkey scripts that will perform some actions by using the mouse.

I made these scripts for myself to be able to play some games in a tablet which lacks of a physical keyboard but has a mouse attached. This way I can exit the games, show their menus, show an on-screen keyboard (which does not work well with some games when they are running in full-screen mode, sadly), etc. by just using the mouse.

Hopefully, they could also be useful for someone else so I decided to share them.

They were tested on both 32 and 64-bit version of Microsoft Windows 10 (tablet and desktop) as well as on 32-bit versions of Microsoft Windows XP (with Service Pack 1) and Microsoft Windows 7. If, after trying a binariy (32-bit version and also 64-bit versions if any), it does not work on your Windows version then you can try to compile it from the source code provided. Please, have in mind that not all Windows versions have “tabtip.exe” or “osk.exe” files.

They can be found on GitHub: https://github.com/jalbam/AutoHotkey_mouse_scripts

Included scripts

pressEsc_32 – It will press the “ESC” (ESCAPE) key when the mouse wheel button (the middle button) is pressed. Compiled for 32-bit but it should also run on 64-bit versions of Microsoft Windows.

pressF5_32 – It will press the “F5” key when the mouse wheel button (the middle button) is pressed. Compiled for 32-bit but it should also run on 64-bit versions of Microsoft Windows.

pressF10_32 – It will press the “F10” key when the mouse wheel button (the middle button) is pressed. Compiled for 32-bit but it should also run on 64-bit versions of Microsoft Windows.

showOSK_32 – If available in the operating system, it will show the “OSK” (osk.exe) which belongs to the “On Screen Keyboard” (“floating” around the screen, as an independent window) when the mouse wheel button (the middle button) is pressed. Compiled for 32-bit.

showOSK_64 – The same as “showOSK_32” but for 64-bit versions of Microsoft Windows. Use it in the case that you get an error using the “showOSK_32” version.

showTabTip_32 – If available in the operating system, it will show the “TabTip” (tabtip.exe) which also belongs to an on-screen keyboad (different from the “osk.exe” one) when the mouse wheel button (the middle button) is pressed. Compiled for 32-bit.

showTabTip_64 – The same as “showTabTip_32” but for 64-bit versions of Microsoft Windows. Use it in the case that you get an error using the “showTabTip_32” version.

How to run

To use the already-compiled binaries, just run them as any other normal program. While they are running, an icon will be shown in the taskbar.

Note that, if desired, more than one script can be run at the same time to be combined.

Compile from the source code

Apart from the binaries for Microsoft Windows, the source code is included so they can be easily modified to edit the actions performed, enhance features, etc.

To compile from the source code, the AutoHotkey software will be needed.

License

This project can be used, reproduced, distributed and modified freely for any non-commercial purposes but always keeping the author’s name and copyright clauses. Other than that, just use this project as you wish but never sell it!

NW.js port for Raspberry Pi

There is a NW.js (formerly node-webkit) binary compiled for the ARMv6 used by Raspberry Pi. It also runs on Raspberry Pi 2 and Raspberry Pi 3 since they are backward compatible with ARMv6. Other compatible hardware should also be able to run this binary.

It can be found on GitHub: https://github.com/jalbam/nwjs_rpi

Instructions

  1. You need a package.nw which is just a .zip file with .nw extension that contains your project (at least, it needs an index.html and a package.json inside). The included package.nw is just an example using the Yasminoku game. Since this is only a port, if you need it you can go to the official web site of NW.js and read the documentation to know more about package.nw, package.json, etc.
  2. Optional: merge nw and package.nw into a single file with the following command:
cat nw package.nw > Your_new_binary_file
  1. Edit fix_libudev.so.0 and fix_libudev.so.1 and replace Your_new_binary_file found in their code by the real name of your binary file (if you did not merge nw and package.nw together, then replace it by just nw).
  2. If you need it, give executable permissions (and other desired permissions) to Your_new_binary_file (or nw) using the chmod command (as root).
  3. Try to run the binary:
./Your_new_binary_file

If you did not merge the nw and package.nw files in one single file (as explained in step 2), you should run this command instead:

./nw
  1. In the case the system complains about libudev.so.0 when you try to run the binary, just type the following command:
./fix_libudev.so.0

Likewise, if needed, do the same for libudev.so.1 running this:

./fix_libudev.so.1

Note: these two commands above will only work if you have followed the step 3 properly before. Each of them only needs to be executed once and never again.

  1. If all works well, you can distribute your project. You will need these files at least (in the same folder): libffmpegsumo.so, nw.pak and Your_new_binary_file (or nw and package.nw instead). I would recommend including fix_libudev.so.0 and fix_libudev.so.1 optionally (modified as explained in step 3) if you think others might need them.

Versions

node-webkit (now called NW.js) version: v.0.7.0-pre

Node.js version: v0.10.12

Tested on

  • Raspberry Pi Model B Revision 2.0 Mounting holes” with 512MB RAM (000e revision) using Raspbian GNU/Linux 7 “wheezy” (Linux raspberrypi 4.1.19+ #858 armv6l GNU/Linux).
  • Raspberry Pi 2 Model B PCB Revision 1.1″ with 1024MB RAM (a01041 revision) using Raspbian GNU/Linux 8 “jessie” (Linux raspberrypi 4.9.35-v7+ #1014 SMP armv7l GNU/Linux).
  • Raspberry Pi 3 Model B PCB Revision 1.2″ with 1024MB RAM (a02082 revision) using Raspbian GNU/Linux 8 “jessie” (Linux raspberrypi 4.1.19-v7+ #858 SMP armv7l GNU/Linux).
  • Raspberry Pi Zero W PCB Revision 1.1″ with 512MB RAM (9000c1 revision) using Raspbian GNU/Linux 9 “stretch” (Linux raspberrypi 4.14.71+ #1145 SMP armv6l GNU/Linux).
  • Raspberry Pi 3 Model B+ PCB Revision 1.3″ with 1024MB RAM (a020d3 revision) using Raspbian GNU/Linux 9 “stretch” (Linux raspberrypi 4.14.71-v7+ #1145 SMP armv7l GNU/Linux).
  • Orange Pi Zero (Allwinner H2+)” with 512MB RAM (hardware sun8i, 0000 revision) using Raspbian GNU/Linux 8 “jessie” (Linux OrangePizero 3.4.39 #2 SMP PREEMPT armv7l GNU/Linux).
  • Orange Pi Zero Plus2 (Allwinner H3)” with 512MB RAM (hardware sun8i, 0000 revision) using Raspbian GNU/Linux 8 “jessie” (Linux OrangePI 3.4.112-opi #1 SMP PREEMPT armv7l GNU/Linux).

Compatibility

  • Raspberry Pi Zero, all models
  • Raspberry Pi, all models
  • Raspberry Pi 2, all models
  • Raspberry Pi 3, all models
  • Other devices with compatible hardware (Orange Pi, Banana Pi, etc.)

Credits

The original binary was shared by Nils Måsén “piksel” (aka “spaculo”) at https://www.youtube.com/watch?v=MqNUYk9Y8jY so thank you very much! 🙂

sockjs_test_server_nwjs – SockJS test server on NW.js

sockjs_test_server_nwjs” is just a simple SockJS server running on Node.js but using NW.js (formerly node-webkit) to provide a simple visual interface for testing purposes. It was made on 29th July 2016 (approximately).

Screenshot

The default listening port is set to 9999 but can be modified easily.

It comes with a self-extracting single-file binary for Windows 32-bit (using 7zip‘s SFX) that runs on Windows XP with SP2 (Service Pack 2) minimum and also on newer Windows versions as Windows 10 (generated with Web2Executable) but also includes the source code so it can be ported to other platforms supported by NW.js easily.

It can be found on GitHub: https://github.com/jalbam/sockjs_test_server_nwjs

fake_rest_server – REST server in PHP

fake_rest_server” is a simple and easy-to-configure REST server made in PHP.

I made it just to create different REST servers very fast for testing purposes. It was made on 12th May 2016 (approximately).

It can be found on GitHub: https://github.com/jalbam/fake_rest_server

Configuring the server

To add new paths (routes) and methods, the developer just needs to create a new folder structure (folder and subfolders if needed) which represents the route and inside one file per method named [method_desired].php (for example, put.php).

To start developing your REST server, you will only need to download the files inside the src/ folder.

You may want to take a look at the src/_code/functions.php file (the engine will include it automatically) as it provides some basic but useful functions. There you can also add new functions or modify the existing ones.

If you want to add data, you can use the src/_code/data/data.php file (automatically included by the engine).

If you want to add configuration data, you can use the src/_code/config.php file (automatically included by the engine).

As the engine defines the USING_REST_SERVER constant, you can protect any of the files with the following line at the beginning:

<?php if (!defined("USING_REST_SERVER") || !USING_REST_SERVER) { return; } ?>

Note: this authorization code above is also defined in the AUTHORIZATION_CODE constant (inside the the src/_code/config.php file).

Example:

1) In the root folder (where the src/_code/ folder and the src/index.php file are placed), create a folder called myRESTService/.

2) Inside the myRESTService/ folder we have just created, create another folder called user/ and inside of it create two files: index.php and get.php.

3) Inside the myRESTService/user/index.php file, place the following code:

<?php
  //Users info (this could be in the "src/_code/config.php" file, but it is just an example):
  $usersData = Array
  (
    //User IDs:
    "1" =>
      Array
      (
        "name" => "John Doe",
        "favouriteFood" => "meat"
      ),
    "2" =>
      Array
      (
        "name" => "Joan Alba Maldonado",
        "favouriteFood" => "pizza"
      )
  );
  
  //Gets the data needed which has been sent through the REST client:
  $userId = getVariable("id"); //"getVariable" and other functions available in the "src/_code/functions.php" file.

4) Inside the myRESTService/user/get.php file put the following code:

<?php
  if ($userId === "") { echo "No id sent!"; }
  else if (array_key_exists($userId, $usersData))
  {
    echo $usersData[$userId]["name"] . " likes eating " . $usersData[$userId]["favouriteFood"];
  }
  else { echo "User cannot be found! (id=" . $userId . ")"; }

5) With this, we will have our REST server configured with the myRESTService/user/ route, accepting the GET method with the id parameter. This example can be found in the example_easy/ folder.

Testing the server

If you do not have a REST client, the server can be tested on any web browser by adding the debug=1 parameter to the URL as well as the method parameter with the method desired (not needed if the method is GET), as for example: http://localhost/fake_rest_server/src/index.php/route_1/subroute?method=post&debug=1&username=Joan

Following the example above, you can use a web browser to visit the following links:

http://localhost/route_to_the_REST_server/index.php/myRESTService/user/?method=get&debug=1&id=1 (it should show “John Doe likes eating meat”)

http://localhost/route_to_the_REST_server/index.php/myRESTService/user/?method=get&debug=1&id=2 (it should show “Joan Alba Maldonado likes eating pizza”)

http://localhost/route_to_the_REST_server/index.php/myRESTService/user/?method=get&debug=1&id=3 (it should show “User cannot be found! (id=3)”)

http://localhost/route_to_the_REST_server/index.php/myRESTService/user/?method=get&debug=1 (it should show “No id sent!”)

Note that the “/” character at the end of the route is optional.

Final comments

It is very easy to extend using PHP language. The project already includes some examples with routes, methods, functions and data as user accounts, etc. as examples (in both the example/ and the example_easy/ folder) but they can be deleted.

The only really-needed code is located in the src/ folder. Inside of it, the route_1/ folder and all of its content can also be deleted since it is just an example.

License

This project can be used, reproduced, distributed and modified freely for any non-commercial purposes but always keeping the author’s name and copyright clauses. Other than that, just use this project as you wish but never sell it!

EASPM123 – Get rid of spam emails!

EASPM123 (Email Anti-Spam 123) is an Easy-to-use JavaScript API that protects any email address you want to use in your website from spambots. First version (1.0) was released in November 2015.

It works in any browser with JavaScript support, even old ones (including Internet Explorer 5.0), offers different security options (very configurable) and it is just 2.57 KiB minified. If you want, you can easily configure it to be used with many languages at the same time.

Despite of this, this script should consider as a way to improve safety against spambots but not the unique method. A good anti-spam for your email (server or client) is still always recommended.

It can be found on GitHub: https://github.com/jalbam/easpm123

Basic idea

The basic idea is to disguise the email address by modifying it using a text that will be removed by the script when the desired JavaScript events are fired (or, if desired, automatically when the document is loaded).

Most spambots will not fire those JavaScript events or, even if they did it, many of the times will not catch the email address after doing it but the previously-shown email address (so they will end with a non-valid email address which includes the text that should have been removed).

The text to be removed should be human-understandable so that a human being could figure out the real email in the case that JavaScript was disabled or something failed. Under these circumstances, to help any human-being to figure out the real email address, this script uses the so-called “without-no-spam” elements which are elements containing the instructions that the human-being should follow to get the real email address. These “without-no-spam” elements will be removed automatically by the script if JavaScript is available.

As nowadays many spambots can already translate “AT” and “DOT” to “@” and “.” respetively, to improve safety this script provides a way to translate any desired text to the AT (@) symbol. The key here is to use a non-so-famous text that no spambot will understand at all.

There are different ways to use this script detailed below, some safer than others. Please, continue reading.

Usage

You can download the project from GitHub directly to include it in your project or you can also use one of the following commands while you are in your project:

Bower:

bower install easpm123

Yarn:

yarn add easpm123

npm (it will need a package.json):

npm i easpm123

The behaviour can be configured easily through the main (and unique) object the script uses (for more information, you can read the instructions in README.htm). But if you are lazy, although it would be less safe, you just need to include the .js file in your website and change the class name (or add to the current classes a new one) of the elements containing the links to the emails (the class name should be “easpm123” by default).

In order to start using this API, the “.js” file you choose (for example, easpm123_min.js which is already minified) must be included in your document. The most common way to do this is by using a tag:

<!-- NOTE: Edit the "src" property to point to the right location of the .js file: -->
<script src="easpm123_min.js" type="text/javascript" language="javascript"></script>

If we decide to use the main (and unique) object, this is how it looks like:

EASPM123
(
    autoLoad,
    //Next values can be set to null to force using default ones or use
    //an empty array if you do not want any value at all:
    linkClasses,
    withoutNoSpamElementClasses,
    linkIDs,
    withoutNoSpamElementIDs,
    textsToClear,
    atSymbolAliases,
    eventNames
);

The parameters accepted are the following ones:

Parameter Type Default value Mandatory? Description
autoLoad boolean true No If it is set to true, the script will be loaded automatically (the run method will not be needed to be called) when the document is ready. If it is set to false, all the rest of parameters will be ignored and they will need to be used in the run method instead.
linkClasses array of strings [“easpm123”] No Class names used by the tags (which contain a link to an email address) that will be affected.
withoutNoSpamElementClasses array of strings [“easpm123_label”] No Class names of the “without-no-spam” elements that will be removed.
linkIDs array of strings [“easpm123”] No IDs used by the tags (which contain a link to an email address) that will be affected.
withoutNoSpamElementIDs array of strings [“easpm123_label”] No IDs used by the “without-no-spam” elements that will be removed.
textsToClear array of strings [“NO_SPAM_WELCOME”] No Texts to be removed (case sensitive) from the email address.
atSymbolAliases array of strings [“{AT_HERE}”] No Texts that will be replaced by the AT (@) symbol.
eventNames array of strings [“mouseover”, “click”, “touchstart”] No Events that will fire the script. Those events will be attached to all affected tags (which contain a link to an email address) and also to all the affected “without-no-spam” elements. Use an empty array to run the script automatically without events.

Note that, except for the first parameter (autoLoad), all the rest of the parameters can accept the null value if we want to use their default value or can also accept an empty array (as for example the [] value) in the case that we do not want any value at all. In the case of the last parameter (eventNames), using an empty array will force the script to run its magic automatically without having to fire any event (not recommended as the safety would be decreased).

If the autoLoad parameter is set to false (not recommended), the rest of parameters will be ignored and the run method will have to be called manually when desired (always after the document has been loaded!). This method accepts the same parameters as the main object except the first one (it does not need the autoLoad parameter). Read below to see an example showing how to use it.

Have in mind that, as soon as the script is included, it will run itself once with the default options. We can run it again (through either the main object or the run method), if desired, after that.

The main object can only be used before the onload event of the window object is fired. If we want to run the script after that, we need to use the run method instead. In fact, the run method can only be used after the onload event of the window object is fired.

See the examples below for more information.

Example #1 – Easiest way for the developer (not so safe), with just HTML:

Note that, after the script is included, it immediately modifies the onload event of the window object (keeping any previous event, so it will not override anything) to execute itself after some milliseconds (it does not do it immediately to get rid of some spambots which will not have this into account). If, during the time between the inclusion of the script and the milliseconds (100 by default) before its executed itself, the onload event of the window object is overrided, this example will simply not work.

This way, any tag whose id is easpm123 or class property contains the easpm123 class, will be affected. The default text to remove from the email will be “NO_SPAM_WELCOME” and the “{AT_HERE}” text will be replaced by the AT (@) symbol.

The text inside of the elements whose id is easpm123_label or class property contains the easpm123_label class will be removed automatically when the page loads. These elements are called “without-no-spam” elements and are useful for the users when JavaScript is not available.

The real email address will be shown when the user is over or clicks or taps the email link (the tag described above).

HTML:

<!-- Using ID: -->
<a id="easpm123" href="mailto:email{*AT_HERE*}NO_SPAM_WELCOMEexample.com">email{*AT_HERE*}<del style="text-decoration:line-through;"><s>NO_SPAM_WELCOME</s></del>example.com</a>
<span id="easpm123_label">(without NO_SPAM_WELCOME)</span>
<br />
<!-- Using class: -->
<a class="easpm123" href="mailto:email{*AT_HERE*}NO_SPAM_WELCOMEexample.com">email{*AT_HERE*}<del style="text-decoration:line-through;"><s>NO_SPAM_WELCOME</s></del>example.com</a>
<span class="easpm123_label">(without NO_SPAM_WELCOME)</span>

Example #2 – Easiest way for the user (very unsafe), with a bit of JavaScript and HTML:

This methods needs a little bit of JavaScript (using an empty array as the eventNames parameter) but will not need any event fired by the user. The script and its magic will be performed automatically. The users can be happier this way but some spambots will be too. Safety wise, this method is not recommended.

As we are using the main object, this must be run before the onload event of the window object is fired.

JavaScript:

EASPM123(true, null, null, null, null, null, null, [] /* eventNames */);

HTML:

Use the same HTML code from the Example #1.

Example #3 – Second easiest way for the user (still unsafe), with a bit of JavaScript and HTML:

This will be little bit safer than the Example #2 as we change default values by the desired ones. Different IDs and class names have been used just to show how it works.

As we are using the main object, this must be run before the onload event of the window object is fired.

JavaScript:

EASPM123
(
    true, //autoLoad.
    ["class_email_link", "class_email_link2"], //linkClasses.
    ["class_without_no_spam_label", "class_without_no_spam_label2"], //withoutNoSpamElementClasses.
    ["id_email_link", "id_email_link2"], //linkIDs.
    ["id_without_no_spam_label", "id_without_no_spam_label2"], //withoutNoSpamElementIDs.
    ["WITHOUT_THIS_TEXT", "TAKE_THIS_OUT"], //textsToClear
    ["[PUT_AT_HERE]", "{HERE_AN_AT_SYMBOL}"], //atSymbolAliases.
    [] //eventNames.
);

HTML:

<!-- Using ID: -->
<a id="id_email_link" href="mailto:email[PUT_AT_HERE]WITHOUT_THIS_TEXTexample.com">email[PUT_AT_HERE]<del style="text-decoration:line-through;"><s>WITHOUT_THIS_TEXT</s></del>example.com</a>
<span id="id_without_no_spam_label">(without NO_SPAM_WELCOME)</span>
<br />
<a id="id_email_link2" href="mailto:email[PUT_AT_HERE]WITHOUT_THIS_TEXTexample.com">email[PUT_AT_HERE]<del style="text-decoration:line-through;"><s>WITHOUT_THIS_TEXT</s></del>example.com</a>
<span id="id_without_no_spam_label2">(without NO_SPAM_WELCOME)</span>
<br />
<!-- Using class: -->
<a class="class_email_link" href="mailto:email{HERE_AN_AT_SYMBOL}TAKE_THIS_OUTexample.com">email{HERE_AN_AT_SYMBOL}<del style="text-decoration:line-through;"><s>TAKE_THIS_OUT</s></del>example.com</a>
<span class="class_without_no_spam_label">(without NO_SPAM_WELCOME)</span>
<br />
<a class="class_email_link2" href="mailto:email{HERE_AN_AT_SYMBOL}TAKE_THIS_OUTexample.com">email{HERE_AN_AT_SYMBOL}<del style="text-decoration:line-through;"><s>TAKE_THIS_OUT</s></del>example.com</a>
<span class="class_without_no_spam_label2">(without NO_SPAM_WELCOME)</span>

Example #4 – Not-so-easy way for the user (safer), with a bit more of JavaScript and HTML:

This is like the Example #3 but only firing the script under the default events (onmouseover, onclick and ontouchstart) and not automatically.

As we are using the main object, this must be run before the onload event of the window object is fired.

JavaScript:

EASPM123
(
    true, //autoLoad.
    ["class_email_link", "class_email_link2"], //linkClasses.
    ["class_without_no_spam_label", "class_without_no_spam_label2"], //withoutNoSpamElementClasses.
    ["id_email_link", "id_email_link2"], //linkIDs.
    ["id_without_no_spam_label", "id_without_no_spam_label2"], //withoutNoSpamElementIDs.
    ["WITHOUT_THIS_TEXT", "TAKE_THIS_OUT"], //textsToClear
    ["[PUT_AT_HERE]", "{HERE_AN_AT_SYMBOL}"], //atSymbolAliases.
);

HTML:

Use the same HTML code from the Example #3.

Example #5 – A little-bit-more-difficult way (a bit safer), with more JavaScript and HTML:

This is like the Example #4 but using the run method instead of the main object. So instead of running the script automatically we will do it manually.

Note that the main object must be used before the onload event of the window object is fired but the run method must be run after that.

For safety purposes, the main object waits by default 100 milliseconds before it runs the script automatically. In this example we will wait a little bit more to add even more safety.

JavaScript:

setTimeout
(
    function()
    {
        EASPM123.run
        (
            ["class_email_link", "class_email_link2"], //linkClasses.
            ["class_without_no_spam_label", "class_without_no_spam_label2"], //withoutNoSpamElementClasses.
            ["id_email_link", "id_email_link2"], //linkIDs.
            ["id_without_no_spam_label", "id_without_no_spam_label2"], //withoutNoSpamElementIDs.
            ["WITHOUT_THIS_TEXT", "TAKE_THIS_OUT"], //textsToClear
            ["[PUT_AT_HERE]", "{HERE_AN_AT_SYMBOL}"], //atSymbolAliases.
            []
        );
    },
    300
);

HTML:

Use the same HTML code from the Example #3.

Improving safety

To improve the safety and get rid of as many spambots as possible I recommend the following:

  1. Do not fire the script automatically (without needing events). So, do not do as the Example #2 or Example #3.
  2. Do not use the default values for the text which replaces the AT (@) symbol. Use your imagination to invent new ones. Look at the Example #4.
  3. Do not use the default values for the text which should be removed from the email address. Use your imagination to invent new ones. Look at the Example #4.
  4. Do not use the default values for the classes or IDs (for both, elements and the “without-no-spam” elements) and use your own ones. Look at the Example #4.
  5. Use the run method instead of the main object and call it some milliseconds after the onload event of the window object is fired. Look at the Example #5.
  6. Images or other elements instead of text can be used inside the “without-no-spam” elements to make it harder for the spambots to figure out the email address. Have in mind that some browsers can have images disabled or even some people could not see them properly.
  7. You can consider about using other events instead of the default ones to fire the script. That could, maybe, improve safety.
  8. If you are paranoid enough, you can consider using different ways to obfuscate the strings in the arrays used in the optional parameters and also use other ways of obfuscating. Again, use your own imagination.

Final comments

Following the instructions and some guidelines (included inside the package), the email addresses should be human-understandable even when JavaScript is disabled.

If you are tired of being spammed, you should try this little script (with an email address which spambots do not know yet!).

Live example: http://htmlpreview.github.io/?https://github.com/jalbam/easpm123/blob/master/test_min_eval.htm

License

Forbidden to use without keeping the author’s name and copyright clauses. Other than that, just use this script freely but never sell it!

Yasminoku – Sudoku game, generator and solver in JavaScript (July 2006)

“Yasminoku” is an open source Sudoku (game, generator and solver) totally written in DHTML (HTML, CSS and JavaScript).

Screenshot

It is my fifth DHTML game and was made in mid 2006.

The game will generate sudokus and the player will have to solve them. It is not only a normal sudoku game but also a sudoku solver, allowing users to introduce their own sudoku in order to solve it.

You can also change the game behaviour easily by editing many of the configuration variables which are at the beginning of the script.

This game doesn’t use any image at all, just pure HTML and CSS.

The game has been quite successful and famous, included for instance in a famous Spanish online newspaper called “Libertad Digital“.

Official languages are Spanish and English. You can find a lot of translations in other languages over the Internet, including German, French, Portuguese, Czech, Hungarian and Chinese.

Other modified and adapted versions of this game can be found on the Internet, including one Opera widget and several translations.

This game has been tested under BeOS, Linux, NetBSD, OpenBSD, FreeBSD, Windows, Mac OS X, BlackBerry Tablet OS, Android, iOS and others.

UPDATE (9th December 2014):

The new improved version (0.75a) comes with some bug fixes, using some CSS3 effects and HTML5, a better mobile devices support, autosave (using Web Storage and falling back to cookies if not supported), it is printer-friendly, it adapts automatically to any screen resolution (200 x 180 is the minimum), improves browser integration (can be included easily in any web site with an IFRAME, for example), is available for and ported to many platforms and can be ported to many more (it is compatible with Apache Cordova, PhoneGap Build, PhoneGap, Intel XDK, BlackBerry WebWorks, virtually any browser extension guidelines and so on), and is now multilingual with language auto-detection (main version includes Chinese, English, Catalan and Spanish languages and it is very easy to add new ones).

It can be controlled by mouse (or finger on mobile devices) and/or keyboard (gamepads on some devices as Wii or some remote control on some TV devices should also work).

Through the new configuration menu, you can choose language (in the case you are not happy with the auto-detected one), disable autosave, change the way the game helps you, set the number of seconds the on-the-fly calculated solution is displayed and disable some visual effects (in order to improve performance).

The game is specially designed to allow to be used inside any other web site (by using an IFRAME, for example). We just need to get the URL (which will be used in the SRC parameter of the IFRAME tag) generated by the “Share” option (inside the configuration menu). If we want to configure it even more, we can set or edit some parameters included in the generated URL (you can read more about it in the game’s website). You could even use another sudoku generator and send the generated sudoku to the game through a parameter of its URL.

Since you can choose the initial numbers, from 0 to 81, keep in mind that sometimes the game can generate sudokus with more than one solution.

Native ports that have been tested should work properly. Browser version will work virtually everywhere, in modern browsers as well as in old ones (including Internet Explorer 5.0).

Apart from the normal version (for web browsers), some ports and versions include Android (including Nokia X and Fire OS which is used by Amazon Kindle Fire, Amazon Fire TV, Amazon Fire TV, Fire Phone, etc.), iOS (iPhone, iPod Touch, iPad), BlackBerry 10, BlackBerry Tablet OS (BlackBerry PlayBook), Nokia Series 40 (S40) / WRT Widget, Nokia Asha widget / W3C Packaged Web App (W3C Widget), Windows Phone 7 & 8, Chrome OS / Chromium OS (Google Chrome App), Firefox OS (Mozilla Firefox App), Mozilla Firefox Add-on, Opera Extension (Opera add-on), Google Chrome extension, Safari extension, Microsoft Edge extension, WebOS, Facebook App, Windows 32 bit (including installer), Apple Mac OS X (Intel), Linux x86 (32 bit and 64 bit), Raspberry Pi and compatible (Linux as Raspbian or Pidora), etc.

To read more about how to use it in your web site, port it to other platforms, translate it to other languages, etc. please, refer to its official site below.

Play online in multiple languages: http://yasminoku.tuxfamily.org/new/online/

Play online in multiple languages (mirror): http://www.dhtmlgames.com/yasminoku/new/online/

Official web site: http://yasminoku.tuxfamily.org/ (mirror at http://www.dhtmlgames.com/yasminoku/).

The repository can be found on GitHub: https://github.com/jalbam/yasminoku