Use TypeScript over Flow, but try another language like ReasonML

Quoting @spcydnts:

“TypeScript is easier for me to recommend because the default project setup is good and the tooling is great. Flow might be easier to add to an existing project but it’s tricky to keep it reliable.

“If you can, use another language altogether. They end up being safer and simpler because typing all the common dynamic patterns in JS is very hard/impossible. My favorite is PureScript. Elm is also good but more niche in its uses and requires more boilerplate code. Reason is also looking pretty good and is less of a paradigm shift from JS.”

@bressain adds:

“If another language isn’t possible, I would argue that you’ll have a better time with TypeScript purely on a tooling support standpoint.”

How to Use MongoDB for Session Storage with Lithium

Step 1

Download this file to app/extensions/adapter/storage/session/Model.php

Step 2

Create a starter app/models/Sessions.php:

<?
namespace app\models;
class Sessions extends \lithium\data\Model {

}
?>

Step 3

Configure app/config/bootstrap/session.php to use the new extension:

Session::config(array(
 'cookie' => array('adapter' => 'Cookie', 'name' => $name),
 'default' => array('adapter' => 'Model', 'session.name' => $name, 'model' => 'Sessions')
 ));

Quickly deleting users from a Facebook group

(This is old. It probably doesn’t work on Facebook anymore.)

Facebook unfortunately requires one to first individually delete users from a group before one can effectively delete the group. If you have thousands of users, this is a pain. You can use the following bookmarklet (I’ve only tested it in Google Chrome) to quickly delete about 100 users. Unfortunately, WordPress.com does not allow me to have drag-and-drop bookmarklet links in my post, so you’ll have to follow these directions:

  1. Copy the text from here.
  2. Create a new bookmark in Google Chrome and paste the text into the URL.
  3. Go to the admin page that lists users from your Facebook group and click the bookmarklet.
  4. When you are directed to the next page of users, click it again.
  5. To speed up the process even more, use multiple tabs on different pages.

For those interested, here is the code (I minified it using YUI Compressor for the bookmarklet):

function confirmDeleteUser() {
	confirmButton = document.querySelector('.uiButton.uiButtonLarge.uiButtonConfirm input');
	if(!confirmButton) {
		setTimeout('deleteAllUsersInGroup()',200);
		return;
	}
	mouseClickEvent = document.createEvent('MouseEvent');
	mouseClickEvent.initMouseEvent('click',true,true);
	confirmButton.dispatchEvent(mouseClickEvent);
	setTimeout('deleteAllUsersInGroup()',200);
}

function switchPage() {
	pageButton = document.querySelector('.next.uiButton:not(.uiButtonDisabled)');
	if(!pageButton) {
		pageButton = document.querySelector('.prev.uiButton:not(.uiButtonDisabled)');
	}
	if(!pageButton) {
		return
	}
	mouseClickEvent = document.createEvent('MouseEvent');
	mouseClickEvent.initMouseEvent('click',true,true);
	pageButton.dispatchEvent(mouseClickEvent);
}

function deleteAllUsersInGroup() {
	/* I pick a random user to account for some quirks in the process */
	deleteButtons = document.querySelectorAll('a.UIImageBlock_Ext.uiCloseButton.uiCloseButtonSmall');
	if(!deleteButtons.length) {
		setTimeout('confirmDeleteUser()',500); /* Usually one last dialog to clear */
		setTimeout('switchPage()',1500);
		return;
	}
	deleteButton = deleteButtons.item(Math.floor(Math.random() * deleteButtons.length))
	mouseClickEvent = document.createEvent('MouseEvent');
	mouseClickEvent.initMouseEvent('click',true,true);
	deleteButton.dispatchEvent(mouseClickEvent);
	deleteButton.parentNode.parentNode.removeChild(deleteButton.parentNode)
	setTimeout('confirmDeleteUser()',200);
};
deleteAllUsersInGroup();