
pgp (grammar parser) 7.x-1.x, 2009-xx-xx (development version)
----------------------------------------
- Changes (2011-01-31):
  * editor.inc
  * - change debugPrint2() calls to debugPrint()
  * editor.inc, parser.inc
  * - add default parameters to three functions to eliminate PHP notices
  * reader.inc
  * - enhance buildBody() and buildBodyComment() treatment of comments appended to a line
  * - #1038752: handle nested logical operators

- Changes (2010-12-04):
  * module
  * - remove pgp_log_memory_use()
  * editor.inc, module
  * - remove calls to pgp_log_memory_use()
  * - refactor functionGetSignature() to call PGPClass::signature()
  * object.inc
  * - PGPClass: add signature() to return function signature

- Changes (2010-11-05):
  * reader.inc
  * - fix for #925010
  * - enhance buildFunctionCall() and buildExpression() with respect to inlineif expressions
  *   - handle nested expressions and function calls without parentheses (e.g. $question ? print "foo" : bar();)
  * list.inc
  * - add comment about deprecation of inlineif and inlineelse statement types

- Changes (2010-10-29):
  * reader.inc
  * - add buildSpecific() to allow parsing only functions whose name is in a list

- Changes (2010-08-27):
  * editor.inc
  * - enhance commentToStatement() to add comment delimiter if not included in parameter
  * list.inc, object.inc, parser.inc
  * - refactor the debug_path() routines to reflect the gpui_dir variable
  * list.inc
  * - enhance search() to return the item found on recursive call to a PGPBase object

- Changes (2010-08-11):
  * reader.inc
  * - allow a semi-colon as a delimiter of the beginning of the body of a case statement block
  * - revert default value of preserveArrayFormat to FALSE
  * object.inc
  * - PGPArray: improve printing of appended comments when preserving white space

- Changes (2010-07-29):
  * list.inc
  * - PGPList: enhance get() to include object type to return
  * - PGPList: enhance searchCallback() to include search direction and starting node for search
  * - PGPList: add searchAll() to return list of items meeting search criteria
  * object.inc
  * - PGPBase: enhance search() to include object type to return and search direction
  * - PGPBase: refactor searchForward() and searchBackward() to call search()
  * - PGPBase: enhance searchCallback() to include search direction
  * - PGPBase: add searchAll() to return list of items meeting search criteria
  * - PGPClass: add getParameterVariable() to strip any default value assignment or inline comments
  * - PGPFunctionCall: enhance stripComments() to create new object instead of cloning
  * - PGPFunctionCall: refactor searchForward() and searchBackward() to call PGPList::search()
  * - PGPAssignment: add getValue() to return the assignment value
  * - PGPArray: add traverse2() to invoke callback on array elements
  * parser.inc
  * - rename error handler variable
  * reader.inc
  * - update documentation

- Changes (2010-07-21):
  * reader.inc
  * - revert prior change after eliminating '&' on insertLast (see 2010-04-20)

- Changes (2010-07-12):
  * list.inc
  * - improve setting of node type in insertListBefore() and insertListAfter()

- Changes (2010-07-09):
  * reader.inc
  * - change $functionCalls property to store the node instead of the function call object
  * - this means getFunctionCalls() now returns a list of nodes

- Changes (2010-07-03):
  * list.inc
  * - enhance search() to include object type to return, search direction, and starting node for search
  * - refactor searchForward() and searchBackward() to call search()
  * - enhance insertListBefore() and insertListAfter() to use the type from the nodes being inserted
  * - enhance clear_r() to check for $current being an object and to unset($list->xxx) instead of $this
  * - enhance strip_comments() to iterate over nodes of an expression
  * object.inc
  * - add strip_comments() missed in previous commit

- Changes (2010-06-23):
  * list.inc
  * - change isType() to use the first 'operand' node (instead of first node)

- Changes (2010-06-18):
  * editor.inc
  * - change default return value in arrayitize() to 'array()'

- Changes (2010-06-13):
  * reader.inc
  * - #763774: handle a statement beginning with a parenthesis

- Changes (2010-06-07):
  * list.inc, reader.inc
  * - #779528: improve memory releasing code to avoid unbounded memory usage

- Changes (2010-04-22):
  * list.inc
  * - correct parsing of statements with '@' (in particular before the new operator)
  * - comment out the remaining '&' on '&$data' in insertXXX() functions
  * object.inc
  * - eliminate PHP warning, turn off unintended debug in PGPAssignment::matches()
  * reader.inc, list.inc
  * - implement break statement as function call

