Protoaculous 1.9.0-1.7.2.0 Minified

What
This is an update to a post from 2011: Protoaculous 1.9.0 Minified. In the older post, I published Protoaculous 1.9.0 which was based on Scriptaculous 1.9.0 and PrototypeJS 1.7.0.

Updates

  1. A newer version of PrototypeJS is out: 1.7.2. So I’ve updated Protoaculous to use the newer version.
  2. Switched away from YUI Compressor to Google Closure Compiler since it produces more compressed files.
  3. I was previously using Scriptaculous version number as Protoaculous’ version number. This type of versioning is flawed because it doesn’t work when only PrototypeJS gets updated. So I’m now using Scriptaculous_version-Prototype_version.
  4. I’ve published the script I use to create new versions of Protoaculous on Github: Protoaculous Bundler.

Direct links

  • https://raw.githubusercontent.com/inderpreet99/protoaculous-bundler/master/dist/protoaculous.1.9.0-1.7.2.0.js
  • https://raw.githubusercontent.com/inderpreet99/protoaculous-bundler/master/dist/protoaculous.1.9.0-1.7.2.0.min.js

Warnings
I have not tested how well the combination of the two scripts perform. Please use caution and testing before using it in a production environment. Although previous versions have performed well.

Issues
While generating protoaculous using Google Closure Compiler, I noticed the following issues, which should probably be fixed by the PrototypeJS team:

Generate protoaculous.1.9.0-1.7.2.0.js and protoaculous.1.9.0-1.7.2.0.min.js in dist...
dist\protoaculous.1.9.0-1.7.2.0.js:4619: WARNING - Suspicious code. The result of the 'getprop' operator is not being used.
  arr[ preferredDoc.childNodes.length ].nodeType;
  ^

