« February 2009 | Main | April 2009 »
March 31, 2009
Building Forms With interface_functions.php & .skini Files
There are a set of functions for rapidly building web forms to work with the SQL functions. These are found in the common_php/interface_functions.php
.
The build_form($form_name, $entity)
Function
This is the guts of the interface system and allows you to build web forms quickly and consistently and avoids problems caused by typos in hand coded mark-up.
The function takes a filehandle for a skins/blah.skini
file, and a hash to populate the form with values if required. I have avoided doing this however, in favour of using AJAX for populating forms when required instead.
build_form('panel_form');
This will look for and read a file in the skins
directory called panel_form.skini
and build the form based upon the settings found therein.
The .skini
Configuration File Format
These files are in Windows .ini
format:
; Each form element should have its own section block. ; ; Sections must be uniquely named as id attributes are assigned ; based upon them ; ; A 1 means that the section is displayed as a block and 0 ; means it is displayed inline. Inline display is trixy and ; requires extra CSS jiggery pokery more often than not. [sections] current_panels = 1 name_section = 1 description_section = 1 location_section = 1 ip_address_section = 1 ; For each item under the 'sections' heading there needs to be a ; separate configuration block. ; ; The block description should include a label entry (usually label_italic) ; and then the form element included in that section. [current_panels] label_italic = "Edit Existing Panel" current_panel_id = select_noadd panel_id = hidden ; If you want to add extra attributes to a form element's tag then ; you can by defining a section headed as below. This is useful for ; adding classes, style attributes or JS event handlers: [current_panel_id] class = four_c onchange = "get_panel_details()" [name_section] label_italic = "Panel Name" panel_name = text [panel_name] class = four_c [description_section] label_italic = "Panel Description" panel_description = textarea [panel_description] class = four_c [location_section] label_italic = "Panel Location" panel_location_id = select_noadd [panel_location_id] class = four_c [ip_address_section] label_italic = "IP Address" ip_address = text [ip_address] class = four_c
The build_repeating_form($form_name, $entity, $the_count)
Function
If you need to build more than one instance of the same form in a single document then you should use this function. This adds the value passed into the third parameter onto the end of all id attributes in the form, separated by an underscore. This is so that we don't duplicate ids.
The get_hour_options()
& get_minute_options()
Function
To be used along with common_php/option_switcher.php
for when you need to choose hours and minutes from <select/>
elements.
Posted by pj at 12:51 PM | Comments (0)
Common Header & Footer Includes
All the applications in the framework share the same header and footer with a simple PHP include, although this is not mandatory, but the header sets up all sorts of JavaScripty and CSS goodness required for the framework.
The files are held in the root.
Posted by pj at 11:56 AM | Comments (0)
March 30, 2009
Doing Database "Create Review Update Delete" With Functions In add_update.php
There are a set of functions for abstracting DB CRUD
functions in the common_php/add_update_functions.php
script.
The add_new_row($table_name)
function
This function adds a new row into the table specified, populating only the insert_by
and insert_date
columns and returning the new primary key value.
The update_table($table_name, $r, $primary_key)
Function
This function is for applying updates to individual rows in a table. It is typically used to update a row with the $r / $_REQUEST
hash from a form submission. The last argument is the primary key of the row in question, which may have been derived from calling the add_new_row()
function.
In the following doozer
example code snippet, the same piece of code can be used to either insert a new row or update an existing one depending on whether or not a primary key has been passed in the request:
if(!$r['page_id']){ $r['page_id'] = add_new_row('simple_page'); } $reply = update_table('simple_page', $r, $r['page_id']);
This function can also be used to delete / expire a row thus:
$reply = update_table('simple_page', array('expired_date' => mktime()), $r['page_id']);
If you want to set a NULL
value in a column, for example to undelete / unexpire a row, use:
$reply = update_table('simple_page', array('expired_date' => 'nulled'), $r['page_id']);
This function can also be used to delete / expire a row thus:
$reply = update_table('simple_page', array('expired_date' => mktime()), $r['page_id']);
The update_table_extra($table_name, $r, $where, $primary_key)
Function
This function behaves in the same way as the above but allows you to add an extra where
clause into the SQL.
$reply = update_table('simple_page', array('expired_date' => mktime()), "page_tags not like '%Public%Document%'", $r['page_id']);
This code expires a particular row in the simple_pages
table but only if it hasn't been tagged as a public document.
The date_splitter('publication_date')
Function
The interface code returns dates in dd/mm/yyyy
format and this needs to be turned into a unix timestamp for storage (date columns should be set as int(20)
).
This function takes a date in the $r
hash and converts it into a timestamp. The function call is a little unusual in that the function doesn't return anything. So where you have a date in $r['publication_date']
call:
date_spliter('publication_date'); $reply = update_table('my_pages', $r, $page_id);
The call above extracts the date from $r
and resets the value with the corresponding timestamp:
function date_splitter($key){ global $r; $b = explode('/', $r[$key]); $ts = mktime(0,0,0, $b[1], $b[0], $b[2]); $r[$key] = $ts; //print_r($r); }
The get_options($reply, $value_column, $label_column)
Function
This functions more properly belongs in the interface_functions.php
file as it is related to form building. Its purpose is to populate <select/>
form elements with a list of options.
It takes a reply hash from just_sql()
as it's first argument, the second two parameters are the column names you want to map to the value and label of the option respectively. The function can be called like so:
return get_options(just_sql("select * from panel_group where expired_date is null order by panel_group_name"), "panel_group_id", "panel_group_name");
The function is used extensively in option_switcher.php
which determines what the option list should be for any <select/>
elements in forms generated by build_form($skini_handle)
.
Posted by pj at 04:05 PM | Comments (0)
Authentication (Login / Logout) & Sessions
Authentication runs of off one table called user
and is based upon email address and a password stored as a hash. Once authenticated the user_id
from the table is passed around using PHP's $_SESSION
variable and relies on cookies.
Sessions are trixy in PHP and you may benefit from referring to the manual - http://uk.php.net/session. You have no real control over the session timeout length for example and currently the user can get unceremoniously dumped out to the login page when the session expires.
The login_doozer.php
script handles registration of new users too. This invloves the user being provided with a registration key from the system administrator. If you wish to change your password or have forgotten it, this same mechanism will do the job. Your old row will be expired and a new one created. The system would benefit from an email verification function.
Once you have logged in your user_id
from the user
table will be used as insert_by
and update_by
values when doing DB inserts and updates from the system and is encoded in the $user_id
variable.
See the login_doozer.php
and logout.php
scripts in one of the example applications for more details.
For an authenticated script your should include the following lines:
<? include("paths.inc.php"); session_start(); if(!$_SESSION['user_id']){ header('Location: login.php'); } $user_id = $_SESSION['user_id']; ................................ ?>
Posted by pj at 03:18 PM | Comments (0)
The just_sql() Function & The $reply Hash
The SQL facility for querying the database and getting results back has been abstracted into one function. This presumes that your application has its tables in a single database. If this is not the case you can use the do_sql($db, $sql, $debug)
function to specify which db credentials .ini file to use for the query where it is different from the value set in $db_name
.
The main function for running a query is just_sql(sprintf("select * from foo where bar = %d", $bar_id))
. I tend to use this function in conjunction for sprintf()
for extra security.
The $reply
Hash
The following code:
$reply = just_sql("select * from equipment where expired_date is null order by update_date desc limit 3"); $rows = $reply['rows']; header('Content-type: text/plain'); print_r($reply);
produces the following reply hash:
Array ( [num_of_rows] => 3 [rows] => Array ( [0] => Array ( [equipment_id] => 31 [name] => DVD Player [description] => [insert_by] => 1 [insert_date] => 1228746274 [update_by] => 1 [update_date] => 1228746274 [expired_date] => ) [1] => Array ( [equipment_id] => 30 [name] => Portable Video Conferencing Equipment [description] => [insert_by] => 1 [insert_date] => 1226590805 [update_by] => 1 [update_date] => 1226590805 [expired_date] => ) [2] => Array ( [equipment_id] => 29 [name] => 7 X PCs [description] => [insert_by] => 1 [insert_date] => 1226327521 [update_by] => 1 [update_date] => 1226327521 [expired_date] => ) ) [first_row] => Array ( [equipment_id] => 31 [name] => DVD Player [description] => [insert_by] => 1 [insert_date] => 1228746274 [update_by] => 1 [update_date] => 1228746274 [expired_date] => ) [status] => 1 [message] => OK [sql] => select * from equipment where expired_date is null order by update_date desc limit 3 )
N.B. The where
clause of the query includes expired_date is null
. Every table should have a number of common columns, including an expired_date
. This is set with a unix_timestamp()
when the row is to be deleted from the DB. In other words, no rows are ever truly deleted, merely expired. You need this test in your where
clauses to exclude "deleted" rows.
The result rows are found in $reply['rows']
as a list of hashes. The first row is found in $reply['first_row']
too in case that's all you need. $reply['num_of_rows']
tells you how many rows were returned and the original query SQL is included in $reply['sql']
for easier debugging of dynamic queries.
Posted by pj at 01:52 PM | Comments (0)
The $r / $_REQUEST Shortcut
Each web application built with the framework has its own paths.inc.php
file for setting up common variables and paths for the application.
paths.inc.php
should be the first include in any application script. One of the roles it performs is to alias the $_REQUEST
global variable. A copy of this variable is created and named $r
. This is for the sake of pith and saves typing as much as anything else.
$r
is used quite extensively in the SQL functions. Elements in application web forms should be named the same as their corresponding DB columns. That way the $_REQUEST/$r
hash can then be passed to the SQL functions to do quick and easy inserts and updates such as in the example below for adding a new user:
$userid = add_new_row('user'); $r['user_password'] = sha1($r['user_password']); $reply = update_table('user', $r, $userid);
Posted by pj at 12:17 PM | Comments (0)
Getting MySQL-python-1.2.2 to work on Fedora
You need to install mysql-devel
:
su cd yum install mysql-devel
Then you need to make sure your /usr/lib/mysql
directory is linked under /usr/local/lib
ln -s /usr/lib/mysql /usr/local/lib/.
Now you can install the library
cd MySQL-python-1.2.2 python setup.py install
Posted by pj at 11:29 AM | Comments (0)
March 29, 2009
Getting MySQL-python-1.2.2 to work with XAMPP
I'm trying to get the Python MySQLdb library to talk to my XAMMP MySQL. Here's how:
1. Before you build the db adaptor, change the site.cfg
file to point to XAMMP's mysql_config
# The path to mysql_config. # Only use this if mysql_config is not on your PATH, or you have some weird # setup that requires it. mysql_config = /Applications/xampp/xamppfiles/bin/mysql_config
2. Link the dylib
cp /Applications/xampp/xamppfiles/lib/mysql/libmysqlclient.15.dylib /usr/local/mysql/lib/mysql/libmysqlclient_r.15.dylib mkdir /Applications/xampp/xamppfiles/include ln -s /usr/local/mysql-5.1.32-osx10.5-powerpc/include /Applications/xampp/xamppfiles/include/mysql
3. You have to point your script to the localhost
using the machines acutally IP address as if it was a remote server.
Posted by pj at 11:59 AM | Comments (0)
CherryPy HTMLTemplate
HTMLTemplate - CherryPy Tools - Trac
Posted by pj at 02:15 AM | Comments (0)
ZPT with CherryPy
svn co svn://svn.zope.org/repos/main/zpkgtools/trunk
Posted by pj at 12:05 AM | Comments (0)
March 28, 2009
Moonlight Mile
Lyrics | The Rolling Stones - Moonlight Mile lyrics
Posted by pj at 12:40 PM | Comments (0)
March 27, 2009
Setting Up Database Connection Credentials With .ini Files
Database credentials are stored in the common_php directory in Windows .ini format files.
[connection_parameters] user = youruser password = yourpasswordhere host = localhost type = mysql db = blah
This file should be saved as a .ini file in common_php
, and usually with the name of your DB. So for a db named blah
, you would name the file blah.ini
, and also set $db_name = 'blah';
in your applications paths.inc.php
file.
If for extra security you want to name your .ini file something else then that's fine as long as to set $db_name
to that.
When the just_sql()
function is called it looks for a .ini file named after whatever $db_name
is set to, and then parses the contents of that file into a hash to extract the connection credentials and open up a connection before performing the SQL transaction.
The .ini files are protected from view from the webserver using a .htaccess
file:
<Files *.ini> order deny,allow deny from all </Files>
Posted by pj at 05:22 PM | Comments (0)
Setting Environment Paths With paths.inc.php
Paths for each individual application are set withing the application directory itself in a file called paths.inc.php.
<?php $r = $_REQUEST; global $debug; $paths = array(); if(file_exists("H:\\xampp\\htdocs\\")){ $docroot = "H:\\xampp\\htdocs\\"; } if(file_exists("/Applications/xampp/htdocs/")){ $docroot = "/Applications/xampp/htdocs/"; } if(file_exists("/userdata/home/depts/lis/")){ $docroot ="/userdata/home/depts/lis/"; } $paths["host"] = $_SERVER["HTTP_HOST"]; $paths["baseref"] = "http://".$paths["host"]."/lis/simple_pages/"; $paths["js"] = "http://".$paths["host"]."/lis/js/"; $paths["js_path"] = $docroot."js/"; $paths["images"] = "http://".$paths["host"]."/lis/images/"; $paths["docroot"] = $docroot; $config['BaseAddress'] = $paths['baseref']; $asterix = '<span class="mandatory" style="color: red;">*</span>'; $db_name = 'libfaq'; $user_id = 1; ?>
This should be the first include in any application script:
<? include("paths.inc.php"); session_start(); if(!$_SESSION['user_id']){ header('Location: login.php'); } header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1 header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); // Date in the past # Turn off warnings error_reporting(E_ERROR | E_PARSE); $debug = false; $title = "LIS Simple Pages Site - Table of Contents"; .........
The script does several things. Firstly, it creates the $paths hash. Secondly, it aliases $_REQUEST to $r. N.B. If your name any other variable $r things will go bady for you. $r can be used with the add / update functions to add and update rows in a table where the column names match the web form elements.
$booking_id = add_new_row('booking); $reply = update_table('booking', $r, $booking_id);
The $db_name filehandle is also set here (as opposed to in db_name.inc.php as previously). This refers to the .ini file name stump where your DB settings and credentials are stored. This is usually named after the database itself, but doesn't have to be.
Note also that a default $user_id
is set here too. This is important for the add / update functions to work in applications where no user_id is set in the session. Normally this is picked up from the session after login and is the user_id
from the user
table, in which case this value gets overwritten.
Posted by pj at 11:34 AM | Comments (0)
March 26, 2009
Python script for producing svn diffs
import os my_file = open('changed_files.txt','r') lines = my_file.readlines() for line in lines: plode = line.strip() els = plode.split('/') os.popen("svn diff -r 455 " + line.strip() + " > " + "_".join(els) + ".diff") print "svn diff -r 455 " + line.strip() + " > " + els[-1] + ".diff"
Posted by pj at 09:31 PM | Comments (0)
.htaccess Tips and Tricks
.HTACCESS files useful tips and tricks
Posted by pj at 08:56 PM | Comments (0)
March 24, 2009
HTML tags you need to know about
10 Rare HTML Tags You Really Should Know - Nettuts
Posted by pj at 03:35 PM | Comments (0)
CherryPy does ZPT
ChoosingATemplatingLanguage - CherryPy - Trac
Posted by pj at 11:14 AM | Comments (0)
March 23, 2009
The common_php directory
The common_php
directory contains a number of common function files that need to be included in each script in any application. It includes PHP files with one or more functions related either to the application framework or to individual web applications.
add_update_functions.php book_request_functions.php calendar.php calendar_style.css check_url.php cip_functions.php convert_line_breaks.php date_parser.php db_name.inc.php do_sql.php email_functions.php has_value.php interface_functions.php is_even.php kpi_functions.php libfaq.ini option_switcher.php quote_me.php read_config.php read_file.php round_me.php target_use_attributes.php upload_file.php user_functions.phpFramework Specific Files
- .htaccess
protection for the credentials files - add_update_functions.php
Functions for adding and updating rows in MySQL tables with the contents of the $_REQUEST hash ($r). - calendar.php
A calendar pop-up used to populates date fields in the interface. - calendar_style.css
Stylesheet for the above - check_url.php
Contains one function for validating URLs - convert_line_breaks.php
Converts new lines to <br/> tags. - db_name.inc.php
Formally a holder for the database name for a single application, but now deprecated. File still needs to be present though. - do_sql.php
Holds a number of key functions related to SQL querying including just_sql($sql) which is used extensively in every application. - email_functions.php
Functions for building multipart email headers for sending attachments and HTML email. - has_value.php
One function of the same name which runs the gauntlet of PHP tests to determine if a value is or isn't set for a particular variable. Note that if a value of zero is set it returns false. Be careful when trying to set zero as a value in SQL transactions.
In terms of MySQL zero is a value (as different from NULL). Because PHP values are scalar and typing is dynamic this can get you into all kinds of trouble if you are testing a value from a MySQL row as a boolean, (zero == false in PHP).function has_value($var){ if(is_array($var)){ return has_value($var[0]); } if(!isset($var)){ return(false); } if(is_null($var)){ return(false); } if($var === 0){ return(false); } if($var === NULL){ return(false); } if($var === 'NULL'){ return(false); } if($var === 'null'){ return(false); } if($var === ""){ return(false); } preg_match('/\w/', $var, $matches); if(count($matches) == 0){ return(false); } return(true); }
- interface_functions.php
Functions for building HTML forms from .skini definitions in the skins/ directory. These are written in Windows .ini file format. Picklists in <select/> elements are handled separately by functions in the option_switcher.php file. - is_even.php
Two functions, one to tell if a number is odd or even and the other to set the style class for alternating rows in a table. - libfaq.ini
DB connection definition and credentials store in a windows .ini file (ensure this file type is excluded from display in the Apache configuration). Used by the functions in do_sql.php.[connection_parameters] user = youruser password = yourpasswordhere host = localhost type = mysql db = yourdbnamehere
- option_switcher.php
Used to define the <options/> for any select form elements built using the interface functions. - quote_me.php
Contains a function of the same name which properly escapes MySQL inserts automatically detecting for get_magic_quotes_gpc to avoid double escaping. - read_config.php
Contains one function of the same name and is used for pulling the contents of a Windows .ini file into a hash. - read_file.php
Functions for reading a file into a string or a list of lines. - round_me.php
An attempt at a function which correctly rounds monetary values to 2 decimal places as PHP's round function does odd things which might be mathematically more accurate but are annoying in the context of pounds and pence and lead to inaccuracies. I'm not clear whether this solves the issue, and it is a work in progress. Use with caution. - upload_file.php
Functions related to uploading files once they get to the server. You need to read the PHP manual to see what extra elements to include in your form for the process to work. The error reporting functions in this code don't work properly. - user_functions.php
Some basic user functions, including functions to determine if the user is an administrator.
Posted by pj at 04:43 PM | Comments (0)
File Structure of the Framework
The file structure for the framework is quite shallow. The root includes the following files and folders:
common_php/ js/ skins/ upload_temp/ header.php footer.php
Posted by pj at 03:54 PM | Comments (0)
Lightweight PHP Web Application Framework - Contents
File Structure of the Framework
Function Include Files in common_php
Setting Environment Paths With paths.inc.php
Setting Up Database Connection Credentials With .ini Files
The
Authentication (Login / Logout) & Sessions
Doing Database "Create Review Update Delete" With Functions In add_update.php
Common Header & Footer Includes
Building Forms With interface_functions.php & .skini Files
Populating select Element Option Lists with option_switcher.php
Using the poppy() JavaScript Function For Application Alerting
Using JavaScript Validation For Mandatory Form Elements
Using prototype.js For Faster JS Development and AJAX
Building Application DB Tables with tables.ini and create_database.php
Posted by pj at 03:41 PM | Comments (0)
Google API Translation
Fuzzy Buckets: Translation Tools
Posted by pj at 12:28 AM | Comments (0)
March 18, 2009
Google Language API Docs
Developer's Guide - Google AJAX Language API - Google Code
Posted by pj at 04:59 PM | Comments (0)
March 17, 2009
Dell Mini Running Mac OS X
How To: Hackintosh a Dell Mini 9 Into the Ultimate OS X Netbook
Posted by pj at 11:04 AM | Comments (0)
March 16, 2009
Edinburgh Kung Fu
Yee's Hung Ga Kung Fu Edinburgh - Home
Posted by pj at 11:09 PM | Comments (0)
March 15, 2009
My Jython Regex Servlet
The servlet:
from javax.servlet.http import HttpServlet import re import string class regexTest(HttpServlet): def doGet(self,request,response): self.doPost (request,response) def doPost(self,request,response): #param_names = request.getParameterNames() writer = response.getWriter() response.setContentType ("text/plain") try: expr = request.getParameterValues("expr")[0] except: final_hash = { "errors" : ['']} final_hash['errors'][0] = 'You must enter an expression.' writer.println(final_hash) sys.exit try: this_text = request.getParameterValues("text")[0] except: final_hash = { "errors" : ['']} final_hash['errors'][0] = 'You must enter some text.' writer.println(final_hash) sys.exit reg = regexTest() try: final_hash = reg.test_it(expr, this_text) except: final_hash = { "errors" : ['']} final_hash['errors'][0] = 'Failed to run test.' writer.println(final_hash) sys.exit #except: writer.println('') #writer.println('') writer.println(final_hash) #def __init__(self, text="Stuff"): # self.text = text def test_it(self, exp, text): final_hash = {} try: this_reg = re.compile(exp) except: final_hash['error'] = ['Your expression did not compile'] return final_hash #print this_reg this_match = this_reg.findall(text) final_hash["results"] = this_match if this_match: return final_hash else: final_hash['error'] = ['Your expression found no matches'] return final_hash #if __name__ == "__main__": # reg = regexTest() # print reg.test_it('[\d]+', 'These are words and phone 07590 574469')
The JSP with the JSON:
<%@ page contentType="text/html" %> <!-- %@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" % --> <html> <head> <link rel="stylesheet" href="styles.css" type="text/css" media="all"/> <script type="text/javascript" src="js/prototype.js"></script> <script type="text/javascript" src="js/set_date.js"></script> <script type="text/javascript"> function do_regex(){ if(($('text').value == '') || ($('regex').value == '')){ alert('You must enter some text and an expression'); return false; } var url = 'regexTest.py'; var params = '?text=' + escape($('text').value) + '&expr=' + escape($('regex').value); var myAjax = new Ajax.Request( url, { method: 'get', parameters: params, onComplete: show_response }); function show_response(this_request){ this_result = this_request.responseText; $('regex_here').value = this_result; } } </script> <title>Regular Expression Test Harness</title> </head> <body> <h2 style="margin-left: 1em;">Regex Test Harness</h2> <form action="#" method="post" style="width: 80%; margin: 2em; border: 1px solid #dcdcdc;"> <p style="margin-left: 1em;"> <label id="text_block_label" class="label_italic">Text <em class="astrix" id="text_mandatory" style="display: none;">*</em></label> <br/> <em id="text_outer"> <input type="text" name="text" id="text" class="four_c" value=""/> </em> </p> <p style="margin-left: 1em;"> <label id="regex_block_label" class="label_italic">Regex <em class="astrix" id="regex_mandatory" style="display: none;">*</em></label> <br/> <em id="regex_outer"> <input type="regex" name="regex" id="regex" class="four_c" value="" onblur="do_regex()"/> </em> <input type="button" value="Go»" class="button" onclick="do_regex()"/> </p> <form> <textarea style="height: 100px; width: 400px; margin: 1em; color: red;" id="regex_here"> </textarea> </form> </form> </body> </html>
Posted by pj at 10:01 PM | Comments (0)
March 14, 2009
phpPGAdmin
Posted by pj at 03:37 PM | Comments (0)
March 12, 2009
BibClassify Keyword Extraction into SKOS RDF
Atlantis Institute of Fictive Science: BibClassify Admin Guide
Posted by pj at 03:10 PM | Comments (0)
March 09, 2009
Getting PyServlet and Jython working
After a couple of days of hairloss I put the following into the container web.xml:
<servlet> <servlet-name>PyServlet</servlet-name> <servlet-class>org.python.util.PyServlet</servlet-class> <param-name>python.home</param-name> <param-value>/usr/local/jython</param-value> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>PyServlet</servlet-name> <url-pattern>*.py</url-pattern> </servlet-mapping>
Also I had to link:
/usr/local/jython/Lib to /Library/Tomcat/Home/conf/common/lib/Lib
and do the same for my application lib directory.
Now my jylets work.
Posted by pj at 11:37 AM | Comments (0)
March 07, 2009
Regular Expressions in JavaScript
Regular Expressions in JavaScript | evolt.org
Posted by pj at 10:32 PM | Comments (0)
Jython Webapp Tutorial
Jython Webapp Tutorial - Part 1 - Writing Servlets in Jython
Posted by pj at 03:41 PM | Comments (0)
Mo' Web Hooks
Posted by pj at 10:19 AM | Comments (0)
What the hell are webhooks?
Posted by pj at 10:17 AM | Comments (0)
March 05, 2009
XSL for Twitter to RDF
twitter-rdf.xsl at a0ec36781e3af9995a3bccb228e48dd51692b814 from tommorris's twitter-rdf - GitHub
Posted by pj at 09:47 PM | Comments (0)
March 01, 2009
Web Curator Tool
Posted by pj at 08:15 PM | Comments (0)