- Changes (2010-04-20):
  * reader.inc
  * - eliminate PHP strict notices that are generated with PHP 5.3

- Changes (2010-04-15):
  * editor.inc
  * - #765050: handle class properties and constants (for API documentation)

- Changes (2010-03-31):
  * reader.inc
  * - restore array rewriting when $preserveArrayFormat == FALSE
  * - set multiline to TRUE if original has newlines (since whitespace is no longer recorded in this case)
  * - improve parsing of increment/decrement operator when followed by whitespace and a parenthesis

- Changes (2010-03-24):
  * reader.inc
  * - ignore whitespace when parsing arrays if $preserveArrayFormat == FALSE
  * - this helps with upgrade routines that create array strings
  * object.inc
  * - change $key to $key2 in searchCallback() and search()

- Changes (2010-03-21):
  * reader.inc
  * - #748382: correct parsing of list statement with whitespace before parentheses

- Changes (2010-03-11):
  * object.inc
  * - PGPArray: add function deleteKey()

- Changes (2010-03-10):
  * object.inc
  * - PGPArray: add functions changeKey() and findNextValue()
  * - PGPArray: modify findKey() to trim quotes before comparison
  * - PGPArray: modify toString() to check preserve property before printing whitespace

- Changes (2010-03-09):
  * reader.inc
  * - #736868: correct parsing of ternary expression as the initial property in a foreach statement
  *   - foreach ({ternary} as $foo) (e.g. inline if is ternary)

- Changes (2010-03-08):
  * add new API function
  * - list.inc: stripComments
  * editor.inc
  * - replace unintended echo with debugPrint2

- Changes (2010-03-05):
  * add new API function
  * - object.inc: isType, modify PGPArray::findValue()
  * reader.inc
  * - restore statement type for T_CONTINUE, T_ECHO, T_RETURN, and T_EXIT

- Changes (2010-03-04):
  * add new API functions
  * - editor.inc: commentToStatement
  * - list.inc: insertStatementBefore and After, and isType
  * - object.inc: insertStatementBefore and After, parameterCount, and clearParameters

- Changes (2010-03-02):
  * reader.inc
  * - correct parsing of:
  *   - statements beginning with new
  *   - inline if expression for the key in an array
  * remove unused files after extracting user interface elements
  * - bulk.inc, inc, test

- Changes (2010-03-01):
  * parser.inc, list.inc, object.inc
  * - refactor the debug print routines
  * bulk.inc, inc, info, install, module, test
  * - remove the user interface elements (these are part of the Grammar Parser UI module)

- Changes (2010-02-26):
  * reader.inc, list.inc, object.inc, writer.inc
  * - correct parsing and rewriting of:
  *   - #726054: indented multi-line comments
  *   - #726054: block body comments (comments on the same line as the block begin token)
  *   - arrays with a value equal to a string expression (whitespace with new line was swallowed)
  * list.inc
  * - replace CR+LF characters with LF (?)
  * install
  * - add requirements checks for PHP memory limit and PHP maximum execution time limit
  * test.inc
  * - update expected output files based on recent changes to parser

- Changes (2010-02-25):
  * reader.inc, list.inc
  * - correct parsing of:
  *   - #724800: expressions inside curly braces
  *   - #724796: block statements without braces whose single statement body is itself a block statement
  * writer.inc
  * - remove trailing spaces from ends of lines

- Changes (2010-02-24): (part 2)
  * module, inc
  * - add bulk parsing form using memory logging and bulk.inc

- Changes (2010-02-24): (part 1)
  * reader.inc
  * - correct (or restore) parsing of:
  *   - #722602: expressions in parentheses following a subtraction operator
  *   - #722596: expression with instanceof (outside of a conditional)
  *   - list() inside an expression
  *   - a function that returns a reference
  *   - bracketed expression, e.g. ${DB_ERROR} = TRUE;
  *   - statements that begin with isset (followed by inline if)
  *   - a nop body (i.e. ';') on conditionals, for and foreach blocks
  *   - multiple expressions in any of the conditions of a for block

- Changes (2010-02-19):
  * reader.inc
  * - add class method calls to function call list

- Changes (2010-02-18):
  * list.inc, object.inc
  * - remove $data (or $elements) from search function parameters
  * - add searchForward, searchBackward, and matches functions