dist\protoaculous.1.9.0-1.7.2.0.js:5602: WARNING - Suspicious code. This code lacks side-effects. Is there a bug?
  if ( elem.parentNode ) {
  ^

dist\protoaculous.1.9.0-1.7.2.0.js:5603: WARNING - Suspicious code. The result of the 'getprop' operator is not being used.
  elem.parentNode.selectedIndex;
  ^

0 error(s), 3 warning(s)

Size information

Size of Prototype.js + Scriptaculous = 314K
Size of Protoaculous.js Minified = 166K

Suggestions

I would suggest:

  1. Turning on gzip functionality (mod_deflate on Apache) for all html and js/css/etc assets in your webserver to get filesizes even lower. This would ensure your users get the files even faster.
  2. Adding very long expiration dates (like years) through your webserver on js/css/etc assets. This would ensure your users do not have to download the files again and again. Since the files are versioned, there should not be a problem in cache busting on newer updates.

 

EXT4 repair on Mac OSX

My NAS WD drive recently became corrupt. It had trouble saving large files and running them. My router constantly complained about not being able to properly run Samba/swap on it.

Not having a Linux OS handy, I had a tall task to repair an EXT4 filesystem on Mac OSX 10.10.

I first tried the open source solutions: fuse-ext2, osxfuse, and ext2fuse (read-only). While these tools work great in allowing access to ext4. They do not include any disk repair tools. e2fsprogs from Homebrew also does not include the fsck utilities.

I also tried using the commercial ExtFS by Paragon. It integrates directly with Disk Utility and is able to verify/check the disk for errors. While it reported the errors properly, it had trouble repairing the filesystem and reported my ext4 partition as ext3. It failed to repair reporting: “Error: Disk Utility can’t repair this disk. Back up as many of your files as possible, reformat the disk, and restore your backed-up files.” Also, ExtFS was very buggy as in it consistently froze the System Preferences and Finder (while ejecting and mounting).

Finally, I installed VirtualBox with an Ubuntu VM and added the USB drive from settings. I had to umount the drive from inside Ubuntu and running fsck -y was a breeze. Now ExtFS by Paragon also reports that the Disk is good.

Releasing DholCutz Bhangra Radio version 2 for Android

After many bad reviews, I finally decided to update DholCutz Bhangra Radio for Android, so version 2 is here. It has the following updates:

  1. Harder, Better, Faster, Stronger
  2. AAC+ Higher sound quality!!!
  3. Background vi hojanda mitra!
  4. Instant song title updates
  5. Links to Requests and Chat
  6. Ganeya Di Agg!

Android Play Store App link: https://play.google.com/store/apps/details?id=com.inderpreetsingh.dcr&hl=en

Screenshot:
Main Screen

mb_strrchr in php 5.1 for compatibility

I needed php’s mb_strrchr function, which is only in php 5.2+. However, my workplace is stuck in php 5.1 and cannot upgrade to php 5.2.

I decided to write a forwards-compatible mb_strrchr() that worked in php 5.1 at least. Please test thoroughly before using. It seemed to work great for the cases I needed it for:

// php 5.1 compat
if( !function_exists('mb_strrchr') ) {
	function mb_strrchr( $haystack, $needle, $part = false, $encoding = '' ) {
		
		$pos = mb_strrpos( $haystack, $needle, $encoding );
		if( $pos === false ) return false;
		
		if( $part === true ) {
			return mb_strcut( $haystack, 0, $pos, $encoding );
		} else {
			return mb_strcut( $haystack, $pos, mb_strlen($haystack), $encoding );
		}
	}
}

VirtualBox Images CentOS keyboard settings problem

I was using readymade CentOS images for VirtualBox from VirtualBoxes CentOS images. I noticed that some of the images come with weird keyboard settings, such that you can’t use the pipe (passing information from command to command), dash (for command parameters), @ (email sign), etc keys. In other words, when you try to type these keys, other keys would appears and vice versa. All of these keys are crucial to running any commands on the CentOS server.

The problem is that the VirtualBox image stores the keyboard setting that was used when it was created. Since this server image was built in Italy, and I am located in the US, there were obviously key differences.

The obvious solution is to change it to your preferred keyboard layout. There are 2 ways of doing it:

  1. Easier way: Install system-config-keyboard through yum. The caveat is this will install 75+ other bloat packages that you probably don’t need. However the command system-config-keyboard would configure your keyboard for you.
    yum install system-config-keyboard
  2. Advanced way: Use
    loadkeys

    command to change the keys temporarily and then make a change to

    /etc/sysconfig/keyboard

    to make a permanent change (after restart).

    loadkeys us # or your own locale
    vim /etc/sysconfig/keyboard # replace KEYTABLE value to your locale

PHP misreporting existence of directory or files

Recently I was working with a WordPress site where I was deleting a network. When the network was deleted, the root site was also deleted (or vice versa). And when the root site deleted, it deleted its own media directory and the parent network’s media directory as well. This worked out OK in most cases (because the root site and root network are one-in-the-same in a multisite network). However in some of my workplace’s custom code, we hooked into both network and site deletion. We tried to delete some extra folders attached with the network and site. Some folders were shared, so once they were deleted, they should’ve shown up as missing. However the folders were showing up as existing on second try and when deleting were giving out errors. So…

PHP has something called stat cache to make file operations faster. It caches information anytime you make a call to functions like “stat(), lstat(), file_exists(), is_writable(), is_readable(), is_executable(), is_file(), is_dir(), is_link(), filectime(), fileatime(), filemtime(), fileinode(), filegroup(), fileowner(), filesize(), filetype(), and fileperms().” Coincidentally, PHP was misreporting the existence of files and folders when they were clearly deleted and glob() would be confirming that fact. In the end, we had to add calls to clearstatcache() to avoid this trap.

I wish there was a way to disable the stat caching for a session, because calling this function every time gets to be a pain.

Things learned from Wordcamp 2012

I attended most of the developer track presentations at Boston’s Wordcamp 2012. I learned about some interesting tools and techniques that I’d like to document for myself and others.

Talk Optimizing for Speed by Ben Metcalfe

  1. YouGetSignal’s Reverse IP Lookup – Shows you how many other hosts live on the same IP Address. This can be helpful for anyone using shared hosting or maybe VPS.
  2. Debug Bar – Get debugging information from each page WordPress page load.
  3. Google XML Sitemaps – Delete this plugin if you have it. (I had it.)
  4. YSlow – Get load times and optimization tips of a page request.

WordPress as a Web Framework by Sam Hotchkiss

  1. MVC frameworks for WordPress
    1. WP MVC – Provides a singleton object and eliminates the metadata bottleneck by providing tables indexed by post IDs.
    2. Tina MVC
  2. _s Theme – Use Automattic’s Blank Theme as a good starting point.

Automating frontend workflow by Aaron Jorbin (blog post, slides)

  1. Autojump – Jump to frequently used directories
  2. Commander.js (nodejs) – Script working with CLI
  3. watch (nodejs) – Watch files/dirs
  4. mockjax – Fake your ajax calls (good for protyping or testing un-related, yet dependent functionality)
  5. Travis CI – continuous integration service (wordpress plugin tests)
  6. Glue – generate css sprites

Microdata for SEO by Dave Ross

  1. Add itemprop, itemscope, etc to any identifiable schema
  2. Google Rich Snippets Tool – Test your microdata
  3. Examples: SiteNavigation element for navigation, Blog element for blog posts, etc
  4. Some quick tidbits: Bing rates sites with microdata higher than sites without, and Google uses the microdata in search results

Enterprise WordPress by Jake Goldman (1up)

  1. Sites to show clients: showcase, WordPress VIP
  2. Maintaining a beautiful WordPress admin

Shortcodes by Jon Bishop

  1. Use oembed rather than plugins to support embedding media from sites like youtube, facebook, etc

Codex by Erick Hitler

  1. Use santize_* functions to save to db: santize_text_field(), sanitize_title()
  2. Use esc_* functions to show data to user (esc_url_raw() is the exception, it is the opposite of esc_url())

Javascript hooks by Luke Gedeon (1up)

  1. Javascript custom events are coming, they will provide functionality similar to WordPress’ action and filter hooks (list of hooks)

SMF2 Gallery2 Integration Problem

I have a SMF2 forum site, where the gallery is implemented through Gallery2 using Oldiesmann’s SMF + G2 Integration Project.

For 2 years, I’ve had the SMF and Gallery work properly together with linked member groups (a mod option), such that member groups auto-synchronized with ones in Gallery. At some point, either with a Gallery or SMF upgrade, users reported that the Gallery part of the site threw cryptic security warnings for non-admins. I explored the issue and figured users were missing in two required groups “Everybody” and “Registered Users”. I had reported it to Oldiesmann, but he claimed he had no control over those required groups and Gallery was self-managing them.

After about a year, I delved into the code and found that in order to sync the groups that a user had in SMF with the groups that a user had in Gallery, the integration code was removing all groups and adding the shared groups. This of course meant that the user was being removed from the required groups: “Everybody” and “Registered Users”. Users with privileged groups did not see the problem.

Here’s the fix that I’ve also submitted to Oldiesmann. But his forum complains when I added the code, so I had to create this post here. It says it does not allow external links (haha).

My fix will ensure that we do not remove the user from required groups and also add the users back into required groups (if necessary). Please note that the cleanup code is necessary because anyone who has ever visited the buggy gallery will have the groups removed, so there’s a lot of cleanup to do. The code provided below should auto-correct this issue.


commit 97075cd4e20d2807011b38cd293ccc38c728db9a
Author: Inderpreet Singh <inderpreet99gmail>
Date:   Sat Jul 28 10:33:40 2012 -0500

    PJ fix for SMF Gallery2 Integration:
    Avoid g2 required groups: Everybody and Registered Users groups from getting removed
    Add user to the required groups (cleanup our mess)

diff --git a/Sources/Gallery.php b/Sources/Gallery.php
index 74652fe..c289678 100755
--- a/Sources/Gallery.php
+++ b/Sources/Gallery.php
@@ -1348,10 +1348,32 @@ function groupCheck()
 	}
 	else
 	{
+
+		// Avoid g2 required groups: Everybody and Registered Users groups from getting removed!
+		$groupstoignore = array('Everybody', 'Registered Users');
+		$groupstoadd = $groupstoignore;
+		foreach($galgroups as $gid => $gname)
+		{
+			if(in_array($gname, $groupstoignore))
+			{
+				unset($galgroups[$gid]);
+				$groupstoadd = array_diff($groupstoadd, array($gname));
+			}
+		}
+		
+		// Add user to the required groups (cleanup our mess)
+		foreach($groupstoadd as $gname) {
+			list($ret, $group) = GalleryCoreApi::fetchGroupByGroupName($gname);
+			if($ret)
+			{
+				fatal_error($ret->getAsText(), 'gallery');
+			}
+			GalleryCoreApi::addUserToGroup($context['user']['g2_uid'], $group->getId());
+		}
+
 		// array_diff will give us an array of all the values in $galgroups that aren't in $galsmfgroups
 		// $galgroups uses the group IDs as the keys, and the group names as the values. We only want the group IDs...
 		$groupstoremove = array_diff(array_keys($galgroups), $galsmfgroups);
-
 		// Remove them from any group(s) they no longer belong to
 		if(count($groupstoremove) > 0)
 		{

Adobe Updater’s Stupidity

I was updating Adobe Reader on a non-profit organization’s laptop and I found this gem: Adobe Updater tries to update it’s Adobe Reader software and complains that it cannot update because its own installer is holding necessary files hostage. Take a look:

WordPress: How to programmatically remove categories returned by get_the_category_list function?

First of all, I would recommend using the wp_list_categories function (which supports ‘exclude’ and ‘exclude_tree’ arguments) instead of get_the_category_list.

Sometimes we do not have the option of choosing which function to use. Also, it is unfortunate that the get_the_category_list function does not provide a hook to target each category in the list. So we have to use a hacky method to remove items. The following code uses regex to parse the string (list of HTML elements separated by a separator) being returned by get_the_category_list function (using ‘the_category’ filter) and removes the appropriate categories.

I would also like to note and the code below removes the “Uncategorized” category (which is the default category and the most common offender users want to remove) and also the “Feature” category (something I was using in my own code).

/**
 * Identifies the "Uncategorized", "Feature" link
 * preg_replace_callback for bu_library_hide_uncategorized function
 * 
 * @param array $regex_parts
 * @return string 
 */
function bu_library_hide_uncategorized_callback($regex_parts) {
	if( !$regex_parts or count((array)$regex_parts) != 2)
		return $regex_parts;
	
	if ( in_array($regex_parts[1], array('Uncategorized', 'Feature')) )
		return '';
	
	return $regex_parts[0];
}

/**
 * Removes the uncategorized category from $thelist string parameter
 * 
 * Ignore wp-admin requests. Unfortunately, 'the_category' filter is used in other places with 1 argument), so we must
 * make the last 2 arguments optional (or we get PHP Warnings) and quit when the 2nd argument is not supplied
 */
function bu_library_hide_uncategorized($thelist, $separator = '', $parents = '') {
	
	// short circuit for lists that do not have uncategorized category,
	// or when this function is called from wp-admin (i.e. missing separator)
	if(is_admin() or !$separator or stripos($thelist, 'Uncategorized') === false) return $thelist;
	
	$listitems = explode($separator, $thelist);
	
	$new_listitems = array();
	foreach($listitems as $item) {
		if ($new_item = preg_replace_callback('!<\s*a[^>]*>(.*?)<\s*/a[^>]*>!im', 'bu_library_hide_uncategorized_callback', $item)) {
			$new_listitems[] = $new_item;
		}
	}
	
	$thelist = implode($separator, $new_listitems);
	return $thelist;
}
add_filter('the_category', 'bu_library_hide_uncategorized', 10, 3);
Return top