CHANGELOG

2.0.5
*	Change in behavior: PUT global variable deprecated in favor of a more
	generic REQBODY global variable which returns the HTTP request body
*	NEW: OpenID plugin (1.x/2.0 consumer) with support for both XRI/Yadis and
	HTML discovery
		F3::route('GET /openid/auth',
			function() {
				$openid=new OpenID;
				// Specify the OpenID account
				$openid->identity='https://www.google.com/accounts/o8/id';
				// Define the return route for validation
				$openid->return_to=F3::get('PROTOCOL').'://'.
					$_SERVER['SERVER_NAME'].'/openid/valid';
				if (!$openid->auth())
					echo 'Unable to authenticate OpenID account '.
						$openid->identity;
			}
		);
		F3::route('GET /openid/valid',
			function() {
				$openid=new OpenID;
				$result=$openid->verified();
				echo 'OpenID account '.$openid->identity.
					($result?'verified':'failed verification');
			}
		);
*	NEW: Text plugin diff() and patch() methods
*	NEW: Code plugin snake() and camel() methods
*	NEW: Net plugin whois() method
*	NEW: Autoloader now supports both .php and .class.php file extensions
*	Jig now supports gzip format
*	FileDB plugin is now NFS-friendly; mutex() implemented
*	map() can now determine if REST method in mapped class is static or
	otherwise
*	Enhanced: validEmail() now uses sockets if extension is available
*	Bug fix: Apache loses track of current directory during script shutdown
*	Bug fix: sitemap() fails on non-HTTP URLs
*	Bug fix: Non-array value of <repeat> group attribute triggers an error
*	Bug fix: PHP interfaces not supported by autoloader

2.0.4
*	TRUE if passed aas 2nd argument of dump() instructs framework to dump
	code using PHP's syntax highlighter; default value: TRUE
*	Position-insensitive treatment of <true> and <false> blocks in F3
	templates
*	Safer handling of FileDB commits
*	Improved PROTOCOL detection
*	dump() and highlight() moved to new Code plugin
*	set(), get(), clear(), exists() now more COOKIE-friendly; use the new
	COOKIES variable to adjust default cookie settings
*	exists() on a session variable now auto-starts a session
*	Change in behavior: 403 Forbidden now generated if DNSBL reports that
	remote IP address is blacklisted (previously 404 Not Found)
*	Change in behavior: 405 Method Not Allowed generated at runtime (along
	with the appropriate HTTP Allow header listing the methods defined in
	the application) if request URI fits route() pattern but request method
	doesn't match
*	Lock-aware file handlers implemented
*	Added check for sent headers in Graphics plugin methods
*	Added 'Fatal Error:' prefix to errors that trigger script shutdown
*	Added 3rd argument to minify(): if TRUE (default), output is echoed;
	if FALSE, output is returned as a string
*	Bug fix: CACHE has no effect on HTML generation of templates
*	Bug fix: framework variables as array elements
*	Bug fix: namespace handling behavior not identical across locales
*	Bug fix: http() triggers error if path is empty
*	Bug fix: ICU format() default language setting
*	Bug fix: http() redirect
*	Bug fix: CACHE detection
*	Bug fix: hotlink and throttle mangled by route()
*	Bug fix: Fatal errors do not ignore custom handler
*	Bug fix: Template engine doesn't handle nested templates properly

2.0.3
*	NEW: Custom session() handlers for DB/Axon and FileDB/Jig
*	NEW: screenshot() added to Graphics plug-in; Grabs Web pages and renders
	HTML via Webkit engine; Crops image and generates thumbnails, if
	specified
*	Improved Geo location(); now uses geoplugin.net for lookup
*	Axon aselect() implemented as an adjunct to select(); returns an
	array of associative arrays similar to afind()
*	LOGS variable is back
*	FileDB auto-commit implemented
*	privateip() argument is now optional; defaults to $_SERVER['REMOTE_ADDR']
*	Bug fix: Auth::sql() not resolving AUTH variable
*	Bug fix: sitemap() doesn't ignore # anchors
*	Bug fix: HTTP 307 status code
*	Bug fix: error code returned by global exception handler

2.0.2
*	NEW: SMTP attach() for e-mail attachments
*	NEW: instance() method implemented in Base class so all inheriting
	classes can be instantiated (and used in chained calls) like:-
		$user=Axon::instance('users')->load();
		$dir=Zip::instance('temp/test.zip')->dir();