- Changes (2010-02-15):
  * editor.inc
  * - add static function getInstance
  * object.inc, reader.inc, module
  * - add option to preserve original format of array expressions (including presence of final comma)
  * reader.inc
  * - improve parsing of doc comments that are associated with the following item in the file
  * - handle a bitwise not (~) operator
  * bulk.inc
  * - add this file with ability to process multiple directories
  * inc
  * - pgp_clean_directory: use unlink instead of file_unmanaged_delete (for portability)
  * info, test
  * - add this file with functional tests

- Changes (2010-02-09):
  * list.inc, object.inc, reader.inc
  * - correct parsing of inline conditional expressions
  * - improve array parsing by handling expressions in parentheses, inline conditionals, and whitespace before keys
  * - handle error suppression operator (@) before a string
  * - correct parsing of certain expressions (e.g. with a unary operator) in a function call parameter
  * - handle continue, echo, return and exit (or die) with or without parentheses

- Changes (2010-02-05):
  * list.inc, object.inc, parser.inc, reader.inc writer.inc
  * - remove unused variables and commented out code, update documentation, etc.
  * inc, install, module
  * - update documentation comments for second person tense

- Changes (2010-02-04): (part 3)
  * object.inc
  * - improve printing of arrays (respecting the $multiline and $original attributes)
  * reader.inc
  * - improve parsing of arrays and other expressions by handling embedded comments and whitespace
  * - improve parsing of arrays by setting the $multiline attribute based on a precedence order
  * - update documentation of formatting that is modified (specifically comments)
  * - improve memory releasing in setSnippet routine

- Changes (2010-02-04): (part 2)
  * list.inc
  * - store line numbers for use with API module integration
  * - handle error suppression operator (@) in toString methods
  * - add is_object condition to statementType and statementValue routines
  * object.inc
  * - correct the printing of a zero value on a continue, echo return, or exit statement
  * reader.inc
  * - correct handling of parentheses in expressions (logical and string)
  * - handle error suppression operator (@) in parsing
  * - conform treatment of reference, suppression, and indirect tokens
  * - store line numbers for use with API module integration
  * - resore handling of special class strings, e.g. parent or self
  * - improve parsing by dropping certain inline comments in statement blocks
  * - restore comments in an interface, class or function body just before the closing brace

- Changes (2010-02-04): (part 1)
  * editor.inc, list.inc, object.inc, reader.inc writer.inc
  * - remove "\n" from debugPrint calls as this routine automatically includes them
  * inc
  * - add if defined test around constant definitions
  * - enhance pgp_log_memory_use to deal with code being run outside of Drupal

- Changes (2010-01-24): (part 4)
  * reader.inc
  * - correct handling of parentheses in expressions

- Changes (2010-01-24): (part 3)
  * list.inc, object.inc
  * - add clear_r function to allow callers to avoid excessive memory consumption
  * reader.inc
  * - add static function getInstance
  * - add reset and clearArray functions to allow callers to avoid excessive memory consumption
  * - setSnippet: pass variable by reference to avoid additional memory consumption
  * writer.inc
  * - add static function getInstance
  * module
  * - call reader::getInstance to avoid creating duplicate objects
  * - call reader::reset to avoid excessive memory consumption
  * inc
  * - add pgp_log_memory_use routine

- Changes (2010-01-24): (part 2)
  * list.inc, object.inc, parser.inc
  * - change debug output from echo to write to file

- Changes (2010-01-24): (part 1)
  * list.inc, object.inc, parser.inc, writer.inc
  * - update documentation comments for second person tense
  * parser.inc
  * - rename get_last_caller routine to getLastCaller for consistency

- Changes (2010-01-20):
  * editor.inc
  * - changes for use with API module integration
  * - refactor called routines to use objects
  * - make public the getReader method
  * - update documentation comments
  * parser.inc
  * - include get_last_caller routine for portability
  * module, inc
  * - implement version-relative code to simplify dual-version code maintenance

- Changes (2010-01-18):
   * object.inc
   * - use '===' with if ($key === 'parentExpression') since PHP evaluates this expression as true when $key = 0

- Changes (2010-01-01):
   * editor.inc
   * - change PGPList to PGPBody in statementsToText
   * object.inc
   * - clean up doc comments

- Changes (2009-12-27): (part 2)
   * list.inc
   * - turn off debug output
   * - annotate which objects call PGPExpression::toString
   * object.inc
   * - turn off debug in PGPConditional
   * writer.inc
   * - comment out unused variables and methods

