PHP Benchmark: The array plus operator VS array_merge

Posted: August 13th, 2011 | Author: | Filed under: PHP | Tags: , , , | No Comments »

Just a quick post about a benchmark that quite surprised me. The array plus operator ($arr1 + $arr2) is over 6 times faster compared to array_merge. I did expect that to be faster, but not that much. This is the benchmark I used:

nadav@shesek:~$ time php -r '$x=array("x"=>1, "y"=>2); $y = array("y"=>3, "z"=>4);
> for ($i=1; $i<=500000; $i++) { $y + $x; }'

real	0m1.437s
user	0m1.392s
sys	0m0.024s

nadav@shesek:~$ time php -r '$x=array("x"=>1, "y"=>2); $y = array("y"=>3, "z"=>4);
> for ($i=1; $i<=500000; $i++) { array_merge($x, $y); }'

real	0m9.994s
user	0m7.472s
sys	0m2.400s

The results were about the same for several executions.

A couple of things should be be noted about the array plus operator:

  1. As opposed to array_merge, it overwrites numeric keys too. If you need to merge the values of two arrays with numeric keys, use array_merge instead
  2. If you need recursive merge, use array_merge_recursive instead.
  3. The values from the first array overwrites the values from the second, as opposed to array_merge. So the equivalent of array_merge($a, $b) is $b + $a, not $a + $b.
  4. Example:

    $arr = array('a' => 1, 'b' => 2, 'c' => 3);
    $arr = array('b' => 4) + $arr;
    // $arr is now array('a' => 1, 'b' => 4, 'c' => 3)
    

Chrome desktop notifications for GitHub

Posted: July 30th, 2011 | Author: | Filed under: General | Tags: , , , , , , | No Comments »

I’ve been looking for something to notify me about new GitHub notifications, and didn’t find anything. As I also wanted to take a look at the desktop notifications API, I decided to write a small Chrome extension that displays GitHub’s notifications as desktop notifications.

There’s no API or feed to get those notifications from, so I ended up scraping that data from the HTML page using XmlHttpRequest. The options page lets you set the interval for checking for new notifications.

You can browse the source at github.com/shesek/github-notifications, or download the packed extesntion here. Released under WTFPL 2.0.


Default arguments in JavaScript

Posted: July 30th, 2011 | Author: | Filed under: Javascript | Tags: , | No Comments »

I’ve thought today on a nice and clean way of handling default function arguments in JavaScript. Because the arguments object in JavaScript defines getters and setters that also interact with the functions’s formal arguments, changing its values also changes the value of the local argument variables. For example:

function foo(bar) {
    arguments[0] = "baz";
    alert(bar); // bar is now "baz", not "qux"
}
foo("qux");

What that means is that we can pass the arguments object to another function, which can take care of setting default values and by that also modify our local argument variables:

window.setDefault = function (args) {
   for (var i = args.length + 1; i<arguments.length; i++) {
       args[i-1] = arguments[i];
   }
};
// Minified:
// window.setDefault=function(a){for(var b=a.length+1;b<arguments.length;b++)a[b-1]=arguments[b]}

(raw, minified (48 bytes))

Than, to use it:

function foo(bar, baz, qux) {
    setDefault(arguments, "bar", "baz", "qux");
    console.log(bar, baz, qux); // "a", "baz", "qux"
}
foo("a");

HTML escaping in Underscore.js templates

Posted: July 20th, 2011 | Author: | Filed under: Javascript | Tags: , , , | No Comments »

When displaying values in HTML templates, you would usually want to escape special HTML characters so that they’re displayed properly and to protect against XSS.

I’ve changed my local Underscore.js (and opened a pull request at Underscore.js’s github) to add support for _.escape() and a new <%== ... %> template syntax (notice the double equal signs) which escapes the value for displaying it in HTML.

If you want to add support for that, you can either apply my commit or simply use this code (make sure to load that after Underscore.js):