*	SMTP plug-in now supports SSLv2 and SSLv3 stream wrappers
*	autoload() and Matrix class refactored
*	Provision for non-alphanumeric MySQL database names in Axon code
*	Bug fix: Axon save() error when no field was modified
*	Bug fix: Axon load() error when table has no primary key
*	Bug fix: schema() error message truncated
*	Bug fix: input() creates a reference to non-existent variable
*	Bug fix: minify() does not ignore absolute URLs

2.0.1
*	ONERROR behavior now identical to route handlers, i.e. beforeRoute() and
	afterRoute() methods are executed if ONERROR points to a class/object
	method
*	Jig begin(), rollback(), and commit() methods implemented
*	DB schema() now uses table_catalog instead of table_schema
*	input() argument list restructured
*	ICU load() now defaults to 'en' if environment variable LANG is invalid
*	DB exec() now uses errorInfo() when a syntax error occurs
*	Bug fix: inTransaction() not supported by all SQL drivers
*	Bug fix: SQL auto-commit
*	Bug fix: array variables not handled properly by input()
*	Bug fix: Extraneous headers sent by serve()
*	Bug fix: minify() and sitemap() don't terminate immediately

2.0.0 release
*	NEW: Axon/M2/Jig afindone() method returns array equivalent of object
	matching criteria
*	NEW: Jig _OR_ operator and _PHP_ callback
*	Data types are now queried by Axon during sync() and referenced
	automatically during save()
*	PHP globals in templates can now be disabled (enabled by default):-
		echo Template::serve('myTemplate.htm','text/html',FALSE);
	The last argument prevents  the use of globals like SESSION, GET, POST,
	COOKIE, etc. so templates have access only to data passed by controllers
*	Zip set() now uses current time as default if not specified
*	Zip is now template token-aware
*	Temporary Zip files now respect TEMP path
*	Change in behavior: expect() return value is now an array
*	Bug fix: Jig find() ignores _id
*	BUg fix: No session_commit() before HTTP redirect