- Changes (2009-12-27): (part 1)
   * object.inc, parser.inc, writer.inc
   * - clean up doc comments
   * writer.inc
   * - remove printString method since PGPString::toString exists

- Changes (2009-12-26): (part 3)
   * writer.inc
   * - remove the refactored PGPWriter::printObject routines

- Changes (2009-12-26): (part 2)
   * list.inc
   * - add PGPBody class to handle body statements for a class, function, if, for, while, etc.
   * object.inc
   * - add toString method to PGPClass, PGPConditional, PGPFor, PGPForEach, PGPCase, PGPDeclare, PGPTryCatch, and PGPAssignment
   * - refactor T_CONTINUE, T_ECHO, T_RETURN, and T_EXIT from array items to PGPAssignment objects
   * reader.inc
   * - use new PGPBody class in buildBody
   * - eliminate the new line character on open tag to make printing simpler
   * - handle printing of T_OPEN_TAG in the new PGPBody->toString method
   * writer.inc
   * - refactor the remaining PGPWriter::printObject routines into PGPObject::toString methods

- Changes (2009-12-26): (part 1)
   * list.inc
   * - refactor PGPList::toString to handle conditions from a conditional
   * object.inc
   * - add toString method to PGPListStatement
   * writer.inc
   * - eliminate more of the routines in PGPWriter by calling toString of each object

- Changes (2009-12-21):
   * editor.inc
   * - conform debug output to change in Coder Upgrade

- Changes (2009-12-14):
   * editor.inc
   * - conform callback in traverseCallback to change in Coder Upgrade
   * - add return type option (node or data) to findFunction
   * - update documentation comments
   * reader.inc
   * - update documentation comments

- Changes (2009-12-05):
   * Change contents of helper lists:
   * - The function call list still contains references to PGPFunctionCall objects.
   * - The other lists now contain references to PGPNode objects.
   * Add helper functions to editor: arrayitize, findFunction, and removeDefaults
   * Add traverse function to PGPNode and PGPBase.
   * Modify traverse function in PGPList.
   * Add conditionsToArray function to PGPConditional.
   * Add helper functions to PGPArray: findKey, getValue, and findValue.
   * Conform while loops to use a condition of $current->next != NULL.
   * Implement blocks without braces for the for and foreach statements.

- Changes (2009-12-04):
   * Turn off debug output:
   * - Comment out the echo statements
   * - Turn off debugPrint2 in parser.inc
   * - Set $debug to FALSE in object.inc
   * Fix parse error on an else block without braces.

- Changes (2009-11-28):
   * Add PGPReader as a parameter to traverseCallback and the callback functions.
   * Move PGPExpression element functions to PGPList.
   * Remove PGPClassExpression and buildClassExpression from source.
   * Add helper functions to PGPArray.
   * Only add a parameter to function or function call objects if there is one.

- Changes (2009-11-23):
   * Add documentation examples of API functions.
   * Rename PGPFunctionCall2 to PGPFunctionCall.
   * Eliminate PGPFunctionCall from PGPEditor classes.
   * Generalize the parameter helper functions in PGPEditor to work on interfaces, classes, and functions.

- Changes (2009-11-22):
   * Add helper functions to PGPClass.
   * Check for variables referring to objects before attempting to invoke code.
   * Fix print_r functions when printing the first level items.

- Changes (2009-11-20):
   * Commit changes made over the last three months.
   * - More cleanup will come as deprecated code is removed
   * Refactor parser API:
   * - use classes for each grammar item
   * - PGPBase is the base class for most grammar-specific items (e.g. class, function, function call, and conditionals)
   * - PGPList is the base class for most everything else (e.g. the file, expression, expression element, and parameters)
   * - Add helper functions where appropriate.
   * Fix printing of nested operator function call (e.g. $result = db_insert('simpletest')->fields($assertion)->execute();).
   * Change module use of print_r in file_put_contents($out_file, print_r($reader->getStatements(), 1)).
   * Use our print_r instead.

- Changes (2009-11-18):
   * Changes made to conform to revised core api or standards:
   * - add 'config' to menu paths
   * - use third person tense in hook_x comments
   * - add $form to parameters of form builder functions
   * - change keys in hook_theme response array
   * - remove 'array' wrapper from '#theme' elements
   * - extract key from $variables array passed to theme_xxx function
   * - add 'array' wrapper to theme() function arguments
   * Add 'engine' directory and move appropriate files to it.

