Mediawiki-Usage/Changes Storage and Visualizations

A coworker and I have been doing some work on visualizations of wiki updates. The server-side code, written in Ruby, stores changes from a media-wiki feed.

Media-wiki Changes Feed

Media-wiki Changes Feed

I got a chance to use the Google Visualization API, which is really simple and useful for a wide variety of domains.

He also turned me on to HAML, which offers a concise, structured way of specifying HTML.

Project Page: http://github.com/hectcastro/mediawiki-usage/
Demo: http://www.angelforge.org/mediawiki-usage/

Media-wiki Changes Visualization

Media-wiki Changes Visualization

Bubble Breaker Using Canvas!

I wanted to try out some canvas element functionality, given that I have a feeling it will steal a lot of Flash’s thunder. I whipped up a bubble-breaker game (the mechanic should be very familiar to you) in a few hours. Enjoy the demo! I may do a quick write up at a later point.

I’ve only tested it in Firefox 3.6. I do not know whether it will work in other browsers.

Demo
Project site

 

bubble breaker 13x13

bubble breaker 13×13

 

bubble breaker 30x30

bubble breaker 30×30

Drupal Org Chart – Graph Viz Update

I have updated the Google Code repository with updates to integrate GraphViz. It expects the PEAR GraphViz package to be installed.  To install it, issue command:

# You must install the beta package.

sudo pear install Image_GraphViz-beta

If you’d rather not mess with PEAR, download the package, extract the class Image_GraphViz, and alter two two lines of code that depend on the PEAR::System package. It should be trivial to change these. They are both basically calls like this:

// create a temporary file with the prefix "graph_"
$file = System::mktemp('graph_');

One possible replacement:

// will use default tmp dir
$file = tempnam('', 'graph_');

Graphiz Problem!

I was working on the Drupal OrgChart module tonight, specifically the rendering of the chart image via GraphViz, and I got stuck for at least an hour on a trifle! I planned to use the PEAR library for GraphViz (Image_GraphViz) and I wrote a function using the class it provides. I run the procedure and get weird errors about not being able to find files and such. After debugging for awhile, I find out that there is a property binPath that is not present. I had expected this to point to my install of GraphViz, which I knew to be especially important because it was in a weird macports directory.

It turns out that I had not installed the version I needed! I didn’t realize the version I wanted was beta, and to download a beta package, you need to explicitly state so in the PEAR command.

sudo pear install Image_GraphViz-beta
#instead of
sudo pear install Image_GraphViz

After downloading the most recent package, it turned out my code worked almost perfectly. What a waste of a night!

The past few days, I also worked on a few other modifications. I removed the requirement for a “subordinate_id” field. Also, I made the profile field names options in the administrative settings page.

The project page is here: http://code.google.com/p/drupal-orgchart/.

Stikked Patch

We’ve been using Stikked for an internal pastebin. The current version on Google Code has a few bugs. I modified this code to fix two problems specifically:

  1. The Download Code link was not working properly
  2. The Short URL functionality was not working, as Snipr had deprecated the version of the API that the program was using

Below is a consolidated diff of the changes. You should be able to use it to apply a patch to 0.5.4 if you are having these issues.

stikked.diff

Index: trunk/system/application/models/pastes.php
===================================================================
--- trunk/system/application/models/pastes.php	(revision 1)
+++ trunk/system/application/models/pastes.php	(revision 2)
@@ -156,14 +156,55 @@
 			$data['snipurl'] = false;
 		}
 		else