2.0.0-b12 (pre-release)
*	NEW: SMTP plug-in now supports SSL and TTL authentication
*	Stronger type checking in Jig method arguments
*	UTF::substr_count() added
*	404 error message now indicates HTTP request method
*	Web::slug() now drops single-quotes
*	route() and map() now have bandwidth throttling control
*	send() moved to base class
*	ICU-formatted strings in F3 templates now use a \ delimiter, instead
	of a double-slash (//):
		{{@var\time()}}
*	Bug fix: Axon/Jig/M2 factory() instantiates objects of root class
	instead of child class/extension
*	Bug fix: sitemap() fails when application is not located in the
	document root
*	Bug fix: Jig/M2 copyFrom() resets object
*	Bug fix: UTF::preg_quote() doesn't escape /
*	Bug fix: ref() doesn't process tokens recursively
*	Bug fix: Jig find() offset/limit calculation
*	Bug fix: Web::sitemap() query strings
*	Bug fix: Auth::onload() clears AUTH variable

2.0.0-b11
*	NEW: append() adds keyed element to a framework array variable
*	NEW: concat() and sprintf() methods for framework string variables
*	NEW: <repeat> template directive now allows counter="{{@var}}" attribute
	for tracking current number of iterations automatically; useful for
	odd/even tests, such as:
		<repeat group="{{@group}}" value="{{@val}}" counter="{{@ctr}}">
			<div class="{{@ctr%2?'odd':'even'}}">{{@val}}</div>
		</repeat>
*	NEW: Axon/Jig/M2 afind() method for returning all records that match
	specified criteria as an array of associative arrays (instead of an
	array of objects)
*	NEW: <include> template directive now allows if="{{@expr}}" attribute for
	inserting a sub-template subject to the boolean value of specified
	expression
*	NEW: htmlencode() and htmldecode() methods - used in the same manner as
	the PHP equivalent htmlentities/htmlspecialchars and html_entity_decode/
	htmlspecialchars_decode but respects the framework's ENCODING global
	variable setting
*	IMPORTS is back and now allows multiple paths; however, route handlers
	should specify the PHP file name, e.g.
		F3::set('IMPORTS','pages/');
		F3::route('GET /about','about.php');
	At runtime, the framework will load pages/about.php when the GET /about
	route is received
*	Pipe (|), semi-colon (;) or comma (,) may now be used as separators for
	route() and input() function chains, IMPORTS and AUTOLOAD paths
*	Improved Jig concurrency control
*	Axon and Jig code optimized; MySQL data access layer now uses SQL92
	information schema
*	F3 template engine now respects TIDY configuration
*	Object->method syntax now more liberal towards whitespaces
*	Change in behavior: 4th argument of set() method dropped; Application is
	now responsible for sanitizing data via scrub() or input()
*	Change in behavior: scrub() and input() do not auto-convert to HTML
	entities anymore
*	Change in behavior: Axon/M2/Jig erase() now allows direct specification
	of deletion criteria; if not specified, criteria used in last load()
	statement is used
*	Bug fix: rollback() on error
*	Bug fix: M2 found() return value
*	Bug fix: Incorrect handling of PHP tags in grab()
*	Bug fix: User-defined functions in F3 templates

2.0.0-b10
*	ICU formatting support for servers that do not have the PHP intl module
	installed (Only number, number/integer, number/currency, and date formats
	are supported)
*	Template syntax when using ICU-formatted strings in dictionaries:
		{{@stringvar//time()}} for F3 templates
		<?php echo $this->get('stringvar',time()); ?> for PHP templates
*	diacritics() is now a framework variable; Default Latin translations will
	be merged with any user-defined DIACRITICS once Web::slug() is called
*	is_array(), push(), pop(), shift(), unshift() for framework variables
	containing arrays
*	Access to read-only framework variables now restricted
*	PHP short tags work even when short_open_tag is disabled (PHP templates)
*	Template engines optimized
*	Bug fix: Routing side effects caused by extraneous spaces in config()
*	Bug fix: Exclusive locks
*	Minor code refactoring

2.0.0-b9
*	NEW: <loop> template directive:
		<loop counter="{{@i}}" from="{{1}}" to="{{@j}}">
			<span>{{i*2}}</span>
		</loop>
	PHP equivalent:
		<?php for ($i=1;$i<$j;$i++): ?>
			<span><?php echo $i*2; ?></span>
		<?php endfor; ?>
	An optional step="{{1}}" attribute may be specified
*	NEW: UTF plug-in - a handy replacement for common mbstring functions
*	NEW: begin(), rollback(), and commit() added to DB class to facilitate
	PDO late-binding/lazy-loading
*	Change in behavior: Non-SELECT sql() calls now return the number of
	rows affected
*	Template engine optimized: better sanity checks
*	TEMP folder now serves as storage for compiled templates; used also as
	secondary cache for servers with allow_url_fopen or allow_url_include
	disabled in php.ini
*	input() back to 1.x behavior: field name passed as 2nd argument of
	callback function
*	Axon/M2/Jig cast() method returns object as array
*	Bug fix: Routing tokens receiving values that end with an RFC 1738
	punctuation

2.0.0-b8
*	NEW: Template engine code rewritten from scratch; now performs just as
	fast as regular PHP templates
*	Change in behavior: Template tokens MUST now use {{@var}} format
*	NEW: Jig (flat-file) ORM with near-identical functionality as Axon/M2
*	mset() now adds a variable prefix if a 2nd argument is specified
*	NEW: prev(), and next() methods for traversing Axon/M2
*	Change in behavior: '*' as 2nd argument of scrub() disables HTML tag
	filters, i.e. permits all HTML tags; however, all characters are still
	converted to HTML entities
*	Change in behavior: minify() dependence on GUI variable removed
*	subst() and resolve() unified
*	Bug fix: Axon save() triggers error when record needs no update

2.0.0-b7
*	NEW: Autoload support for namespace/class.php and namespace_class.php
*	Generic array utilities moved to Matrix class:
		pick(), sort(), transpose() and changekey()
*	Check for short PHP tags added to grab()
*	Bug fix: error() generates stack trace on 404
*	Bug fix: <F3:include> inside <F3:repeat>
*	Minor code refactoring

2.0.0-b6
*	Reverted sql() back to static; exec() now used for object mode
*	Framework now supports object notation in set(), get(), clear(), and
	exists():
		F3::set('abc',new stdClass);
		F3::set('abc->x',123);
		F3::set('abc->y',array());
		F3::set('abc->y.1','hello');
		F3::set('abc->y.2',
			function() {
				return 'world';
			});
		print_r(F3::get('abc'));
*	DB framework variable is now instantiated automatically, e.g.:
		$db=new DB('sqlite:/data/test.db');
		$db->sql('SELECT * FROM mytable;');
		print_r($this->get('DB'));
	As a result, no reference to $db is necessary when creating a new
	Axon:
		$axon=new Axon('mytable');
	Note however that Axon constructor's 2nd argument is required when
	working with multiple databases
*	dump() method for displaying HTML-friendly PHP expressions
*	stringify() enhanced
*	Improved SQL error reporting
*	Minor code refactoring

2.0.0-b5
*	Change in behavior: GUI variable dropped in Graphics methods;
	file argument in invert(), grayscale(), thumb() must specify full path
*	reroute() now accepts template tokens
*	Axon plug-in now accepts parameterized queries by passing an array as
	first argument to the load() method:
		$project->load(array('project_id=:id',array(':id'=>'f3')));
	which is equivalent to:
		$project->load('project_id="f3"');
*	Template tokens can now be applied to class names in dynamic route
	handlers
*	Minor code refactoring

2.0.0-b4
*	NEW: grab() method: retrieves file contents, runs any PHP code in a
	sandbox and returns the result
*	NEW: TIDY array variable - used by render() to clean/repair HTML;
	For an explanation about available configuration options, visit
	http://tidy.sourceforge.net/docs/quickref.html
*	NEW: SMTP plug-in
		$mail=new SMTP;
		$mail->set('from','<admin@example.com>');
		$mail->set('to','"Mail Recipient" <recipient@test.org>');
		$mail->set('subject','Thank you');
		$mail->send('Thanks for supporting Fat-Free!');
	Accepts cc, bcc, x-mailer, reply-to, mime-version, content-type headers
*	slug() is now filesystem-friendly
*	Template tokens for dynamic route handlers
		F3::route('GET /@token','{@PARAMS.token}');
		F3::route('GET /page/@action','Page->{@PARAMS.action}');
*	Bug fix: clear() session handling

2.0.0-b3
*	NEW: PROTOCOL framework variable; return value: 'http' or 'https'
*	Recursive replacement of framework variable variables in arrays
*	Axon erase() method now has an argument to prevent accidental deletion
	of records when no prior find()/findOne() was invoked
*	Function and class/object method chains in route() and input() for
	backward-compatibility with pre-2.0 versions
*	Default dimensions for captcha()
*	Bug fix: sitemap()
*	Bug fix: beforeRoute()/afterRoute() not executed when custom error page
	is defined
*	Bug fix: Premature binding of route handlers which causes unnecessary
	object loading

2.0.0-b2
*	Axon/M2 compatibility with previous versions (DB variable)
*	Additional check if onload() method is declared static in application
*	Workaround for premature file creation when using SQLite PDO
*	Support for static methods passed to route() as string
*	Bug fix: DB error checks

2.0.0-b1

*	NEW: F3::beforeRoute() and F3::afterRoute() event listeners
*	Axon/M2 event listeners: beforeLoad(), afterLoad(), beforeSave(),
	afterSave(), beforeErase(), afterErase(), beforeSync(), afterSync()
*	LANGUAGE/LOCALES auto-detection
*	Minor bug fixes

2.0.0-alpha

*	Base class stripped to the bare minimum (framework variables, routing,
	cache engine, error handling); Everything else is a plug-in - including
	the template engine
*	NEW: Object mode
		$app=require 'base.php';
		$app->route('GET /',
			function() {
				echo 'Hello, world!';
			}
		);
		$app->run();
*	NEW: Routing now supports new syntax for object instantiation
		F3::route('GET /','Main->home');
	instead of:
		F3::route('GET /',array(new Main,'home'));
	which allows $this-> prefix to be used to access framework methods
	(in the above example, Main class should extend F3instance)
*	NEW: Fatal errors caught by error and exception handlers
*	Procedural code support dropped (IMPORTS and routing chains); F3 is now
	strictly object-oriented
*	Axon/M2 find() now returns Axon/M2 objects (instead of arrays)
*	Template engine now allows access to properties of framework variables
	containing objects:
		$foo=new stdClass;
		$foo->phrase='99 bottles of beer';
		F3::set('myvar',$foo);
	To display the properties, use the syntax: {@myvar->phrase}
*	Framework variables defined as anonymous functions:
		F3::set('func',
			function($a,$b) {
				return $a.', '.$b;
			}
		);
	Template engine now interprets token as expected:
		{@func('hello','world')}
*	RELEASE variable dropped; DEBUG has been expanded instead:
		0 - suppress stack trace (for production use)
		1 - normal stack trace (noise removed)
		2 - detailed trace
		3 - verbose