- Changes (2009-08-24):
   * Change calls to file_check_directory to file_prepare_directory in light of core function rename.

- Changes (2009-08-17):
   * Add PGPList class (a custom doubly linked list of PGPNode objects).
   * Add PGPNode class to hold grammar statements, pointers to next and previous statements, and the containing list.
   * Refactor the grammar array to a PGPList object to allow for complex edits to multiple lines.
   * Implement list of function calls.
   * Add new functions for use with PGPEditor (buildSnippet and printSnippet).
   * Expose private functions for use with PGPEditor (printParameters and printConditionVariable).
   * Enhance PGPEditor API for use with code editing (e.g. for Coder Upgrade).
   * Clean up comments.

- Changes (2009-08-04):
   * Clean up uncommitted comments (move some to CHANGELOG or class doc_block, delete others).
   * Fix printing of comment after ';' which was being placed on next line.
   * Handle double '$' and '++' inside array index (Ex: $$var = isset($match[++$i]) ? $match[$i] : '';).
   * Handle consecutive comments (inside array statement) (see common.inc from 6.x on lines 473-5).

- Notes (2009-07-20): (INTERNAL ONLY) (NOT DONE)
   * Add support for '@' syntax

- Changes (2009-07-13):
   * Fix use of $temp in assigning pointers to helper array values.
   * Fix eval function call inside a function call parameter list (Ex: print eval(...);).
   * Handle if without braces (Ex: if (!$data) continue;). (Could also rewrite without braces in writer.)
   * Add custom constant T_DEFINE for 'define' so we can always call $writer->statementTypeToString.
   * Add PGPEditor class (initially for use with API module).

- Changes (2009-07-10):
   * Finally implemented 'else if' syntax.
   * Add custom token constants.
   * Add arrays and getters for interfaces, classes, functions, function calls, defines and globals.

- Changes (2009-07-07):
   * Implement heredoc tokens.

- Changes (2009-07-06):
   * Implement function call when function name is a complex variable expression.
   * Omit blank lines when function, class or interface body is empty (as opposed to missing).
   * Clean up comments.

- Changes (2009-07-06): (INTERNAL ONLY)
   * Tokens implemented:
   * - [371] => T_START_HEREDOC
   * - [372] => T_END_HEREDOC

- Changes (2009-06-23):
   * Implemented all but 7 tokens (only the two heredoc tokens matter).
   * Removed static modifier from arrays in base class.
   * Added exception and error handler routines.
   * Code has been tested with includes/database.inc, simpletest/drupal_web_test_case.php and uts.module.

- Changes (2009-06-20): (INTERNAL ONLY)
   * Not [$query] in return $this->preparedStatements[$query]; (DONE)
   * Not ++ in return "db_temporary_" . $this->temporaryNameIndex++; (DONE)
   * Not doc_comment before regular comment @ 1529 (DONE)
   * Not [A]rray in function parameter (NOT DONE)
   * Not spacing in parameter list @ 2640 (NOT DONE)
   * Not doc_comment as last token @ 2689 (DONE)

- Notes (2009-06-20): (INTERNAL ONLY)
   * An expression like the following is incorrectly recognized as an assignment instead of a function call
   * $method[$i]($p1, $p2, 'p3');
   * The above expression is valid based on a test
   * There are no actual occurences in core of this type of expression (so far)
   * Can we lookback when we encounter a '(' to see if it is preceded by an operator plus whitespace?
   * Also valid $method[($i)](($p1), ($p2), ('p3'));
   * So we need to keep count of parens seen so far on statement
   * If left count exceeds right (and not inside a square bracket) then we are in a function call?

- Changes (2009-06-19):
   * Add base parser class.
   * Modify reader and writer classes to extend base class.
   * Rename some functions.
   * Add some skeleton code to classes.
   * Update module code to call new functions.

- Notes (2009-06-18): (INTERNAL ONLY)
   * Areas where we have addressed the handling of non-standard whitespace:
   * - expressions around operators
   * - array definitions around the double arrow operator
   * - parentheses around a function parameter list

   * Areas where we have left it alone:
   * - multiline whitespace used in logical expression
   * - Example: if (...) && (...) where the second condition is on a new line
   * - the above can easily be fixed with a regular expression at the end
   * - arround parenthesis in other places
   * - try it and see