-		{
-			$target = 'http://snipr.com/site/snip?r=simple&link='.site_url('view/'.$data['pid']);
+		{
+			// this next blob just copied from snipr's examples,
+			// with some modifications of course
+
+			// REQUIRED FIELDS
+			$sniplink  = site_url('view/'.$data['pid']);
+			$snipuser  = $this->config->item('snipr_user');            // YOUR USER ID REQUIRED
+			$snipapi   = $this->config->item('snipr_apikey');               // FIND IN YOUR "SETTINGS" PAGE
+
+			// OPTIONAL FIELDS
+			$snipnick   = '';            // MEANINGFUL NICKNAME FOR SNIPURL
+			$sniptitle  = $data['title'];  // TITLE IF ANY
+			$snippk     = '';                      // PRIVATE KEY IF ANY
+			$snipowner  = '';                      // IF THE SNIP OWNER IS SOMEONE ELSE
+			$snipformat = 'simple';                      // DEFAULT RESPONSE IS IN XML, SEND "simple"
+			                                       // FOR JUST THE SNIPURL
+			$snipformat_includepk = "";            // SET TO "Y" IF YOU WANT THE PRIVATE KEY
+			                                       // RETURNED IN THE SNIPURL ALONG WITH THE ALIAS
+
+			//----------------------------------
+			// NO NEED TO EDIT BEYOND THIS POINT
+			//----------------------------------
+			$URL        = 'http://snipr.com/site/getsnip';
+			$sniplink   = rawurlencode($sniplink);
+			$snipnick   = rawurlencode($snipnick);
+			$sniptitle  = rawurlencode($sniptitle);
+
+
+			$post_data =  'sniplink='  . $sniplink  . '&' .
+			              'snipnick='  . $snipnick  . '&' .
+			              'snipuser='  . $snipuser  . '&' .
+			              'snipapi='   . $snipapi   . '&' .
+			              'sniptitle=' . $sniptitle . '&' .
+			              'snipowner=' . $snipowner . '&' .
+			              'snipformat='. $snipformat. '&' .
+			              'snippk='    . $snippk
+			  ;
+
+
+			$target = $this->config->item('snipr_link');
 			$ch = curl_init();
 			curl_setopt($ch, CURLOPT_URL, $target);
+			curl_setopt($ch, CURLOPT_POST, true);
+			curl_setopt($ch, CURLOPT_HEADER, 0);
+			curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
 			curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

 			$data['snipurl'] = curl_exec($ch);
-
+
 			curl_close($ch);

 			if(empty($data['snipurl']))
@@ -189,6 +230,7 @@

 	function checkPaste($seg=2)
 	{
+
 		if($this->uri->segment($seg) == "")
 		{
 			return false;
Index: trunk/system/application/config/routes.php
===================================================================
--- trunk/system/application/config/routes.php	(revision 1)
+++ trunk/system/application/config/routes.php	(revision 2)
@@ -46,6 +46,7 @@
 $route['cron/:any'] = "main/cron";

 $route['view/raw/:any'] = 'main/raw/';
+$route['view/download/:any'] = 'main/download/';
 $route['view/options'] = 'main/view_options';
 $route['view/:any'] = 'main/view';
 $route['lists'] = 'main/lists';
Index: trunk/system/application/config/config.php
===================================================================
--- trunk/system/application/config/config.php	(revision 1)
+++ trunk/system/application/config/config.php	(revision 2)
@@ -308,4 +308,16 @@
 $config['rewrite_short_tags'] = FALSE;

+/*
+|--------------------------------------------------------------------------
+| Snipr Settings - Used for short URL
+|--------------------------------------------------------------------------
+|
+| Settings for Snipr API
+|
+*/
+$config['snipr_link'] = 'http://snipurl.com/site/getsnip';
+$config['snipr_user'] = ''; // snipr user name
+$config['snipr_apikey'] = '';
+
 ?>
\ No newline at end of file
Index: trunk/system/application/views/view/download.php
===================================================================
--- trunk/system/application/views/view/download.php	(revision 1)
+++ trunk/system/application/views/view/download.php	(revision 2)
@@ -1,6 +1,6 @@
 <?php

-header('Content-disposition: attachment');
+header('Content-disposition: attachment;filename='.$title.'.'.$lang_code);
 echo html_entity_decode($raw);

 ?>
\ No newline at end of file
Index: trunk/system/libraries/URI.php
===================================================================
--- trunk/system/libraries/URI.php	(revision 1)
+++ trunk/system/libraries/URI.php	(revision 2)
@@ -186,8 +186,15 @@
 	{
 		if ($str != '' AND $this->config->item('permitted_uri_chars') != '')
 		{
-			if ( ! preg_match("|^[".preg_quote($this->config->item('permitted_uri_chars'))."]+$|i", $str))
+			$matches = array();
+			$pattern = "|^[".preg_quote($this->config->item('permitted_uri_chars'))."]+$|i";
+			if ( ! preg_match($pattern, $str, $matches))
 			{
+				echo '<pre>*'.$str.'*<br>';
+				echo 'allowed: '.$pattern.'<br>';
+				var_dump($matches);
+				var_dump(debug_backtrace());
+				echo '</pre>';
 				exit('The URI you submitted has disallowed characters.');
 			}
 		}

Tron Bot

I spent a few hours cooking up an entry for this Tron Bot AI Competition. The starter packages they provided made it really easy to enter. I created an entry in python. The competition page is: http://csclub.uwaterloo.ca/contest/

The strategy for my bot:

  1. I tried to implement painter’s flood fill per Wikipedia. This worked okay and I got to around ~300.
  2. Then I implemented A*. The strategy was to get within 5 squares of the enemy, and then flood fill. My reasoning was that if I had a better fill algorithm, I would win at that point.
  3. Next, I tried to implement minimax with alpha-beta pruning. It’s not tested, but it should be fairly close. All I am missing is a utility function (well, that is probably the most impt piece!). For the utility function, I wanted to bisect the playing field by finding the perpendicular bisector between the players, then flood-filling to determine the number of blank spaces in each player’s respective region. I have the bisection algorithm done, but got bored once I started implementing the flood fill.

The project page is, it contains the source as well: https://github.com/jamiely/tron-bot-waterloo

Bot runs:

Stikker

Some coworkers and I have been working on Stikker, a cli interface for the Stikked FOSS php pastebin. I haven’t used it for awhile, but we recently set it up at work to facilitate code sharing. Unfortunately, it hasn’t been updated recently and there are some things which are broken which I’ll need to address. One of the great things about OSS is that fixing things yourself is possible!

CiteThis! Update 0.17

I modified CiteThis! with the following features this weekend:

  • Added a citation list box, where you can queue all your citations.
  • Removed the custom citation box from the preferences pane (it was not of use anymore)
  • Fixed APA citation format to include last accessed date.
  • Added some handling of author/titles:
    • If title includes the host name of the site such as “news blah blah – CNN”, then the host name will be removed from the title.
    • If the author ends with any special characters, they will be removed
    • If author contains AP, or Associated Press, that will be stripped.
  • Author determination:
    • Added handling of some common author classes, like when an element has a class called “byline” or “author”
  • Site-specific handling
    • Added handling of some more sites: ABCNews, Fox, CNet, Yahoo News

https://addons.mozilla.org/en-US/firefox/addon/7972

CiteThis! Update 0.16

I made an update at the request of someone who e-mailed me.  This post describes this version:

  • Custom citation formatting broken! (Will be addressed in next update.)
  • Added variable citations depending on what fields are specified
  • Added custom date formatting based on datejs
  • Added custom handling of Wikipedia citations

https://addons.mozilla.org/en-US/firefox/addon/7972

Update to CiteThis!

I updated my CiteThis! Firefox Extension with a few of the following features:
Several updates including:

  • Created preferences pane to allow selection of different reference styles
  • Provided option for a customized citation string
  • Implement some automatic author discovery for the page
  • Improved performance by avoiding updates when hidden

https://addons.mozilla.org/en-US/firefox/addon/7972