_.templateSettings.encode = /<%==([\s\S]+?)%>/g;
_.extend(_, {
	// Taken from Backbone.js's escapeHTML()
	escape: function(string) {
			return (''+string).replace(/&(?!\w+;|#\d+;|#x[\da-f]+;)/gi, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#x27;').replace(/\//g,'&#x2F;');
	},
	template: function(str, data) {
		var c  = _.templateSettings;
		var tmpl = 'var __p=[],print=function(){__p.push.apply(__p,arguments);};' +
			'with(obj||{}){__p.push(\'' +
			str.replace(/\\/g, '\\\\')
				.replace(/'/g, "\\'")
				.replace(c.encode, function(match, code) {
					return "',_.escape(" + code.replace(/\\'/g, "'") + "),'";
				})
				.replace(c.interpolate, function(match, code) {
					return "'," + code.replace(/\\'/g, "'") + ",'";
				})
				.replace(c.evaluate || null, function(match, code) {
					return "');" + code.replace(/\\'/g, "'")
						.replace(/[\r\n\t]/g, ' ') + "__p.push('";
				})
				.replace(/\r/g, '\\r')
				.replace(/\n/g, '\\n')
				.replace(/\t/g, '\\t')
				+ "');}return __p.join('');";
		var func = new Function('obj', tmpl);
		return data ? func(data) : func;
	}
});

(raw, minified (835 bytes))

If you prefer and have no backward-compatibility issues with it, you can change the <%= ... %> syntax to be escaped by default, and use the double equal sign for cases you do want unescaped HTML. Use that code instead:

_.extend(_.templateSettings, {
	encode: /<%=([\s\S]+?)%>/g,
	interpolate : /<%==([\s\S]+?)%>/g
});
_.extend(_, {
	// Taken from Backbone.js's escapeHTML()
	escape: function(string) {
			return (''+string).replace(/&(?!\w+;|#\d+;|#x[\da-f]+;)/gi, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#x27;').replace(/\//g,'&#x2F;');
	},
	template: function(str, data) {
		var c  = _.templateSettings;
		var tmpl = 'var __p=[],print=function(){__p.push.apply(__p,arguments);};' +
			'with(obj||{}){__p.push(\'' +
			str.replace(/\\/g, '\\\\')
				.replace(/'/g, "\\'")
				.replace(c.interpolate, function(match, code) {
					return "'," + code.replace(/\\'/g, "'") + ",'";
				})
				.replace(c.encode, function(match, code) {
					return "',_.escape(" + code.replace(/\\'/g, "'") + "),'";
				})
				.replace(c.evaluate || null, function(match, code) {
					return "');" + code.replace(/\\'/g, "'")
						.replace(/[\r\n\t]/g, ' ') + "__p.push('";
				})
				.replace(/\r/g, '\\r')
				.replace(/\n/g, '\\n')
				.replace(/\t/g, '\\t')
				+ "');}return __p.join('');";
		var func = new Function('obj', tmpl);
		return data ? func(data) : func;
	}
});

(raw, minified (878 bytes))

P.S. Can anyone think of a nicer syntax than <%== ... %>? I don’t really like it, but I didn’t come up with anything better…


“Singleton” initializer in Javascript

Posted: July 19th, 2011 | Author: | Filed under: Javascript, Web Development | Tags: , , | No Comments »

The nature of javascript makes it quite easy to have singleton-like behavior without actually using the singleton design pattern – simply define an object with some properties and use that. No need to do anything more than that, really – there’s no reason to create a prototyped function, create an instance and keep a reference to it when javascript gives you a much more natural and elegant solution.

For example:

var Foo = {
  bar: 123,
  a: function() { /* ... */ }
  /* ... */
};
// Simply use Foo as a "singleton"

However, one thing that is missing from the singleton pattern is that the constructor is called only once, and only at the moment someone requests an instance, so it doesn’t run any code to initialize the object unless actually necessary.

Here’s my way of doing that in javascript:

var ObjectInitializer = function(object) {
  var initialized = false;
  return function() {
    if (!initialized) {
      object.initialize();
      initialized = true;
    }
    return object;
  };
};

To use that, simply add an initialize property on the object with the code to execute when the object is requested the first time, and pass it to ObjectInitializer, which’ll return an anonymous function that calls the initialize method the first time its accessed and returns the object, or simply returns the object otherwise.

Example:

var Foo = ObjectInitializer({
  a: 3,
  b: 2,
  initialize: function() {
    this.b += this.a;
  },
  increase: function() {
    this.b++;
    return this;
  }
});

var foo = Foo();
alert(foo.b); // 5
foo.increase();
alert(foo.b); // 6
var bar = Foo();
alert(bar.increase().b); // 7
alert(Foo().increase().b); // 8

Recursive Backbone.Model’s toJSON()

Posted: July 18th, 2011 | Author: | Filed under: Javascript, Web Development | Tags: , , , , | No Comments »

If you’re using collections and models as attributes for other models, calling toJSON() on Backbone.Model objects isn’t very useful as it returns the models and collections as-is. I’ve opened an issue requesting to make it recursive, but it seems like its not going to be added.

If anyone still wants this functionality, you can use that modified version of Backbone.Model.prototype.toJSON that I added to the issue:

Backbone.Model.prototype.toJSON = function() {
    if (this._isSerializing) {
        return this.id || this.cid;
    }
    this._isSerializing = true;
    var json = _.clone(this.attributes);
    _.each(json, function(value, name) {
        _.isFunction(value.toJSON) && (obj[name] = value.toJSON());
    });
    this._isSerializing = false;
    return json;
}

akismet_recheck_queue returning a blank page / not found?

Posted: July 17th, 2011 | Author: | Filed under: Wordpress | Tags: , , , , , | No Comments »

If your blog has large number of comments in the moderation queue, akismet “check for spam” option that tries to filter out spam from your moderation queue could execute for too long, die, and return either a blank page or a ‘page not found’ error.

However, Akismet does manage to check some comments every time you run it, so if you’ll keep refreshing it you’ll see the number of comments in the moderation queue drop slowly.

As I have over 50K of comments in the moderation queue and no time to keep hitting refresh, I wrote a small hacky javascript code that does that automatically by refreshing an iframe. Just paste the following code in the address bar while you’re on any page (make sure you change YOUR-WORDPRESS_URL) and let it run for some time (make sure the page you wrote that in stays open):

javascript:(function(f,b){b.appendChild(f); f.style.display='none'; setInterval(function() { f.src='http://YOUR-WORDPRESS-URL/wp-admin/admin.php?action=akismet_recheck_queue&'+Math.random(); }, 15000);})(document.createElement('iframe'), document.body)

Or simply click here, input your base WordPress URL and let it run overnight (make sure to keep this post open until it finishes).


Create jQuery-UI widgets from HTML markup

Posted: April 19th, 2011 | Author: | Filed under: jQuery | No Comments »

Many times I add UI enhancements using jQuery UI, like buttons, datepickers, tabs, etc that requires very simple JavaScript code without much logic. Having to add JavaScript code for those small enhancements quickly became annoying for me. To overcome this, I’ve been using CSS classes like “jq-datepicker”, than execute $(‘.jq-datepicker’).datepicker() in a file that’s globally used on all pages of the website – a much better solution, but not quite perfect.

Today I thought on a very simple concept that makes is extremely easy to create jQuery UI widgets from HTML markup – why not simply add an attribute with the jQuery method to execute on the element?

Some examples would make it clearer: (only works on the single post page)

  • Button:

    <a href="#" data-jq="button">Hello, World</a>
    

    Hello, World

  • Date picker:

    <input type="text" data-jq="datepicker" />
    

Code:

Very simple. Looks for elements with ‘data-jq’ attribute, iterate over them and call the specified method on them:

(function($){ $(function() {
	$('[data-jq]').each(function() {$(this)[$(this).data('jq')]();});
}); })(jQuery);

Is adding custom attributes valid?

Technically? No. HTML5 does support custom attributes when their name is prefixed with ‘data-’. However, the HTML5 specs are not done yet and its not fully supported in all browsers.
That being said – it does currently work well on all the major browsers and you know it’ll continue working into the future when HTML5 is officially out. Also, if you’re use the HTML5 DOCTYPE (<!DOCTYPE html>), it’ll pass HTML5 validation.

What about arguments?

What if you need to pass arguments to that call? I personally think that those arguments doesn’t belong in HTML. The purpose of this isn’t to have your JavaScript logic in your HTML, but merely mark that an element should use a specific widget. If you need arguments, create a custom jQuery.fn method that wraps the call to the jQuery method with those arguments (or any other complex logic), than use that method. For example, if you want to use the datepicker widget with a different dateFormat, create jQuery.fn.mydatepicker() method:

$.fn.mydatepicker = function() {
	return this.datepicker({dateFormat: 'yy-mm-dd'});
};

Than use that method for the data-jq attribute:

<input type="text" data-jq="mydatepicker" />

However, it is possible to add support for custom arguments. Again, I do not recommend it, but its easily doable:

(function($){ $(function() {
	$('[data-jq]').each(function() {
		var $t = $(this), args = $t.data('jqa') ? $.parseJSON($t.data('jqa')) : [];
		$t[$t.data('jq')].apply($t, $.isArray(args)?args:[args]);
	});
}); })(jQuery);

Than you can define an ‘data-jqa’ attribute with a JSON string. It can either be a single argument, or an array of arguments. For example, to set the dateFormat using that attribute, you could this code which’ll produce the same result as above:

<input type="text" data-jq="datepicker" data-jqa="{&quot;dateFormat&quot;:&quot;yy-mm-dd&quot;}" />

Do note that it uses jQuery.parseJSON(), which requires a valid JSON string, so you must use double quotes for string literals and quote the object keys, which makes the HTML somewhat ugly, especially with the html encoding for the quotes.



Quick fix for Trac Babel/Locale issue

Posted: March 10th, 2011 | Author: | Filed under: Trac | Tags: , , | No Comments »

After installing Babel on our development machine, Trac died with that error:
OSError: [Errno 2] No such file or directory: '/usr/local/lib/python2.6/dist-packages/Trac-0.12-py2.6.egg/trac/locale'

The issue seems to be related to #9439: When installing Trac, it checks whether Babel is installed or not. When Babel is installed, Trac also installs the locale files. The problem occurs when Babel is installed after installing Trac, because Trac expects the locale files to exists when Babel is installed.

As I don’t use locale with Trac, I couldn’t delete Babel (because I do use it with other stuff) and I didn’t want to re-install Trac – I took the hacky solution and modified trac/web/main.py so it’ll ignore the fact that Babel is installed and won’t use it at all. This can be done by commenting out the part that tries to import babel and setting the Locale to None manually. Open trac/web/main.py, look for (should be at line 29):

try:
    from babel import Locale
except ImportError:
    Locale = None

and replace with:

#try:
#    from babel import Locale
#except ImportError:
#    Locale = None
Locale = None

Yes – very much hacky, but it works as a quick solution for now, as we must have Trac up and running. I will be looking for a better solution and update this post.


Backup all SVN repostiroes using a one-liner Shell script

Posted: March 9th, 2011 | Author: | Filed under: SVN | Tags: , , , | No Comments »

Just a quick one-liner to backup all your SVN repositories. It lists the directories under the main SVN directory, uses xargs to run the dump for every repository, gzip’s the dump and saves each dump to a file named according to the repository name and the current date.

In this example, the main SVN directory is /var/svn/ and the backup location is /backup/svn/. Change those to the paths used by you.

ls /var/svn/ | xargs -I {} sh -c "svnadmin dump /var/svn/{} | gzip -c > /backup/svn/{}.`date +'%F'`.dump.gz"

You can also SCP the backup to a remote server using this:

ls /var/svn/ | xargs -I {} sh -c "svnadmin dump /var/svn/{} | gzip -c > /backup/svn/{}.`date +'%F'`.dump.gz; scp -p /backup/svn/{}.`date +'%F'`.dump.gz username@hostname:/backup/svn/"