- Changes (2009-06-13): (INTERNAL ONLY)
   * Tokens implemented:
   * - [260] => T_EVAL
   * - [266] => T_PRINT
   * - [289] => T_UNSET_CAST
   * - [290] => T_BOOL_CAST
   * - [291] => T_OBJECT_CAST
   * - [292] => T_ARRAY_CAST
   * - [293] => T_STRING_CAST
   * - [294] => T_DOUBLE_CAST
   * - [295] => T_INT_CAST
   * - [298] => T_CLONE
   * - [300] => T_EXIT
   * - [304] => T_ENDIF
   * - [308] => T_STRING_VARNAME (when using T_DOLLAR_OPEN_CURLY_BRACES)
   * - [310] => T_NUM_STRING (???)
   * - [319] => T_ENDWHILE
   * - [321] => T_ENDFOR
   * - [323] => T_ENDFOREACH
   * - [324] => T_DECLARE (not present in 7.x includes directory)
   * - [325] => T_ENDDECLARE
   * - [328] => T_ENDSWITCH
   * - [334] => T_CONST (Manually added)
   * - [347] => T_VAR (with classes and objects)
   * - [353] => T_INTERFACE
   * - [358] => T_LIST
   * - [360] => T_CLASS_C (magic constants)
   * - [361] => T_METHOD_C (magic constants)
   * - [362] => T_FUNC_C (magic constants)
   * - [363] => T_LINE (magic constants)
   * - [364] => T_FILE (magic constants)
   * - [xxx] => T_DIR (magic constants) (Added in PHP 5.3.0.)
   * - [373] => T_DOLLAR_OPEN_CURLY_BRACES (${)
   * - [374] => T_CURLY_OPEN

- Changes (2009-06-11): (INTERNAL ONLY)
   * Tokens implemented:
   * - [288] => T_INSTANCEOF (Manually added)
   * - [299] => T_NEW
   * - [336] => T_TRY
   * - [337] => T_CATCH
   * - [338] => T_THROW
   * - [354] => T_EXTENDS (Manually added) (May be handled)
   * - [355] => T_IMPLEMENTS (Manually added) (May be handled)
   * - [375] => T_DOUBLE_COLON

- Changes (2009-06-05): (INTERNAL ONLY)
   * Grammar elements implemented:
   * - modifiers for class, method or variable
   * - type specification in a formal parameter (this may parse as an operand; array fails)
   * - constant (define or const [T_CONST] in PHP 5.3.0)
   * - try catch, throw
   * - declare(skip this)
   * - cast, instanceof, variable, new, literal,
   * - list assignment (list is a grammar element not a function per se), ignore errors
   * - curly braces surrounding an expression
   * - converts '{}' to '[]' when used as an index to string
   * - require, include or the _once versions (T_REQUIRE_ONCE, etc.)
   * - multi-line comments surrounded by '/*' and '*\/' without using the '*' on intermediate lines.
         (we remove \n characters in cleanComment???)
   * - array done inline in code (not a function or function call) (not Drupal standard)

   * - see uts.module
   * - in some cases in array definition when value following double arrow does not end with a comma
   * - examples
   * - function calls 'access arguments' => array('access administration pages')
   * - a negative number (integer)
   * - double quotes on expression, 'href' => "admin/uts/studies/$study->nid/edit"
   * - concatenation after function call like require_once drupal_get_path('module', 'uts') . '/uts.help.inc';
   * - concatenation inside array key $form['email'][$key]['uts_mail_' . $key . '_subject']
   * - the above is an expression that serves as the parameter to the require_once 'function'
   * - parens around logical like '#value' => ($study_nid !== NULL)
   * - double quotes in array indices
   * - unary operators after array index like $items["$base/$module"]['page arguments'][1]++;
   * - index expression with concatenation like $form['email'][$key]['uts_mail_' . $key . '_subject']
   * - TRUE or FALSE? In function call parameters? Like count(uts_session_load_all($study->nid, TRUE));
   * - empty (T_EMPTY), unset (T_UNSET)
   * - defines and the comments before them
   * - space after continue
   * - array when used as type qualifier in function parameter list uts_tasks_import($study_nid, array $tasks)

   * - see database.inc
   * - type declarations in function parameters like 'array $args = array()' (both are T_ARRAY)
   * - :: (T_DOUBLE_COLON)

- Changes (2009-06-01):
   * Add module files.
   * Add menu items, permissions, and other basics.
   * Add a directory called 'pgp' beneath the files directory.
   * Add code to call parser classes for reading and writing source code.
