MDL-20632 latest zend framework lib import
authorPetr Skoda <skodak@moodle.org>
Sat, 24 Oct 2009 19:49:26 +0000 (19:49 +0000)
committerPetr Skoda <skodak@moodle.org>
Sat, 24 Oct 2009 19:49:26 +0000 (19:49 +0000)
40 files changed:
lib/zend/Zend/Acl.php [new file with mode: 0644]
lib/zend/Zend/Application.php [new file with mode: 0644]
lib/zend/Zend/Auth.php [new file with mode: 0644]
lib/zend/Zend/Cache.php [new file with mode: 0644]
lib/zend/Zend/Config.php [new file with mode: 0644]
lib/zend/Zend/Crypt.php [new file with mode: 0644]
lib/zend/Zend/Currency.php [new file with mode: 0644]
lib/zend/Zend/Date.php
lib/zend/Zend/Db.php [new file with mode: 0644]
lib/zend/Zend/Debug.php [new file with mode: 0644]
lib/zend/Zend/Dojo.php [new file with mode: 0644]
lib/zend/Zend/Exception.php
lib/zend/Zend/Feed.php [new file with mode: 0644]
lib/zend/Zend/Filter.php [new file with mode: 0644]
lib/zend/Zend/Form.php [new file with mode: 0644]
lib/zend/Zend/Gdata.php
lib/zend/Zend/InfoCard.php [new file with mode: 0644]
lib/zend/Zend/Json.php [new file with mode: 0644]
lib/zend/Zend/Layout.php [new file with mode: 0644]
lib/zend/Zend/Ldap.php [new file with mode: 0644]
lib/zend/Zend/Loader.php
lib/zend/Zend/Locale.php [new file with mode: 0644]
lib/zend/Zend/Log.php [new file with mode: 0644]
lib/zend/Zend/Mail.php [new file with mode: 0644]
lib/zend/Zend/Memory.php [new file with mode: 0644]
lib/zend/Zend/Mime.php
lib/zend/Zend/Navigation.php [new file with mode: 0644]
lib/zend/Zend/OpenId.php [new file with mode: 0644]
lib/zend/Zend/Paginator.php [new file with mode: 0644]
lib/zend/Zend/Pdf.php [new file with mode: 0644]
lib/zend/Zend/ProgressBar.php [new file with mode: 0644]
lib/zend/Zend/Queue.php [new file with mode: 0644]
lib/zend/Zend/Registry.php
lib/zend/Zend/Session.php [new file with mode: 0644]
lib/zend/Zend/TimeSync.php [new file with mode: 0644]
lib/zend/Zend/Translate.php [new file with mode: 0644]
lib/zend/Zend/Uri.php
lib/zend/Zend/Validate.php [new file with mode: 0644]
lib/zend/Zend/Version.php
lib/zend/Zend/View.php [new file with mode: 0644]

diff --git a/lib/zend/Zend/Acl.php b/lib/zend/Zend/Acl.php
new file mode 100644 (file)
index 0000000..f39cfaf
--- /dev/null
@@ -0,0 +1,1119 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Acl
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+
+/**
+ * @see Zend_Acl_Resource_Interface
+ */
+require_once 'Zend/Acl/Resource/Interface.php';
+
+
+/**
+ * @see Zend_Acl_Role_Registry
+ */
+require_once 'Zend/Acl/Role/Registry.php';
+
+
+/**
+ * @see Zend_Acl_Assert_Interface
+ */
+require_once 'Zend/Acl/Assert/Interface.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Acl
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Acl
+{
+    /**
+     * Rule type: allow
+     */
+    const TYPE_ALLOW = 'TYPE_ALLOW';
+
+    /**
+     * Rule type: deny
+     */
+    const TYPE_DENY  = 'TYPE_DENY';
+
+    /**
+     * Rule operation: add
+     */
+    const OP_ADD = 'OP_ADD';
+
+    /**
+     * Rule operation: remove
+     */
+    const OP_REMOVE = 'OP_REMOVE';
+
+    /**
+     * Role registry
+     *
+     * @var Zend_Acl_Role_Registry
+     */
+    protected $_roleRegistry = null;
+
+    /**
+     * Resource tree
+     *
+     * @var array
+     */
+    protected $_resources = array();
+
+    /**
+     * @var Zend_Acl_Role_Interface
+     */
+    protected $_isAllowedRole     = null;
+    
+    /**
+     * @var Zend_Acl_Resource_Interface
+     */
+    protected $_isAllowedResource = null;
+    
+    /**
+     * ACL rules; whitelist (deny everything to all) by default
+     *
+     * @var array
+     */
+    protected $_rules = array(
+        'allResources' => array(
+            'allRoles' => array(
+                'allPrivileges' => array(
+                    'type'   => self::TYPE_DENY,
+                    'assert' => null
+                    ),
+                'byPrivilegeId' => array()
+                ),
+            'byRoleId' => array()
+            ),
+        'byResourceId' => array()
+        );
+
+    /**
+     * Adds a Role having an identifier unique to the registry
+     *
+     * The $parents parameter may be a reference to, or the string identifier for,
+     * a Role existing in the registry, or $parents may be passed as an array of
+     * these - mixing string identifiers and objects is ok - to indicate the Roles
+     * from which the newly added Role will directly inherit.
+     *
+     * In order to resolve potential ambiguities with conflicting rules inherited
+     * from different parents, the most recently added parent takes precedence over
+     * parents that were previously added. In other words, the first parent added
+     * will have the least priority, and the last parent added will have the
+     * highest priority.
+     *
+     * @param  Zend_Acl_Role_Interface              $role
+     * @param  Zend_Acl_Role_Interface|string|array $parents
+     * @uses   Zend_Acl_Role_Registry::add()
+     * @return Zend_Acl Provides a fluent interface
+     */
+    public function addRole($role, $parents = null)
+    {
+        if (is_string($role)) {
+            $role = new Zend_Acl_Role($role);
+        }
+        
+        if (!$role instanceof Zend_Acl_Role_Interface) {
+            require_once 'Zend/Acl/Exception.php';
+            throw new Zend_Acl_Exception('addRole() expects $role to be of type Zend_Acl_Role_Interface');
+        }
+       
+       
+        $this->_getRoleRegistry()->add($role, $parents);
+
+        return $this;
+    }
+
+    /**
+     * Returns the identified Role
+     *
+     * The $role parameter can either be a Role or Role identifier.
+     *
+     * @param  Zend_Acl_Role_Interface|string $role
+     * @uses   Zend_Acl_Role_Registry::get()
+     * @return Zend_Acl_Role_Interface
+     */
+    public function getRole($role)
+    {
+        return $this->_getRoleRegistry()->get($role);
+    }
+
+    /**
+     * Returns true if and only if the Role exists in the registry
+     *
+     * The $role parameter can either be a Role or a Role identifier.
+     *
+     * @param  Zend_Acl_Role_Interface|string $role
+     * @uses   Zend_Acl_Role_Registry::has()
+     * @return boolean
+     */
+    public function hasRole($role)
+    {
+        return $this->_getRoleRegistry()->has($role);
+    }
+
+    /**
+     * Returns true if and only if $role inherits from $inherit
+     *
+     * Both parameters may be either a Role or a Role identifier. If
+     * $onlyParents is true, then $role must inherit directly from
+     * $inherit in order to return true. By default, this method looks
+     * through the entire inheritance DAG to determine whether $role
+     * inherits from $inherit through its ancestor Roles.
+     *
+     * @param  Zend_Acl_Role_Interface|string $role
+     * @param  Zend_Acl_Role_Interface|string $inherit
+     * @param  boolean                        $onlyParents
+     * @uses   Zend_Acl_Role_Registry::inherits()
+     * @return boolean
+     */
+    public function inheritsRole($role, $inherit, $onlyParents = false)
+    {
+        return $this->_getRoleRegistry()->inherits($role, $inherit, $onlyParents);
+    }
+
+    /**
+     * Removes the Role from the registry
+     *
+     * The $role parameter can either be a Role or a Role identifier.
+     *
+     * @param  Zend_Acl_Role_Interface|string $role
+     * @uses   Zend_Acl_Role_Registry::remove()
+     * @return Zend_Acl Provides a fluent interface
+     */
+    public function removeRole($role)
+    {
+        $this->_getRoleRegistry()->remove($role);
+
+        if ($role instanceof Zend_Acl_Role_Interface) {
+            $roleId = $role->getRoleId();
+        } else {
+            $roleId = $role;
+        }
+
+        foreach ($this->_rules['allResources']['byRoleId'] as $roleIdCurrent => $rules) {
+            if ($roleId === $roleIdCurrent) {
+                unset($this->_rules['allResources']['byRoleId'][$roleIdCurrent]);
+            }
+        }
+        foreach ($this->_rules['byResourceId'] as $resourceIdCurrent => $visitor) {
+            if (array_key_exists('byRoleId', $visitor)) {
+                foreach ($visitor['byRoleId'] as $roleIdCurrent => $rules) {
+                    if ($roleId === $roleIdCurrent) {
+                        unset($this->_rules['byResourceId'][$resourceIdCurrent]['byRoleId'][$roleIdCurrent]);
+                    }
+                }
+            }
+        }
+
+        return $this;
+    }
+
+    /**
+     * Removes all Roles from the registry
+     *
+     * @uses   Zend_Acl_Role_Registry::removeAll()
+     * @return Zend_Acl Provides a fluent interface
+     */
+    public function removeRoleAll()
+    {
+        $this->_getRoleRegistry()->removeAll();
+
+        foreach ($this->_rules['allResources']['byRoleId'] as $roleIdCurrent => $rules) {
+            unset($this->_rules['allResources']['byRoleId'][$roleIdCurrent]);
+        }
+        foreach ($this->_rules['byResourceId'] as $resourceIdCurrent => $visitor) {
+            foreach ($visitor['byRoleId'] as $roleIdCurrent => $rules) {
+                unset($this->_rules['byResourceId'][$resourceIdCurrent]['byRoleId'][$roleIdCurrent]);
+            }
+        }
+
+        return $this;
+    }
+
+    /**
+     * Adds a Resource having an identifier unique to the ACL
+     *
+     * The $parent parameter may be a reference to, or the string identifier for,
+     * the existing Resource from which the newly added Resource will inherit.
+     *
+     * @param  Zend_Acl_Resource_Interface|string $resource
+     * @param  Zend_Acl_Resource_Interface|string $parent
+     * @throws Zend_Acl_Exception
+     * @return Zend_Acl Provides a fluent interface
+     */
+    public function addResource($resource, $parent = null)
+    {
+       if (is_string($resource)) {
+               $resource = new Zend_Acl_Resource($resource);
+       }
+       
+       if (!$resource instanceof Zend_Acl_Resource_Interface) {
+            require_once 'Zend/Acl/Exception.php';
+            throw new Zend_Acl_Exception('addResource() expects $resource to be of type Zend_Acl_Resource_Interface');
+       }
+       
+        $resourceId = $resource->getResourceId();
+
+        if ($this->has($resourceId)) {
+            require_once 'Zend/Acl/Exception.php';
+            throw new Zend_Acl_Exception("Resource id '$resourceId' already exists in the ACL");
+        }
+
+        $resourceParent = null;
+
+        if (null !== $parent) {
+            try {
+                if ($parent instanceof Zend_Acl_Resource_Interface) {
+                    $resourceParentId = $parent->getResourceId();
+                } else {
+                    $resourceParentId = $parent;
+                }
+                $resourceParent = $this->get($resourceParentId);
+            } catch (Zend_Acl_Exception $e) {
+                throw new Zend_Acl_Exception("Parent Resource id '$resourceParentId' does not exist");
+            }
+            $this->_resources[$resourceParentId]['children'][$resourceId] = $resource;
+        }
+
+        $this->_resources[$resourceId] = array(
+            'instance' => $resource,
+            'parent'   => $resourceParent,
+            'children' => array()
+            );
+
+        return $this;
+    }
+    
+    /**
+     * Adds a Resource having an identifier unique to the ACL
+     *
+     * The $parent parameter may be a reference to, or the string identifier for,
+     * the existing Resource from which the newly added Resource will inherit.
+     *
+     * @deprecated in version 1.9.1 and will be available till 2.0.  New code
+     *             should use addResource() instead.
+     * 
+     * @param  Zend_Acl_Resource_Interface        $resource
+     * @param  Zend_Acl_Resource_Interface|string $parent
+     * @throws Zend_Acl_Exception
+     * @return Zend_Acl Provides a fluent interface
+     */
+    public function add(Zend_Acl_Resource_Interface $resource, $parent = null)
+    {
+        return $this->addResource($resource, $parent);
+    }
+
+    /**
+     * Returns the identified Resource
+     *
+     * The $resource parameter can either be a Resource or a Resource identifier.
+     *
+     * @param  Zend_Acl_Resource_Interface|string $resource
+     * @throws Zend_Acl_Exception
+     * @return Zend_Acl_Resource_Interface
+     */
+    public function get($resource)
+    {
+        if ($resource instanceof Zend_Acl_Resource_Interface) {
+            $resourceId = $resource->getResourceId();
+        } else {
+            $resourceId = (string) $resource;
+        }
+
+        if (!$this->has($resource)) {
+            require_once 'Zend/Acl/Exception.php';
+            throw new Zend_Acl_Exception("Resource '$resourceId' not found");
+        }
+
+        return $this->_resources[$resourceId]['instance'];
+    }
+
+    /**
+     * Returns true if and only if the Resource exists in the ACL
+     *
+     * The $resource parameter can either be a Resource or a Resource identifier.
+     *
+     * @param  Zend_Acl_Resource_Interface|string $resource
+     * @return boolean
+     */
+    public function has($resource)
+    {
+        if ($resource instanceof Zend_Acl_Resource_Interface) {
+            $resourceId = $resource->getResourceId();
+        } else {
+            $resourceId = (string) $resource;
+        }
+
+        return isset($this->_resources[$resourceId]);
+    }
+
+    /**
+     * Returns true if and only if $resource inherits from $inherit
+     *
+     * Both parameters may be either a Resource or a Resource identifier. If
+     * $onlyParent is true, then $resource must inherit directly from
+     * $inherit in order to return true. By default, this method looks
+     * through the entire inheritance tree to determine whether $resource
+     * inherits from $inherit through its ancestor Resources.
+     *
+     * @param  Zend_Acl_Resource_Interface|string $resource
+     * @param  Zend_Acl_Resource_Interface|string $inherit
+     * @param  boolean                            $onlyParent
+     * @throws Zend_Acl_Resource_Registry_Exception
+     * @return boolean
+     */
+    public function inherits($resource, $inherit, $onlyParent = false)
+    {
+        try {
+            $resourceId     = $this->get($resource)->getResourceId();
+            $inheritId = $this->get($inherit)->getResourceId();
+        } catch (Zend_Acl_Exception $e) {
+            throw $e;
+        }
+
+        if (null !== $this->_resources[$resourceId]['parent']) {
+            $parentId = $this->_resources[$resourceId]['parent']->getResourceId();
+            if ($inheritId === $parentId) {
+                return true;
+            } else if ($onlyParent) {
+                return false;
+            }
+        } else {
+            return false;
+        }
+
+        while (null !== $this->_resources[$parentId]['parent']) {
+            $parentId = $this->_resources[$parentId]['parent']->getResourceId();
+            if ($inheritId === $parentId) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Removes a Resource and all of its children
+     *
+     * The $resource parameter can either be a Resource or a Resource identifier.
+     *
+     * @param  Zend_Acl_Resource_Interface|string $resource
+     * @throws Zend_Acl_Exception
+     * @return Zend_Acl Provides a fluent interface
+     */
+    public function remove($resource)
+    {
+        try {
+            $resourceId = $this->get($resource)->getResourceId();
+        } catch (Zend_Acl_Exception $e) {
+            throw $e;
+        }
+
+        $resourcesRemoved = array($resourceId);
+        if (null !== ($resourceParent = $this->_resources[$resourceId]['parent'])) {
+            unset($this->_resources[$resourceParent->getResourceId()]['children'][$resourceId]);
+        }
+        foreach ($this->_resources[$resourceId]['children'] as $childId => $child) {
+            $this->remove($childId);
+            $resourcesRemoved[] = $childId;
+        }
+
+        foreach ($resourcesRemoved as $resourceIdRemoved) {
+            foreach ($this->_rules['byResourceId'] as $resourceIdCurrent => $rules) {
+                if ($resourceIdRemoved === $resourceIdCurrent) {
+                    unset($this->_rules['byResourceId'][$resourceIdCurrent]);
+                }
+            }
+        }
+
+        unset($this->_resources[$resourceId]);
+
+        return $this;
+    }
+
+    /**
+     * Removes all Resources
+     *
+     * @return Zend_Acl Provides a fluent interface
+     */
+    public function removeAll()
+    {
+        foreach ($this->_resources as $resourceId => $resource) {
+            foreach ($this->_rules['byResourceId'] as $resourceIdCurrent => $rules) {
+                if ($resourceId === $resourceIdCurrent) {
+                    unset($this->_rules['byResourceId'][$resourceIdCurrent]);
+                }
+            }
+        }
+
+        $this->_resources = array();
+
+        return $this;
+    }
+
+    /**
+     * Adds an "allow" rule to the ACL
+     *
+     * @param  Zend_Acl_Role_Interface|string|array     $roles
+     * @param  Zend_Acl_Resource_Interface|string|array $resources
+     * @param  string|array                             $privileges
+     * @param  Zend_Acl_Assert_Interface                $assert
+     * @uses   Zend_Acl::setRule()
+     * @return Zend_Acl Provides a fluent interface
+     */
+    public function allow($roles = null, $resources = null, $privileges = null, Zend_Acl_Assert_Interface $assert = null)
+    {
+        return $this->setRule(self::OP_ADD, self::TYPE_ALLOW, $roles, $resources, $privileges, $assert);
+    }
+
+    /**
+     * Adds a "deny" rule to the ACL
+     *
+     * @param  Zend_Acl_Role_Interface|string|array     $roles
+     * @param  Zend_Acl_Resource_Interface|string|array $resources
+     * @param  string|array                             $privileges
+     * @param  Zend_Acl_Assert_Interface                $assert
+     * @uses   Zend_Acl::setRule()
+     * @return Zend_Acl Provides a fluent interface
+     */
+    public function deny($roles = null, $resources = null, $privileges = null, Zend_Acl_Assert_Interface $assert = null)
+    {
+        return $this->setRule(self::OP_ADD, self::TYPE_DENY, $roles, $resources, $privileges, $assert);
+    }
+
+    /**
+     * Removes "allow" permissions from the ACL
+     *
+     * @param  Zend_Acl_Role_Interface|string|array     $roles
+     * @param  Zend_Acl_Resource_Interface|string|array $resources
+     * @param  string|array                             $privileges
+     * @uses   Zend_Acl::setRule()
+     * @return Zend_Acl Provides a fluent interface
+     */
+    public function removeAllow($roles = null, $resources = null, $privileges = null)
+    {
+        return $this->setRule(self::OP_REMOVE, self::TYPE_ALLOW, $roles, $resources, $privileges);
+    }
+
+    /**
+     * Removes "deny" restrictions from the ACL
+     *
+     * @param  Zend_Acl_Role_Interface|string|array     $roles
+     * @param  Zend_Acl_Resource_Interface|string|array $resources
+     * @param  string|array                             $privileges
+     * @uses   Zend_Acl::setRule()
+     * @return Zend_Acl Provides a fluent interface
+     */
+    public function removeDeny($roles = null, $resources = null, $privileges = null)
+    {
+        return $this->setRule(self::OP_REMOVE, self::TYPE_DENY, $roles, $resources, $privileges);
+    }
+
+    /**
+     * Performs operations on ACL rules
+     *
+     * The $operation parameter may be either OP_ADD or OP_REMOVE, depending on whether the
+     * user wants to add or remove a rule, respectively:
+     *
+     * OP_ADD specifics:
+     *
+     *      A rule is added that would allow one or more Roles access to [certain $privileges
+     *      upon] the specified Resource(s).
+     *
+     * OP_REMOVE specifics:
+     *
+     *      The rule is removed only in the context of the given Roles, Resources, and privileges.
+     *      Existing rules to which the remove operation does not apply would remain in the
+     *      ACL.
+     *
+     * The $type parameter may be either TYPE_ALLOW or TYPE_DENY, depending on whether the
+     * rule is intended to allow or deny permission, respectively.
+     *
+     * The $roles and $resources parameters may be references to, or the string identifiers for,
+     * existing Resources/Roles, or they may be passed as arrays of these - mixing string identifiers
+     * and objects is ok - to indicate the Resources and Roles to which the rule applies. If either
+     * $roles or $resources is null, then the rule applies to all Roles or all Resources, respectively.
+     * Both may be null in order to work with the default rule of the ACL.
+     *
+     * The $privileges parameter may be used to further specify that the rule applies only
+     * to certain privileges upon the Resource(s) in question. This may be specified to be a single
+     * privilege with a string, and multiple privileges may be specified as an array of strings.
+     *
+     * If $assert is provided, then its assert() method must return true in order for
+     * the rule to apply. If $assert is provided with $roles, $resources, and $privileges all
+     * equal to null, then a rule having a type of:
+     *
+     *      TYPE_ALLOW will imply a type of TYPE_DENY, and
+     *
+     *      TYPE_DENY will imply a type of TYPE_ALLOW
+     *
+     * when the rule's assertion fails. This is because the ACL needs to provide expected
+     * behavior when an assertion upon the default ACL rule fails.
+     *
+     * @param  string                                   $operation
+     * @param  string                                   $type
+     * @param  Zend_Acl_Role_Interface|string|array     $roles
+     * @param  Zend_Acl_Resource_Interface|string|array $resources
+     * @param  string|array                             $privileges
+     * @param  Zend_Acl_Assert_Interface                $assert
+     * @throws Zend_Acl_Exception
+     * @uses   Zend_Acl_Role_Registry::get()
+     * @uses   Zend_Acl::get()
+     * @return Zend_Acl Provides a fluent interface
+     */
+    public function setRule($operation, $type, $roles = null, $resources = null, $privileges = null,
+                            Zend_Acl_Assert_Interface $assert = null)
+    {
+        // ensure that the rule type is valid; normalize input to uppercase
+        $type = strtoupper($type);
+        if (self::TYPE_ALLOW !== $type && self::TYPE_DENY !== $type) {
+            require_once 'Zend/Acl/Exception.php';
+            throw new Zend_Acl_Exception("Unsupported rule type; must be either '" . self::TYPE_ALLOW . "' or '"
+                                       . self::TYPE_DENY . "'");
+        }
+
+        // ensure that all specified Roles exist; normalize input to array of Role objects or null
+        if (!is_array($roles)) {
+            $roles = array($roles);
+        } else if (0 === count($roles)) {
+            $roles = array(null);
+        }
+        $rolesTemp = $roles;
+        $roles = array();
+        foreach ($rolesTemp as $role) {
+            if (null !== $role) {
+                $roles[] = $this->_getRoleRegistry()->get($role);
+            } else {
+                $roles[] = null;
+            }
+        }
+        unset($rolesTemp);
+
+        // ensure that all specified Resources exist; normalize input to array of Resource objects or null
+        if (!is_array($resources)) {
+            $resources = array($resources);
+        } else if (0 === count($resources)) {
+            $resources = array(null);
+        }
+        $resourcesTemp = $resources;
+        $resources = array();
+        foreach ($resourcesTemp as $resource) {
+            if (null !== $resource) {
+                $resources[] = $this->get($resource);
+            } else {
+                $resources[] = null;
+            }
+        }
+        unset($resourcesTemp);
+
+        // normalize privileges to array
+        if (null === $privileges) {
+            $privileges = array();
+        } else if (!is_array($privileges)) {
+            $privileges = array($privileges);
+        }
+
+        switch ($operation) {
+
+            // add to the rules
+            case self::OP_ADD:
+                foreach ($resources as $resource) {
+                    foreach ($roles as $role) {
+                        $rules =& $this->_getRules($resource, $role, true);
+                        if (0 === count($privileges)) {
+                            $rules['allPrivileges']['type']   = $type;
+                            $rules['allPrivileges']['assert'] = $assert;
+                            if (!isset($rules['byPrivilegeId'])) {
+                                $rules['byPrivilegeId'] = array();
+                            }
+                        } else {
+                            foreach ($privileges as $privilege) {
+                                $rules['byPrivilegeId'][$privilege]['type']   = $type;
+                                $rules['byPrivilegeId'][$privilege]['assert'] = $assert;
+                            }
+                        }
+                    }
+                }
+                break;
+
+            // remove from the rules
+            case self::OP_REMOVE:
+                foreach ($resources as $resource) {
+                    foreach ($roles as $role) {
+                        $rules =& $this->_getRules($resource, $role);
+                        if (null === $rules) {
+                            continue;
+                        }
+                        if (0 === count($privileges)) {
+                            if (null === $resource && null === $role) {
+                                if ($type === $rules['allPrivileges']['type']) {
+                                    $rules = array(
+                                        'allPrivileges' => array(
+                                            'type'   => self::TYPE_DENY,
+                                            'assert' => null
+                                            ),
+                                        'byPrivilegeId' => array()
+                                        );
+                                }
+                                continue;
+                            }
+                            if ($type === $rules['allPrivileges']['type']) {
+                                unset($rules['allPrivileges']);
+                            }
+                        } else {
+                            foreach ($privileges as $privilege) {
+                                if (isset($rules['byPrivilegeId'][$privilege]) &&
+                                    $type === $rules['byPrivilegeId'][$privilege]['type']) {
+                                    unset($rules['byPrivilegeId'][$privilege]);
+                                }
+                            }
+                        }
+                    }
+                }
+                break;
+
+            default:
+                require_once 'Zend/Acl/Exception.php';
+                throw new Zend_Acl_Exception("Unsupported operation; must be either '" . self::OP_ADD . "' or '"
+                                           . self::OP_REMOVE . "'");
+        }
+
+        return $this;
+    }
+
+    /**
+     * Returns true if and only if the Role has access to the Resource
+     *
+     * The $role and $resource parameters may be references to, or the string identifiers for,
+     * an existing Resource and Role combination.
+     *
+     * If either $role or $resource is null, then the query applies to all Roles or all Resources,
+     * respectively. Both may be null to query whether the ACL has a "blacklist" rule
+     * (allow everything to all). By default, Zend_Acl creates a "whitelist" rule (deny
+     * everything to all), and this method would return false unless this default has
+     * been overridden (i.e., by executing $acl->allow()).
+     *
+     * If a $privilege is not provided, then this method returns false if and only if the
+     * Role is denied access to at least one privilege upon the Resource. In other words, this
+     * method returns true if and only if the Role is allowed all privileges on the Resource.
+     *
+     * This method checks Role inheritance using a depth-first traversal of the Role registry.
+     * The highest priority parent (i.e., the parent most recently added) is checked first,
+     * and its respective parents are checked similarly before the lower-priority parents of
+     * the Role are checked.
+     *
+     * @param  Zend_Acl_Role_Interface|string     $role
+     * @param  Zend_Acl_Resource_Interface|string $resource
+     * @param  string                             $privilege
+     * @uses   Zend_Acl::get()
+     * @uses   Zend_Acl_Role_Registry::get()
+     * @return boolean
+     */
+    public function isAllowed($role = null, $resource = null, $privilege = null)
+    {
+       // reset role & resource to null
+       $this->_isAllowedRole = $this->_isAllowedResource = null;
+       
+        if (null !== $role) {
+               // keep track of originally called role
+               $this->_isAllowedRole = $role;
+            $role = $this->_getRoleRegistry()->get($role);
+            if (!$this->_isAllowedRole instanceof Zend_Acl_Role_Interface) {
+               $this->_isAllowedRole = $role;
+            }
+        }
+
+        if (null !== $resource) {
+               // keep track of originally called resource
+               $this->_isAllowedResource = $resource;
+            $resource = $this->get($resource);
+            if (!$this->_isAllowedResource instanceof Zend_Acl_Resource_Interface) {
+               $this->_isAllowedResource = $resource;
+            }
+        }
+
+        if (null === $privilege) {
+            // query on all privileges
+            do {
+                // depth-first search on $role if it is not 'allRoles' pseudo-parent
+                if (null !== $role && null !== ($result = $this->_roleDFSAllPrivileges($role, $resource, $privilege))) {
+                    return $result;
+                }
+
+                // look for rule on 'allRoles' psuedo-parent
+                if (null !== ($rules = $this->_getRules($resource, null))) {
+                    foreach ($rules['byPrivilegeId'] as $privilege => $rule) {
+                        if (self::TYPE_DENY === ($ruleTypeOnePrivilege = $this->_getRuleType($resource, null, $privilege))) {
+                            return false;
+                        }
+                    }
+                    if (null !== ($ruleTypeAllPrivileges = $this->_getRuleType($resource, null, null))) {
+                        return self::TYPE_ALLOW === $ruleTypeAllPrivileges;
+                    }
+                }
+
+                // try next Resource
+                $resource = $this->_resources[$resource->getResourceId()]['parent'];
+
+            } while (true); // loop terminates at 'allResources' pseudo-parent
+        } else {
+            // query on one privilege
+            do {
+                // depth-first search on $role if it is not 'allRoles' pseudo-parent
+                if (null !== $role && null !== ($result = $this->_roleDFSOnePrivilege($role, $resource, $privilege))) {
+                    return $result;
+                }
+
+                // look for rule on 'allRoles' pseudo-parent
+                if (null !== ($ruleType = $this->_getRuleType($resource, null, $privilege))) {
+                    return self::TYPE_ALLOW === $ruleType;
+                } else if (null !== ($ruleTypeAllPrivileges = $this->_getRuleType($resource, null, null))) {
+                    return self::TYPE_ALLOW === $ruleTypeAllPrivileges;
+                }
+
+                // try next Resource
+                $resource = $this->_resources[$resource->getResourceId()]['parent'];
+
+            } while (true); // loop terminates at 'allResources' pseudo-parent
+        }
+    }
+
+    /**
+     * Returns the Role registry for this ACL
+     *
+     * If no Role registry has been created yet, a new default Role registry
+     * is created and returned.
+     *
+     * @return Zend_Acl_Role_Registry
+     */
+    protected function _getRoleRegistry()
+    {
+        if (null === $this->_roleRegistry) {
+            $this->_roleRegistry = new Zend_Acl_Role_Registry();
+        }
+        return $this->_roleRegistry;
+    }
+
+    /**
+     * Performs a depth-first search of the Role DAG, starting at $role, in order to find a rule
+     * allowing/denying $role access to all privileges upon $resource
+     *
+     * This method returns true if a rule is found and allows access. If a rule exists and denies access,
+     * then this method returns false. If no applicable rule is found, then this method returns null.
+     *
+     * @param  Zend_Acl_Role_Interface     $role
+     * @param  Zend_Acl_Resource_Interface $resource
+     * @return boolean|null
+     */
+    protected function _roleDFSAllPrivileges(Zend_Acl_Role_Interface $role, Zend_Acl_Resource_Interface $resource = null)
+    {
+        $dfs = array(
+            'visited' => array(),
+            'stack'   => array()
+            );
+
+        if (null !== ($result = $this->_roleDFSVisitAllPrivileges($role, $resource, $dfs))) {
+            return $result;
+        }
+
+        while (null !== ($role = array_pop($dfs['stack']))) {
+            if (!isset($dfs['visited'][$role->getRoleId()])) {
+                if (null !== ($result = $this->_roleDFSVisitAllPrivileges($role, $resource, $dfs))) {
+                    return $result;
+                }
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Visits an $role in order to look for a rule allowing/denying $role access to all privileges upon $resource
+     *
+     * This method returns true if a rule is found and allows access. If a rule exists and denies access,
+     * then this method returns false. If no applicable rule is found, then this method returns null.
+     *
+     * This method is used by the internal depth-first search algorithm and may modify the DFS data structure.
+     *
+     * @param  Zend_Acl_Role_Interface     $role
+     * @param  Zend_Acl_Resource_Interface $resource
+     * @param  array                  $dfs
+     * @return boolean|null
+     * @throws Zend_Acl_Exception
+     */
+    protected function _roleDFSVisitAllPrivileges(Zend_Acl_Role_Interface $role, Zend_Acl_Resource_Interface $resource = null,
+                                                 &$dfs = null)
+    {
+        if (null === $dfs) {
+            /**
+             * @see Zend_Acl_Exception
+             */
+            require_once 'Zend/Acl/Exception.php';
+            throw new Zend_Acl_Exception('$dfs parameter may not be null');
+        }
+
+        if (null !== ($rules = $this->_getRules($resource, $role))) {
+            foreach ($rules['byPrivilegeId'] as $privilege => $rule) {
+                if (self::TYPE_DENY === ($ruleTypeOnePrivilege = $this->_getRuleType($resource, $role, $privilege))) {
+                    return false;
+                }
+            }
+            if (null !== ($ruleTypeAllPrivileges = $this->_getRuleType($resource, $role, null))) {
+                return self::TYPE_ALLOW === $ruleTypeAllPrivileges;
+            }
+        }
+
+        $dfs['visited'][$role->getRoleId()] = true;
+        foreach ($this->_getRoleRegistry()->getParents($role) as $roleParentId => $roleParent) {
+            $dfs['stack'][] = $roleParent;
+        }
+
+        return null;
+    }
+
+    /**
+     * Performs a depth-first search of the Role DAG, starting at $role, in order to find a rule
+     * allowing/denying $role access to a $privilege upon $resource
+     *
+     * This method returns true if a rule is found and allows access. If a rule exists and denies access,
+     * then this method returns false. If no applicable rule is found, then this method returns null.
+     *
+     * @param  Zend_Acl_Role_Interface     $role
+     * @param  Zend_Acl_Resource_Interface $resource
+     * @param  string                      $privilege
+     * @return boolean|null
+     * @throws Zend_Acl_Exception
+     */
+    protected function _roleDFSOnePrivilege(Zend_Acl_Role_Interface $role, Zend_Acl_Resource_Interface $resource = null,
+                                            $privilege = null)
+    {
+        if (null === $privilege) {
+            /**
+             * @see Zend_Acl_Exception
+             */
+            require_once 'Zend/Acl/Exception.php';
+            throw new Zend_Acl_Exception('$privilege parameter may not be null');
+        }
+
+        $dfs = array(
+            'visited' => array(),
+            'stack'   => array()
+            );
+
+        if (null !== ($result = $this->_roleDFSVisitOnePrivilege($role, $resource, $privilege, $dfs))) {
+            return $result;
+        }
+
+        while (null !== ($role = array_pop($dfs['stack']))) {
+            if (!isset($dfs['visited'][$role->getRoleId()])) {
+                if (null !== ($result = $this->_roleDFSVisitOnePrivilege($role, $resource, $privilege, $dfs))) {
+                    return $result;
+                }
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Visits an $role in order to look for a rule allowing/denying $role access to a $privilege upon $resource
+     *
+     * This method returns true if a rule is found and allows access. If a rule exists and denies access,
+     * then this method returns false. If no applicable rule is found, then this method returns null.
+     *
+     * This method is used by the internal depth-first search algorithm and may modify the DFS data structure.
+     *
+     * @param  Zend_Acl_Role_Interface     $role
+     * @param  Zend_Acl_Resource_Interface $resource
+     * @param  string                      $privilege
+     * @param  array                       $dfs
+     * @return boolean|null
+     * @throws Zend_Acl_Exception
+     */
+    protected function _roleDFSVisitOnePrivilege(Zend_Acl_Role_Interface $role, Zend_Acl_Resource_Interface $resource = null,
+                                                $privilege = null, &$dfs = null)
+    {
+        if (null === $privilege) {
+            /**
+             * @see Zend_Acl_Exception
+             */
+            require_once 'Zend/Acl/Exception.php';
+            throw new Zend_Acl_Exception('$privilege parameter may not be null');
+        }
+
+        if (null === $dfs) {
+            /**
+             * @see Zend_Acl_Exception
+             */
+            require_once 'Zend/Acl/Exception.php';
+            throw new Zend_Acl_Exception('$dfs parameter may not be null');
+        }
+
+        if (null !== ($ruleTypeOnePrivilege = $this->_getRuleType($resource, $role, $privilege))) {
+            return self::TYPE_ALLOW === $ruleTypeOnePrivilege;
+        } else if (null !== ($ruleTypeAllPrivileges = $this->_getRuleType($resource, $role, null))) {
+            return self::TYPE_ALLOW === $ruleTypeAllPrivileges;
+        }
+
+        $dfs['visited'][$role->getRoleId()] = true;
+        foreach ($this->_getRoleRegistry()->getParents($role) as $roleParentId => $roleParent) {
+            $dfs['stack'][] = $roleParent;
+        }
+
+        return null;
+    }
+
+    /**
+     * Returns the rule type associated with the specified Resource, Role, and privilege
+     * combination.
+     *
+     * If a rule does not exist or its attached assertion fails, which means that
+     * the rule is not applicable, then this method returns null. Otherwise, the
+     * rule type applies and is returned as either TYPE_ALLOW or TYPE_DENY.
+     *
+     * If $resource or $role is null, then this means that the rule must apply to
+     * all Resources or Roles, respectively.
+     *
+     * If $privilege is null, then the rule must apply to all privileges.
+     *
+     * If all three parameters are null, then the default ACL rule type is returned,
+     * based on whether its assertion method passes.
+     *
+     * @param  Zend_Acl_Resource_Interface $resource
+     * @param  Zend_Acl_Role_Interface     $role
+     * @param  string                      $privilege
+     * @return string|null
+     */
+    protected function _getRuleType(Zend_Acl_Resource_Interface $resource = null, Zend_Acl_Role_Interface $role = null,
+                                    $privilege = null)
+    {
+        // get the rules for the $resource and $role
+        if (null === ($rules = $this->_getRules($resource, $role))) {
+            return null;
+        }
+
+        // follow $privilege
+        if (null === $privilege) {
+            if (isset($rules['allPrivileges'])) {
+                $rule = $rules['allPrivileges'];
+            } else {
+                return null;
+            }
+        } else if (!isset($rules['byPrivilegeId'][$privilege])) {
+            return null;
+        } else {
+            $rule = $rules['byPrivilegeId'][$privilege];
+        }
+
+        // check assertion first
+        if ($rule['assert']) {
+            $assertion = $rule['assert'];
+            $assertionValue = $assertion->assert(
+                $this,
+                ($this->_isAllowedRole instanceof Zend_Acl_Role_Interface) ? $this->_isAllowedRole : $role,
+                ($this->_isAllowedResource instanceof Zend_Acl_Resource_Interface) ? $this->_isAllowedResource : $resource,
+                $privilege
+                );
+        } 
+        
+        if (null === $rule['assert'] || $assertionValue) {
+            return $rule['type'];
+        } else if (null !== $resource || null !== $role || null !== $privilege) {
+            return null;
+        } else if (self::TYPE_ALLOW === $rule['type']) {
+            return self::TYPE_DENY;
+        } else {
+            return self::TYPE_ALLOW;
+        }
+    }
+
+    /**
+     * Returns the rules associated with a Resource and a Role, or null if no such rules exist
+     *
+     * If either $resource or $role is null, this means that the rules returned are for all Resources or all Roles,
+     * respectively. Both can be null to return the default rule set for all Resources and all Roles.
+     *
+     * If the $create parameter is true, then a rule set is first created and then returned to the caller.
+     *
+     * @param  Zend_Acl_Resource_Interface $resource
+     * @param  Zend_Acl_Role_Interface     $role
+     * @param  boolean                     $create
+     * @return array|null
+     */
+    protected function &_getRules(Zend_Acl_Resource_Interface $resource = null, Zend_Acl_Role_Interface $role = null,
+                                  $create = false)
+    {
+        // create a reference to null
+        $null = null;
+        $nullRef =& $null;
+
+        // follow $resource
+        do {
+            if (null === $resource) {
+                $visitor =& $this->_rules['allResources'];
+                break;
+            }
+            $resourceId = $resource->getResourceId();
+            if (!isset($this->_rules['byResourceId'][$resourceId])) {
+                if (!$create) {
+                    return $nullRef;
+                }
+                $this->_rules['byResourceId'][$resourceId] = array();
+            }
+            $visitor =& $this->_rules['byResourceId'][$resourceId];
+        } while (false);
+
+
+        // follow $role
+        if (null === $role) {
+            if (!isset($visitor['allRoles'])) {
+                if (!$create) {
+                    return $nullRef;
+                }
+                $visitor['allRoles']['byPrivilegeId'] = array();
+            }
+            return $visitor['allRoles'];
+        }
+        $roleId = $role->getRoleId();
+        if (!isset($visitor['byRoleId'][$roleId])) {
+            if (!$create) {
+                return $nullRef;
+            }
+            $visitor['byRoleId'][$roleId]['byPrivilegeId'] = array();
+        }
+        return $visitor['byRoleId'][$roleId];
+    }
+
+    
+    /**
+     * @return array of registered roles
+     *
+     */
+    public function getRegisteredRoles()
+    { 
+        return $this->_getRoleRegistry()->getRoles(); 
+    } 
+
+}
diff --git a/lib/zend/Zend/Application.php b/lib/zend/Zend/Application.php
new file mode 100644 (file)
index 0000000..a2c8478
--- /dev/null
@@ -0,0 +1,397 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Application
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/**
+ * @category   Zend
+ * @package    Zend_Application
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Application
+{
+    /**
+     * Autoloader to use
+     * 
+     * @var Zend_Loader_Autoloader
+     */
+    protected $_autoloader;
+
+    /**
+     * Bootstrap
+     * 
+     * @var Zend_Application_Bootstrap_BootstrapAbstract
+     */
+    protected $_bootstrap;
+
+    /**
+     * Application environment
+     * 
+     * @var string
+     */
+    protected $_environment;
+
+    /**
+     * Flattened (lowercase) option keys
+     * 
+     * @var array
+     */
+    protected $_optionKeys = array();
+
+    /**
+     * Options for Zend_Application
+     * 
+     * @var array
+     */
+    protected $_options = array();
+
+    /**
+     * Constructor
+     *
+     * Initialize application. Potentially initializes include_paths, PHP 
+     * settings, and bootstrap class.
+     * 
+     * @param  string                   $environment 
+     * @param  string|array|Zend_Config $options String path to configuration file, or array/Zend_Config of configuration options
+     * @throws Zend_Application_Exception When invalid options are provided
+     * @return void
+     */
+    public function __construct($environment, $options = null)
+    {
+        $this->_environment = (string) $environment;
+
+        require_once 'Zend/Loader/Autoloader.php';
+        $this->_autoloader = Zend_Loader_Autoloader::getInstance();
+
+        if (null !== $options) {
+            if (is_string($options)) {
+                $options = $this->_loadConfig($options);
+            } elseif ($options instanceof Zend_Config) {
+                $options = $options->toArray();
+            } elseif (!is_array($options)) {
+                throw new Zend_Application_Exception('Invalid options provided; must be location of config file, a config object, or an array');
+            }
+
+            $this->setOptions($options);
+        }
+    }
+
+    /**
+     * Retrieve current environment
+     * 
+     * @return string
+     */
+    public function getEnvironment()
+    {
+        return $this->_environment;
+    }
+
+    /**
+     * Retrieve autoloader instance
+     * 
+     * @return Zend_Loader_Autoloader
+     */
+    public function getAutoloader()
+    {
+        return $this->_autoloader;
+    }
+
+    /**
+     * Set application options
+     * 
+     * @param  array $options 
+     * @throws Zend_Application_Exception When no bootstrap path is provided
+     * @throws Zend_Application_Exception When invalid bootstrap information are provided
+     * @return Zend_Application
+     */
+    public function setOptions(array $options)
+    {
+        if (!empty($options['config'])) {
+            $options = $this->mergeOptions($options, $this->_loadConfig($options['config']));
+        }
+        
+        $this->_options = $options;
+
+        $options = array_change_key_case($options, CASE_LOWER);
+
+        $this->_optionKeys = array_keys($options);
+
+        if (!empty($options['phpsettings'])) {
+            $this->setPhpSettings($options['phpsettings']);
+        }
+        
+        if (!empty($options['includepaths'])) {
+            $this->setIncludePaths($options['includepaths']);
+        }
+        
+        if (!empty($options['autoloadernamespaces'])) {
+            $this->setAutoloaderNamespaces($options['autoloadernamespaces']);
+        }
+
+        if (!empty($options['autoloaderzfpath'])) {
+            $autoloader = $this->getAutoloader();
+            if (method_exists($autoloader, 'setZfPath')) {
+                $zfPath    = $options['autoloaderzfpath'];
+                $zfVersion = !empty($options['autoloaderzfversion']) 
+                           ? $options['autoloaderzfversion'] 
+                           : 'latest';
+                $autoloader->setZfPath($zfPath, $zfVersion);
+            }
+        }
+
+        if (!empty($options['bootstrap'])) {
+            $bootstrap = $options['bootstrap'];
+            
+            if (is_string($bootstrap)) {
+                $this->setBootstrap($bootstrap);
+            } elseif (is_array($bootstrap)) {
+                if (empty($bootstrap['path'])) {
+                    throw new Zend_Application_Exception('No bootstrap path provided');
+                }
+                
+                $path  = $bootstrap['path'];
+                $class = null;
+                
+                if (!empty($bootstrap['class'])) {
+                    $class = $bootstrap['class'];
+                }
+                
+                $this->setBootstrap($path, $class);
+            } else {
+                throw new Zend_Application_Exception('Invalid bootstrap information provided');
+            }
+        }
+
+        return $this;
+    }
+
+    /**
+     * Retrieve application options (for caching)
+     * 
+     * @return array
+     */
+    public function getOptions()
+    {
+        return $this->_options;
+    }
+
+    /**
+     * Is an option present?
+     * 
+     * @param  string $key 
+     * @return bool
+     */
+    public function hasOption($key)
+    {
+        return in_array(strtolower($key), $this->_optionKeys);
+    }
+
+    /**
+     * Retrieve a single option
+     * 
+     * @param  string $key 
+     * @return mixed
+     */
+    public function getOption($key)
+    {
+        if ($this->hasOption($key)) {
+            $options = $this->getOptions();
+            $options = array_change_key_case($options, CASE_LOWER);
+            return $options[strtolower($key)];
+        }
+        return null;
+    }
+
+    /**
+     * Merge options recursively
+     * 
+     * @param  array $array1 
+     * @param  mixed $array2 
+     * @return array
+     */
+    public function mergeOptions(array $array1, $array2 = null)
+    {
+        if (is_array($array2)) {
+            foreach ($array2 as $key => $val) {
+                if (is_array($array2[$key])) {
+                    $array1[$key] = (array_key_exists($key, $array1) && is_array($array1[$key]))
+                                  ? $this->mergeOptions($array1[$key], $array2[$key]) 
+                                  : $array2[$key];
+                } else {
+                    $array1[$key] = $val;
+                }
+            }
+        }
+        return $array1;
+    }
+
+    /**
+     * Set PHP configuration settings
+     * 
+     * @param  array $settings 
+     * @param  string $prefix Key prefix to prepend to array values (used to map . separated INI values)
+     * @return Zend_Application
+     */
+    public function setPhpSettings(array $settings, $prefix = '')
+    {
+        foreach ($settings as $key => $value) {
+            $key = empty($prefix) ? $key : $prefix . $key;
+            if (is_scalar($value)) {
+                ini_set($key, $value);
+            } elseif (is_array($value)) {
+                $this->setPhpSettings($value, $key . '.');
+            }
+        }
+        
+        return $this;
+    }
+
+    /**
+     * Set include path
+     * 
+     * @param  array $paths 
+     * @return Zend_Application
+     */
+    public function setIncludePaths(array $paths)
+    {
+        $path = implode(PATH_SEPARATOR, $paths);
+        set_include_path($path . PATH_SEPARATOR . get_include_path());
+        return $this;
+    }
+
+    /**
+     * Set autoloader namespaces
+     * 
+     * @param  array $namespaces 
+     * @return Zend_Application
+     */
+    public function setAutoloaderNamespaces(array $namespaces)
+    {
+        $autoloader = $this->getAutoloader();
+        
+        foreach ($namespaces as $namespace) {
+            $autoloader->registerNamespace($namespace);
+        }
+        
+        return $this;
+    }
+
+    /**
+     * Set bootstrap path/class
+     * 
+     * @param  string $path 
+     * @param  string $class 
+     * @return Zend_Application
+     */
+    public function setBootstrap($path, $class = null)
+    {
+        // setOptions() can potentially send a null value; specify default 
+        // here
+        if (null === $class) {
+            $class = 'Bootstrap';
+        }
+
+        if (!class_exists($class, false)) {
+            require_once $path;
+            if (!class_exists($class, false)) {
+                throw new Zend_Application_Exception('Bootstrap class not found');
+            }
+        }
+        $this->_bootstrap = new $class($this);
+
+        if (!$this->_bootstrap instanceof Zend_Application_Bootstrap_Bootstrapper) {
+            throw new Zend_Application_Exception('Bootstrap class does not implement Zend_Application_Bootstrap_Bootstrapper');
+        }
+        
+        return $this;
+    }
+
+    /**
+     * Get bootstrap object
+     * 
+     * @return Zend_Application_Bootstrap_BootstrapAbstract
+     */
+    public function getBootstrap()
+    {
+        if (null === $this->_bootstrap) {
+            $this->_bootstrap = new Zend_Application_Bootstrap_Bootstrap($this);
+        }
+        return $this->_bootstrap;
+    }
+
+    /**
+     * Bootstrap application
+     *
+     * @param  null|string|array $resource
+     * @return Zend_Application
+     */
+    public function bootstrap($resource = null)
+    {
+        $this->getBootstrap()->bootstrap($resource);
+        return $this;
+    }
+
+    /**
+     * Run the application
+     * 
+     * @return void
+     */
+    public function run()
+    {
+        $this->getBootstrap()->run();
+    }
+
+    /**
+     * Load configuration file of options
+     * 
+     * @param  string $file
+     * @throws Zend_Application_Exception When invalid configuration file is provided 
+     * @return array
+     */
+    protected function _loadConfig($file)
+    {
+        $environment = $this->getEnvironment();
+        $suffix      = strtolower(pathinfo($file, PATHINFO_EXTENSION));
+        
+        switch ($suffix) {
+            case 'ini':
+                $config = new Zend_Config_Ini($file, $environment);
+                break;
+                
+            case 'xml':
+                $config = new Zend_Config_Xml($file, $environment);
+                break;
+                
+            case 'php':
+            case 'inc':
+                $config = include $file;
+                if (!is_array($config)) {
+                    throw new Zend_Application_Exception('Invalid configuration file provided; PHP file does not return array value');
+                }
+                return $config;
+                break;
+                
+            default:
+                throw new Zend_Application_Exception('Invalid configuration file provided; unknown config type');
+        }
+        
+        return $config->toArray();
+    }
+}
diff --git a/lib/zend/Zend/Auth.php b/lib/zend/Zend/Auth.php
new file mode 100644 (file)
index 0000000..7fbd5bf
--- /dev/null
@@ -0,0 +1,169 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Auth
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Auth
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Auth
+{
+    /**
+     * Singleton instance
+     *
+     * @var Zend_Auth
+     */
+    protected static $_instance = null;
+
+    /**
+     * Persistent storage handler
+     *
+     * @var Zend_Auth_Storage_Interface
+     */
+    protected $_storage = null;
+
+    /**
+     * Singleton pattern implementation makes "new" unavailable
+     *
+     * @return void
+     */
+    protected function __construct()
+    {}
+
+    /**
+     * Singleton pattern implementation makes "clone" unavailable
+     *
+     * @return void
+     */
+    protected function __clone()
+    {}
+
+    /**
+     * Returns an instance of Zend_Auth
+     *
+     * Singleton pattern implementation
+     *
+     * @return Zend_Auth Provides a fluent interface
+     */
+    public static function getInstance()
+    {
+        if (null === self::$_instance) {
+            self::$_instance = new self();
+        }
+
+        return self::$_instance;
+    }
+
+    /**
+     * Returns the persistent storage handler
+     *
+     * Session storage is used by default unless a different storage adapter has been set.
+     *
+     * @return Zend_Auth_Storage_Interface
+     */
+    public function getStorage()
+    {
+        if (null === $this->_storage) {
+            /**
+             * @see Zend_Auth_Storage_Session
+             */
+            require_once 'Zend/Auth/Storage/Session.php';
+            $this->setStorage(new Zend_Auth_Storage_Session());
+        }
+
+        return $this->_storage;
+    }
+
+    /**
+     * Sets the persistent storage handler
+     *
+     * @param  Zend_Auth_Storage_Interface $storage
+     * @return Zend_Auth Provides a fluent interface
+     */
+    public function setStorage(Zend_Auth_Storage_Interface $storage)
+    {
+        $this->_storage = $storage;
+        return $this;
+    }
+
+    /**
+     * Authenticates against the supplied adapter
+     *
+     * @param  Zend_Auth_Adapter_Interface $adapter
+     * @return Zend_Auth_Result
+     */
+    public function authenticate(Zend_Auth_Adapter_Interface $adapter)
+    {
+        $result = $adapter->authenticate();
+
+        /**
+         * ZF-7546 - prevent multiple succesive calls from storing inconsistent results
+         * Ensure storage has clean state
+         */ 
+        if ($this->hasIdentity()) {
+            $this->clearIdentity();
+        }
+        
+        if ($result->isValid()) {
+            $this->getStorage()->write($result->getIdentity());
+        }
+
+        return $result;
+    }
+
+    /**
+     * Returns true if and only if an identity is available from storage
+     *
+     * @return boolean
+     */
+    public function hasIdentity()
+    {
+        return !$this->getStorage()->isEmpty();
+    }
+
+    /**
+     * Returns the identity from storage or null if no identity is available
+     *
+     * @return mixed|null
+     */
+    public function getIdentity()
+    {
+        $storage = $this->getStorage();
+
+        if ($storage->isEmpty()) {
+            return null;
+        }
+
+        return $storage->read();
+    }
+
+    /**
+     * Clears the identity from persistent storage
+     *
+     * @return void
+     */
+    public function clearIdentity()
+    {
+        $this->getStorage()->clear();
+    }
+}
diff --git a/lib/zend/Zend/Cache.php b/lib/zend/Zend/Cache.php
new file mode 100644 (file)
index 0000000..7853437
--- /dev/null
@@ -0,0 +1,245 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Cache
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+
+/**
+ * @package    Zend_Cache
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+abstract class Zend_Cache
+{
+
+    /**
+     * Standard frontends
+     *
+     * @var array
+     */
+    public static $standardFrontends = array('Core', 'Output', 'Class', 'File', 'Function', 'Page');
+
+    /**
+     * Standard backends
+     *
+     * @var array
+     */
+    public static $standardBackends = array('File', 'Sqlite', 'Memcached', 'Apc', 'ZendPlatform', 'Xcache', 'TwoLevels');
+
+    /**
+     * Standard backends which implement the ExtendedInterface
+     * 
+     * @var array
+     */
+    public static $standardExtendedBackends = array('File', 'Apc', 'TwoLevels', 'Memcached', 'Sqlite');
+    
+    /**
+     * Only for backward compatibily (may be removed in next major release)
+     *
+     * @var array
+     * @deprecated
+     */
+    public static $availableFrontends = array('Core', 'Output', 'Class', 'File', 'Function', 'Page');
+
+    /**
+     * Only for backward compatibily (may be removed in next major release)
+     *
+     * @var array
+     * @deprecated
+     */
+    public static $availableBackends = array('File', 'Sqlite', 'Memcached', 'Apc', 'ZendPlatform', 'Xcache', 'TwoLevels');
+
+    /**
+     * Consts for clean() method
+     */
+    const CLEANING_MODE_ALL              = 'all';
+    const CLEANING_MODE_OLD              = 'old';
+    const CLEANING_MODE_MATCHING_TAG     = 'matchingTag';
+    const CLEANING_MODE_NOT_MATCHING_TAG = 'notMatchingTag';
+    const CLEANING_MODE_MATCHING_ANY_TAG = 'matchingAnyTag';
+    
+    /**
+     * Factory
+     *
+     * @param mixed  $frontend        frontend name (string) or Zend_Cache_Frontend_ object
+     * @param mixed  $backend         backend name (string) or Zend_Cache_Backend_ object
+     * @param array  $frontendOptions associative array of options for the corresponding frontend constructor
+     * @param array  $backendOptions  associative array of options for the corresponding backend constructor
+     * @param boolean $customFrontendNaming if true, the frontend argument is used as a complete class name ; if false, the frontend argument is used as the end of "Zend_Cache_Frontend_[...]" class name
+     * @param boolean $customBackendNaming if true, the backend argument is used as a complete class name ; if false, the backend argument is used as the end of "Zend_Cache_Backend_[...]" class name
+     * @param boolean $autoload if true, there will no require_once for backend and frontend (usefull only for custom backends/frontends)
+     * @throws Zend_Cache_Exception
+     * @return Zend_Cache_Core|Zend_Cache_Frontend
+     */
+    public static function factory($frontend, $backend, $frontendOptions = array(), $backendOptions = array(), $customFrontendNaming = false, $customBackendNaming = false, $autoload = false)
+    {
+        if (is_string($backend)) {
+            $backendObject = self::_makeBackend($backend, $backendOptions, $customBackendNaming, $autoload);
+        } else {
+            if ((is_object($backend)) && (in_array('Zend_Cache_Backend_Interface', class_implements($backend)))) {
+                $backendObject = $backend;
+            } else {
+                self::throwException('backend must be a backend name (string) or an object which implements Zend_Cache_Backend_Interface');
+            }
+        }
+        if (is_string($frontend)) {
+            $frontendObject = self::_makeFrontend($frontend, $frontendOptions, $customFrontendNaming, $autoload);
+        } else {
+            if (is_object($frontend)) {
+                $frontendObject = $frontend;
+            } else {
+                self::throwException('frontend must be a frontend name (string) or an object');
+            }
+        }
+        $frontendObject->setBackend($backendObject);
+        return $frontendObject;
+    }
+    
+    /**
+     * Frontend Constructor
+     *
+     * @param string  $backend
+     * @param array   $backendOptions
+     * @param boolean $customBackendNaming
+     * @param boolean $autoload
+     * @return Zend_Cache_Backend
+     */
+    public static function _makeBackend($backend, $backendOptions, $customBackendNaming = false, $autoload = false)
+    {
+        if (!$customBackendNaming) {
+            $backend  = self::_normalizeName($backend);
+        }
+        if (in_array($backend, Zend_Cache::$standardBackends)) {
+            // we use a standard backend
+            $backendClass = 'Zend_Cache_Backend_' . $backend;
+            // security controls are explicit
+            require_once str_replace('_', DIRECTORY_SEPARATOR, $backendClass) . '.php';
+        } else {
+            // we use a custom backend
+            if (!preg_match('~^[\w]+$~D', $backend)) {
+                Zend_Cache::throwException("Invalid backend name [$backend]");
+            }
+            if (!$customBackendNaming) {
+                // we use this boolean to avoid an API break
+                $backendClass = 'Zend_Cache_Backend_' . $backend;
+            } else {
+                $backendClass = $backend;
+            }
+            if (!$autoload) {
+                $file = str_replace('_', DIRECTORY_SEPARATOR, $backendClass) . '.php';
+                if (!(self::_isReadable($file))) {
+                    self::throwException("file $file not found in include_path");
+                }
+                require_once $file;
+            }
+        }
+        return new $backendClass($backendOptions);
+    }
+    
+    /**
+     * Backend Constructor
+     *
+     * @param string  $frontend
+     * @param array   $frontendOptions
+     * @param boolean $customFrontendNaming
+     * @param boolean $autoload
+     * @return Zend_Cache_Core|Zend_Cache_Frontend
+     */
+    public static function _makeFrontend($frontend, $frontendOptions = array(), $customFrontendNaming = false, $autoload = false)
+    {
+        if (!$customFrontendNaming) {
+            $frontend = self::_normalizeName($frontend);
+        }
+        if (in_array($frontend, self::$standardFrontends)) {
+            // we use a standard frontend
+            // For perfs reasons, with frontend == 'Core', we can interact with the Core itself
+            $frontendClass = 'Zend_Cache_' . ($frontend != 'Core' ? 'Frontend_' : '') . $frontend;
+            // security controls are explicit
+            require_once str_replace('_', DIRECTORY_SEPARATOR, $frontendClass) . '.php';
+        } else {
+            // we use a custom frontend
+            if (!preg_match('~^[\w]+$~D', $frontend)) {
+                Zend_Cache::throwException("Invalid frontend name [$frontend]");
+            }
+            if (!$customFrontendNaming) {
+                // we use this boolean to avoid an API break
+                $frontendClass = 'Zend_Cache_Frontend_' . $frontend;
+            } else {
+                $frontendClass = $frontend;
+            }
+            if (!$autoload) {
+                $file = str_replace('_', DIRECTORY_SEPARATOR, $frontendClass) . '.php';
+                if (!(self::_isReadable($file))) {
+                    self::throwException("file $file not found in include_path");
+                }
+                require_once $file;
+            }
+        }
+        return new $frontendClass($frontendOptions);
+    }
+
+    /**
+     * Throw an exception
+     *
+     * Note : for perf reasons, the "load" of Zend/Cache/Exception is dynamic
+     * @param  string $msg  Message for the exception
+     * @throws Zend_Cache_Exception
+     */
+    public static function throwException($msg)
+    {
+        // For perfs reasons, we use this dynamic inclusion
+        require_once 'Zend/Cache/Exception.php';
+        throw new Zend_Cache_Exception($msg);
+    }
+
+    /**
+     * Normalize frontend and backend names to allow multiple words TitleCased
+     *
+     * @param  string $name  Name to normalize
+     * @return string
+     */
+    protected static function _normalizeName($name)
+    {
+        $name = ucfirst(strtolower($name));
+        $name = str_replace(array('-', '_', '.'), ' ', $name);
+        $name = ucwords($name);
+        $name = str_replace(' ', '', $name);
+        return $name;
+    }
+
+    /**
+     * Returns TRUE if the $filename is readable, or FALSE otherwise.
+     * This function uses the PHP include_path, where PHP's is_readable()
+     * does not.
+     *
+     * Note : this method comes from Zend_Loader (see #ZF-2891 for details)
+     *
+     * @param string   $filename
+     * @return boolean
+     */
+    private static function _isReadable($filename)
+    {
+        if (!$fh = @fopen($filename, 'r', true)) {
+            return false;
+        }
+        @fclose($fh);
+        return true;
+    }
+
+}
diff --git a/lib/zend/Zend/Config.php b/lib/zend/Zend/Config.php
new file mode 100644 (file)
index 0000000..5a10b6d
--- /dev/null
@@ -0,0 +1,456 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Config
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Config
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Config implements Countable, Iterator
+{
+    /**
+     * Whether in-memory modifications to configuration data are allowed
+     *
+     * @var boolean
+     */
+    protected $_allowModifications;
+
+    /**
+     * Iteration index
+     *
+     * @var integer
+     */
+    protected $_index;
+
+    /**
+     * Number of elements in configuration data
+     *
+     * @var integer
+     */
+    protected $_count;
+
+    /**
+     * Contains array of configuration data
+     *
+     * @var array
+     */
+    protected $_data;
+
+    /**
+     * Used when unsetting values during iteration to ensure we do not skip
+     * the next element
+     *
+     * @var boolean
+     */
+    protected $_skipNextIteration;
+
+    /**
+     * Contains which config file sections were loaded. This is null
+     * if all sections were loaded, a string name if one section is loaded
+     * and an array of string names if multiple sections were loaded.
+     *
+     * @var mixed
+     */
+    protected $_loadedSection;
+
+    /**
+     * This is used to track section inheritance. The keys are names of sections that
+     * extend other sections, and the values are the extended sections.
+     *
+     * @var array
+     */
+    protected $_extends = array();
+
+    /**
+     * Load file error string.
+     * 
+     * Is null if there was no error while file loading
+     *
+     * @var string
+     */
+    protected $_loadFileErrorStr = null;
+
+    /**
+     * Zend_Config provides a property based interface to
+     * an array. The data are read-only unless $allowModifications
+     * is set to true on construction.
+     *
+     * Zend_Config also implements Countable and Iterator to
+     * facilitate easy access to the data.
+     *
+     * @param  array   $array
+     * @param  boolean $allowModifications
+     * @return void
+     */
+    public function __construct(array $array, $allowModifications = false)
+    {
+        $this->_allowModifications = (boolean) $allowModifications;
+        $this->_loadedSection = null;
+        $this->_index = 0;
+        $this->_data = array();
+        foreach ($array as $key => $value) {
+            if (is_array($value)) {
+                $this->_data[$key] = new self($value, $this->_allowModifications);
+            } else {
+                $this->_data[$key] = $value;
+            }
+        }
+        $this->_count = count($this->_data);
+    }
+
+    /**
+     * Retrieve a value and return $default if there is no element set.
+     *
+     * @param string $name
+     * @param mixed $default
+     * @return mixed
+     */
+    public function get($name, $default = null)
+    {
+        $result = $default;
+        if (array_key_exists($name, $this->_data)) {
+            $result = $this->_data[$name];
+        }
+        return $result;
+    }
+
+    /**
+     * Magic function so that $obj->value will work.
+     *
+     * @param string $name
+     * @return mixed
+     */
+    public function __get($name)
+    {
+        return $this->get($name);
+    }
+
+    /**
+     * Only allow setting of a property if $allowModifications
+     * was set to true on construction. Otherwise, throw an exception.
+     *
+     * @param  string $name
+     * @param  mixed  $value
+     * @throws Zend_Config_Exception
+     * @return void
+     */
+    public function __set($name, $value)
+    {
+        if ($this->_allowModifications) {
+            if (is_array($value)) {
+                $this->_data[$name] = new self($value, true);
+            } else {
+                $this->_data[$name] = $value;
+            }
+            $this->_count = count($this->_data);
+        } else {
+            /** @see Zend_Config_Exception */
+            require_once 'Zend/Config/Exception.php';
+            throw new Zend_Config_Exception('Zend_Config is read only');
+        }
+    }
+    
+    /**
+     * Deep clone of this instance to ensure that nested Zend_Configs
+     * are also cloned.
+     * 
+     * @return void
+     */
+    public function __clone()
+    {
+      $array = array();
+      foreach ($this->_data as $key => $value) {
+          if ($value instanceof Zend_Config) {
+              $array[$key] = clone $value;
+          } else {
+              $array[$key] = $value;
+          }
+      }
+      $this->_data = $array;
+    }
+
+    /**
+     * Return an associative array of the stored data.
+     *
+     * @return array
+     */
+    public function toArray()
+    {
+        $array = array();
+        $data = $this->_data;
+        foreach ($data as $key => $value) {
+            if ($value instanceof Zend_Config) {
+                $array[$key] = $value->toArray();
+            } else {
+                $array[$key] = $value;
+            }
+        }
+        return $array;
+    }
+
+    /**
+     * Support isset() overloading on PHP 5.1
+     *
+     * @param string $name
+     * @return boolean
+     */
+    public function __isset($name)
+    {
+        return isset($this->_data[$name]);
+    }
+
+    /**
+     * Support unset() overloading on PHP 5.1
+     *
+     * @param  string $name
+     * @throws Zend_Config_Exception
+     * @return void
+     */
+    public function __unset($name)
+    {
+        if ($this->_allowModifications) {
+            unset($this->_data[$name]);
+            $this->_count = count($this->_data);
+            $this->_skipNextIteration = true;
+        } else {
+            /** @see Zend_Config_Exception */
+            require_once 'Zend/Config/Exception.php';
+            throw new Zend_Config_Exception('Zend_Config is read only');
+        }
+
+    }
+
+    /**
+     * Defined by Countable interface
+     *
+     * @return int
+     */
+    public function count()
+    {
+        return $this->_count;
+    }
+
+    /**
+     * Defined by Iterator interface
+     *
+     * @return mixed
+     */
+    public function current()
+    {
+        $this->_skipNextIteration = false;
+        return current($this->_data);
+    }
+
+    /**
+     * Defined by Iterator interface
+     *
+     * @return mixed
+     */
+    public function key()
+    {
+        return key($this->_data);
+    }
+
+    /**
+     * Defined by Iterator interface
+     *
+     */
+    public function next()
+    {
+        if ($this->_skipNextIteration) {
+            $this->_skipNextIteration = false;
+            return;
+        }
+        next($this->_data);
+        $this->_index++;
+    }
+
+    /**
+     * Defined by Iterator interface
+     *
+     */
+    public function rewind()
+    {
+        $this->_skipNextIteration = false;
+        reset($this->_data);
+        $this->_index = 0;
+    }
+
+    /**
+     * Defined by Iterator interface
+     *
+     * @return boolean
+     */
+    public function valid()
+    {
+        return $this->_index < $this->_count;
+    }
+
+    /**
+     * Returns the section name(s) loaded.
+     *
+     * @return mixed
+     */
+    public function getSectionName()
+    {
+        if(is_array($this->_loadedSection) && count($this->_loadedSection) == 1) {
+            $this->_loadedSection = $this->_loadedSection[0];
+        }
+        return $this->_loadedSection;
+    }
+
+    /**
+     * Returns true if all sections were loaded
+     *
+     * @return boolean
+     */
+    public function areAllSectionsLoaded()
+    {
+        return $this->_loadedSection === null;
+    }
+
+
+    /**
+     * Merge another Zend_Config with this one. The items
+     * in $merge will override the same named items in
+     * the current config.
+     *
+     * @param Zend_Config $merge
+     * @return Zend_Config
+     */
+    public function merge(Zend_Config $merge)
+    {
+        foreach($merge as $key => $item) {
+            if(array_key_exists($key, $this->_data)) {
+                if($item instanceof Zend_Config && $this->$key instanceof Zend_Config) {
+                    $this->$key = $this->$key->merge(new Zend_Config($item->toArray(), !$this->readOnly()));
+                } else {
+                    $this->$key = $item;
+                }
+            } else {
+                if($item instanceof Zend_Config) {
+                    $this->$key = new Zend_Config($item->toArray(), !$this->readOnly());
+                } else {
+                    $this->$key = $item;
+                }
+            }
+        }
+
+        return $this;
+    }
+
+    /**
+     * Prevent any more modifications being made to this instance. Useful
+     * after merge() has been used to merge multiple Zend_Config objects
+     * into one object which should then not be modified again.
+     *
+     */
+    public function setReadOnly()
+    {
+        $this->_allowModifications = false;
+        foreach ($this->_data as $key => $value) {
+            if ($value instanceof Zend_Config) {
+                $value->setReadOnly();
+            }
+        }
+    }
+    
+    /**
+     * Returns if this Zend_Config object is read only or not.
+     *
+     * @return boolean
+     */
+    public function readOnly()
+    {
+        return !$this->_allowModifications;
+    }
+    
+    /**
+     * Get the current extends
+     *
+     * @return array
+     */
+    public function getExtends()
+    {
+        return $this->_extends;
+    }
+    
+    /**
+     * Set an extend for Zend_Config_Writer
+     *
+     * @param  string $extendingSection
+     * @param  string $extendedSection
+     * @return void
+     */
+    public function setExtend($extendingSection, $extendedSection = null)
+    {
+        if ($extendedSection === null && isset($this->_extends[$extendingSection])) {
+            unset($this->_extends[$extendingSection]);
+        } else if ($extendedSection !== null) {
+            $this->_extends[$extendingSection] = $extendedSection;
+        }
+    }
+    
+    /**
+     * Throws an exception if $extendingSection may not extend $extendedSection,
+     * and tracks the section extension if it is valid.
+     *
+     * @param  string $extendingSection
+     * @param  string $extendedSection
+     * @throws Zend_Config_Exception
+     * @return void
+     */
+    protected function _assertValidExtend($extendingSection, $extendedSection)
+    {
+        // detect circular section inheritance
+        $extendedSectionCurrent = $extendedSection;
+        while (array_key_exists($extendedSectionCurrent, $this->_extends)) {
+            if ($this->_extends[$extendedSectionCurrent] == $extendingSection) {
+                /** @see Zend_Config_Exception */
+                require_once 'Zend/Config/Exception.php';
+                throw new Zend_Config_Exception('Illegal circular inheritance detected');
+            }
+            $extendedSectionCurrent = $this->_extends[$extendedSectionCurrent];
+        }
+        // remember that this section extends another section
+        $this->_extends[$extendingSection] = $extendedSection;
+    }
+
+    /**
+     * Handle any errors from simplexml_load_file or parse_ini_file
+     *
+     * @param integer $errno
+     * @param string $errstr
+     * @param string $errfile
+     * @param integer $errline
+     */
+    protected function _loadFileErrorHandler($errno, $errstr, $errfile, $errline)
+    { 
+        if ($this->_loadFileErrorStr === null) {
+            $this->_loadFileErrorStr = $errstr;
+        } else {
+            $this->_loadFileErrorStr .= (PHP_EOL . $errstr);
+        }
+    }
+
+}
diff --git a/lib/zend/Zend/Crypt.php b/lib/zend/Zend/Crypt.php
new file mode 100644 (file)
index 0000000..f40291a
--- /dev/null
@@ -0,0 +1,167 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Crypt
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/**
+ * @category   Zend
+ * @package    Zend_Crypt
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Crypt
+{
+
+    const TYPE_OPENSSL = 'openssl';
+    const TYPE_HASH = 'hash';
+    const TYPE_MHASH = 'mhash';
+
+    protected static $_type = null;
+
+    /**
+     * @var array
+     */
+    protected static $_supportedAlgosOpenssl = array(
+        'md2',
+        'md4',
+        'mdc2',
+        'rmd160',
+        'sha',
+        'sha1',
+        'sha224',
+        'sha256',
+        'sha384',
+        'sha512'
+    );
+
+    /**
+     * @var array
+     */
+    protected static $_supportedAlgosMhash = array(
+        'adler32',
+        'crc32',
+        'crc32b',
+        'gost',
+        'haval128',
+        'haval160',
+        'haval192',
+        'haval256',
+        'md4',
+        'md5',
+        'ripemd160',
+        'sha1',
+        'sha256',
+        'tiger',
+        'tiger128',
+        'tiger160'
+    );
+
+    /**
+     * @param string $algorithm
+     * @param string $data
+     * @param bool $binaryOutput
+     * @return unknown
+     */
+    public static function hash($algorithm, $data, $binaryOutput = false)
+    {
+        $algorithm = strtolower($algorithm);
+        if (function_exists($algorithm)) {
+            return $algorithm($data, $binaryOutput);
+        }
+        self::_detectHashSupport($algorithm);
+        $supportedMethod = '_digest' . ucfirst(self::$_type);
+        $result = self::$supportedMethod($algorithm, $data, $binaryOutput);
+    }
+
+    /**
+     * @param string $algorithm
+     * @throws Zend_Crypt_Exception
+     */
+    protected static function _detectHashSupport($algorithm)
+    {
+        if (function_exists('hash')) {
+            self::$_type = self::TYPE_HASH;
+            if (in_array($algorithm, hash_algos())) {
+               return;
+            }
+        }
+        if (function_exists('mhash')) {
+            self::$_type = self::TYPE_MHASH;
+            if (in_array($algorithm, self::$_supportedAlgosMhash)) {
+               return;
+            }
+        }
+        if (function_exists('openssl_digest')) {
+            if ($algorithm == 'ripemd160') {
+                $algorithm = 'rmd160';
+            }
+            self::$_type = self::TYPE_OPENSSL;
+            if (in_array($algorithm, self::$_supportedAlgosOpenssl)) {
+               return;
+            }
+        }
+        /**
+         * @see Zend_Crypt_Exception
+         */
+        require_once 'Zend/Crypt/Exception.php';
+        throw new Zend_Crypt_Exception('\'' . $algorithm . '\' is not supported by any available extension or native function');
+    }
+
+    /**
+     * @param string $algorithm
+     * @param string $data
+     * @param bool $binaryOutput
+     * @return string
+     */
+    protected static function _digestHash($algorithm, $data, $binaryOutput)
+    {
+        return hash($algorithm, $data, $binaryOutput);
+    }
+
+    /**
+     * @param string $algorithm
+     * @param string $data
+     * @param bool $binaryOutput
+     * @return string
+     */
+    protected static function _digestMhash($algorithm, $data, $binaryOutput)
+    {
+        $constant = constant('MHASH_' . strtoupper($algorithm));
+        $binary = mhash($constant, $data);
+        if ($binaryOutput) {
+            return $binary;
+        }
+        return bin2hex($binary);
+    }
+
+    /**
+     * @param string $algorithm
+     * @param string $data
+     * @param bool $binaryOutput
+     * @return string
+     */
+    protected static function _digestOpenssl($algorithm, $data, $binaryOutput)
+    {
+        if ($algorithm == 'ripemd160') {
+            $algorithm = 'rmd160';
+        }
+        return openssl_digest($data, $algorithm, $binaryOutput);
+    }
+
+}
\ No newline at end of file
diff --git a/lib/zend/Zend/Currency.php b/lib/zend/Zend/Currency.php
new file mode 100644 (file)
index 0000000..bc5d2f7
--- /dev/null
@@ -0,0 +1,624 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category  Zend
+ * @package   Zend_Currency
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license   http://framework.zend.com/license/new-bsd     New BSD License
+ * @version   $Id$
+ */
+
+/**
+ * include needed classes
+ */
+require_once 'Zend/Locale.php';
+require_once 'Zend/Locale/Data.php';
+require_once 'Zend/Locale/Format.php';
+
+/**
+ * Class for handling currency notations
+ *
+ * @category  Zend
+ * @package   Zend_Currency
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license   http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Currency
+{
+    // Constants for defining what currency symbol should be displayed
+    const NO_SYMBOL     = 1;
+    const USE_SYMBOL    = 2;
+    const USE_SHORTNAME = 3;
+    const USE_NAME      = 4;
+
+    // Constants for defining the position of the currencysign
+    const STANDARD = 8;
+    const RIGHT    = 16;
+    const LEFT     = 32;
+
+    /**
+     * Locale for this currency
+     *
+     * @var string
+     */
+    private $_locale = null;
+
+    /**
+     * Options array
+     *
+     * The following options are available
+     * 'position'  => Position for the currency sign
+     * 'script'    => Script for the output
+     * 'format'    => Locale for numeric output
+     * 'display'   => Currency detail to show
+     * 'precision' => Precision for the currency
+     * 'name'      => Name for this currency
+     * 'currency'  => 3 lettered international abbreviation
+     * 'symbol'    => Currency symbol
+     *
+     * @var array
+     * @see Zend_Locale
+     */
+    protected $_options = array(
+        'position'  => self::STANDARD,
+        'script'    => null,
+        'format'    => null,
+        'display'   => self::NO_SYMBOL,
+        'precision' => 2,
+        'name'      => null,
+        'currency'  => null,
+        'symbol'    => null
+    );
+
+    /**
+     * Creates a currency instance. Every supressed parameter is used from the actual or the given locale.
+     *
+     * @param  string             $currency OPTIONAL currency short name
+     * @param  string|Zend_Locale $locale   OPTIONAL locale name
+     * @throws Zend_Currency_Exception When currency is invalid
+     */
+    public function __construct($currency = null, $locale = null)
+    {
+        if (Zend_Locale::isLocale($currency, true, false)) {
+            $temp     = $locale;
+            $locale   = $currency;
+            $currency = $temp;
+        }
+
+        $this->setLocale($locale);
+
+        // Get currency details
+        $this->_options['currency'] = self::getShortName($currency, $this->_locale);
+        $this->_options['name']     = self::getName($currency, $this->_locale);
+        $this->_options['symbol']   = self::getSymbol($currency, $this->_locale);
+
+        if (($this->_options['currency'] === null) and ($this->_options['name'] === null)) {
+            require_once 'Zend/Currency/Exception.php';
+            throw new Zend_Currency_Exception("Currency '$currency' not found");
+        }
+
+        // Get the format
+        $this->_options['display']  = self::NO_SYMBOL;
+        if (empty($this->_options['symbol']) === false) {
+            $this->_options['display'] = self::USE_SYMBOL;
+        } else if (empty($this->_options['currency']) === false) {
+            $this->_options['display'] = self::USE_SHORTNAME;
+        }
+    }
+
+    /**
+     * Returns a localized currency string
+     *
+     * @param  integer|float $value   Currency value
+     * @param  array         $options OPTIONAL options to set temporary
+     * @throws Zend_Currency_Exception When the value is not a number
+     * @return string
+     */
+    public function toCurrency($value, array $options = array())
+    {
+        // Validate the passed number
+        if ((isset($value) === false) or (is_numeric($value) === false)) {
+            require_once 'Zend/Currency/Exception.php';
+            throw new Zend_Currency_Exception("Value '$value' has to be numeric");
+        }
+
+        $options = $this->_checkOptions($options) + $this->_options;
+
+        // Format the number
+        $format = $options['format'];
+        $locale = $this->_locale;
+        if (empty($format)) {
+            $format = Zend_Locale_Data::getContent($this->_locale, 'currencynumber');
+        } else if (Zend_Locale::isLocale($format, true, false)) {
+            $locale = $format;
+            $format = Zend_Locale_Data::getContent($format, 'currencynumber');
+        }
+
+        $symbols  = Zend_Locale_Data::getList($locale, 'symbols');
+        $original = $value;
+        $value    = Zend_Locale_Format::toNumber($value, array('locale'        => $locale,
+                                                               'number_format' => $format,
+                                                              'precision'     => $options['precision']));
+
+        if ($options['position'] !== self::STANDARD) {
+            $value = str_replace('¤', '', $value);
+            $space = '';
+            if (iconv_strpos($value, ' ') !== false) {
+                $value = str_replace(' ', '', $value);
+                $space = ' ';
+            }
+
+            if ($options['position'] == self::LEFT) {
+                $value = '¤' . $space . $value;
+            } else {
+                $value = $value . $space . '¤';
+            }
+        }
+
+        // Localize the number digits
+        if (empty($options['script']) === false) {
+            $value = Zend_Locale_Format::convertNumerals($value, 'Latn', $options['script']);
+        }
+
+        // Get the sign to be placed next to the number
+        if (is_numeric($options['display']) === false) {
+            $sign = $options['display'];
+        } else {
+            switch($options['display']) {
+                case self::USE_SYMBOL:
+                    $sign = $this->_extractPattern($options['symbol'], $original);
+                    break;
+
+                case self::USE_SHORTNAME:
+                    $sign = $options['currency'];
+                    break;
+
+                case self::USE_NAME:
+                    $sign = $options['name'];
+                    break;
+
+                default:
+                    $sign = '';
+                    $value = str_replace(' ', '', $value);
+                    break;
+            }
+        }
+
+        $value = str_replace('¤', $sign, $value);
+        return $value;
+    }
+
+    /**
+     * Internal method to extract the currency pattern
+     * when a choice is given based on the given value
+     *
+     * @param  string $pattern
+     * @param  float|integer $value
+     * @return string
+     */
+    private function _extractPattern($pattern, $value)
+    {
+        if (strpos($pattern, '|') === false) {
+            return $pattern;
+        }
+
+        $patterns = explode('|', $pattern);
+        $token    = $pattern;
+        $value    = trim(str_replace('¤', '', $value));
+        krsort($patterns);
+        foreach($patterns as $content) {
+            if (strpos($content, '<') !== false) {
+                $check = iconv_substr($content, 0, iconv_strpos($content, '<'));
+                $token = iconv_substr($content, iconv_strpos($content, '<') + 1);
+                if ($check < $value) {
+                    return $token;
+                }
+            } else {
+                $check = iconv_substr($content, 0, iconv_strpos($content, '≤'));
+                $token = iconv_substr($content, iconv_strpos($content, '≤') + 1);
+                if ($check <= $value) {
+                    return $token;
+                }
+            }
+
+        }
+
+        return $token;
+    }
+
+    /**
+     * Sets the formating options of the localized currency string
+     * If no parameter is passed, the standard setting of the
+     * actual set locale will be used
+     *
+     * @param  array $options (Optional) Options to set
+     * @return Zend_Currency
+     */
+    public function setFormat(array $options = array())
+    {
+        $this->_options = $this->_checkOptions($options) + $this->_options;
+        return $this;
+    }
+
+    /**
+     * Internal function for checking static given locale parameter
+     *
+     * @param  string             $currency (Optional) Currency name
+     * @param  string|Zend_Locale $locale   (Optional) Locale to display informations
+     * @throws Zend_Currency_Exception When locale contains no region
+     * @return string The extracted locale representation as string
+     */
+    private function _checkParams($currency = null, $locale = null)
+    {
+        // Manage the params
+        if ((empty($locale)) and (!empty($currency)) and
+            (Zend_Locale::isLocale($currency, true, false))) {
+            $locale   = $currency;
+            $currency = null;
+        }
+
+        // Validate the locale and get the country short name
+        $country = null;
+        if ((Zend_Locale::isLocale($locale, true, false)) and (strlen($locale) > 4)) {
+            $country = substr($locale, (strpos($locale, '_') + 1));
+        } else {
+            require_once 'Zend/Currency/Exception.php';
+            throw new Zend_Currency_Exception("No region found within the locale '" . (string) $locale . "'");
+        }
+
+        // Get the available currencies for this country
+        $data = Zend_Locale_Data::getContent($locale, 'currencytoregion', $country);
+        if ((empty($currency) === false) and (empty($data) === false)) {
+            $abbreviation = $currency;
+        } else {
+            $abbreviation = $data;
+        }
+
+        return array('locale' => $locale, 'currency' => $currency, 'name' => $abbreviation, 'country' => $country);
+    }
+
+    /**
+     * Returns the actual or details of other currency symbols,
+     * when no symbol is available it returns the currency shortname (f.e. FIM for Finnian Mark)
+     *
+     * @param  string             $currency (Optional) Currency name
+     * @param  string|Zend_Locale $locale   (Optional) Locale to display informations
+     * @return string
+     */
+    public function getSymbol($currency = null, $locale = null)
+    {
+        if (($currency === null) and ($locale === null)) {
+            return $this->_options['symbol'];
+        }
+
+        $params = self::_checkParams($currency, $locale);
+
+        // Get the symbol
+        $symbol = Zend_Locale_Data::getContent($params['locale'], 'currencysymbol', $params['currency']);
+        if (empty($symbol) === true) {
+            $symbol = Zend_Locale_Data::getContent($params['locale'], 'currencysymbol', $params['name']);
+        }
+
+        if (empty($symbol) === true) {
+            return null;
+        }
+
+        return $symbol;
+    }
+
+    /**
+     * Returns the actual or details of other currency shortnames
+     *
+     * @param  string             $currency OPTIONAL Currency's name
+     * @param  string|Zend_Locale $locale   OPTIONAL The locale
+     * @return string
+     */
+    public function getShortName($currency = null, $locale = null)
+    {
+        if (($currency === null) and ($locale === null)) {
+            return $this->_options['currency'];
+        }
+
+        $params = self::_checkParams($currency, $locale);
+
+        // Get the shortname
+        if (empty($params['currency']) === true) {
+            return $params['name'];
+        }
+
+        $list = Zend_Locale_Data::getContent($params['locale'], 'currencytoname', $params['currency']);
+        if (empty($list) === true) {
+            $list = Zend_Locale_Data::getContent($params['locale'], 'nametocurrency', $params['currency']);
+            if (empty($list) === false) {
+                $list = $params['currency'];
+            }
+        }
+
+        if (empty($list) === true) {
+            return null;
+        }
+
+        return $list;
+    }
+
+    /**
+     * Returns the actual or details of other currency names
+     *
+     * @param  string             $currency (Optional) Currency's short name
+     * @param  string|Zend_Locale $locale   (Optional) The locale
+     * @return string
+     */
+    public function getName($currency = null, $locale = null)
+    {
+        if (($currency === null) and ($locale === null)) {
+            return $this->_options['name'];
+        }
+
+        $params = self::_checkParams($currency, $locale);
+
+        // Get the name
+        $name = Zend_Locale_Data::getContent($params['locale'], 'nametocurrency', $params['currency']);
+        if (empty($name) === true) {
+            $name = Zend_Locale_Data::getContent($params['locale'], 'nametocurrency', $params['name']);
+        }
+
+        if (empty($name) === true) {
+            return null;
+        }
+
+        return $name;
+    }
+
+    /**
+     * Returns a list of regions where this currency is or was known
+     *
+     * @param  string $currency OPTIONAL Currency's short name
+     * @throws Zend_Currency_Exception When no currency was defined
+     * @return array List of regions
+     */
+    public function getRegionList($currency = null)
+    {
+        if ($currency === null) {
+            $currency = $this->_options['currency'];
+        }
+
+        if (empty($currency) === true) {
+            require_once 'Zend/Currency/Exception.php';
+            throw new Zend_Currency_Exception('No currency defined');
+        }
+
+        $data = Zend_Locale_Data::getContent('', 'regiontocurrency', $currency);
+
+        $result = explode(' ', $data);
+        return $result;
+    }
+
+    /**
+     * Returns a list of currencies which are used in this region
+     * a region name should be 2 charachters only (f.e. EG, DE, US)
+     * If no region is given, the actual region is used
+     *
+     * @param  string $region OPTIONAL Region to return the currencies for
+     * @return array List of currencies
+     */
+    public function getCurrencyList($region = null)
+    {
+        if (empty($region) === true) {
+            if (strlen($this->_locale) > 4) {
+                $region = substr($this->_locale, (strpos($this->_locale, '_') + 1));
+            }
+        }
+
+        return Zend_Locale_Data::getList('', 'regiontocurrency', $region);
+    }
+
+    /**
+     * Returns the actual currency name
+     *
+     * @return string
+     */
+    public function toString()
+    {
+        return (empty($this->_options['name']) === false) ? $this->_options['name'] : $this->_options['currency'];
+    }
+
+    /**
+     * Returns the currency name
+     *
+     * @return string
+     */
+    public function __toString()
+    {
+        return $this->toString();
+    }
+
+    /**
+     * Returns the set cache
+     *
+     * @return Zend_Cache_Core The set cache
+     */
+    public static function getCache()
+    {
+        $cache = Zend_Locale_Data::getCache();
+        return $cache;
+    }
+
+    /**
+     * Sets a cache for Zend_Currency
+     *
+     * @param  Zend_Cache_Core $cache Cache to set
+     * @return void
+     */
+    public static function setCache(Zend_Cache_Core $cache)
+    {
+        Zend_Locale_Data::setCache($cache);
+    }
+
+    /**
+     * Returns true when a cache is set
+     *
+     * @return boolean
+     */
+    public static function hasCache()
+    {
+        return Zend_Locale_Data::hasCache();
+    }
+
+    /**
+     * Removes any set cache
+     *
+     * @return void
+     */
+    public static function removeCache()
+    {
+        Zend_Locale_Data::removeCache();
+    }
+
+    /**
+     * Clears all set cache data
+     *
+     * @return void
+     */
+    public static function clearCache()
+    {
+        Zend_Locale_Data::clearCache();
+    }
+
+    /**
+     * Sets a new locale for data retreivement
+     * Example: 'de_XX' will be set to 'de' because 'de_XX' does not exist
+     * 'xx_YY' will be set to 'root' because 'xx' does not exist
+     *
+     * @param  string|Zend_Locale $locale (Optional) Locale for parsing input
+     * @throws Zend_Currency_Exception When the given locale does not exist
+     * @return Zend_Currency Provides fluent interface
+     */
+    public function setLocale($locale = null)
+    {
+        require_once 'Zend/Locale.php';
+        try {
+            $this->_locale = Zend_Locale::findLocale($locale);
+        } catch (Zend_Locale_Exception $e) {
+            require_once 'Zend/Currency/Exception.php';
+            throw new Zend_Currency_Exception($e->getMessage());
+        }
+
+        // Get currency details
+        $this->_options['currency'] = $this->getShortName(null, $this->_locale);
+        $this->_options['name']     = $this->getName(null, $this->_locale);
+        $this->_options['symbol']   = $this->getSymbol(null, $this->_locale);
+
+        return $this;
+    }
+
+    /**
+     * Returns the actual set locale
+     *
+     * @return string
+     */
+    public function getLocale()
+    {
+        return $this->_locale;
+    }
+
+    /**
+     * Internal method for checking the options array
+     *
+     * @param  array $options Options to check
+     * @throws Zend_Currency_Exception On unknown position
+     * @throws Zend_Currency_Exception On unknown locale
+     * @throws Zend_Currency_Exception On unknown display
+     * @throws Zend_Currency_Exception On precision not between -1 and 30
+     * @throws Zend_Currency_Exception On problem with script conversion
+     * @throws Zend_Currency_Exception On unknown options
+     * @return array
+     */
+    private function _checkOptions(array $options = array())
+    {
+        if (count($options) === 0) {
+            return $this->_options;
+        }
+
+        foreach ($options as $name => $value) {
+            $name = strtolower($name);
+            if ($name !== 'format') {
+                if (gettype($value) === 'string') {
+                    $value = strtolower($value);
+                }
+            }
+
+            switch($name) {
+                case 'position':
+                    if (($value !== self::STANDARD) and ($value !== self::RIGHT) and ($value !== self::LEFT)) {
+                        require_once 'Zend/Currency/Exception.php';
+                        throw new Zend_Currency_Exception("Unknown position '" . $value . "'");
+                    }
+
+                    break;
+
+                case 'format':
+                    if ((empty($value) === false) and (Zend_Locale::isLocale($value, null, false) === false)) {
+                        require_once 'Zend/Currency/Exception.php';
+                        throw new Zend_Currency_Exception("'" .
+                            ((gettype($value) === 'object') ? get_class($value) : $value)
+                            . "' is not a known locale.");
+                    }
+                    break;
+
+                case 'display':
+                    if (is_numeric($value) and ($value !== self::NO_SYMBOL) and ($value !== self::USE_SYMBOL) and
+                        ($value !== self::USE_SHORTNAME) and ($value !== self::USE_NAME)) {
+                        require_once 'Zend/Currency/Exception.php';
+                        throw new Zend_Currency_Exception("Unknown display '$value'");
+                    }
+                    break;
+
+                case 'precision':
+                    if ($value === null) {
+                        $value = -1;
+                    }
+
+                    if (($value < -1) or ($value > 30)) {
+                        require_once 'Zend/Currency/Exception.php';
+                        throw new Zend_Currency_Exception("'$value' precision has to be between -1 and 30.");
+                    }
+                    break;
+
+                case 'script':
+                    try {
+                        Zend_Locale_Format::convertNumerals(0, $options['script']);
+                    } catch (Zend_Locale_Exception $e) {
+                        require_once 'Zend/Currency/Exception.php';
+                        throw new Zend_Currency_Exception($e->getMessage());
+                    }
+                    break;
+
+                case 'name':
+                    // Break intentionally omitted
+                case 'currency':
+                    // Break intentionally omitted
+                case 'symbol':
+                    // Unchecked options
+                    break;
+
+                default:
+                    require_once 'Zend/Currency/Exception.php';
+                    throw new Zend_Currency_Exception("Unknown option: '$name' = '$value'");
+                    break;
+            }
+        }
+
+        return $options;
+    }
+}
index 54a834b5ecb533b004b081277515a4939e52217e..158aed160555a3320862ccf9e05954171301b164 100644 (file)
@@ -14,7 +14,7 @@
  *
  * @category  Zend
  * @package   Zend_Date
- * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
  * @license   http://framework.zend.com/license/new-bsd     New BSD License
  * @version   $Id$
  */
@@ -30,7 +30,7 @@ require_once 'Zend/Locale/Math.php';
 /**
  * @category  Zend
  * @package   Zend_Date
- * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
  * @license   http://framework.zend.com/license/new-bsd     New BSD License
  */
 class Zend_Date extends Zend_Date_DateObject
@@ -50,96 +50,75 @@ class Zend_Date extends Zend_Date_DateObject
     );
 
     // Class wide Date Constants
-    // day formats
-    const DAY            = 'DAY';            // d - 2 digit day of month, 01-31
-    const DAY_SHORT      = 'DAY_SHORT';      // j - 1,2 digit day of month, 1-31
-
-    const DAY_SUFFIX     = 'DAY_SUFFIX';     // S - english suffix day of month, st-th
-    const DAY_OF_YEAR    = 'DAY_OF_YEAR';    // z - Number of day of year
-
-    const WEEKDAY        = 'WEEKDAY';        // l - full day name - locale aware, Monday - Sunday
-    const WEEKDAY_SHORT  = 'WEEKDAY_SHORT';  // --- 3 letter day of week - locale aware, Mon-Sun
-    const WEEKDAY_NARROW = 'WEEKDAY_NARROW'; // --- 1 letter day name - locale aware, M-S
-    const WEEKDAY_NAME   = 'WEEKDAY_NAME';   // D - abbreviated day name, 1-3 letters - locale aware, Mon-Sun
-
-    const WEEKDAY_8601   = 'WEEKDAY_8601';   // N - digit weekday ISO 8601, 1-7 1 = monday, 7=sunday
-    const WEEKDAY_DIGIT  = 'WEEKDAY_DIGIT';  // w - weekday, 0-6 0=sunday, 6=saturday
-
-    // week formats
-    const WEEK           = 'WEEK';           // W - number of week ISO8601, 1-53
-
-    // month formats
-    const MONTH          = 'MONTH';          // m - 2 digit month, 01-12
-    const MONTH_SHORT    = 'MONTH_SHORT';    // n - 1 digit month, no leading zeros, 1-12
-
-    const MONTH_DAYS     = 'MONTH_DAYS';     // t - Number of days this month
-
-    const MONTH_NAME        = 'MONTH_NAME';         // F - full month name - locale aware, January-December
-    const MONTH_NAME_SHORT  = 'MONTH_NAME_SHORT';  // M - 3 letter monthname - locale aware, Jan-Dec
-    const MONTH_NAME_NARROW = 'MONTH_NAME_NARROW'; // --- 1 letter month name - locale aware, J-D
-
-    // year formats
-    const YEAR           = 'YEAR';           // Y - 4 digit year
-    const YEAR_SHORT     = 'YEAR_SHORT';     // y - 2 digit year, leading zeros 00-99
-
-    const YEAR_8601      = 'YEAR_8601';      // o - number of year ISO8601
-    const YEAR_SHORT_8601= 'YEAR_SHORT_8601';// --- 2 digit number of year ISO8601
-
-    const LEAPYEAR       = 'LEAPYEAR';       // L - is leapyear ?, 0-1
-
-    // time formats
-    const MERIDIEM       = 'MERIDIEM';       // A,a - AM/PM - locale aware, AM/PM
-    const SWATCH         = 'SWATCH';         // B - Swatch Internet Time
-
-    const HOUR           = 'HOUR';           // H - 2 digit hour, leading zeros, 00-23
-    const HOUR_SHORT     = 'HOUR_SHORT';     // G - 1 digit hour, no leading zero, 0-23
-
-    const HOUR_AM        = 'HOUR_AM';        // h - 2 digit hour, leading zeros, 01-12 am/pm
-    const HOUR_SHORT_AM  = 'HOUR_SHORT_AM';  // g - 1 digit hour, no leading zero, 1-12 am/pm
-
-    const MINUTE         = 'MINUTE';         // i - 2 digit minute, leading zeros, 00-59
-    const MINUTE_SHORT   = 'MINUTE_SHORT';   // --- 1 digit minute, no leading zero, 0-59
-
-    const SECOND         = 'SECOND';         // s - 2 digit second, leading zeros, 00-59
-    const SECOND_SHORT   = 'SECOND_SHORT';   // --- 1 digit second, no leading zero, 0-59
-
-    const MILLISECOND    = 'MILLISECOND';    // --- milliseconds
-
-    // timezone formats
-    const TIMEZONE_NAME  = 'TIMEZONE_NAME';  // e - timezone string
-    const DAYLIGHT       = 'DAYLIGHT';       // I - is Daylight saving time ?, 0-1
-    const GMT_DIFF       = 'GMT_DIFF';       // O - GMT difference, -1200 +1200
-    const GMT_DIFF_SEP   = 'GMT_DIFF_SEP';   // P - seperated GMT diff, -12:00 +12:00
-    const TIMEZONE       = 'TIMEZONE';       // T - timezone, EST, GMT, MDT
-    const TIMEZONE_SECS  = 'TIMEZONE_SECS';  // Z - timezone offset in seconds, -43200 +43200
-
-    // date strings
-    const ISO_8601       = 'ISO_8601';       // c - ISO 8601 date string
-    const RFC_2822       = 'RFC_2822';       // r - RFC 2822 date string
-    const TIMESTAMP      = 'TIMESTAMP';      // U - unix timestamp
-
-    // additional formats
-    const ERA            = 'ERA';            // --- short name of era, locale aware,
-    const ERA_NAME       = 'ERA_NAME';       // --- full name of era, locale aware,
-    const DATES          = 'DATES';          // --- standard date, locale aware
-    const DATE_FULL      = 'DATE_FULL';      // --- full date, locale aware
-    const DATE_LONG      = 'DATE_LONG';      // --- long date, locale aware
-    const DATE_MEDIUM    = 'DATE_MEDIUM';    // --- medium date, locale aware
-    const DATE_SHORT     = 'DATE_SHORT';     // --- short date, locale aware
-    const TIMES          = 'TIMES';          // --- standard time, locale aware
-    const TIME_FULL      = 'TIME_FULL';      // --- full time, locale aware
-    const TIME_LONG      = 'TIME_LONG';      // --- long time, locale aware
-    const TIME_MEDIUM    = 'TIME_MEDIUM';    // --- medium time, locale aware
-    const TIME_SHORT     = 'TIME_SHORT';     // --- short time, locale aware
-    const ATOM           = 'ATOM';           // --- DATE_ATOM
-    const COOKIE         = 'COOKIE';         // --- DATE_COOKIE
-    const RFC_822        = 'RFC_822';        // --- DATE_RFC822
-    const RFC_850        = 'RFC_850';        // --- DATE_RFC850
-    const RFC_1036       = 'RFC_1036';       // --- DATE_RFC1036
-    const RFC_1123       = 'RFC_1123';       // --- DATE_RFC1123
-    const RFC_3339       = 'RFC_3339';       // --- DATE_RFC3339
-    const RSS            = 'RSS';            // --- DATE_RSS
-    const W3C            = 'W3C';            // --- DATE_W3C
+    const DAY               = 'dd';
+    const DAY_SHORT         = 'd';
+    const DAY_SUFFIX        = 'SS';
+    const DAY_OF_YEAR       = 'D';
+    const WEEKDAY           = 'EEEE';
+    const WEEKDAY_SHORT     = 'EEE';
+    const WEEKDAY_NARROW    = 'E';
+    const WEEKDAY_NAME      = 'EE';
+    const WEEKDAY_8601      = 'eee';
+    const WEEKDAY_DIGIT     = 'e';
+    const WEEK              = 'ww';
+    const MONTH             = 'MM';
+    const MONTH_SHORT       = 'M';
+    const MONTH_DAYS        = 'ddd';
+    const MONTH_NAME        = 'MMMM';
+    const MONTH_NAME_SHORT  = 'MMM';
+    const MONTH_NAME_NARROW = 'MMMMM';
+    const YEAR              = 'y';
+    const YEAR_SHORT        = 'yy';
+    const YEAR_8601         = 'Y';
+    const YEAR_SHORT_8601   = 'YY';
+    const LEAPYEAR          = 'l';
+    const MERIDIEM          = 'a';
+    const SWATCH            = 'B';
+    const HOUR              = 'HH';
+    const HOUR_SHORT        = 'H';
+    const HOUR_AM           = 'hh';
+    const HOUR_SHORT_AM     = 'h';
+    const MINUTE            = 'mm';
+    const MINUTE_SHORT      = 'm';
+    const SECOND            = 'ss';
+    const SECOND_SHORT      = 's';
+    const MILLISECOND       = 'S';
+    const TIMEZONE_NAME     = 'zzzz';
+    const DAYLIGHT          = 'I';
+    const GMT_DIFF          = 'Z';
+    const GMT_DIFF_SEP      = 'ZZZZ';
+    const TIMEZONE          = 'z';
+    const TIMEZONE_SECS     = 'X';
+    const ISO_8601          = 'c';
+    const RFC_2822          = 'r';
+    const TIMESTAMP         = 'U';
+    const ERA               = 'G';
+    const ERA_NAME          = 'GGGG';
+    const ERA_NARROW        = 'GGGGG';
+    const DATES             = 'F';
+    const DATE_FULL         = 'FFFFF';
+    const DATE_LONG         = 'FFFF';
+    const DATE_MEDIUM       = 'FFF';
+    const DATE_SHORT        = 'FF';
+    const TIMES             = 'WW';
+    const TIME_FULL         = 'TTTTT';
+    const TIME_LONG         = 'TTTT';
+    const TIME_MEDIUM       = 'TTT';
+    const TIME_SHORT        = 'TT';
+    const DATETIME          = 'K';
+    const DATETIME_FULL     = 'KKKKK';
+    const DATETIME_LONG     = 'KKKK';
+    const DATETIME_MEDIUM   = 'KKK';
+    const DATETIME_SHORT    = 'KK';
+    const ATOM              = 'OOO';
+    const COOKIE            = 'CCC';
+    const RFC_822           = 'R';
+    const RFC_850           = 'RR';
+    const RFC_1036          = 'RRR';
+    const RFC_1123          = 'RRRR';
+    const RFC_3339          = 'RRRRR';
+    const RSS               = 'SSS';
+    const W3C               = 'WWW';
 
     /**
      * Generates the standard date object, could be a unix timestamp, localized date,
@@ -157,32 +136,38 @@ class Zend_Date extends Zend_Date_DateObject
      */
     public function __construct($date = null, $part = null, $locale = null)
     {
-        if (($date !== null) and !($date instanceof Zend_TimeSync_Protocol) and (Zend_Locale::isLocale($date, true, false))) {
+        if (is_object($date) and !($date instanceof Zend_TimeSync_Protocol) and
+            !($date instanceof Zend_Date)) {
+            if ($locale instanceof Zend_Locale) {
+                $locale = $date;
+                $date   = null;
+                $part   = null;
+            } else {
+                $date = (string) $date;
+            }
+        }
+
+        if (($date !== null) and !is_array($date) and !($date instanceof Zend_TimeSync_Protocol) and
+            !($date instanceof Zend_Date) and !defined($date) and Zend_Locale::isLocale($date, true, false)) {
             $locale = $date;
-            $date = null;
-            $part = null;
-        } else if (($part !== null) and (Zend_Locale::isLocale($part, null, false))) {
+            $date   = null;
+            $part   = null;
+        } else if (($part !== null) and !defined($part) and Zend_Locale::isLocale($part, true, false)) {
             $locale = $part;
             $part   = null;
         }
 
-        if (empty($locale)) {
-            require_once 'Zend/Registry.php';
-            if (Zend_Registry::isRegistered('Zend_Locale') === true) {
-                $locale = Zend_Registry::get('Zend_Locale');
-            }
-        }
-
         $this->setLocale($locale);
-
-        if (is_string($date) && defined('self::' . $date)) {
+        if (is_string($date) && ($part === null) && (strlen($date) <= 5)) {
             $part = $date;
             $date = null;
         }
 
-        if (is_null($date)) {
-            $date = self::now($locale);
-            if (($part !== null) && ($part !== self::TIMESTAMP)) {
+        if ($date === null) {
+            if ($part === null) {
+                $date = time();
+            } else if ($part !== self::TIMESTAMP) {
+                $date = self::now($locale);
                 $date = $date->get($part);
             }
         }
@@ -212,11 +197,30 @@ class Zend_Date extends Zend_Date_DateObject
             $this->set($date, $part, $this->_locale);
 
             // DST fix
-            if ((is_array($date) === true) and (isset($date['hour']) === true)) {
+            if (is_array($date) === true) {
+                if (!isset($date['hour'])) {
+                    $date['hour'] = 0;
+                }
+
                 $hour = $this->toString('H');
                 $hour = $date['hour'] - $hour;
-                if ($hour !== 0) {
-                    $this->addTimestamp($hour * 3600);
+                switch ($hour) {
+                    case 1 :
+                    case -23 :
+                        $this->addTimestamp(3600);
+                        break;
+                    case -1 :
+                    case 23 :
+                        $this->subTimestamp(3600);
+                        break;
+                    case 2 :
+                    case -22 :
+                        $this->addTimestamp(7200);
+                        break;
+                    case -2 :
+                    case 22 :
+                        $this->subTimestamp(7200);
+                        break;
                 }
             }
         } else {
@@ -406,12 +410,32 @@ class Zend_Date extends Zend_Date_DateObject
      */
     public function toString($format = null, $type = null, $locale = null)
     {
-        if ((strlen($format) != 2) and ($format !== null) and (Zend_Locale::isLocale($format, null, false))) {
+        if (is_object($format)) {
+            if ($format instanceof Zend_Locale) {
+                $locale = $format;
+                $format = null;
+            } else {
+                $format = (string) $format;
+            }
+        }
+
+        if (is_object($type)) {
+            if ($type instanceof Zend_Locale) {
+                $locale = $type;
+                $type   = null;
+            } else {
+                $type = (string) $type;
+            }
+        }
+
+        if (($format !== null) and !defined($format) and
+            ($format != 'ee') and ($format != 'ss') and Zend_Locale::isLocale($format, null, false)) {
             $locale = $format;
             $format = null;
         }
 
-        if (($type !== null) and (Zend_Locale::isLocale($type, null, false))) {
+        if (($type !== null) and ($type != 'php') and ($type != 'iso') and
+            Zend_Locale::isLocale($type, null, false)) {
             $locale = $type;
             $type = null;
         }
@@ -426,297 +450,7 @@ class Zend_Date extends Zend_Date_DateObject
             $format = Zend_Locale_Format::convertPhpToIsoFormat($format);
         }
 
-        // get format tokens
-        $j = 0;
-        $comment = false;
-        $output = array();
-        for($i = 0; $i < strlen($format); ++$i) {
-
-            if ($format[$i] == "'") {
-                if ($comment == false) {
-                    $comment = true;
-                    ++$j;
-                    $output[$j] = "'";
-                } else if (isset($format[$i+1]) and ($format[$i+1] == "'")) {
-                    $output[$j] .= "'";
-                    ++$i;
-                } else {
-                    $comment = false;
-                }
-                continue;
-            }
-
-            if (isset($output[$j]) and ($output[$j][0] == $format[$i]) or
-                ($comment == true)) {
-                $output[$j] .= $format[$i];
-            } else {
-                ++$j;
-                $output[$j] = $format[$i];
-            }
-        }
-
-        $notset = false;
-        // fill format tokens with date information
-        for($i = 1; $i <= count($output); ++$i) {
-            // fill fixed tokens
-            switch ($output[$i]) {
-
-                // special formats
-                case 'SS' :
-                    $output[$i] = $this->date('S', $this->getUnixTimestamp(), false);
-                    break;
-
-                case 'eee' :
-                    $output[$i] = $this->date('N', $this->getUnixTimestamp(), false);
-                    break;
-
-                case 'ddd' :
-                    $output[$i] = $this->date('t', $this->getUnixTimestamp(), false);
-                    break;
-
-                case 'l' :
-                    $output[$i] = $this->date('L', $this->getUnixTimestamp(), false);
-                    break;
-
-                case 'B' :
-                    $output[$i] = $this->date('B', $this->getUnixTimestamp(), false);
-                    break;
-
-                case 'I' :
-                    $output[$i] = $this->date('I', $this->getUnixTimestamp(), false);
-                    break;
-
-                case 'X' :
-                    $output[$i] = $this->date('Z', $this->getUnixTimestamp(), false);
-                    break;
-
-                case 'r' :
-                    $output[$i] = $this->date('r', $this->getUnixTimestamp(), false);
-                    break;
-
-                case 'U' :
-                    $output[$i] = $this->getUnixTimestamp();
-                    break;
-
-                    // eras
-                case 'GGGGG' :
-                    $output[$i] = iconv_substr($this->get(self::ERA, $locale), 0, 1, 'UTF-8') . ".";
-                    break;
-
-                case 'GGGG' :
-                    $output[$i] = $this->get(self::ERA_NAME, $locale);
-                    break;
-
-                case 'GGG' :
-                case 'GG'  :
-                case 'G'   :
-                    $output[$i] = $this->get(self::ERA, $locale);
-                    break;
-
-                // years
-                case 'yy' :
-                    $output[$i] = str_pad($this->get(self::YEAR_SHORT, $locale), 2, '0', STR_PAD_LEFT);
-                    break;
-
-                // ISO years
-                case 'YY' :
-                    $output[$i] = str_pad($this->get(self::YEAR_SHORT_8601, $locale), 2, '0', STR_PAD_LEFT);
-                    break;
-
-                // months
-                case 'MMMMM' :
-                    $output[$i] = iconv_substr($this->get(self::MONTH_NAME_NARROW, $locale), 0, 1, 'UTF-8');
-                    break;
-
-                case 'MMMM' :
-                    $output[$i] = $this->get(self::MONTH_NAME, $locale);
-                    break;
-
-                case 'MMM' :
-                    $output[$i] = $this->get(self::MONTH_NAME_SHORT, $locale);
-                    break;
-
-                case 'MM' :
-                    $output[$i] = $this->get(self::MONTH, $locale);
-                    break;
-
-                case 'M' :
-                    $output[$i] = $this->get(self::MONTH_SHORT, $locale);
-                    break;
-
-                // week
-                case 'ww' :
-                    $output[$i] = str_pad($this->get(self::WEEK, $locale), 2, '0', STR_PAD_LEFT);
-                    break;
-
-                case 'w' :
-                    $output[$i] = $this->get(self::WEEK, $locale);
-                    break;
-
-                // monthday
-                case 'dd' :
-                    $output[$i] = $this->get(self::DAY, $locale);
-                    break;
-
-                case 'd' :
-                    $output[$i] = $this->get(self::DAY_SHORT, $locale);
-                    break;
-
-                // yearday
-                case 'DDD' :
-                    $output[$i] = str_pad($this->get(self::DAY_OF_YEAR, $locale), 3, '0', STR_PAD_LEFT);
-                    break;
-
-                case 'DD' :
-                    $output[$i] = str_pad($this->get(self::DAY_OF_YEAR, $locale), 2, '0', STR_PAD_LEFT);
-                    break;
-
-                case 'D' :
-                    $output[$i] = $this->get(self::DAY_OF_YEAR, $locale);
-                    break;
-
-                // weekday
-                case 'EEEEE' :
-                    $output[$i] = $this->get(self::WEEKDAY_NARROW, $locale);
-                    break;
-
-                case 'EEEE' :
-                    $output[$i] = $this->get(self::WEEKDAY, $locale);
-                    break;
-
-                case 'EEE' :
-                    $output[$i] = $this->get(self::WEEKDAY_SHORT, $locale);
-                    break;
-
-                case 'EE' :
-                    $output[$i] = $this->get(self::WEEKDAY_NAME, $locale);
-                    break;
-
-                case 'E' :
-                    $output[$i] = $this->get(self::WEEKDAY_NARROW, $locale);
-                    break;
-
-                // weekday number
-                case 'ee' :
-                    $output[$i] = str_pad($this->get(self::WEEKDAY_8601, $locale), 2, '0', STR_PAD_LEFT);
-                    break;
-
-                case 'e' :
-                    $output[$i] = $this->get(self::WEEKDAY_8601, $locale);
-                    break;
-
-
-                // period
-                case 'a' :
-                    $output[$i] = $this->get(self::MERIDIEM, $locale);
-                    break;
-
-                // hour
-                case 'hh' :
-                    $output[$i] = $this->get(self::HOUR_AM, $locale);
-                    break;
-
-                case 'h' :
-                    $output[$i] = $this->get(self::HOUR_SHORT_AM, $locale);
-                    break;
-
-                case 'HH' :
-                    $output[$i] = $this->get(self::HOUR, $locale);
-                    break;
-
-                case 'H' :
-                    $output[$i] = $this->get(self::HOUR_SHORT, $locale);
-                    break;
-
-                // minute
-                case 'mm' :
-                    $output[$i] = $this->get(self::MINUTE, $locale);
-                    break;
-
-                case 'm' :
-                    $output[$i] = $this->get(self::MINUTE_SHORT, $locale);
-                    break;
-
-                // second
-                case 'ss' :
-                    $output[$i] = $this->get(self::SECOND, $locale);
-                    break;
-
-                case 's' :
-                    $output[$i] = $this->get(self::SECOND_SHORT, $locale);
-                    break;
-
-                case 'S' :
-                    $output[$i] = $this->get(self::MILLISECOND, $locale);
-                    break;
-
-                // zone
-                // @todo  v needs to be reworked as it's the long wall time and not the timezone
-                case 'vvvv' :
-                case 'zzzz' :
-                    $output[$i] = $this->get(self::TIMEZONE_NAME, $locale);
-                    break;
-
-                // @todo  v needs to be reworked as it's the short wall time and not the timezone
-                case 'v' :
-                case 'zzz' :
-                case 'zz'  :
-                case 'z'   :
-                    $output[$i] = $this->get(self::TIMEZONE, $locale);
-                    break;
-
-                // zone offset
-                case 'ZZZZ' :
-                    $output[$i] = $this->get(self::GMT_DIFF_SEP, $locale);
-                    break;
-
-                case 'ZZZ' :
-                case 'ZZ'  :
-                case 'Z'   :
-                    $output[$i] = $this->get(self::GMT_DIFF, $locale);
-                    break;
-
-                default :
-                    $notset = true;
-                    break;
-            }
-
-            // fill variable tokens
-            if ($notset == true) {
-                if (($output[$i][0] !== "'") and (preg_match('/y+/', $output[$i]))) {
-                    $length     = iconv_strlen($output[$i], 'UTF-8');
-                    $output[$i] = $this->get(self::YEAR, $locale);
-                    $output[$i] = str_pad($output[$i], $length, '0', STR_PAD_LEFT);
-                }
-
-                if (($output[$i][0] !== "'") and (preg_match('/Y+/', $output[$i]))) {
-                    $length     = iconv_strlen($output[$i], 'UTF-8');
-                    $output[$i] = $this->get(self::YEAR_8601, $locale);
-                    $output[$i] = str_pad($output[$i], $length, '0', STR_PAD_LEFT);
-                }
-
-                if (($output[$i][0] !== "'") and (preg_match('/A+/', $output[$i]))) {
-                    $length = iconv_strlen($output[$i], 'UTF-8');
-                    $hour   = $this->get(self::HOUR,        $locale);
-                    $minute = $this->get(self::MINUTE,      $locale);
-                    $second = $this->get(self::SECOND,      $locale);
-                    $milli  = $this->get(self::MILLISECOND, $locale);
-
-                    $seconds    = $milli + ($second * 1000) + ($minute * 60000) + ($hour * 3600000);
-                    $output[$i] = str_pad($seconds, $length, '0', STR_PAD_LEFT);
-                }
-
-                if ($output[$i][0] === "'") {
-                    $output[$i] = iconv_substr($output[$i],
-                                               1,
-                                               iconv_strlen($output[$i], 'UTF-8') - 1,
-                                               'UTF-8');
-                }
-            }
-            $notset = false;
-        }
-
-        return implode('', $output);
+        return $this->get($format, $locale);
     }
 
     /**
@@ -775,7 +509,7 @@ class Zend_Date extends Zend_Date_DateObject
      *
      * @param  string              $part    OPTIONAL Part of the date to return, if null the timestamp is returned
      * @param  string|Zend_Locale  $locale  OPTIONAL Locale for parsing input
-     * @return integer|string  date or datepart
+     * @return string  date or datepart
      */
     public function get($part = null, $locale = null)
     {
@@ -783,7 +517,7 @@ class Zend_Date extends Zend_Date_DateObject
             $locale = $this->getLocale();
         }
 
-        if (($part !== null) and (Zend_Locale::isLocale($part, null, false))) {
+        if (($part !== null) && (strlen($part) !== 2) && (Zend_Locale::isLocale($part, null, false))) {
             $locale = $part;
             $part = null;
         }
@@ -792,303 +526,443 @@ class Zend_Date extends Zend_Date_DateObject
             $part = self::TIMESTAMP;
         }
 
-        if (!defined("self::".$part)) {
-            return $this->toString($part, $locale);
+        return $this->date($this->_toToken($part, $locale), $this->getUnixTimestamp(), false);
+    }
+
+    /**
+     * Internal method to apply tokens
+     *
+     * @param string $part
+     * @param string $locale
+     * @return string
+     */
+    private function _toToken($part, $locale) {
+        // get format tokens
+        $comment = false;
+        $format  = '';
+        $orig    = '';
+        for ($i = 0; $i < strlen($part); ++$i) {
+            if ($part[$i] == "'") {
+                $comment = $comment ? false : true;
+                if (isset($part[$i+1]) && ($part[$i+1] == "'")) {
+                    $comment = $comment ? false : true;
+                    $format .= "\\'";
+                    ++$i;
+                }
+
+                $orig = '';
+                continue;
+            }
+
+            if ($comment) {
+                $format .= '\\' . $part[$i];
+                $orig = '';
+            } else {
+                $orig .= $part[$i];
+                if (!isset($part[$i+1]) || (isset($orig[0]) && ($orig[0] != $part[$i+1]))) {
+                    $format .= $this->_parseIsoToDate($orig, $locale);
+                    $orig  = '';
+                }
+            }
         }
 
-        switch($part) {
+        return $format;
+    }
 
-            // day formats
+    /**
+     * Internal parsing method
+     *
+     * @param string $token
+     * @param string $locale
+     * @return string
+     */
+    private function _parseIsoToDate($token, $locale) {
+        switch($token) {
             case self::DAY :
-                return $this->date('d', $this->getUnixTimestamp(), false);
+                return 'd';
                 break;
 
             case self::WEEKDAY_SHORT :
                 $weekday = strtolower($this->date('D', $this->getUnixTimestamp(), false));
-                $day = Zend_Locale_Data::getContent($locale, 'day', array('gregorian', 'format', 'wide', $weekday));
-                return iconv_substr($day, 0, 3, 'UTF-8');
+                $day     = Zend_Locale_Data::getContent($locale, 'day', array('gregorian', 'format', 'wide', $weekday));
+                return $this->_toComment(iconv_substr($day, 0, 3, 'UTF-8'));
                 break;
 
             case self::DAY_SHORT :
-                return $this->date('j', $this->getUnixTimestamp(), false);
+                return 'j';
                 break;
 
             case self::WEEKDAY :
                 $weekday = strtolower($this->date('D', $this->getUnixTimestamp(), false));
-                return Zend_Locale_Data::getContent($locale, 'day', array('gregorian', 'format', 'wide', $weekday));
+                return $this->_toComment(Zend_Locale_Data::getContent($locale, 'day', array('gregorian', 'format', 'wide', $weekday)));
                 break;
 
             case self::WEEKDAY_8601 :
-                return $this->date('N', $this->getUnixTimestamp(), false);
+                return 'N';
+                break;
+
+            case 'ee' :
+                return $this->_toComment(str_pad($this->date('N', $this->getUnixTimestamp(), false), 2, '0', STR_PAD_LEFT));
                 break;
 
             case self::DAY_SUFFIX :
-                return $this->date('S', $this->getUnixTimestamp(), false);
+                return 'S';
                 break;
 
             case self::WEEKDAY_DIGIT :
-                return $this->date('w', $this->getUnixTimestamp(), false);
+                return 'w';
                 break;
 
             case self::DAY_OF_YEAR :
-                return $this->date('z', $this->getUnixTimestamp(), false);
+                return 'z';
+                break;
+
+            case 'DDD' :
+                return $this->_toComment(str_pad($this->date('z', $this->getUnixTimestamp(), false), 3, '0', STR_PAD_LEFT));
+                break;
+
+            case 'DD' :
+                return $this->_toComment(str_pad($this->date('z', $this->getUnixTimestamp(), false), 2, '0', STR_PAD_LEFT));
                 break;
 
             case self::WEEKDAY_NARROW :
+            case 'EEEEE' :
                 $weekday = strtolower($this->date('D', $this->getUnixTimestamp(), false));
                 $day = Zend_Locale_Data::getContent($locale, 'day', array('gregorian', 'format', 'abbreviated', $weekday));
-                return iconv_substr($day, 0, 1, 'UTF-8');
+                return $this->_toComment(iconv_substr($day, 0, 1, 'UTF-8'));
                 break;
 
             case self::WEEKDAY_NAME :
                 $weekday = strtolower($this->date('D', $this->getUnixTimestamp(), false));
-                return Zend_Locale_Data::getContent($locale, 'day', array('gregorian', 'format', 'abbreviated', $weekday));
+                return $this->_toComment(Zend_Locale_Data::getContent($locale, 'day', array('gregorian', 'format', 'abbreviated', $weekday)));
+                break;
+
+            case 'w' :
+                $week = $this->date('W', $this->getUnixTimestamp(), false);
+                return $this->_toComment(($week[0] == '0') ? $week[1] : $week);
                 break;
 
-            // week formats
             case self::WEEK :
-                return $this->date('W', $this->getUnixTimestamp(), false);
+                return 'W';
                 break;
 
-            // month formats
             case self::MONTH_NAME :
                 $month = $this->date('n', $this->getUnixTimestamp(), false);
-                return Zend_Locale_Data::getContent($locale, 'month', array('gregorian', 'format', 'wide', $month));
+                return $this->_toComment(Zend_Locale_Data::getContent($locale, 'month', array('gregorian', 'format', 'wide', $month)));
                 break;
 
             case self::MONTH :
-                return $this->date('m', $this->getUnixTimestamp(), false);
+                return 'm';
                 break;
 
             case self::MONTH_NAME_SHORT :
                 $month = $this->date('n', $this->getUnixTimestamp(), false);
-                return Zend_Locale_Data::getContent($locale, 'month', array('gregorian', 'format', 'abbreviated', $month));
+                return $this->_toComment(Zend_Locale_Data::getContent($locale, 'month', array('gregorian', 'format', 'abbreviated', $month)));
                 break;
 
             case self::MONTH_SHORT :
-                return $this->date('n', $this->getUnixTimestamp(), false);
+                return 'n';
                 break;
 
             case self::MONTH_DAYS :
-                return $this->date('t', $this->getUnixTimestamp(), false);
+                return 't';
                 break;
 
             case self::MONTH_NAME_NARROW :
                 $month = $this->date('n', $this->getUnixTimestamp(), false);
                 $mon = Zend_Locale_Data::getContent($locale, 'month', array('gregorian', 'format', 'abbreviated', $month));
-                return iconv_substr($mon, 0, 1, 'UTF-8');
+                return $this->_toComment(iconv_substr($mon, 0, 1, 'UTF-8'));
                 break;
 
-            // year formats
             case self::LEAPYEAR :
-                return $this->date('L', $this->getUnixTimestamp(), false);
+                return 'L';
                 break;
 
             case self::YEAR_8601 :
-                return $this->date('o', $this->getUnixTimestamp(), false);
+                return 'o';
                 break;
 
             case self::YEAR :
-                return $this->date('Y', $this->getUnixTimestamp(), false);
+                return 'Y';
                 break;
 
             case self::YEAR_SHORT :
-                return $this->date('y', $this->getUnixTimestamp(), false);
+                return 'y';
                 break;
 
-
             case self::YEAR_SHORT_8601 :
-                return substr($this->date('o', $this->getUnixTimestamp(), false), -2, 2);
+                return $this->_toComment(substr($this->date('o', $this->getUnixTimestamp(), false), -2, 2));
                 break;
 
-            // time formats
             case self::MERIDIEM :
                 $am = $this->date('a', $this->getUnixTimestamp(), false);
                 if ($am == 'am') {
-                    return Zend_Locale_Data::getContent($locale, 'am');
+                    return $this->_toComment(Zend_Locale_Data::getContent($locale, 'am'));
                 }
-                return Zend_Locale_Data::getContent($locale, 'pm');
+
+                return $this->_toComment(Zend_Locale_Data::getContent($locale, 'pm'));
                 break;
 
             case self::SWATCH :
-                return $this->date('B', $this->getUnixTimestamp(), false);
+                return 'B';
                 break;
 
             case self::HOUR_SHORT_AM :
-                return $this->date('g', $this->getUnixTimestamp(), false);
+                return 'g';
                 break;
 
             case self::HOUR_SHORT :
-                return $this->date('G', $this->getUnixTimestamp(), false);
+                return 'G';
                 break;
 
             case self::HOUR_AM :
-                return $this->date('h', $this->getUnixTimestamp(), false);
+                return 'h';
                 break;
 
             case self::HOUR :
-                return $this->date('H', $this->getUnixTimestamp(), false);
+                return 'H';
                 break;
 
             case self::MINUTE :
-                return $this->date('i', $this->getUnixTimestamp(), false);
+                return $this->_toComment(str_pad($this->date('i', $this->getUnixTimestamp(), false), 2, '0', STR_PAD_LEFT));
                 break;
 
             case self::SECOND :
-                return $this->date('s', $this->getUnixTimestamp(), false);
+                return $this->_toComment(str_pad($this->date('s', $this->getUnixTimestamp(), false), 2, '0', STR_PAD_LEFT));
                 break;
 
             case self::MINUTE_SHORT :
-                return $this->date('i', $this->getUnixTimestamp(), false);
+                return 'i';
                 break;
 
             case self::SECOND_SHORT :
-                return $this->date('s', $this->getUnixTimestamp(), false);
+                return 's';
                 break;
 
             case self::MILLISECOND :
-                return $this->_fractional;
+                return $this->_toComment($this->_fractional);
                 break;
 
-            // timezone formats
             case self::TIMEZONE_NAME :
-                return $this->date('e', $this->getUnixTimestamp(), false);
+            case 'vvvv' :
+                return 'e';
                 break;
 
             case self::DAYLIGHT :
-                return $this->date('I', $this->getUnixTimestamp(), false);
+                return 'I';
                 break;
 
             case self::GMT_DIFF :
-                return $this->date('O', $this->getUnixTimestamp(), false);
+            case 'ZZ' :
+            case 'ZZZ' :
+                return 'O';
                 break;
 
             case self::GMT_DIFF_SEP :
-                return $this->date('P', $this->getUnixTimestamp(), false);
+                return 'P';
                 break;
 
             case self::TIMEZONE :
-                return $this->date('T', $this->getUnixTimestamp(), false);
+            case 'v' :
+            case 'zz' :
+            case 'zzz' :
+                return 'T';
                 break;
 
             case self::TIMEZONE_SECS :
-                return $this->date('Z', $this->getUnixTimestamp(), false);
+                return 'Z';
                 break;
 
-            // date strings
             case self::ISO_8601 :
-                return $this->date('c', $this->getUnixTimestamp(), false);
+                return 'c';
                 break;
 
             case self::RFC_2822 :
-                return $this->date('r', $this->getUnixTimestamp(), false);
+                return 'r';
                 break;
 
             case self::TIMESTAMP :
-                return $this->getUnixTimestamp();
+                return 'U';
                 break;
 
-            // additional formats
             case self::ERA :
+            case 'GG' :
+            case 'GGG' :
                 $year = $this->date('Y', $this->getUnixTimestamp(), false);
                 if ($year < 0) {
-                    return Zend_Locale_Data::getContent($locale, 'era', array('gregorian', 'Abbr', '0'));
+                    return $this->_toComment(Zend_Locale_Data::getContent($locale, 'era', array('gregorian', 'Abbr', '0')));
                 }
-                return Zend_Locale_Data::getContent($locale, 'era', array('gregorian', 'Abbr', '1'));
+
+                return $this->_toComment(Zend_Locale_Data::getContent($locale, 'era', array('gregorian', 'Abbr', '1')));
+                break;
+
+            case self::ERA_NARROW :
+                $year = $this->date('Y', $this->getUnixTimestamp(), false);
+                if ($year < 0) {
+                    return $this->_toComment(iconv_substr(Zend_Locale_Data::getContent($locale, 'era', array('gregorian', 'Abbr', '0')), 0, 1, 'UTF-8')) . '.';
+                }
+
+                return $this->_toComment(iconv_substr(Zend_Locale_Data::getContent($locale, 'era', array('gregorian', 'Abbr', '1')), 0, 1, 'UTF-8')) . '.';
                 break;
 
             case self::ERA_NAME :
                 $year = $this->date('Y', $this->getUnixTimestamp(), false);
                 if ($year < 0) {
-                    return Zend_Locale_Data::getContent($locale, 'era', array('gregorian', 'Names', '0'));
+                    return $this->_toComment(Zend_Locale_Data::getContent($locale, 'era', array('gregorian', 'Names', '0')));
                 }
-                return Zend_Locale_Data::getContent($locale, 'era', array('gregorian', 'Names', '1'));
+
+                return $this->_toComment(Zend_Locale_Data::getContent($locale, 'era', array('gregorian', 'Names', '1')));
                 break;
 
             case self::DATES :
-                return $this->toString(Zend_Locale_Format::getDateFormat($locale), 'iso', $locale);
+                return $this->_toToken(Zend_Locale_Format::getDateFormat($locale), $locale);
                 break;
 
             case self::DATE_FULL :
-                $date = Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'full'));
-                return $this->toString($date, 'iso', $locale);
+                return $this->_toToken(Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'full')), $locale);
                 break;
 
             case self::DATE_LONG :
-                $date = Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'long'));
-                return $this->toString($date, 'iso', $locale);
+                return $this->_toToken(Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'long')), $locale);
                 break;
 
             case self::DATE_MEDIUM :
-                $date = Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'medium'));
-                return $this->toString($date, 'iso', $locale);
+                return $this->_toToken(Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'medium')), $locale);
                 break;
 
             case self::DATE_SHORT :
-                $date = Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'short'));
-                return $this->toString($date, 'iso', $locale);
+                return $this->_toToken(Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'short')), $locale);
                 break;
 
             case self::TIMES :
-                return $this->toString(Zend_Locale_Format::getTimeFormat($locale), 'iso', $locale);
+                return $this->_toToken(Zend_Locale_Format::getTimeFormat($locale), $locale);
                 break;
 
             case self::TIME_FULL :
-                $time = Zend_Locale_Data::getContent($locale, 'time', 'full');
-                return $this->toString($time, 'iso', $locale);
+                return $this->_toToken(Zend_Locale_Data::getContent($locale, 'time', 'full'), $locale);
                 break;
 
             case self::TIME_LONG :
-                $time = Zend_Locale_Data::getContent($locale, 'time', 'long');
-                return $this->toString($time, 'iso', $locale);
+                return $this->_toToken(Zend_Locale_Data::getContent($locale, 'time', 'long'), $locale);
                 break;
 
             case self::TIME_MEDIUM :
-                $time = Zend_Locale_Data::getContent($locale, 'time', 'medium');
-                return $this->toString($time, 'iso', $locale);
+                return $this->_toToken(Zend_Locale_Data::getContent($locale, 'time', 'medium'), $locale);
                 break;
 
             case self::TIME_SHORT :
-                $time = Zend_Locale_Data::getContent($locale, 'time', 'short');
-                return $this->toString($time, 'iso', $locale);
+                return $this->_toToken(Zend_Locale_Data::getContent($locale, 'time', 'short'), $locale);
+                break;
+
+            case self::DATETIME :
+                return $this->_toToken(Zend_Locale_Format::getDateTimeFormat($locale), $locale);
+                break;
+
+            case self::DATETIME_FULL :
+                return $this->_toToken(Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'full')), $locale);
+                break;
+
+            case self::DATETIME_LONG :
+                return $this->_toToken(Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'long')), $locale);
+                break;
+
+            case self::DATETIME_MEDIUM :
+                return $this->_toToken(Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'medium')), $locale);
+                break;
+
+            case self::DATETIME_SHORT :
+                return $this->_toToken(Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'short')), $locale);
                 break;
 
             case self::ATOM :
-                return $this->date('Y\-m\-d\TH\:i\:sP', $this->getUnixTimestamp(), false);
+                return 'Y\-m\-d\TH\:i\:sP';
                 break;
 
             case self::COOKIE :
-                return $this->date('l\, d\-M\-y H\:i\:s e', $this->getUnixTimestamp(), false);
+                return 'l\, d\-M\-y H\:i\:s e';
                 break;
 
             case self::RFC_822 :
-                return $this->date('D\, d M y H\:i\:s O', $this->getUnixTimestamp(), false);
+                return 'D\, d M y H\:i\:s O';
                 break;
 
             case self::RFC_850 :
-                return $this->date('l\, d\-M\-y H\:i\:s e', $this->getUnixTimestamp(), false);
+                return 'l\, d\-M\-y H\:i\:s e';
                 break;
 
             case self::RFC_1036 :
-                return $this->date('D\, d M y H\:i\:s O', $this->getUnixTimestamp(), false);
+                return 'D\, d M y H\:i\:s O';
                 break;
 
             case self::RFC_1123 :
-                return $this->date('D\, d M Y H\:i\:s O', $this->getUnixTimestamp(), false);
+                return 'D\, d M Y H\:i\:s O';
                 break;
 
             case self::RFC_3339 :
-                return $this->date('Y\-m\-d\TH\:i\:sP', $this->getUnixTimestamp(), false);
+                return 'Y\-m\-d\TH\:i\:sP';
                 break;
 
             case self::RSS :
-                return $this->date('D\, d M Y H\:i\:s O', $this->getUnixTimestamp(), false);
+                return 'D\, d M Y H\:i\:s O';
                 break;
 
             case self::W3C :
-                return $this->date('Y\-m\-d\TH\:i\:sP', $this->getUnixTimestamp(), false);
+                return 'Y\-m\-d\TH\:i\:sP';
+                break;
+        }
+
+        if ($token == '') {
+            return '';
+        }
+
+        switch ($token[0]) {
+            case 'y' :
+                if ((strlen($token) == 4) && (abs($this->getUnixTimestamp()) <= 0x7FFFFFFF)) {
+                    return 'Y';
+                }
+
+                $length = iconv_strlen($token, 'UTF-8');
+                return $this->_toComment(str_pad($this->date('Y', $this->getUnixTimestamp(), false), $length, '0', STR_PAD_LEFT));
+                break;
+
+            case 'Y' :
+                if ((strlen($token) == 4) && (abs($this->getUnixTimestamp()) <= 0x7FFFFFFF)) {
+                    return 'o';
+                }
+
+                $length = iconv_strlen($token, 'UTF-8');
+                return $this->_toComment(str_pad($this->date('o', $this->getUnixTimestamp(), false), $length, '0', STR_PAD_LEFT));
+                break;
+
+            case 'A' :
+                $length  = iconv_strlen($token, 'UTF-8');
+                $result  = $this->_fractional;
+                $result += $this->date('s', $this->getUnixTimestamp(), false) * 1000;
+                $result += $this->date('i', $this->getUnixTimestamp(), false) * 60000;
+                $result += $this->date('H', $this->getUnixTimestamp(), false) * 3600000;
+
+                return $this->_toComment(str_pad($result, $length, '0', STR_PAD_LEFT));
                 break;
         }
+
+        return $this->_toComment($token);
+    }
+
+    /**
+     * Private function to make a comment of a token
+     *
+     * @param string $token
+     * @return string
+     */
+    private function _toComment($token)
+    {
+        $token = str_split($token);
+        $result = '';
+        foreach ($token as $tok) {
+            $result .= '\\' . $tok;
+        }
+
+        return $result;
     }
 
     /**
@@ -1286,9 +1160,17 @@ class Zend_Date extends Zend_Date_DateObject
         if (is_array($zone)) {
             return $this->getTimezone();
         }
+
         if ($zone instanceof Zend_Date) {
             return $zone->getTimezone();
         }
+
+        $match = array();
+        preg_match('/\dZ$/', $zone, $match);
+        if (!empty($match)) {
+            return "Etc/UTC";
+        }
+
         preg_match('/([+-]\d{2}):{0,1}\d{2}/', $zone, $match);
         if (!empty($match) and ($match[count($match) - 1] <= 12) and ($match[count($match) - 1] >= -12)) {
             $zone = "Etc/GMT";
@@ -1297,7 +1179,7 @@ class Zend_Date extends Zend_Date_DateObject
             return $zone;
         }
 
-        preg_match('/([[:alpha:]\/]{3,30})/', $zone, $match);
+        preg_match('/([[:alpha:]\/]{3,30})(?!.*([[:alpha:]\/]{3,30}))/', $zone, $match);
         try {
             if (!empty($match) and (!is_int($match[count($match) - 1]))) {
                 $oldzone = $this->getTimezone();
@@ -1376,12 +1258,12 @@ class Zend_Date extends Zend_Date_DateObject
      */
     private function _calculate($calc, $date, $part, $locale)
     {
-        if (is_null($date) === true) {
+        if ($date === null) {
             require_once 'Zend/Date/Exception.php';
             throw new Zend_Date_Exception('parameter $date must be set, null is not allowed');
         }
 
-        if (($part !== null) and (Zend_Locale::isLocale($part, null, false))) {
+        if (($part !== null) && (strlen($part) !== 2) && (Zend_Locale::isLocale($part, null, false))) {
             $locale = $part;
             $part   = null;
         }
@@ -1715,7 +1597,7 @@ class Zend_Date extends Zend_Date_DateObject
                         $date += $found;
                         $calc = 'set';
                         if (self::$_options['extend_month'] == false) {
-                            $parts = $this->getDateParts($this->mktime(0, 0, 0, $date, $day, $year, false));
+                            $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false));
                             if ($parts['mday'] != $day) {
                                 $fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day);
                             }
@@ -1724,7 +1606,7 @@ class Zend_Date extends Zend_Date_DateObject
                         $date = $month - $found;
                         $calc = 'set';
                         if (self::$_options['extend_month'] == false) {
-                            $parts = $this->getDateParts($this->mktime(0, 0, 0, $date, $day, $year, false));
+                            $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false));
                             if ($parts['mday'] != $day) {
                                 $fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day);
                             }
@@ -1746,7 +1628,7 @@ class Zend_Date extends Zend_Date_DateObject
                         $date += $month;
                         $calc = 'set';
                         if (self::$_options['extend_month'] == false) {
-                            $parts = $this->getDateParts($this->mktime(0, 0, 0, $date, $day, $year, false));
+                            $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false));
                             if ($parts['mday'] != $day) {
                                 $fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day);
                             }
@@ -1755,7 +1637,7 @@ class Zend_Date extends Zend_Date_DateObject
                         $date = $month - $date;
                         $calc = 'set';
                         if (self::$_options['extend_month'] == false) {
-                            $parts = $this->getDateParts($this->mktime(0, 0, 0, $date, $day, $year, false));
+                            $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false));
                             if ($parts['mday'] != $day) {
                                 $fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day);
                             }
@@ -1787,7 +1669,7 @@ class Zend_Date extends Zend_Date_DateObject
                         $date += $found;
                         $calc = 'set';
                         if (self::$_options['extend_month'] === false) {
-                            $parts = $this->getDateParts($this->mktime(0, 0, 0, $date, $day, $year, false));
+                            $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false));
                             if ($parts['mday'] != $day) {
                                 $fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day);
                             }
@@ -1796,7 +1678,7 @@ class Zend_Date extends Zend_Date_DateObject
                         $date = $month - $found;
                         $calc = 'set';
                         if (self::$_options['extend_month'] === false) {
-                            $parts = $this->getDateParts($this->mktime(0, 0, 0, $date, $day, $year, false));
+                            $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false));
                             if ($parts['mday'] != $day) {
                                 $fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day);
                             }
@@ -1818,7 +1700,7 @@ class Zend_Date extends Zend_Date_DateObject
                         $date += $month;
                         $calc  = 'set';
                         if (self::$_options['extend_month'] === false) {
-                            $parts = $this->getDateParts($this->mktime(0, 0, 0, $date, $day, $year, false));
+                            $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false));
                             if ($parts['mday'] != $day) {
                                 $fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day);
                             }
@@ -1827,7 +1709,7 @@ class Zend_Date extends Zend_Date_DateObject
                         $date = $month - $date;
                         $calc = 'set';
                         if (self::$_options['extend_month'] === false) {
-                            $parts = $this->getDateParts($this->mktime(0, 0, 0, $date, $day, $year, false));
+                            $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false));
                             if ($parts['mday'] != $day) {
                                 $fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day);
                             }
@@ -1865,7 +1747,7 @@ class Zend_Date extends Zend_Date_DateObject
                         $date += $found;
                         $calc  = 'set';
                         if (self::$_options['extend_month'] === false) {
-                            $parts = $this->getDateParts($this->mktime(0, 0, 0, $date, $day, $year, false));
+                            $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false));
                             if ($parts['mday'] != $day) {
                                 $fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day);
                             }
@@ -1874,7 +1756,7 @@ class Zend_Date extends Zend_Date_DateObject
                         $date = $month - $found;
                         $calc = 'set';
                         if (self::$_options['extend_month'] === false) {
-                            $parts = $this->getDateParts($this->mktime(0, 0, 0, $date, $day, $year, false));
+                            $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false));
                             if ($parts['mday'] != $day) {
                                 $fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day);
                             }
@@ -2332,8 +2214,13 @@ class Zend_Date extends Zend_Date_DateObject
                         $day   = 1;
                         $year  = 1970;
                     }
-                    return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], 0,       $month, $day, $year, true),
-                                                 $this->mktime($hour,           $minute,           $second, $month, $day, $year, true), false);
+
+                    if (!isset($parsed['second'])) {
+                        $parsed['second'] = 0;
+                    }
+
+                    return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], $month, $day, $year, true),
+                                                 $this->mktime($hour,           $minute,           $second,           $month, $day, $year, true), false);
                 } catch (Zend_Locale_Exception $e) {
                     require_once 'Zend/Date/Exception.php';
                     throw new Zend_Date_Exception($e->getMessage(), $date);
@@ -2383,8 +2270,127 @@ class Zend_Date extends Zend_Date_DateObject
                         $day   = 1;
                         $year  = 1970;
                     }
-                    return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], 0,       $month, $day, $year, true),
-                                                 $this->mktime($hour,           $minute,           $second, $month, $day, $year, true), false);
+
+                    if (!isset($parsed['second'])) {
+                        $parsed['second'] = 0;
+                    }
+
+                    return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], $month, $day, $year, true),
+                                                 $this->mktime($hour,           $minute,           $second,           $month, $day, $year, true), false);
+                } catch (Zend_Locale_Exception $e) {
+                    require_once 'Zend/Date/Exception.php';
+                    throw new Zend_Date_Exception($e->getMessage(), $date);
+                }
+                break;
+
+            case self::DATETIME:
+                try {
+                    $parsed = Zend_Locale_Format::getDateTime($date, array('locale' => $locale, 'format_type' => 'iso', 'fix_date' => true));
+                    if (($calc == 'set') || ($calc == 'cmp')) {
+                        --$parsed['month'];
+                        --$month;
+                        --$parsed['day'];
+                        --$day;
+                        $parsed['year'] -= 1970;
+                        $year  -= 1970;
+                    }
+                    return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true),
+                                                 $this->mktime($hour,           $minute,           $second,           1 + $month,           1 + $day,           1970 + $year,           true), $hour);
+                } catch (Zend_Locale_Exception $e) {
+                    require_once 'Zend/Date/Exception.php';
+                    throw new Zend_Date_Exception($e->getMessage(), $date);
+                }
+                break;
+
+            case self::DATETIME_FULL:
+                try {
+                    $format = Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'full'));
+                    $parsed = Zend_Locale_Format::getDateTime($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale));
+
+                    if (($calc == 'set') || ($calc == 'cmp')) {
+                        --$parsed['month'];
+                        --$month;
+                        --$parsed['day'];
+                        --$day;
+                        $parsed['year'] -= 1970;
+                        $year  -= 1970;
+                    }
+
+                    if (!isset($parsed['second'])) {
+                        $parsed['second'] = 0;
+                    }
+
+                    return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true),
+                                                 $this->mktime($hour,           $minute,           $second,           1 + $month,           1 + $day,           1970 + $year,           true), $hour);
+                } catch (Zend_Locale_Exception $e) {
+                    require_once 'Zend/Date/Exception.php';
+                    throw new Zend_Date_Exception($e->getMessage(), $date);
+                }
+                break;
+
+            case self::DATETIME_LONG:
+                try {
+                    $format = Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'long'));
+                    $parsed = Zend_Locale_Format::getDateTime($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale));
+
+                    if (($calc == 'set') || ($calc == 'cmp')){
+                        --$parsed['month'];
+                        --$month;
+                        --$parsed['day'];
+                        --$day;
+                        $parsed['year'] -= 1970;
+                        $year  -= 1970;
+                    }
+                    return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true),
+                                                 $this->mktime($hour,           $minute,           $second,           1 + $month,           1 + $day,           1970 + $year,           true), $hour);
+                } catch (Zend_Locale_Exception $e) {
+                    require_once 'Zend/Date/Exception.php';
+                    throw new Zend_Date_Exception($e->getMessage(), $date);
+                }
+                break;
+
+            case self::DATETIME_MEDIUM:
+                try {
+                    $format = Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'medium'));
+                    $parsed = Zend_Locale_Format::getDateTime($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale));
+                    if (($calc == 'set') || ($calc == 'cmp')) {
+                        --$parsed['month'];
+                        --$month;
+                        --$parsed['day'];
+                        --$day;
+                        $parsed['year'] -= 1970;
+                        $year  -= 1970;
+                    }
+                    return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true),
+                                                 $this->mktime($hour,           $minute,           $second,           1 + $month,           1 + $day,           1970 + $year,           true), $hour);
+                } catch (Zend_Locale_Exception $e) {
+                    require_once 'Zend/Date/Exception.php';
+                    throw new Zend_Date_Exception($e->getMessage(), $date);
+                }
+                break;
+
+            case self::DATETIME_SHORT:
+                try {
+                    $format = Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'short'));
+                    $parsed = Zend_Locale_Format::getDateTime($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale));
+
+                    $parsed['year'] = self::getFullYear($parsed['year']);
+
+                    if (($calc == 'set') || ($calc == 'cmp')) {
+                        --$parsed['month'];
+                        --$month;
+                        --$parsed['day'];
+                        --$day;
+                        $parsed['year'] -= 1970;
+                        $year  -= 1970;
+                    }
+
+                    if (!isset($parsed['second'])) {
+                        $parsed['second'] = 0;
+                    }
+
+                    return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true),
+                                                 $this->mktime($hour,           $minute,           $second,           1 + $month,           1 + $day,           1970 + $year,           true), $hour);
                 } catch (Zend_Locale_Exception $e) {
                     require_once 'Zend/Date/Exception.php';
                     throw new Zend_Date_Exception($e->getMessage(), $date);
@@ -2685,18 +2691,14 @@ class Zend_Date extends Zend_Date_DateObject
      */
     private function _time($calc, $time, $format, $locale)
     {
-        if (is_null($time)) {
+        if ($time === null) {
             require_once 'Zend/Date/Exception.php';
             throw new Zend_Date_Exception('parameter $time must be set, null is not allowed');
         }
 
-        if ($locale === null) {
-            $locale = $this->getLocale();
-        }
-
         if ($time instanceof Zend_Date) {
             // extract time from object
-            $time = $time->get(self::TIME_MEDIUM, $locale);
+            $time = $time->get('HH:mm:ss');
         } else {
             if (is_array($time)) {
                 if ((isset($time['hour']) === true) or (isset($time['minute']) === true) or
@@ -2711,21 +2713,22 @@ class Zend_Date extends Zend_Date_DateObject
                     $format = Zend_Locale_Format::convertPhpToIsoFormat($format);
                 }
                 try {
+                    if ($locale === null) {
+                        $locale = $this->getLocale();
+                    }
+
                     $parsed = Zend_Locale_Format::getTime($time, array('date_format' => $format, 'locale' => $locale, 'format_type' => 'iso'));
                 } catch (Zend_Locale_Exception $e) {
                     require_once 'Zend/Date/Exception.php';
                     throw new Zend_Date_Exception($e->getMessage());
                 }
             }
-            $time = new self(0, self::TIMESTAMP, $locale);
-            $time->setTimezone('UTC');
-            $time->set($parsed['hour'],   self::HOUR);
-            $time->set($parsed['minute'], self::MINUTE);
-            $time->set($parsed['second'], self::SECOND);
-            $time = $time->get(self::TIME_MEDIUM, $locale);
+            $time  = str_pad($parsed['hour'], 2, '0', STR_PAD_LEFT) . ":";
+            $time .= str_pad($parsed['minute'], 2, '0', STR_PAD_LEFT) . ":";
+            $time .= str_pad($parsed['second'], 2, '0', STR_PAD_LEFT);
         }
 
-        $return = $this->_calcdetail($calc, $time, self::TIME_MEDIUM, $locale);
+        $return = $this->_calcdetail($calc, $time, self::TIMES, 'de');
         if ($calc != 'cmp') {
             return $this;
         }
@@ -2812,7 +2815,7 @@ class Zend_Date extends Zend_Date_DateObject
      */
     public function getDate($locale = null)
     {
-        $date = $this->copyPart(self::DATE_FULL, $locale);
+        $date = $this->copyPart(self::DATE_MEDIUM, $locale);
         $date->addTimestamp($this->getGmtOffset());
         return $date;
     }
@@ -2829,23 +2832,19 @@ class Zend_Date extends Zend_Date_DateObject
      */
     private function _date($calc, $date, $format, $locale)
     {
-        if (is_null($date)) {
+        if ($date === null) {
             require_once 'Zend/Date/Exception.php';
             throw new Zend_Date_Exception('parameter $date must be set, null is not allowed');
         }
 
-        if ($locale === null) {
-            $locale = $this->getLocale();
-        }
-
         if ($date instanceof Zend_Date) {
             // extract date from object
-            $date = $date->get(self::DATE_FULL, $locale);
+            $date = $date->get('d.M.Y');
         } else {
             if (is_array($date)) {
-                if ((isset($time['year']) === true) or (isset($time['month']) === true) or
-                    (isset($time['day']) === true)) {
-                    $parsed = $time;
+                if ((isset($date['year']) === true) or (isset($date['month']) === true) or
+                    (isset($date['day']) === true)) {
+                    $parsed = $date;
                 } else {
                     require_once 'Zend/Date/Exception.php';
                     throw new Zend_Date_Exception("no day,month or year given in array");
@@ -2855,6 +2854,10 @@ class Zend_Date extends Zend_Date_DateObject
                     $format = Zend_Locale_Format::convertPhpToIsoFormat($format);
                 }
                 try {
+                    if ($locale === null) {
+                        $locale = $this->getLocale();
+                    }
+
                     $parsed = Zend_Locale_Format::getDate($date, array('date_format' => $format, 'locale' => $locale, 'format_type' => 'iso'));
                     if ((strpos(strtoupper($format), 'YY') !== false) and (strpos(strtoupper($format), 'YYYY') === false)) {
                         $parsed['year'] = self::getFullYear($parsed['year']);
@@ -2864,15 +2867,10 @@ class Zend_Date extends Zend_Date_DateObject
                     throw new Zend_Date_Exception($e->getMessage());
                 }
             }
-            $date = new self(0, self::TIMESTAMP, $locale);
-            $date->setTimezone('UTC');
-            $date->set($parsed['year'], self::YEAR);
-            $date->set($parsed['month'], self::MONTH);
-            $date->set($parsed['day'], self::DAY);
-            $date = $date->get(self::DATE_FULL, $locale);
+            $date  = $parsed['day'] . "." . $parsed['month'] . "." . $parsed['year'];
         }
 
-        $return = $this->_calcdetail($calc, $date, self::DATE_FULL, $locale);
+        $return = $this->_calcdetail($calc, $date, self::DATE_MEDIUM, 'de');
         if ($calc != 'cmp') {
             return $this;
         }
@@ -3373,7 +3371,7 @@ class Zend_Date extends Zend_Date_DateObject
      */
     private function _calcvalue($calc, $value, $type, $parameter, $locale)
     {
-        if (is_null($value)) {
+        if ($value === null) {
             require_once 'Zend/Date/Exception.php';
             throw new Zend_Date_Exception("parameter $type must be set, null is not allowed");
         }
@@ -3508,7 +3506,7 @@ class Zend_Date extends Zend_Date_DateObject
      */
     private function _month($calc, $month, $locale)
     {
-        if (is_null($month)) {
+        if ($month === null) {
             require_once 'Zend/Date/Exception.php';
             throw new Zend_Date_Exception('parameter $month must be set, null is not allowed');
         }
@@ -3539,7 +3537,7 @@ class Zend_Date extends Zend_Date_DateObject
                 $cnt = 0;
                 foreach ($monthlist as $key => $value) {
                     if (strtoupper($value) == strtoupper($month)) {
-                        $found = $key + 1;
+                        $found = ($key % 12) + 1;
                         break;
                     }
                     ++$cnt;
@@ -3663,7 +3661,7 @@ class Zend_Date extends Zend_Date_DateObject
      */
     private function _day($calc, $day, $locale)
     {
-        if (is_null($day)) {
+        if ($day === null) {
             require_once 'Zend/Date/Exception.php';
             throw new Zend_Date_Exception('parameter $day must be set, null is not allowed');
         }
@@ -3811,7 +3809,7 @@ class Zend_Date extends Zend_Date_DateObject
      */
     private function _weekday($calc, $weekday, $locale)
     {
-        if (is_null($weekday)) {
+        if ($weekday === null) {
             require_once 'Zend/Date/Exception.php';
             throw new Zend_Date_Exception('parameter $weekday must be set, null is not allowed');
         }
@@ -4389,7 +4387,7 @@ class Zend_Date extends Zend_Date_DateObject
      */
     public function subMilliSecond($milli = null, $precision = null)
     {
-        return $this->addMilliSecond(0 - $milli);
+        return $this->addMilliSecond(0 - $milli, $precision);
     }
 
     /**
@@ -4525,16 +4523,13 @@ class Zend_Date extends Zend_Date_DateObject
      */
     public function setLocale($locale = null)
     {
-        if (!Zend_Locale::isLocale($locale, true, false)) {
-            if (!Zend_Locale::isLocale($locale, false, false)) {
-                require_once 'Zend/Date/Exception.php';
-                throw new Zend_Date_Exception("Given locale ({$locale}) does not exist", (string) $locale);
-            }
-
-            $locale = new Zend_Locale($locale);
+        try {
+            $this->_locale = Zend_Locale::findLocale($locale);
+        } catch (Zend_Locale_Exception $e) {
+            require_once 'Zend/Date/Exception.php';
+            throw new Zend_Date_Exception($e->getMessage());
         }
 
-        $this->_locale = (string) $locale;
         return $this;
     }
 
@@ -4555,14 +4550,15 @@ class Zend_Date extends Zend_Date_DateObject
      * If no format is given the standard dateformat for the actual locale is used.
      * f.e. 30.February.2007 will return false if format is 'dd.MMMM.YYYY'
      *
-     * @param  string             $date   Date to parse for correctness
-     * @param  string             $format (Optional) Format for parsing the date string
-     * @param  string|Zend_Locale $locale (Optional) Locale for parsing date parts
-     * @return boolean            True when all date parts are correct
+     * @param  string|array|Zend_Date $date   Date to parse for correctness
+     * @param  string                 $format (Optional) Format for parsing the date string
+     * @param  string|Zend_Locale     $locale (Optional) Locale for parsing date parts
+     * @return boolean                True when all date parts are correct
      */
     public static function isDate($date, $format = null, $locale = null)
     {
-        if (!is_string($date) and !is_numeric($date) and !($date instanceof Zend_Date)) {
+        if (!is_string($date) && !is_numeric($date) && !($date instanceof Zend_Date) &&
+            !is_array($date)) {
             return false;
         }
 
@@ -4571,47 +4567,32 @@ class Zend_Date extends Zend_Date_DateObject
             $format = null;
         }
 
-        if (empty($locale)) {
-            require_once 'Zend/Registry.php';
-            if (Zend_Registry::isRegistered('Zend_Locale') === true) {
-                $locale = Zend_Registry::get('Zend_Locale');
-            }
-        }
-
-        if (!Zend_Locale::isLocale($locale, true, false)) {
-            if (!Zend_Locale::isLocale($locale, false, false)) {
-                require_once 'Zend/Date/Exception.php';
-                throw new Zend_Date_Exception("Given locale ({$locale}) does not exist", (string) $locale);
-            }
-
-            $locale = new Zend_Locale($locale);
-        }
+        $locale = Zend_Locale::findLocale($locale);
 
-        $locale = (string) $locale;
         if ($format === null) {
             $format = Zend_Locale_Format::getDateFormat($locale);
         } else if (self::$_options['format_type'] == 'php') {
             $format = Zend_Locale_Format::convertPhpToIsoFormat($format);
         }
 
-        try {
-            $parsed = Zend_Locale_Format::getDate($date, array('locale' => $locale,
-                                                  'date_format' => $format, 'format_type' => 'iso',
-                                                  'fix_date' => false));
-
-            if (isset($parsed['year']) and ((strpos(strtoupper($format), 'YY') !== false) and
-                (strpos(strtoupper($format), 'YYYY') === false))) {
-                $parsed['year'] = self::getFullYear($parsed['year']);
+        $format = self::_getLocalizedToken($format, $locale);
+        if (!is_array($date)) {
+            try {
+                $parsed = Zend_Locale_Format::getDate($date, array('locale' => $locale,
+                                                      'date_format' => $format, 'format_type' => 'iso',
+                                                      'fix_date' => false));
+            } catch (Zend_Locale_Exception $e) {
+                // Date can not be parsed
+                return false;
             }
-        } catch (Zend_Locale_Exception $e) {
-            // Date can not be parsed
-            return false;
+        } else {
+            $parsed = $date;
         }
 
         if (((strpos($format, 'Y') !== false) or (strpos($format, 'y') !== false)) and
             (!isset($parsed['year']))) {
             // Year expected but not found
-            return false;
+                return false;
         }
 
         if ((strpos($format, 'M') !== false) and (!isset($parsed['month']))) {
@@ -4627,7 +4608,7 @@ class Zend_Date extends Zend_Date_DateObject
         if (((strpos($format, 'H') !== false) or (strpos($format, 'h') !== false)) and
             (!isset($parsed['hour']))) {
             // Hour expected but not found
-            return false;
+                return false;
         }
 
         if ((strpos($format, 'm') !== false) and (!isset($parsed['minute']))) {
@@ -4642,7 +4623,7 @@ class Zend_Date extends Zend_Date_DateObject
 
         // Set not given dateparts
         if (isset($parsed['hour']) === false) {
-            $parsed['hour'] = 0;
+            $parsed['hour'] = 12;
         }
 
         if (isset($parsed['minute']) === false) {
@@ -4665,9 +4646,16 @@ class Zend_Date extends Zend_Date_DateObject
             $parsed['year'] = 1970;
         }
 
+        if (self::isYearLeapYear($parsed['year'])) {
+            $parsed['year'] = 1972;
+        } else {
+            $parsed['year'] = 1971;
+        }
+
         $date      = new self($parsed, null, $locale);
         $timestamp = $date->mktime($parsed['hour'], $parsed['minute'], $parsed['second'],
                                    $parsed['month'], $parsed['day'], $parsed['year']);
+
         if ($parsed['year'] != $date->date('Y', $timestamp)) {
             // Given year differs from parsed year
             return false;
@@ -4701,4 +4689,84 @@ class Zend_Date extends Zend_Date_DateObject
         return true;
     }
 
+    /**
+     * Returns the ISO Token for all localized constants
+     *
+     * @param string $token Token to normalize
+     * @param string $locale Locale to search
+     * @return string
+     */
+    protected static function _getLocalizedToken($token, $locale)
+    {
+        switch($token) {
+            case self::ISO_8601 :
+                return "dd mm yy";
+                break;
+            case self::RFC_2822 :
+                return "EEE, dd MMM yyyy HH:mm:ss";
+                break;
+            case self::DATES :
+                return Zend_Locale_Data::getContent($locale, 'date');
+                break;
+            case self::DATE_FULL :
+                return Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'full'));
+                break;
+            case self::DATE_LONG :
+                return Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'long'));
+                break;
+            case self::DATE_MEDIUM :
+                return Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'medium'));
+                break;
+            case self::DATE_SHORT :
+                return Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'short'));
+                break;
+            case self::TIMES :
+                return Zend_Locale_Data::getContent($locale, 'date');
+                break;
+            case self::TIME_FULL :
+                return Zend_Locale_Data::getContent($locale, 'time', array('gregorian', 'full'));
+                break;
+            case self::TIME_LONG :
+                return Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'long'));
+                break;
+            case self::TIME_MEDIUM :
+                return Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'medium'));
+                break;
+            case self::TIME_SHORT :
+                return Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'short'));
+                break;
+            case self::DATETIME :
+                return Zend_Locale_Data::getContent($locale, 'datetime');
+                break;
+            case self::DATETIME_FULL :
+                return Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'full'));
+                break;
+            case self::DATETIME_LONG :
+                return Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'long'));
+                break;
+            case self::DATETIME_MEDIUM :
+                return Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'medium'));
+                break;
+            case self::DATETIME_SHORT :
+                return Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'short'));
+                break;
+            case self::ATOM :
+            case self::RFC_3339 :
+            case self::W3C :
+                return "yyyy-MM-DD HH:mm:ss";
+                break;
+            case self::COOKIE :
+            case self::RFC_850 :
+                return "EEEE, dd-MM-yyyy HH:mm:ss";
+                break;
+            case self::RFC_822 :
+            case self::RFC_1036 :
+            case self::RFC_1123 :
+            case self::RSS :
+                return "EEE, dd MM yyyy HH:mm:ss";
+                break;
+        }
+
+        return $token;
+    }
 }
diff --git a/lib/zend/Zend/Db.php b/lib/zend/Zend/Db.php
new file mode 100644 (file)
index 0000000..1c7df20
--- /dev/null
@@ -0,0 +1,281 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Db
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+
+/**
+ * Class for connecting to SQL databases and performing common operations.
+ *
+ * @category   Zend
+ * @package    Zend_Db
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Db
+{
+
+    /**
+     * Use the PROFILER constant in the config of a Zend_Db_Adapter.
+     */
+    const PROFILER = 'profiler';
+
+    /**
+     * Use the CASE_FOLDING constant in the config of a Zend_Db_Adapter.
+     */
+    const CASE_FOLDING = 'caseFolding';
+
+    /**
+     * Use the AUTO_QUOTE_IDENTIFIERS constant in the config of a Zend_Db_Adapter.
+     */
+    const AUTO_QUOTE_IDENTIFIERS = 'autoQuoteIdentifiers';
+
+    /**
+     * Use the ALLOW_SERIALIZATION constant in the config of a Zend_Db_Adapter.
+     */
+    const ALLOW_SERIALIZATION = 'allowSerialization';
+
+    /**
+     * Use the AUTO_RECONNECT_ON_UNSERIALIZE constant in the config of a Zend_Db_Adapter.
+     */
+    const AUTO_RECONNECT_ON_UNSERIALIZE = 'autoReconnectOnUnserialize';
+
+    /**
+     * Use the INT_TYPE, BIGINT_TYPE, and FLOAT_TYPE with the quote() method.
+     */
+    const INT_TYPE    = 0;
+    const BIGINT_TYPE = 1;
+    const FLOAT_TYPE  = 2;
+
+    /**
+     * PDO constant values discovered by this script result:
+     *
+     * $list = array(
+     *    'PARAM_BOOL', 'PARAM_NULL', 'PARAM_INT', 'PARAM_STR', 'PARAM_LOB',
+     *    'PARAM_STMT', 'PARAM_INPUT_OUTPUT', 'FETCH_LAZY', 'FETCH_ASSOC',
+     *    'FETCH_NUM', 'FETCH_BOTH', 'FETCH_OBJ', 'FETCH_BOUND',
+     *    'FETCH_COLUMN', 'FETCH_CLASS', 'FETCH_INTO', 'FETCH_FUNC',
+     *    'FETCH_GROUP', 'FETCH_UNIQUE', 'FETCH_CLASSTYPE', 'FETCH_SERIALIZE',
+     *    'FETCH_NAMED', 'ATTR_AUTOCOMMIT', 'ATTR_PREFETCH', 'ATTR_TIMEOUT',
+     *    'ATTR_ERRMODE', 'ATTR_SERVER_VERSION', 'ATTR_CLIENT_VERSION',
+     *    'ATTR_SERVER_INFO', 'ATTR_CONNECTION_STATUS', 'ATTR_CASE',
+     *    'ATTR_CURSOR_NAME', 'ATTR_CURSOR', 'ATTR_ORACLE_NULLS',
+     *    'ATTR_PERSISTENT', 'ATTR_STATEMENT_CLASS', 'ATTR_FETCH_TABLE_NAMES',
+     *    'ATTR_FETCH_CATALOG_NAMES', 'ATTR_DRIVER_NAME',
+     *    'ATTR_STRINGIFY_FETCHES', 'ATTR_MAX_COLUMN_LEN', 'ERRMODE_SILENT',
+     *    'ERRMODE_WARNING', 'ERRMODE_EXCEPTION', 'CASE_NATURAL',
+     *    'CASE_LOWER', 'CASE_UPPER', 'NULL_NATURAL', 'NULL_EMPTY_STRING',
+     *    'NULL_TO_STRING', 'ERR_NONE', 'FETCH_ORI_NEXT',
+     *    'FETCH_ORI_PRIOR', 'FETCH_ORI_FIRST', 'FETCH_ORI_LAST',
+     *    'FETCH_ORI_ABS', 'FETCH_ORI_REL', 'CURSOR_FWDONLY', 'CURSOR_SCROLL',
+     *    'ERR_CANT_MAP', 'ERR_SYNTAX', 'ERR_CONSTRAINT', 'ERR_NOT_FOUND',
+     *    'ERR_ALREADY_EXISTS', 'ERR_NOT_IMPLEMENTED', 'ERR_MISMATCH',
+     *    'ERR_TRUNCATED', 'ERR_DISCONNECTED', 'ERR_NO_PERM',
+     * );
+     *
+     * $const = array();
+     * foreach ($list as $name) {
+     *    $const[$name] = constant("PDO::$name");
+     * }
+     * var_export($const);
+     */
+    const ATTR_AUTOCOMMIT = 0;
+    const ATTR_CASE = 8;
+    const ATTR_CLIENT_VERSION = 5;
+    const ATTR_CONNECTION_STATUS = 7;
+    const ATTR_CURSOR = 10;
+    const ATTR_CURSOR_NAME = 9;
+    const ATTR_DRIVER_NAME = 16;
+    const ATTR_ERRMODE = 3;
+    const ATTR_FETCH_CATALOG_NAMES = 15;
+    const ATTR_FETCH_TABLE_NAMES = 14;
+    const ATTR_MAX_COLUMN_LEN = 18;
+    const ATTR_ORACLE_NULLS = 11;
+    const ATTR_PERSISTENT = 12;
+    const ATTR_PREFETCH = 1;
+    const ATTR_SERVER_INFO = 6;
+    const ATTR_SERVER_VERSION = 4;
+    const ATTR_STATEMENT_CLASS = 13;
+    const ATTR_STRINGIFY_FETCHES = 17;
+    const ATTR_TIMEOUT = 2;
+    const CASE_LOWER = 2;
+    const CASE_NATURAL = 0;
+    const CASE_UPPER = 1;
+    const CURSOR_FWDONLY = 0;
+    const CURSOR_SCROLL = 1;
+    const ERR_ALREADY_EXISTS = NULL;
+    const ERR_CANT_MAP = NULL;
+    const ERR_CONSTRAINT = NULL;
+    const ERR_DISCONNECTED = NULL;
+    const ERR_MISMATCH = NULL;
+    const ERR_NO_PERM = NULL;
+    const ERR_NONE = '00000';
+    const ERR_NOT_FOUND = NULL;
+    const ERR_NOT_IMPLEMENTED = NULL;
+    const ERR_SYNTAX = NULL;
+    const ERR_TRUNCATED = NULL;
+    const ERRMODE_EXCEPTION = 2;
+    const ERRMODE_SILENT = 0;
+    const ERRMODE_WARNING = 1;
+    const FETCH_ASSOC = 2;
+    const FETCH_BOTH = 4;
+    const FETCH_BOUND = 6;
+    const FETCH_CLASS = 8;
+    const FETCH_CLASSTYPE = 262144;
+    const FETCH_COLUMN = 7;
+    const FETCH_FUNC = 10;
+    const FETCH_GROUP = 65536;
+    const FETCH_INTO = 9;
+    const FETCH_LAZY = 1;
+    const FETCH_NAMED = 11;
+    const FETCH_NUM = 3;
+    const FETCH_OBJ = 5;
+    const FETCH_ORI_ABS = 4;
+    const FETCH_ORI_FIRST = 2;
+    const FETCH_ORI_LAST = 3;
+    const FETCH_ORI_NEXT = 0;
+    const FETCH_ORI_PRIOR = 1;
+    const FETCH_ORI_REL = 5;
+    const FETCH_SERIALIZE = 524288;
+    const FETCH_UNIQUE = 196608;
+    const NULL_EMPTY_STRING = 1;
+    const NULL_NATURAL = 0;
+    const NULL_TO_STRING = NULL;
+    const PARAM_BOOL = 5;
+    const PARAM_INPUT_OUTPUT = -2147483648;
+    const PARAM_INT = 1;
+    const PARAM_LOB = 3;
+    const PARAM_NULL = 0;
+    const PARAM_STMT = 4;
+    const PARAM_STR = 2;
+
+    /**
+     * Factory for Zend_Db_Adapter_Abstract classes.
+     *
+     * First argument may be a string containing the base of the adapter class
+     * name, e.g. 'Mysqli' corresponds to class Zend_Db_Adapter_Mysqli.  This
+     * name is currently case-insensitive, but is not ideal to rely on this behavior.
+     * If your class is named 'My_Company_Pdo_Mysql', where 'My_Company' is the namespace
+     * and 'Pdo_Mysql' is the adapter name, it is best to use the name exactly as it
+     * is defined in the class.  This will ensure proper use of the factory API.
+     *
+     * First argument may alternatively be an object of type Zend_Config.
+     * The adapter class base name is read from the 'adapter' property.
+     * The adapter config parameters are read from the 'params' property.
+     *
+     * Second argument is optional and may be an associative array of key-value
+     * pairs.  This is used as the argument to the adapter constructor.
+     *
+     * If the first argument is of type Zend_Config, it is assumed to contain
+     * all parameters, and the second argument is ignored.
+     *
+     * @param  mixed $adapter String name of base adapter class, or Zend_Config object.
+     * @param  mixed $config  OPTIONAL; an array or Zend_Config object with adapter parameters.
+     * @return Zend_Db_Adapter_Abstract
+     * @throws Zend_Db_Exception
+     */
+    public static function factory($adapter, $config = array())
+    {
+        if ($config instanceof Zend_Config) {
+            $config = $config->toArray();
+        }
+
+        /*
+         * Convert Zend_Config argument to plain string
+         * adapter name and separate config object.
+         */
+        if ($adapter instanceof Zend_Config) {
+            if (isset($adapter->params)) {
+                $config = $adapter->params->toArray();
+            }
+            if (isset($adapter->adapter)) {
+                $adapter = (string) $adapter->adapter;
+            } else {
+                $adapter = null;
+            }
+        }
+
+        /*
+         * Verify that adapter parameters are in an array.
+         */
+        if (!is_array($config)) {
+            /**
+             * @see Zend_Db_Exception
+             */
+            require_once 'Zend/Db/Exception.php';
+            throw new Zend_Db_Exception('Adapter parameters must be in an array or a Zend_Config object');
+        }
+
+        /*
+         * Verify that an adapter name has been specified.
+         */
+        if (!is_string($adapter) || empty($adapter)) {
+            /**
+             * @see Zend_Db_Exception
+             */
+            require_once 'Zend/Db/Exception.php';
+            throw new Zend_Db_Exception('Adapter name must be specified in a string');
+        }
+
+        /*
+         * Form full adapter class name
+         */
+        $adapterNamespace = 'Zend_Db_Adapter';
+        if (isset($config['adapterNamespace'])) {
+            if ($config['adapterNamespace'] != '') {
+                $adapterNamespace = $config['adapterNamespace'];
+            }
+            unset($config['adapterNamespace']);
+        }
+
+        // Adapter no longer normalized- see http://framework.zend.com/issues/browse/ZF-5606
+        $adapterName = $adapterNamespace . '_';
+        $adapterName .= str_replace(' ', '_', ucwords(str_replace('_', ' ', strtolower($adapter))));
+
+        /*
+         * Load the adapter class.  This throws an exception
+         * if the specified class cannot be loaded.
+         */
+        if (!class_exists($adapterName)) {
+            require_once 'Zend/Loader.php';
+            Zend_Loader::loadClass($adapterName);
+        }
+
+        /*
+         * Create an instance of the adapter class.
+         * Pass the config to the adapter class constructor.
+         */
+        $dbAdapter = new $adapterName($config);
+
+        /*
+         * Verify that the object created is a descendent of the abstract adapter type.
+         */
+        if (! $dbAdapter instanceof Zend_Db_Adapter_Abstract) {
+            /**
+             * @see Zend_Db_Exception
+             */
+            require_once 'Zend/Db/Exception.php';
+            throw new Zend_Db_Exception("Adapter class '$adapterName' does not extend Zend_Db_Adapter_Abstract");
+        }
+
+        return $dbAdapter;
+    }
+
+}
diff --git a/lib/zend/Zend/Debug.php b/lib/zend/Zend/Debug.php
new file mode 100644 (file)
index 0000000..f56d5d9
--- /dev/null
@@ -0,0 +1,108 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Debug
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/**
+ * Concrete class for generating debug dumps related to the output source.
+ *
+ * @category   Zend
+ * @package    Zend_Debug
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+
+class Zend_Debug
+{
+
+    /**
+     * @var string
+     */
+    protected static $_sapi = null;
+
+    /**
+     * Get the current value of the debug output environment.
+     * This defaults to the value of PHP_SAPI.
+     *
+     * @return string;
+     */
+    public static function getSapi()
+    {
+        if (self::$_sapi === null) {
+            self::$_sapi = PHP_SAPI;
+        }
+        return self::$_sapi;
+    }
+
+    /**
+     * Set the debug ouput environment.
+     * Setting a value of null causes Zend_Debug to use PHP_SAPI.
+     *
+     * @param string $sapi
+     * @return void;
+     */
+    public static function setSapi($sapi)
+    {
+        self::$_sapi = $sapi;
+    }
+
+    /**
+     * Debug helper function.  This is a wrapper for var_dump() that adds
+     * the <pre /> tags, cleans up newlines and indents, and runs
+     * htmlentities() before output.
+     *
+     * @param  mixed  $var   The variable to dump.
+     * @param  string $label OPTIONAL Label to prepend to output.
+     * @param  bool   $echo  OPTIONAL Echo output if true.
+     * @return string
+     */
+    public static function dump($var, $label=null, $echo=true)
+    {
+        // format the label
+        $label = ($label===null) ? '' : rtrim($label) . ' ';
+
+        // var_dump the variable into a buffer and keep the output
+        ob_start();
+        var_dump($var);
+        $output = ob_get_clean();
+
+        // neaten the newlines and indents
+        $output = preg_replace("/\]\=\>\n(\s+)/m", "] => ", $output);
+        if (self::getSapi() == 'cli') {
+            $output = PHP_EOL . $label
+                    . PHP_EOL . $output
+                    . PHP_EOL;
+        } else {
+            if(!extension_loaded('xdebug')) {
+                $output = htmlspecialchars($output, ENT_QUOTES);
+            }
+
+            $output = '<pre>'
+                    . $label
+                    . $output
+                    . '</pre>';
+        }
+
+        if ($echo) {
+            echo($output);
+        }
+        return $output;
+    }
+
+}
diff --git a/lib/zend/Zend/Dojo.php b/lib/zend/Zend/Dojo.php
new file mode 100644 (file)
index 0000000..2175bf6
--- /dev/null
@@ -0,0 +1,87 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Dojo
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+
+/**
+ * Enable Dojo components
+ * 
+ * @package    Zend_Dojo
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+class Zend_Dojo
+{
+    /**
+     *  @const string Base path to AOL CDN
+     */
+    const CDN_BASE_AOL = 'http://o.aolcdn.com/dojo/';
+
+    /**
+     * @const string Path to dojo on AOL CDN (following version string)
+     */
+    const CDN_DOJO_PATH_AOL = '/dojo/dojo.xd.js';
+
+    /**
+     *  @const string Base path to Google CDN
+     */
+    const CDN_BASE_GOOGLE = 'http://ajax.googleapis.com/ajax/libs/dojo/';
+
+    /**
+     * @const string Path to dojo on Google CDN (following version string)
+     */
+    const CDN_DOJO_PATH_GOOGLE = '/dojo/dojo.xd.js';
+
+    /**
+     * Dojo-enable a form instance
+     * 
+     * @param  Zend_Form $form 
+     * @return void
+     */
+    public static function enableForm(Zend_Form $form)
+    {
+        $form->addPrefixPath('Zend_Dojo_Form_Decorator', 'Zend/Dojo/Form/Decorator', 'decorator')
+             ->addPrefixPath('Zend_Dojo_Form_Element', 'Zend/Dojo/Form/Element', 'element')
+             ->addElementPrefixPath('Zend_Dojo_Form_Decorator', 'Zend/Dojo/Form/Decorator', 'decorator')
+             ->addDisplayGroupPrefixPath('Zend_Dojo_Form_Decorator', 'Zend/Dojo/Form/Decorator')
+             ->setDefaultDisplayGroupClass('Zend_Dojo_Form_DisplayGroup');
+
+        foreach ($form->getSubForms() as $subForm) {
+            self::enableForm($subForm);
+        }
+
+        if (null !== ($view = $form->getView())) {
+            self::enableView($view);
+        }
+    }
+
+    /**
+     * Dojo-enable a view instance
+     * 
+     * @param  Zend_View_Interface $view 
+     * @return void
+     */
+    public static function enableView(Zend_View_Interface $view)
+    {
+        if (false === $view->getPluginLoader('helper')->getPaths('Zend_Dojo_View_Helper')) {
+            $view->addHelperPath('Zend/Dojo/View/Helper', 'Zend_Dojo_View_Helper');
+        }
+    }
+}
+
index 599d8a033e99bba9c6364ecff357fd1d0681a7df..04ffa37ef01996a22e8a0d2488bfc20df2126fae 100644 (file)
  *
  * @category   Zend
  * @package    Zend
- * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
  */
 
 
 /**
  * @category   Zend
  * @package    Zend
- * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
  */
 class Zend_Exception extends Exception
diff --git a/lib/zend/Zend/Feed.php b/lib/zend/Zend/Feed.php
new file mode 100644 (file)
index 0000000..83c6824
--- /dev/null
@@ -0,0 +1,411 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Feed
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+
+/**
+ * Feed utility class
+ *
+ * Base Zend_Feed class, containing constants and the Zend_Http_Client instance
+ * accessor.
+ *
+ * @category   Zend
+ * @package    Zend_Feed
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Feed
+{
+
+    /**
+     * HTTP client object to use for retrieving feeds
+     *
+     * @var Zend_Http_Client
+     */
+    protected static $_httpClient = null;
+
+    /**
+     * Override HTTP PUT and DELETE request methods?
+     *
+     * @var boolean
+     */
+    protected static $_httpMethodOverride = false;
+
+    /**
+     * @var array
+     */
+    protected static $_namespaces = array(
+        'opensearch' => 'http://a9.com/-/spec/opensearchrss/1.0/',
+        'atom'       => 'http://www.w3.org/2005/Atom',
+        'rss'        => 'http://blogs.law.harvard.edu/tech/rss',
+    );
+
+
+    /**
+     * Set the HTTP client instance
+     *
+     * Sets the HTTP client object to use for retrieving the feeds.
+     *
+     * @param  Zend_Http_Client $httpClient
+     * @return void
+     */
+    public static function setHttpClient(Zend_Http_Client $httpClient)
+    {
+        self::$_httpClient = $httpClient;
+    }
+
+
+    /**
+     * Gets the HTTP client object. If none is set, a new Zend_Http_Client will be used.
+     *
+     * @return Zend_Http_Client_Abstract
+     */
+    public static function getHttpClient()
+    {
+        if (!self::$_httpClient instanceof Zend_Http_Client) {
+            /**
+             * @see Zend_Http_Client
+             */
+            require_once 'Zend/Http/Client.php';
+            self::$_httpClient = new Zend_Http_Client();
+        }
+
+        return self::$_httpClient;
+    }
+
+
+    /**
+     * Toggle using POST instead of PUT and DELETE HTTP methods
+     *
+     * Some feed implementations do not accept PUT and DELETE HTTP
+     * methods, or they can't be used because of proxies or other
+     * measures. This allows turning on using POST where PUT and
+     * DELETE would normally be used; in addition, an
+     * X-Method-Override header will be sent with a value of PUT or
+     * DELETE as appropriate.
+     *
+     * @param  boolean $override Whether to override PUT and DELETE.
+     * @return void
+     */
+    public static function setHttpMethodOverride($override = true)
+    {
+        self::$_httpMethodOverride = $override;
+    }
+
+
+    /**
+     * Get the HTTP override state
+     *
+     * @return boolean
+     */
+    public static function getHttpMethodOverride()
+    {
+        return self::$_httpMethodOverride;
+    }
+
+
+    /**
+     * Get the full version of a namespace prefix
+     *
+     * Looks up a prefix (atom:, etc.) in the list of registered
+     * namespaces and returns the full namespace URI if
+     * available. Returns the prefix, unmodified, if it's not
+     * registered.
+     *
+     * @return string
+     */
+    public static function lookupNamespace($prefix)
+    {
+        return isset(self::$_namespaces[$prefix]) ?
+            self::$_namespaces[$prefix] :
+            $prefix;
+    }
+
+
+    /**
+     * Add a namespace and prefix to the registered list
+     *
+     * Takes a prefix and a full namespace URI and adds them to the
+     * list of registered namespaces for use by
+     * Zend_Feed::lookupNamespace().
+     *
+     * @param  string $prefix The namespace prefix
+     * @param  string $namespaceURI The full namespace URI
+     * @return void
+     */
+    public static function registerNamespace($prefix, $namespaceURI)
+    {
+        self::$_namespaces[$prefix] = $namespaceURI;
+    }
+
+
+    /**
+     * Imports a feed located at $uri.
+     *
+     * @param  string $uri
+     * @throws Zend_Feed_Exception
+     * @return Zend_Feed_Abstract
+     */
+    public static function import($uri)
+    {
+        $client = self::getHttpClient();
+        $client->setUri($uri);
+        $response = $client->request('GET');
+        if ($response->getStatus() !== 200) {
+            /**
+             * @see Zend_Feed_Exception
+             */
+            require_once 'Zend/Feed/Exception.php';
+            throw new Zend_Feed_Exception('Feed failed to load, got response code ' . $response->getStatus());
+        }
+        $feed = $response->getBody();
+        return self::importString($feed);
+    }
+
+
+    /**
+     * Imports a feed represented by $string.
+     *
+     * @param  string $string
+     * @throws Zend_Feed_Exception
+     * @return Zend_Feed_Abstract
+     */
+    public static function importString($string)
+    {
+        // Load the feed as an XML DOMDocument object
+        $libxml_errflag = libxml_use_internal_errors(true);
+        $doc = new DOMDocument;
+        if (trim($string) == '') {
+            require_once 'Zend/Feed/Exception.php';
+            throw new Zend_Feed_Exception('Document/string being imported'
+            . ' is an Empty string or comes from an empty HTTP response');
+        }
+        $status = $doc->loadXML($string);
+        libxml_use_internal_errors($libxml_errflag);
+
+
+        if (!$status) {
+            // prevent the class to generate an undefined variable notice (ZF-2590)
+            // Build error message
+            $error = libxml_get_last_error();
+            if ($error && $error->message) {
+                $errormsg = "DOMDocument cannot parse XML: {$error->message}";
+            } else {
+                $errormsg = "DOMDocument cannot parse XML";
+            }
+
+
+            /**
+             * @see Zend_Feed_Exception
+             */
+            require_once 'Zend/Feed/Exception.php';
+            throw new Zend_Feed_Exception($errormsg);
+        }
+
+        // Try to find the base feed element or a single <entry> of an Atom feed
+        if ($doc->getElementsByTagName('feed')->item(0) ||
+            $doc->getElementsByTagName('entry')->item(0)) {
+            /**
+             * @see Zend_Feed_Atom
+             */
+            require_once 'Zend/Feed/Atom.php';
+            // return a newly created Zend_Feed_Atom object
+            return new Zend_Feed_Atom(null, $string);
+        }
+
+        // Try to find the base feed element of an RSS feed
+        if ($doc->getElementsByTagName('channel')->item(0)) {
+            /**
+             * @see Zend_Feed_Rss
+             */
+            require_once 'Zend/Feed/Rss.php';
+            // return a newly created Zend_Feed_Rss object
+            return new Zend_Feed_Rss(null, $string);
+        }
+
+        // $string does not appear to be a valid feed of the supported types
+        /**
+         * @see Zend_Feed_Exception
+         */
+        require_once 'Zend/Feed/Exception.php';
+        throw new Zend_Feed_Exception('Invalid or unsupported feed format');
+    }
+
+
+    /**
+     * Imports a feed from a file located at $filename.
+     *
+     * @param  string $filename
+     * @throws Zend_Feed_Exception
+     * @return Zend_Feed_Abstract
+     */
+    public static function importFile($filename)
+    {
+        @ini_set('track_errors', 1);
+        $feed = @file_get_contents($filename);
+        @ini_restore('track_errors');
+        if ($feed === false) {
+            /**
+             * @see Zend_Feed_Exception
+             */
+            require_once 'Zend/Feed/Exception.php';
+            throw new Zend_Feed_Exception("File could not be loaded: $php_errormsg");
+        }
+        return self::importString($feed);
+    }
+
+
+    /**
+     * Attempts to find feeds at $uri referenced by <link ... /> tags. Returns an
+     * array of the feeds referenced at $uri.
+     *
+     * @todo Allow findFeeds() to follow one, but only one, code 302.
+     *
+     * @param  string $uri
+     * @throws Zend_Feed_Exception
+     * @return array
+     */
+    public static function findFeeds($uri)
+    {
+        // Get the HTTP response from $uri and save the contents
+        $client = self::getHttpClient();
+        $client->setUri($uri);
+        $response = $client->request();
+        if ($response->getStatus() !== 200) {
+            /**
+             * @see Zend_Feed_Exception
+             */
+            require_once 'Zend/Feed/Exception.php';
+            throw new Zend_Feed_Exception("Failed to access $uri, got response code " . $response->getStatus());
+        }
+        $contents = $response->getBody();
+
+        // Parse the contents for appropriate <link ... /> tags
+        @ini_set('track_errors', 1);
+        $pattern = '~(<link[^>]+)/?>~i';
+        $result = @preg_match_all($pattern, $contents, $matches);
+        @ini_restore('track_errors');
+        if ($result === false) {
+            /**
+             * @see Zend_Feed_Exception
+             */
+            require_once 'Zend/Feed/Exception.php';
+            throw new Zend_Feed_Exception("Internal error: $php_errormsg");
+        }
+
+        // Try to fetch a feed for each link tag that appears to refer to a feed
+        $feeds = array();
+        if (isset($matches[1]) && count($matches[1]) > 0) {
+            foreach ($matches[1] as $link) {
+                // force string to be an utf-8 one
+                if (!mb_check_encoding($link, 'UTF-8')) {
+                    $link = mb_convert_encoding($link, 'UTF-8');
+                }
+                $xml = @simplexml_load_string(rtrim($link, ' /') . ' />');
+                if ($xml === false) {
+                    continue;
+                }
+                $attributes = $xml->attributes();
+                if (!isset($attributes['rel']) || !@preg_match('~^(?:alternate|service\.feed)~i', $attributes['rel'])) {
+                    continue;
+                }
+                if (!isset($attributes['type']) ||
+                        !@preg_match('~^application/(?:atom|rss|rdf)\+xml~', $attributes['type'])) {
+                    continue;
+                }
+                if (!isset($attributes['href'])) {
+                    continue;
+                }
+                try {
+                    // checks if we need to canonize the given uri
+                    try {
+                        $uri = Zend_Uri::factory((string) $attributes['href']);
+                    } catch (Zend_Uri_Exception $e) {
+                        // canonize the uri
+                        $path = (string) $attributes['href'];
+                        $query = $fragment = '';
+                        if (substr($path, 0, 1) != '/') {
+                            // add the current root path to this one
+                            $path = rtrim($client->getUri()->getPath(), '/') . '/' . $path;
+                        }
+                        if (strpos($path, '?') !== false) {
+                            list($path, $query) = explode('?', $path, 2);
+                        }
+                        if (strpos($query, '#') !== false) {
+                            list($query, $fragment) = explode('#', $query, 2);
+                        }
+                        $uri = Zend_Uri::factory($client->getUri(true));
+                        $uri->setPath($path);
+                        $uri->setQuery($query);
+                        $uri->setFragment($fragment);
+                    }
+
+                    $feed = self::import($uri);
+                } catch (Exception $e) {
+                    continue;
+                }
+                $feeds[$uri->getUri()] = $feed;
+            }
+        }
+
+        // Return the fetched feeds
+        return $feeds;
+    }
+
+    /**
+     * Construct a new Zend_Feed_Abstract object from a custom array
+     *
+     * @param  array  $data
+     * @param  string $format (rss|atom) the requested output format
+     * @return Zend_Feed_Abstract
+     */
+    public static function importArray(array $data, $format = 'atom')
+    {
+        $obj = 'Zend_Feed_' . ucfirst(strtolower($format));
+        if (!class_exists($obj)) {
+            require_once 'Zend/Loader.php';
+            Zend_Loader::loadClass($obj);
+        }
+
+        /**
+         * @see Zend_Feed_Builder
+         */
+        require_once 'Zend/Feed/Builder.php';
+        return new $obj(null, null, new Zend_Feed_Builder($data));
+    }
+
+    /**
+     * Construct a new Zend_Feed_Abstract object from a Zend_Feed_Builder_Interface data source
+     *
+     * @param  Zend_Feed_Builder_Interface $builder this object will be used to extract the data of the feed
+     * @param  string                      $format (rss|atom) the requested output format
+     * @return Zend_Feed_Abstract
+     */
+    public static function importBuilder(Zend_Feed_Builder_Interface $builder, $format = 'atom')
+    {
+        $obj = 'Zend_Feed_' . ucfirst(strtolower($format));
+        if (!class_exists($obj)) {
+            require_once 'Zend/Loader.php';
+            Zend_Loader::loadClass($obj);
+        }
+        return new $obj(null, null, $builder);
+    }
+}
diff --git a/lib/zend/Zend/Filter.php b/lib/zend/Zend/Filter.php
new file mode 100644 (file)
index 0000000..fe97688
--- /dev/null
@@ -0,0 +1,192 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/**
+ * @see Zend_Filter_Interface
+ */
+require_once 'Zend/Filter/Interface.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Filter implements Zend_Filter_Interface
+{
+    /**
+     * Filter chain
+     *
+     * @var array
+     */
+    protected $_filters = array();
+
+    /**
+     * Default Namespaces
+     *
+     * @var array
+     */
+    protected static $_defaultNamespaces = array();
+
+    /**
+     * Adds a filter to the end of the chain
+     *
+     * @param  Zend_Filter_Interface $filter
+     * @return Zend_Filter Provides a fluent interface
+     */
+    public function addFilter(Zend_Filter_Interface $filter)
+    {
+        $this->_filters[] = $filter;
+        return $this;
+    }
+
+    /**
+     * Returns $value filtered through each filter in the chain
+     *
+     * Filters are run in the order in which they were added to the chain (FIFO)
+     *
+     * @param  mixed $value
+     * @return mixed
+     */
+    public function filter($value)
+    {
+        $valueFiltered = $value;
+        foreach ($this->_filters as $filter) {
+            $valueFiltered = $filter->filter($valueFiltered);
+        }
+        return $valueFiltered;
+    }
+
+    /**
+     * Returns the set default namespaces
+     *
+     * @return array
+     */
+    public static function getDefaultNamespaces()
+    {
+        return self::$_defaultNamespaces;
+    }
+
+    /**
+     * Sets new default namespaces
+     *
+     * @param array|string $namespace
+     * @return null
+     */
+    public static function setDefaultNamespaces($namespace)
+    {
+        if (!is_array($namespace)) {
+            $namespace = array((string) $namespace);
+        }
+
+        self::$_defaultNamespaces = $namespace;
+    }
+
+    /**
+     * Adds a new default namespace
+     *
+     * @param array|string $namespace
+     * @return null
+     */
+    public static function addDefaultNamespaces($namespace)
+    {
+        if (!is_array($namespace)) {
+            $namespace = array((string) $namespace);
+        }
+
+        self::$_defaultNamespaces = array_unique(array_merge(self::$_defaultNamespaces, $namespace));
+    }
+
+    /**
+     * Returns true when defaultNamespaces are set
+     *
+     * @return boolean
+     */
+    public static function hasDefaultNamespaces()
+    {
+        return (!empty(self::$_defaultNamespaces));
+    }
+
+    /**
+     * @deprecated
+     * @see Zend_Filter::filterStatic()
+     *
+     * @param  mixed        $value
+     * @param  string       $classBaseName
+     * @param  array        $args          OPTIONAL
+     * @param  array|string $namespaces    OPTIONAL
+     * @return mixed
+     * @throws Zend_Filter_Exception
+     */
+    public static function get($value, $classBaseName, array $args = array(), $namespaces = array())
+    {
+        trigger_error(
+            'Zend_Filter::get() is deprecated as of 1.9.0; please update your code to utilize Zend_Filter::filterStatic()',
+            E_USER_NOTICE
+        );
+
+        return self::filterStatic($value, $classBaseName, $args, $namespaces);
+    }
+
+    /**
+     * Returns a value filtered through a specified filter class, without requiring separate
+     * instantiation of the filter object.
+     *
+     * The first argument of this method is a data input value, that you would have filtered.
+     * The second argument is a string, which corresponds to the basename of the filter class,
+     * relative to the Zend_Filter namespace. This method automatically loads the class,
+     * creates an instance, and applies the filter() method to the data input. You can also pass
+     * an array of constructor arguments, if they are needed for the filter class.
+     *
+     * @param  mixed        $value
+     * @param  string       $classBaseName
+     * @param  array        $args          OPTIONAL
+     * @param  array|string $namespaces    OPTIONAL
+     * @return mixed
+     * @throws Zend_Filter_Exception
+     */
+    public static function filterStatic($value, $classBaseName, array $args = array(), $namespaces = array())
+    {
+        require_once 'Zend/Loader.php';
+        $namespaces = array_merge((array) $namespaces, self::$_defaultNamespaces, array('Zend_Filter'));
+        foreach ($namespaces as $namespace) {
+            $className = $namespace . '_' . ucfirst($classBaseName);
+            if (!class_exists($className)) {
+                try {
+                    Zend_Loader::loadClass($className);
+                } catch (Zend_Exception $ze) {
+                    continue;
+                }
+            }
+            $class = new ReflectionClass($className);
+            if ($class->implementsInterface('Zend_Filter_Interface')) {
+                if ($class->hasMethod('__construct')) {
+                    $object = $class->newInstanceArgs($args);
+                } else {
+                    $object = $class->newInstance();
+                }
+                return $object->filter($value);
+            }
+        }
+        require_once 'Zend/Filter/Exception.php';
+        throw new Zend_Filter_Exception("Filter class not found from basename '$classBaseName'");
+    }
+}
diff --git a/lib/zend/Zend/Form.php b/lib/zend/Zend/Form.php
new file mode 100644 (file)
index 0000000..4316ea6
--- /dev/null
@@ -0,0 +1,3079 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Form
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+
+/** @see Zend_Validate_Interface */
+require_once 'Zend/Validate/Interface.php';
+
+/**
+ * Zend_Form
+ *
+ * @category   Zend
+ * @package    Zend_Form
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+class Zend_Form implements Iterator, Countable, Zend_Validate_Interface
+{
+    /**#@+
+     * Plugin loader type constants
+     */
+    const DECORATOR = 'DECORATOR';
+    const ELEMENT = 'ELEMENT';
+    /**#@-*/
+
+    /**#@+
+     * Method type constants
+     */
+    const METHOD_DELETE = 'delete';
+    const METHOD_GET    = 'get';
+    const METHOD_POST   = 'post';
+    const METHOD_PUT    = 'put';
+    /**#@-*/
+
+    /**#@+
+     * Encoding type constants
+     */
+    const ENCTYPE_URLENCODED = 'application/x-www-form-urlencoded';
+    const ENCTYPE_MULTIPART  = 'multipart/form-data';
+    /**#@-*/
+
+    /**
+     * Form metadata and attributes
+     * @var array
+     */
+    protected $_attribs = array();
+
+    /**
+     * Decorators for rendering
+     * @var array
+     */
+    protected $_decorators = array();
+
+    /**
+     * Default display group class
+     * @var string
+     */
+    protected $_defaultDisplayGroupClass = 'Zend_Form_DisplayGroup';
+
+    /**
+     * Form description
+     * @var string
+     */
+    protected $_description;
+
+    /**
+     * Should we disable loading the default decorators?
+     * @var bool
+     */
+    protected $_disableLoadDefaultDecorators = false;
+
+    /**
+     * Display group prefix paths
+     * @var array
+     */
+    protected $_displayGroupPrefixPaths = array();
+
+    /**
+     * Groups of elements grouped for display purposes
+     * @var array
+     */
+    protected $_displayGroups = array();
+
+    /**
+     * Global decorators to apply to all elements
+     * @var null|array
+     */
+    protected $_elementDecorators;
+
+    /**
+     * Prefix paths to use when creating elements
+     * @var array
+     */
+    protected $_elementPrefixPaths = array();
+
+    /**
+     * Form elements
+     * @var array
+     */
+    protected $_elements = array();
+
+    /**
+     * Array to which elements belong (if any)
+     * @var string
+     */
+    protected $_elementsBelongTo;
+
+    /**
+     * Custom form-level error messages
+     * @var array
+     */
+    protected $_errorMessages = array();
+
+    /**
+     * Are there errors in the form?
+     * @var bool
+     */
+    protected $_errorsExist = false;
+
+    /**
+     * Has the form been manually flagged as an error?
+     * @var bool
+     */
+    protected $_errorsForced = false;
+
+    /**
+     * Form order
+     * @var int|null
+     */
+    protected $_formOrder;
+
+    /**
+     * Whether or not form elements are members of an array
+     * @var bool
+     */
+    protected $_isArray = false;
+
+    /**
+     * Form legend
+     * @var string
+     */
+    protected $_legend;
+
+    /**
+     * Plugin loaders
+     * @var array
+     */
+    protected $_loaders = array();
+
+    /**
+     * Allowed form methods
+     * @var array
+     */
+    protected $_methods = array('delete', 'get', 'post', 'put');
+
+    /**
+     * Order in which to display and iterate elements
+     * @var array
+     */
+    protected $_order = array();
+
+    /**
+     * Whether internal order has been updated or not
+     * @var bool
+     */
+    protected $_orderUpdated = false;
+
+    /**
+     * Sub form prefix paths
+     * @var array
+     */
+    protected $_subFormPrefixPaths = array();
+
+    /**
+     * Sub forms
+     * @var array
+     */
+    protected $_subForms = array();
+
+    /**
+     * @var Zend_Translate
+     */
+    protected $_translator;
+
+    /**
+     * Global default translation adapter
+     * @var Zend_Translate
+     */
+    protected static $_translatorDefault;
+
+    /**
+     * is the translator disabled?
+     * @var bool
+     */
+    protected $_translatorDisabled = false;
+
+    /**
+     * @var Zend_View_Interface
+     */
+    protected $_view;
+
+    /**
+     * Constructor
+     *
+     * Registers form view helper as decorator
+     *
+     * @param mixed $options
+     * @return void
+     */
+    public function __construct($options = null)
+    {
+        if (is_array($options)) {
+            $this->setOptions($options);
+        } elseif ($options instanceof Zend_Config) {
+            $this->setConfig($options);
+        }
+
+        // Extensions...
+        $this->init();
+
+        $this->loadDefaultDecorators();
+    }
+
+    /**
+     * Clone form object and all children
+     *
+     * @return void
+     */
+    public function __clone()
+    {
+        $elements = array();
+        foreach ($this->getElements() as $name => $element) {
+            $elements[] = clone $element;
+        }
+        $this->setElements($elements);
+
+        $subForms = array();
+        foreach ($this->getSubForms() as $name => $subForm) {
+            $subForms[$name] = clone $subForm;
+        }
+        $this->setSubForms($subForms);
+
+        $displayGroups = array();
+        foreach ($this->_displayGroups as $group)  {
+            $clone    = clone $group;
+            $elements = array();
+            foreach ($clone->getElements() as $name => $e) {
+                $elements[] = $this->getElement($name);
+            }
+            $clone->setElements($elements);
+            $displayGroups[] = $clone;
+        }
+        $this->setDisplayGroups($displayGroups);
+    }
+
+    /**
+     * Reset values of form
+     *
+     * @return Zend_Form
+     */
+    public function reset()
+    {
+        foreach ($this->getElements() as $element) {
+            $element->setValue(null);
+        }
+        foreach ($this->getSubForms() as $subForm) {
+            $subForm->reset();
+        }
+
+        return $this;
+    }
+
+    /**
+     * Initialize form (used by extending classes)
+     *
+     * @return void
+     */
+    public function init()
+    {
+    }
+
+    /**
+     * Set form state from options array
+     *
+     * @param  array $options
+     * @return Zend_Form
+     */
+    public function setOptions(array $options)
+    {
+        if (isset($options['prefixPath'])) {
+            $this->addPrefixPaths($options['prefixPath']);
+            unset($options['prefixPath']);
+        }
+
+        if (isset($options['elementPrefixPath'])) {
+            $this->addElementPrefixPaths($options['elementPrefixPath']);
+            unset($options['elementPrefixPath']);
+        }
+
+        if (isset($options['displayGroupPrefixPath'])) {
+            $this->addDisplayGroupPrefixPaths($options['displayGroupPrefixPath']);
+            unset($options['displayGroupPrefixPath']);
+        }
+
+        if (isset($options['elementDecorators'])) {
+            $this->_elementDecorators = $options['elementDecorators'];
+            unset($options['elementDecorators']);
+        }
+
+        if (isset($options['elements'])) {
+            $this->setElements($options['elements']);
+            unset($options['elements']);
+        }
+
+        if (isset($options['defaultDisplayGroupClass'])) {
+            $this->setDefaultDisplayGroupClass($options['defaultDisplayGroupClass']);
+            unset($options['defaultDisplayGroupClass']);
+        }
+
+        if (isset($options['displayGroupDecorators'])) {
+            $displayGroupDecorators = $options['displayGroupDecorators'];
+            unset($options['displayGroupDecorators']);
+        }
+
+        if (isset($options['elementsBelongTo'])) {
+            $elementsBelongTo = $options['elementsBelongTo'];
+            unset($options['elementsBelongTo']);
+        }
+
+        if (isset($options['attribs'])) {
+            $this->addAttribs($options['attribs']);
+            unset($options['attribs']);
+        }
+
+        $forbidden = array(
+            'Options', 'Config', 'PluginLoader', 'SubForms', 'View', 'Translator',
+            'Attrib', 'Default',
+        );
+
+        foreach ($options as $key => $value) {
+            $normalized = ucfirst($key);
+            if (in_array($normalized, $forbidden)) {
+                continue;
+            }
+
+            $method = 'set' . $normalized;
+            if (method_exists($this, $method)) {
+                $this->$method($value);
+            } else {
+                $this->setAttrib($key, $value);
+            }
+        }
+
+        if (isset($displayGroupDecorators)) {
+            $this->setDisplayGroupDecorators($displayGroupDecorators);
+        }
+
+        if (isset($elementsBelongTo)) {
+            $this->setElementsBelongTo($elementsBelongTo);
+        }
+
+        return $this;
+    }
+
+    /**
+     * Set form state from config object
+     *
+     * @param  Zend_Config $config
+     * @return Zend_Form
+     */
+    public function setConfig(Zend_Config $config)
+    {
+        return $this->setOptions($config->toArray());
+    }
+
+
+    // Loaders
+
+    /**
+     * Set plugin loaders for use with decorators and elements
+     *
+     * @param  Zend_Loader_PluginLoader_Interface $loader
+     * @param  string $type 'decorator' or 'element'
+     * @return Zend_Form
+     * @throws Zend_Form_Exception on invalid type
+     */
+    public function setPluginLoader(Zend_Loader_PluginLoader_Interface $loader, $type = null)
+    {
+        $type = strtoupper($type);
+        switch ($type) {
+            case self::DECORATOR:
+            case self::ELEMENT:
+                $this->_loaders[$type] = $loader;
+                return $this;
+            default:
+                require_once 'Zend/Form/Exception.php';
+                throw new Zend_Form_Exception(sprintf('Invalid type "%s" provided to setPluginLoader()', $type));
+        }
+    }
+
+    /**
+     * Retrieve plugin loader for given type
+     *
+     * $type may be one of:
+     * - decorator
+     * - element
+     *
+     * If a plugin loader does not exist for the given type, defaults are
+     * created.
+     *
+     * @param  string $type
+     * @return Zend_Loader_PluginLoader_Interface
+     */
+    public function getPluginLoader($type = null)
+    {
+        $type = strtoupper($type);
+        if (!isset($this->_loaders[$type])) {
+            switch ($type) {
+                case self::DECORATOR:
+                    $prefixSegment = 'Form_Decorator';
+                    $pathSegment   = 'Form/Decorator';
+                    break;
+                case self::ELEMENT:
+                    $prefixSegment = 'Form_Element';
+                    $pathSegment   = 'Form/Element';
+                    break;
+                default:
+                    require_once 'Zend/Form/Exception.php';
+                    throw new Zend_Form_Exception(sprintf('Invalid type "%s" provided to getPluginLoader()', $type));
+            }
+
+            require_once 'Zend/Loader/PluginLoader.php';
+            $this->_loaders[$type] = new Zend_Loader_PluginLoader(
+                array('Zend_' . $prefixSegment . '_' => 'Zend/' . $pathSegment . '/')
+            );
+        }
+
+        return $this->_loaders[$type];
+    }
+
+    /**
+     * Add prefix path for plugin loader
+     *
+     * If no $type specified, assumes it is a base path for both filters and
+     * validators, and sets each according to the following rules:
+     * - decorators: $prefix = $prefix . '_Decorator'
+     * - elements: $prefix = $prefix . '_Element'
+     *
+     * Otherwise, the path prefix is set on the appropriate plugin loader.
+     *
+     * If $type is 'decorators', sets the path in the decorator plugin loader
+     * for all elements. Additionally, if no $type is provided,
+     * {@link Zend_Form_Element::addPrefixPath()} is called on each element.
+     *
+     * @param  string $prefix
+     * @param  string $path
+     * @param  string $type
+     * @return Zend_Form
+     * @throws Zend_Form_Exception for invalid type
+     */
+    public function addPrefixPath($prefix, $path, $type = null)
+    {
+        $type = strtoupper($type);
+        switch ($type) {
+            case self::DECORATOR:
+            case self::ELEMENT:
+                $loader = $this->getPluginLoader($type);
+                $loader->addPrefixPath($prefix, $path);
+                return $this;
+            case null:
+                $prefix = rtrim($prefix, '_');
+                $path   = rtrim($path, DIRECTORY_SEPARATOR);
+                foreach (array(self::DECORATOR, self::ELEMENT) as $type) {
+                    $cType        = ucfirst(strtolower($type));
+                    $pluginPath   = $path . DIRECTORY_SEPARATOR . $cType . DIRECTORY_SEPARATOR;
+                    $pluginPrefix = $prefix . '_' . $cType;
+                    $loader       = $this->getPluginLoader($type);
+                    $loader->addPrefixPath($pluginPrefix, $pluginPath);
+                }
+                return $this;
+            default:
+                require_once 'Zend/Form/Exception.php';
+                throw new Zend_Form_Exception(sprintf('Invalid type "%s" provided to getPluginLoader()', $type));
+        }
+    }
+
+    /**
+     * Add many prefix paths at once
+     *
+     * @param  array $spec
+     * @return Zend_Form
+     */
+    public function addPrefixPaths(array $spec)
+    {
+        if (isset($spec['prefix']) && isset($spec['path'])) {
+            return $this->addPrefixPath($spec['prefix'], $spec['path']);
+        }
+        foreach ($spec as $type => $paths) {
+            if (is_numeric($type) && is_array($paths)) {
+                $type = null;
+                if (isset($paths['prefix']) && isset($paths['path'])) {
+                    if (isset($paths['type'])) {
+                        $type = $paths['type'];
+                    }
+                    $this->addPrefixPath($paths['prefix'], $paths['path'], $type);
+                }
+            } elseif (!is_numeric($type)) {
+                if (!isset($paths['prefix']) || !isset($paths['path'])) {
+                    continue;
+                }
+                $this->addPrefixPath($paths['prefix'], $paths['path'], $type);
+            }
+        }
+        return $this;
+    }
+
+    /**
+     * Add prefix path for all elements
+     *
+     * @param  string $prefix
+     * @param  string $path
+     * @param  string $type
+     * @return Zend_Form
+     */
+    public function addElementPrefixPath($prefix, $path, $type = null)
+    {
+        $this->_elementPrefixPaths[] = array(
+            'prefix' => $prefix,
+            'path'   => $path,
+            'type'   => $type,
+        );
+
+        foreach ($this->getElements() as $element) {
+            $element->addPrefixPath($prefix, $path, $type);
+        }
+
+        foreach ($this->getSubForms() as $subForm) {
+            $subForm->addElementPrefixPath($prefix, $path, $type);
+        }
+
+        return $this;
+    }
+
+    /**
+     * Add prefix paths for all elements
+     *
+     * @param  array $spec
+     * @return Zend_Form
+     */
+    public function addElementPrefixPaths(array $spec)
+    {
+        $this->_elementPrefixPaths = $this->_elementPrefixPaths + $spec;
+
+        foreach ($this->getElements() as $element) {
+            $element->addPrefixPaths($spec);
+        }
+
+        return $this;
+    }
+
+    /**
+     * Add prefix path for all display groups
+     *
+     * @param  string $prefix
+     * @param  string $path
+     * @return Zend_Form
+     */
+    public function addDisplayGroupPrefixPath($prefix, $path)
+    {
+        $this->_displayGroupPrefixPaths[] = array(
+            'prefix' => $prefix,
+            'path'   => $path,
+        );
+
+        foreach ($this->getDisplayGroups() as $group) {
+            $group->addPrefixPath($prefix, $path);
+        }
+
+        return $this;
+    }
+
+    /**
+     * Add multiple display group prefix paths at once
+     *
+     * @param  array $spec
+     * @return Zend_Form
+     */
+    public function addDisplayGroupPrefixPaths(array $spec)
+    {
+        foreach ($spec as $key => $value) {
+            if (is_string($value) && !is_numeric($key)) {
+                $this->addDisplayGroupPrefixPath($key, $value);
+                continue;
+            }
+
+            if (is_string($value) && is_numeric($key)) {
+                continue;
+            }
+
+            if (is_array($value)) {
+                $count = count($value);
+                if (array_keys($value) === range(0, $count - 1)) {
+                    if ($count < 2) {
+                        continue;
+                    }
+                    $prefix = array_shift($value);
+                    $path   = array_shift($value);
+                    $this->addDisplayGroupPrefixPath($prefix, $path);
+                    continue;
+                }
+                if (array_key_exists('prefix', $value) && array_key_exists('path', $value)) {
+                    $this->addDisplayGroupPrefixPath($value['prefix'], $value['path']);
+                }
+            }
+        }
+        return $this;
+    }
+
+    // Form metadata:
+
+    /**
+     * Set form attribute
+     *
+     * @param  string $key
+     * @param  mixed $value
+     * @return Zend_Form
+     */
+    public function setAttrib($key, $value)
+    {
+        $key = (string) $key;
+        $this->_attribs[$key] = $value;
+        return $this;
+    }
+
+    /**
+     * Add multiple form attributes at once
+     *
+     * @param  array $attribs
+     * @return Zend_Form
+     */
+    public function addAttribs(array $attribs)
+    {
+        foreach ($attribs as $key => $value) {
+            $this->setAttrib($key, $value);
+        }
+        return $this;
+    }
+
+    /**
+     * Set multiple form attributes at once
+     *
+     * Overwrites any previously set attributes.
+     *
+     * @param  array $attribs
+     * @return Zend_Form
+     */
+    public function setAttribs(array $attribs)
+    {
+        $this->clearAttribs();
+        return $this->addAttribs($attribs);
+    }
+
+    /**
+     * Retrieve a single form attribute
+     *
+     * @param  string $key
+     * @return mixed
+     */
+    public function getAttrib($key)
+    {
+        $key = (string) $key;
+        if (!isset($this->_attribs[$key])) {
+            return null;
+        }
+
+        return $this->_attribs[$key];
+    }
+
+    /**
+     * Retrieve all form attributes/metadata
+     *
+     * @return array
+     */
+    public function getAttribs()
+    {
+        return $this->_attribs;
+    }
+
+    /**
+     * Remove attribute
+     *
+     * @param  string $key
+     * @return bool
+     */
+    public function removeAttrib($key)
+    {
+        if (isset($this->_attribs[$key])) {
+            unset($this->_attribs[$key]);
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Clear all form attributes
+     *
+     * @return Zend_Form
+     */
+    public function clearAttribs()
+    {
+        $this->_attribs = array();
+        return $this;
+    }
+
+    /**
+     * Set form action
+     *
+     * @param  string $action
+     * @return Zend_Form
+     */
+    public function setAction($action)
+    {
+        return $this->setAttrib('action', (string) $action);
+    }
+
+    /**
+     * Get form action
+     *
+     * Sets default to '' if not set.
+     *
+     * @return string
+     */
+    public function getAction()
+    {
+        $action = $this->getAttrib('action');
+        if (null === $action) {
+            $action = '';
+            $this->setAction($action);
+        }
+        return $action;
+    }
+
+    /**
+     * Set form method
+     *
+     * Only values in {@link $_methods()} allowed
+     *
+     * @param  string $method
+     * @return Zend_Form
+     * @throws Zend_Form_Exception
+     */
+    public function setMethod($method)
+    {
+        $method = strtolower($method);
+        if (!in_array($method, $this->_methods)) {
+            require_once 'Zend/Form/Exception.php';
+            throw new Zend_Form_Exception(sprintf('"%s" is an invalid form method', $method));
+        }
+        $this->setAttrib('method', $method);
+        return $this;
+    }
+
+    /**
+     * Retrieve form method
+     *
+     * @return string
+     */
+    public function getMethod()
+    {
+        if (null === ($method = $this->getAttrib('method'))) {
+            $method = self::METHOD_POST;
+            $this->setAttrib('method', $method);
+        }
+        return strtolower($method);
+    }
+
+    /**
+     * Set encoding type
+     *
+     * @param  string $value
+     * @return Zend_Form
+     */
+    public function setEnctype($value)
+    {
+        $this->setAttrib('enctype', $value);
+        return $this;
+    }
+
+    /**
+     * Get encoding type
+     *
+     * @return string
+     */
+    public function getEnctype()
+    {
+        if (null === ($enctype = $this->getAttrib('enctype'))) {
+            $enctype = self::ENCTYPE_URLENCODED;
+            $this->setAttrib('enctype', $enctype);
+        }
+        return $this->getAttrib('enctype');
+    }
+
+    /**
+     * Filter a name to only allow valid variable characters
+     *
+     * @param  string $value
+     * @param  bool $allowBrackets
+     * @return string
+     */
+    public function filterName($value, $allowBrackets = false)
+    {
+        $charset = '^a-zA-Z0-9_\x7f-\xff';
+        if ($allowBrackets) {
+            $charset .= '\[\]';
+        }
+        return preg_replace('/[' . $charset . ']/', '', (string) $value);
+    }
+
+    /**
+     * Set form name
+     *
+     * @param  string $name
+     * @return Zend_Form
+     */
+    public function setName($name)
+    {
+        $name = $this->filterName($name);
+        if (('0' !== $name) && empty($name)) {
+            require_once 'Zend/Form/Exception.php';
+            throw new Zend_Form_Exception('Invalid name provided; must contain only valid variable characters and be non-empty');
+        }
+
+        return $this->setAttrib('name', $name);
+    }
+
+    /**
+     * Get name attribute
+     *
+     * @return null|string
+     */
+    public function getName()
+    {
+        return $this->getAttrib('name');
+    }
+
+    /**
+     * Get fully qualified name
+     *
+     * Places name as subitem of array and/or appends brackets.
+     *
+     * @return string
+     */
+    public function getFullyQualifiedName()
+    {
+        return $this->getName();
+    }
+
+    /**
+     * Get element id
+     *
+     * @return string
+     */
+    public function getId()
+    {
+        if (null !== ($id = $this->getAttrib('id'))) {
+            return $id;
+        }
+
+        $id = $this->getFullyQualifiedName();
+
+        // Bail early if no array notation detected
+        if (!strstr($id, '[')) {
+            return $id;
+        }
+
+        // Strip array notation
+        if ('[]' == substr($id, -2)) {
+            $id = substr($id, 0, strlen($id) - 2);
+        }
+        $id = str_replace('][', '-', $id);
+        $id = str_replace(array(']', '['), '-', $id);
+        $id = trim($id, '-');
+
+        return $id;
+    }
+
+    /**
+     * Set form legend
+     *
+     * @param  string $value
+     * @return Zend_Form
+     */
+    public function setLegend($value)
+    {
+        $this->_legend = (string) $value;
+        return $this;
+    }
+
+    /**
+     * Get form legend
+     *
+     * @return string
+     */
+    public function getLegend()
+    {
+        return $this->_legend;
+    }
+
+    /**
+     * Set form description
+     *
+     * @param  string $value
+     * @return Zend_Form
+     */
+    public function setDescription($value)
+    {
+        $this->_description = (string) $value;
+        return $this;
+    }
+
+    /**
+     * Retrieve form description
+     *
+     * @return string
+     */
+    public function getDescription()
+    {
+        return $this->_description;
+    }
+
+    /**
+     * Set form order
+     *
+     * @param  int $index
+     * @return Zend_Form
+     */
+    public function setOrder($index)
+    {
+        $this->_formOrder = (int) $index;
+        return $this;
+    }
+
+    /**
+     * Get form order
+     *
+     * @return int|null
+     */
+    public function getOrder()
+    {
+        return $this->_formOrder;
+    }
+
+    // Element interaction:
+
+    /**
+     * Add a new element
+     *
+     * $element may be either a string element type, or an object of type
+     * Zend_Form_Element. If a string element type is provided, $name must be
+     * provided, and $options may be optionally provided for configuring the
+     * element.
+     *
+     * If a Zend_Form_Element is provided, $name may be optionally provided,
+     * and any provided $options will be ignored.
+     *
+     * @param  string|Zend_Form_Element $element
+     * @param  string $name
+     * @param  array|Zend_Config $options
+     * @return Zend_Form
+     */
+    public function addElement($element, $name = null, $options = null)
+    {
+        if (is_string($element)) {
+            if (null === $name) {
+                require_once 'Zend/Form/Exception.php';
+                throw new Zend_Form_Exception('Elements specified by string must have an accompanying name');
+            }
+
+            if (is_array($this->_elementDecorators)) {
+                if (null === $options) {
+                    $options = array('decorators' => $this->_elementDecorators);
+                } elseif ($options instanceof Zend_Config) {
+                    $options = $options->toArray();
+                }
+                if (is_array($options)
+                    && !array_key_exists('decorators', $options)
+                ) {
+                    $options['decorators'] = $this->_elementDecorators;
+                }
+            }
+
+            $this->_elements[$name] = $this->createElement($element, $name, $options);
+        } elseif ($element instanceof Zend_Form_Element) {
+            $prefixPaths              = array();
+            $prefixPaths['decorator'] = $this->getPluginLoader('decorator')->getPaths();
+            if (!empty($this->_elementPrefixPaths)) {
+                $prefixPaths = array_merge($prefixPaths, $this->_elementPrefixPaths);
+            }
+
+            if (null === $name) {
+                $name = $element->getName();
+            }
+
+            $this->_elements[$name] = $element;
+            $this->_elements[$name]->addPrefixPaths($prefixPaths);
+        }
+
+        $this->_order[$name] = $this->_elements[$name]->getOrder();
+        $this->_orderUpdated = true;
+        $this->_setElementsBelongTo($name);
+
+        return $this;
+    }
+
+    /**
+     * Create an element
+     *
+     * Acts as a factory for creating elements. Elements created with this
+     * method will not be attached to the form, but will contain element
+     * settings as specified in the form object (including plugin loader
+     * prefix paths, default decorators, etc.).
+     *
+     * @param  string $type
+     * @param  string $name
+     * @param  array|Zend_Config $options
+     * @return Zend_Form_Element
+     */
+    public function createElement($type, $name, $options = null)
+    {
+        if (!is_string($type)) {
+            require_once 'Zend/Form/Exception.php';
+            throw new Zend_Form_Exception('Element type must be a string indicating type');
+        }
+
+        if (!is_string($name)) {
+            require_once 'Zend/Form/Exception.php';
+            throw new Zend_Form_Exception('Element name must be a string');
+        }
+
+        $prefixPaths              = array();
+        $prefixPaths['decorator'] = $this->getPluginLoader('decorator')->getPaths();
+        if (!empty($this->_elementPrefixPaths)) {
+            $prefixPaths = array_merge($prefixPaths, $this->_elementPrefixPaths);
+        }
+
+        if ($options instanceof Zend_Config) {
+            $options = $options->toArray();
+        }
+
+        if ((null === $options) || !is_array($options)) {
+            $options = array('prefixPath' => $prefixPaths);
+        } elseif (is_array($options)) {
+            if (array_key_exists('prefixPath', $options)) {
+                $options['prefixPath'] = array_merge($prefixPaths, $options['prefixPath']);
+            } else {
+                $options['prefixPath'] = $prefixPaths;
+            }
+        }
+
+        $class = $this->getPluginLoader(self::ELEMENT)->load($type);
+        $element = new $class($name, $options);
+
+        return $element;
+    }
+
+    /**
+     * Add multiple elements at once
+     *
+     * @param  array $elements
+     * @return Zend_Form
+     */
+    public function addElements(array $elements)
+    {
+        foreach ($elements as $key => $spec) {
+            $name = null;
+            if (!is_numeric($key)) {
+                $name = $key;
+            }
+
+            if (is_string($spec) || ($spec instanceof Zend_Form_Element)) {
+                $this->addElement($spec, $name);
+                continue;
+            }
+
+            if (is_array($spec)) {
+                $argc = count($spec);
+                $options = array();
+                if (isset($spec['type'])) {
+                    $type = $spec['type'];
+                    if (isset($spec['name'])) {
+                        $name = $spec['name'];
+                    }
+                    if (isset($spec['options'])) {
+                        $options = $spec['options'];
+                    }
+                    $this->addElement($type, $name, $options);
+                } else {
+                    switch ($argc) {
+                        case 0:
+                            continue;
+                        case (1 <= $argc):
+                            $type = array_shift($spec);
+                        case (2 <= $argc):
+                            if (null === $name) {
+                                $name = array_shift($spec);
+                            } else {
+                                $options = array_shift($spec);
+                            }
+                        case (3 <= $argc):
+                            if (empty($options)) {
+                                $options = array_shift($spec);
+                            }
+                        default:
+                            $this->addElement($type, $name, $options);
+                    }
+                }
+            }
+        }
+        return $this;
+    }
+
+    /**
+     * Set form elements (overwrites existing elements)
+     *
+     * @param  array $elements
+     * @return Zend_Form
+     */
+    public function setElements(array $elements)
+    {
+        $this->clearElements();
+        return $this->addElements($elements);
+    }
+
+    /**
+     * Retrieve a single element
+     *
+     * @param  string $name
+     * @return Zend_Form_Element|null
+     */
+    public function getElement($name)
+    {
+        if (array_key_exists($name, $this->_elements)) {
+            return $this->_elements[$name];
+        }
+        return null;
+    }
+
+    /**
+     * Retrieve all elements
+     *
+     * @return array
+     */
+    public function getElements()
+    {
+        return $this->_elements;
+    }
+
+    /**
+     * Remove element
+     *
+     * @param  string $name
+     * @return boolean
+     */
+    public function removeElement($name)
+    {
+        $name = (string) $name;
+        if (isset($this->_elements[$name])) {
+            unset($this->_elements[$name]);
+            if (array_key_exists($name, $this->_order)) {
+                unset($this->_order[$name]);
+                $this->_orderUpdated = true;
+            } else {
+                foreach ($this->_displayGroups as $group) {
+                    if (null !== $group->getElement($name)) {
+                        $group->removeElement($name);
+                    }
+                }
+            }
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Remove all form elements
+     *
+     * @return Zend_Form
+     */
+    public function clearElements()
+    {
+        foreach (array_keys($this->_elements) as $key) {
+            if (array_key_exists($key, $this->_order)) {
+                unset($this->_order[$key]);
+            }
+        }
+        $this->_elements     = array();
+        $this->_orderUpdated = true;
+        return $this;
+    }
+
+    /**
+     * Set default values for elements
+     *
+     * Sets values for all elements specified in the array of $defaults.
+     * 
+     * @param  array $defaults
+     * @return Zend_Form
+     */
+    public function setDefaults(array $defaults)
+    {
+        foreach ($this->getElements() as $name => $element) {
+            if (array_key_exists($name, $defaults)) {
+                $this->setDefault($name, $defaults[$name]);
+            }
+        }
+        foreach ($this->getSubForms() as $name => $form) {
+            if (array_key_exists($name, $defaults)) {
+                $form->setDefaults($defaults[$name]);
+            } else {
+                $form->setDefaults($defaults);
+            }
+        }
+        return $this;
+    }
+
+    /**
+     * Set default value for an element
+     *
+     * @param  string $name
+     * @param  mixed $value
+     * @return Zend_Form
+     */
+    public function setDefault($name, $value)
+    {
+        $name = (string) $name;
+        if ($element = $this->getElement($name)) {
+            $element->setValue($value);
+        } else {
+            if (is_scalar($value)) {
+                foreach ($this->getSubForms() as $subForm) {
+                    $subForm->setDefault($name, $value);
+                }
+            } elseif (is_array($value) && ($subForm = $this->getSubForm($name))) {
+                $subForm->setDefaults($value);
+            }
+        }
+        return $this;
+    }
+
+    /**
+     * Retrieve value for single element
+     *
+     * @param  string $name
+     * @return mixed
+     */
+    public function getValue($name)
+    {
+        if ($element = $this->getElement($name)) {
+            return $element->getValue();
+        }
+
+        if ($subForm = $this->getSubForm($name)) {
+            return $subForm->getValues(true);
+        }
+
+        foreach ($this->getSubForms() as $subForm) {
+            if ($name == $subForm->getElementsBelongTo()) {
+                return $subForm->getValues(true);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Retrieve all form element values
+     *
+     * @param  bool $suppressArrayNotation
+     * @return array
+     */
+    public function getValues($suppressArrayNotation = false)
+    {
+        $values = array();
+        foreach ($this->getElements() as $key => $element) {
+            if (!$element->getIgnore()) {
+                $values[$key] = $element->getValue();
+            }
+        }
+        foreach ($this->getSubForms() as $key => $subForm) {
+            $fValues = $this->_attachToArray($subForm->getValues(true), $subForm->getElementsBelongTo());
+            $values = array_merge($values, $fValues);
+        }
+
+        if (!$suppressArrayNotation && $this->isArray()) {
+            $values = $this->_attachToArray($values, $this->getElementsBelongTo());
+        }
+
+        return $values;
+    }
+
+    /**
+     * Get unfiltered element value
+     *
+     * @param  string $name
+     * @return mixed
+     */
+    public function getUnfilteredValue($name)
+    {
+        if ($element = $this->getElement($name)) {
+            return $element->getUnfilteredValue();
+        }
+        return null;
+    }
+
+    /**
+     * Retrieve all unfiltered element values
+     *
+     * @return array
+     */
+    public function getUnfilteredValues()
+    {
+        $values = array();
+        foreach ($this->getElements() as $key => $element) {
+            $values[$key] = $element->getUnfilteredValue();
+        }
+
+        return $values;
+    }
+
+    /**
+     * Set all elements' filters
+     *
+     * @param  array $filters
+     * @return Zend_Form
+     */
+    public function setElementFilters(array $filters)
+    {
+        foreach ($this->getElements() as $element) {
+            $element->setFilters($filters);
+        }
+        return $this;
+    }
+
+    /**
+     * Set name of array elements belong to
+     *
+     * @param  string $array
+     * @return Zend_Form
+     */
+    public function setElementsBelongTo($array)
+    {
+        $origName = $this->getElementsBelongTo();
+        $name = $this->filterName($array, true);
+        if (empty($name)) {
+            $name = null;
+        }
+        $this->_elementsBelongTo = $name;
+
+        if (null === $name) {
+            $this->setIsArray(false);
+            if (null !== $origName) {
+                $this->_setElementsBelongTo();
+            }
+        } else {
+            $this->setIsArray(true);
+            $this->_setElementsBelongTo();
+        }
+
+        return $this;
+    }
+
+    /**
+     * Set array to which elements belong
+     *
+     * @param  string $name Element name
+     * @return void
+     */
+    protected function _setElementsBelongTo($name = null)
+    {
+        $array = $this->getElementsBelongTo();
+
+        if (null === $array) {
+            return;
+        }
+
+        if (null === $name) {
+            foreach ($this->getElements() as $element) {
+                $element->setBelongsTo($array);
+            }
+        } else {
+            if (null !== ($element = $this->getElement($name))) {
+                $element->setBelongsTo($array);
+            }
+        }
+    }
+
+    /**
+     * Get name of array elements belong to
+     *
+     * @return string|null
+     */
+    public function getElementsBelongTo()
+    {
+        if ((null === $this->_elementsBelongTo) && $this->isArray()) {
+            $name = $this->getName();
+            if (!empty($name)) {
+                return $name;
+            }
+        }
+        return $this->_elementsBelongTo;
+    }
+
+    /**
+     * Set flag indicating elements belong to array
+     *
+     * @param  bool $flag Value of flag
+     * @return Zend_Form
+     */
+    public function setIsArray($flag)
+    {
+        $this->_isArray = (bool) $flag;
+        return $this;
+    }
+
+    /**
+     * Get flag indicating if elements belong to an array
+     *
+     * @return bool
+     */
+    public function isArray()
+    {
+        return $this->_isArray;
+    }
+
+    // Element groups:
+
+    /**
+     * Add a form group/subform
+     *
+     * @param  Zend_Form $form
+     * @param  string $name
+     * @param  int $order
+     * @return Zend_Form
+     */
+    public function addSubForm(Zend_Form $form, $name, $order = null)
+    {
+        $name = (string) $name;
+        foreach ($this->_loaders as $type => $loader) {
+            $loaderPaths = $loader->getPaths();
+            foreach ($loaderPaths as $prefix => $paths) {
+                foreach ($paths as $path) {
+                    $form->addPrefixPath($prefix, $path, $type);
+                }
+            }
+        }
+
+        if (!empty($this->_elementPrefixPaths)) {
+            foreach ($this->_elementPrefixPaths as $spec) {
+                list($prefix, $path, $type) = array_values($spec);
+                $form->addElementPrefixPath($prefix, $path, $type);
+            }
+        }
+
+        if (!empty($this->_displayGroupPrefixPaths)) {
+            foreach ($this->_displayGroupPrefixPaths as $spec) {
+                list($prefix, $path) = array_values($spec);
+                $form->addDisplayGroupPrefixPath($prefix, $path);
+            }
+        }
+
+        if (null !== $order) {
+            $form->setOrder($order);
+        }
+
+        $form->setName($name);
+        $this->_subForms[$name] = $form;
+        $this->_order[$name]    = $order;
+        $this->_orderUpdated    = true;
+        return $this;
+    }
+
+    /**
+     * Add multiple form subForms/subforms at once
+     *
+     * @param  array $subForms
+     * @return Zend_Form
+     */
+    public function addSubForms(array $subForms)
+    {
+        foreach ($subForms as $key => $spec) {
+            $name = null;
+            if (!is_numeric($key)) {
+                $name = $key;
+            }
+
+            if ($spec instanceof Zend_Form) {
+                $this->addSubForm($spec, $name);
+                continue;
+            }
+
+            if (is_array($spec)) {
+                $argc  = count($spec);
+                $order = null;
+                switch ($argc) {
+                    case 0:
+                        continue;
+                    case (1 <= $argc):
+                        $subForm = array_shift($spec);
+                    case (2 <= $argc):
+                        $name  = array_shift($spec);
+                    case (3 <= $argc):
+                        $order = array_shift($spec);
+                    default:
+                        $this->addSubForm($subForm, $name, $order);
+                }
+            }
+        }
+        return $this;
+    }
+
+    /**
+     * Set multiple form subForms/subforms (overwrites)
+     *
+     * @param  array $subForms
+     * @return Zend_Form
+     */
+    public function setSubForms(array $subForms)
+    {
+        $this->clearSubForms();
+        return $this->addSubForms($subForms);
+    }
+
+    /**
+     * Retrieve a form subForm/subform
+     *
+     * @param  string $name
+     * @return Zend_Form|null
+     */
+    public function getSubForm($name)
+    {
+        $name = (string) $name;
+        if (isset($this->_subForms[$name])) {
+            return $this->_subForms[$name];
+        }
+        return null;
+    }
+
+    /**
+     * Retrieve all form subForms/subforms
+     *
+     * @return array
+     */
+    public function getSubForms()
+    {
+        return $this->_subForms;
+    }
+
+    /**
+     * Remove form subForm/subform
+     *
+     * @param  string $name
+     * @return boolean
+     */
+    public function removeSubForm($name)
+    {
+        $name = (string) $name;
+        if (array_key_exists($name, $this->_subForms)) {
+            unset($this->_subForms[$name]);
+            if (array_key_exists($name, $this->_order)) {
+                unset($this->_order[$name]);
+                $this->_orderUpdated = true;
+            }
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Remove all form subForms/subforms
+     *
+     * @return Zend_Form
+     */
+    public function clearSubForms()
+    {
+        foreach (array_keys($this->_subForms) as $key) {
+            if (array_key_exists($key, $this->_order)) {
+                unset($this->_order[$key]);
+            }
+        }
+        $this->_subForms     = array();
+        $this->_orderUpdated = true;
+        return $this;
+    }
+
+
+    // Display groups:
+
+    /**
+     * Set default display group class
+     *
+     * @param  string $class
+     * @return Zend_Form
+     */
+    public function setDefaultDisplayGroupClass($class)
+    {
+        $this->_defaultDisplayGroupClass = (string) $class;
+        return $this;
+    }
+
+    /**
+     * Retrieve default display group class
+     *
+     * @return string
+     */
+    public function getDefaultDisplayGroupClass()
+    {
+        return $this->_defaultDisplayGroupClass;
+    }
+
+    /**
+     * Add a display group
+     *
+     * Groups named elements for display purposes.
+     *
+     * If a referenced element does not yet exist in the form, it is omitted.
+     *
+     * @param  array $elements
+     * @param  string $name
+     * @param  array|Zend_Config $options
+     * @return Zend_Form
+     * @throws Zend_Form_Exception if no valid elements provided
+     */
+    public function addDisplayGroup(array $elements, $name, $options = null)
+    {
+        $group = array();
+        foreach ($elements as $element) {
+            if (isset($this->_elements[$element])) {
+                $add = $this->getElement($element);
+                if (null !== $add) {
+                    unset($this->_order[$element]);
+                    $group[] = $add;
+                }
+            }
+        }
+        if (empty($group)) {
+            require_once 'Zend/Form/Exception.php';
+            throw new Zend_Form_Exception('No valid elements specified for display group');
+        }
+
+        $name = (string) $name;
+
+        if (is_array($options)) {
+            $options['elements'] = $group;
+        } elseif ($options instanceof Zend_Config) {
+            $options = $options->toArray();
+            $options['elements'] = $group;
+        } else {
+            $options = array('elements' => $group);
+        }
+
+        if (isset($options['displayGroupClass'])) {
+            $class = $options['displayGroupClass'];
+            unset($options['displayGroupClass']);
+        } else {
+            $class = $this->getDefaultDisplayGroupClass();
+        }
+
+        if (!class_exists($class)) {
+            require_once 'Zend/Loader.php';
+            Zend_Loader::loadClass($class);
+        }
+        $this->_displayGroups[$name] = new $class(
+            $name,
+            $this->getPluginLoader(self::DECORATOR),
+            $options
+        );
+
+        if (!empty($this->_displayGroupPrefixPaths)) {
+            $this->_displayGroups[$name]->addPrefixPaths($this->_displayGroupPrefixPaths);
+        }
+
+        $this->_order[$name] = $this->_displayGroups[$name]->getOrder();
+        $this->_orderUpdated = true;
+        return $this;
+    }
+
+    /**
+     * Add a display group object (used with cloning)
+     *
+     * @param  Zend_Form_DisplayGroup $group
+     * @param  string|null $name
+     * @return Zend_Form
+     */
+    protected function _addDisplayGroupObject(Zend_Form_DisplayGroup $group, $name = null)
+    {
+        if (null === $name) {
+            $name = $group->getName();
+            if (empty($name)) {
+                require_once 'Zend/Form/Exception.php';
+                throw new Zend_Form_Exception('Invalid display group added; requires name');
+            }
+        }
+
+        $this->_displayGroups[$name] = $group;
+
+        if (!empty($this->_displayGroupPrefixPaths)) {
+            $this->_displayGroups[$name]->addPrefixPaths($this->_displayGroupPrefixPaths);
+        }
+
+        $this->_order[$name] = $this->_displayGroups[$name]->getOrder();
+        $this->_orderUpdated = true;
+        return $this;
+    }
+
+    /**
+     * Add multiple display groups at once
+     *
+     * @param  array $groups
+     * @return Zend_Form
+     */
+    public function addDisplayGroups(array $groups)
+    {
+        foreach ($groups as $key => $spec) {
+            $name = null;
+            if (!is_numeric($key)) {
+                $name = $key;
+            }
+
+            if ($spec instanceof Zend_Form_DisplayGroup) {
+                $this->_addDisplayGroupObject($spec);
+            }
+
+            if (!is_array($spec) || empty($spec)) {
+                continue;
+            }
+
+            $argc    = count($spec);
+            $options = array();
+
+            if (isset($spec['elements'])) {
+                $elements = $spec['elements'];
+                if (isset($spec['name'])) {
+                    $name = $spec['name'];
+                }
+                if (isset($spec['options'])) {
+                    $options = $spec['options'];
+                }
+                $this->addDisplayGroup($elements, $name, $options);
+            } else {
+                switch ($argc) {
+                    case (1 <= $argc):
+                        $elements = array_shift($spec);
+                        if (!is_array($elements) && (null !== $name)) {
+                            $elements = array_merge((array) $elements, $spec);
+                            $this->addDisplayGroup($elements, $name);
+                            break;
+                        }
+                    case (2 <= $argc):
+                        if (null !== $name) {
+                            $options = array_shift($spec);
+                            $this->addDisplayGroup($elements, $name, $options);
+                            break;
+                        }
+                        $name = array_shift($spec);
+                    case (3 <= $argc):
+                        $options = array_shift($spec);
+                    default:
+                        $this->addDisplayGroup($elements, $name, $options);
+                }
+            }
+        }
+        return $this;
+    }
+
+    /**
+     * Add multiple display groups (overwrites)
+     *
+     * @param  array $groups
+     * @return Zend_Form
+     */
+    public function setDisplayGroups(array $groups)
+    {
+        return $this->clearDisplayGroups()
+                    ->addDisplayGroups($groups);
+    }
+
+    /**
+     * Return a display group
+     *
+     * @param  string $name
+     * @return Zend_Form_DisplayGroup|null
+     */
+    public function getDisplayGroup($name)
+    {
+        $name = (string) $name;
+        if (isset($this->_displayGroups[$name])) {
+            return $this->_displayGroups[$name];
+        }
+
+        return null;
+    }
+
+    /**
+     * Return all display groups
+     *
+     * @return array
+     */
+    public function getDisplayGroups()
+    {
+        return $this->_displayGroups;
+    }
+
+    /**
+     * Remove a display group by name
+     *
+     * @param  string $name
+     * @return boolean
+     */
+    public function removeDisplayGroup($name)
+    {
+        $name = (string) $name;
+        if (array_key_exists($name, $this->_displayGroups)) {
+            foreach ($this->_displayGroups[$name] as $key => $element) {
+                if (array_key_exists($key, $this->_elements)) {
+                    $this->_order[$key]  = $element->getOrder();
+                    $this->_orderUpdated = true;
+                }
+            }
+            unset($this->_displayGroups[$name]);
+
+            if (array_key_exists($name, $this->_order)) {
+                unset($this->_order[$name]);
+                $this->_orderUpdated = true;
+            }
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Remove all display groups
+     *
+     * @return Zend_Form
+     */
+    public function clearDisplayGroups()
+    {
+        foreach ($this->_displayGroups as $key => $group) {
+            if (array_key_exists($key, $this->_order)) {
+                unset($this->_order[$key]);
+            }
+            foreach ($group as $name => $element) {
+                if (isset($this->_elements[$name])) {
+                    $this->_order[$name] = $element->getOrder();
+                }
+                $this->_order[$name] = $element->getOrder();
+            }
+        }
+        $this->_displayGroups = array();
+        $this->_orderUpdated  = true;
+        return $this;
+    }
+
+
+    // Processing
+
+    /**
+     * Populate form
+     *
+     * Proxies to {@link setDefaults()}
+     *
+     * @param  array $values
+     * @return Zend_Form
+     */
+    public function populate(array $values)
+    {
+        return $this->setDefaults($values);
+    }
+
+    /**
+     * Determine array key name from given value
+     *
+     * Given a value such as foo[bar][baz], returns the last element (in this case, 'baz').
+     *
+     * @param  string $value
+     * @return string
+     */
+    protected function _getArrayName($value)
+    {
+        if (empty($value) || !is_string($value)) {
+            return $value;
+        }
+
+        if (!strstr($value, '[')) {
+            return $value;
+        }
+
+        $endPos = strlen($value) - 1;
+        if (']' != $value[$endPos]) {
+            return $value;
+        }
+
+        $start = strrpos($value, '[') + 1;
+        $name = substr($value, $start, $endPos - $start);
+        return $name;
+    }
+
+    /**
+     * Extract the value by walking the array using given array path.
+     *
+     * Given an array path such as foo[bar][baz], returns the value of the last
+     * element (in this case, 'baz').
+     *
+     * @param  array $value Array to walk
+     * @param  string $arrayPath Array notation path of the part to extract
+     * @return string
+     */
+    protected function _dissolveArrayValue($value, $arrayPath)
+    {
+        // As long as we have more levels
+        while ($arrayPos = strpos($arrayPath, '[')) {
+            // Get the next key in the path
+            $arrayKey = trim(substr($arrayPath, 0, $arrayPos), ']');
+
+            // Set the potentially final value or the next search point in the array
+            if (isset($value[$arrayKey])) {
+                $value = $value[$arrayKey];
+            }
+
+            // Set the next search point in the path
+            $arrayPath = trim(substr($arrayPath, $arrayPos + 1), ']');
+        }
+
+        if (isset($value[$arrayPath])) {
+            $value = $value[$arrayPath];
+        }
+
+        return $value;
+    }
+
+    /**
+     * Converts given arrayPath to an array and attaches given value at the end of it.
+     *
+     * @param  mixed $value The value to attach
+     * @param  string $arrayPath Given array path to convert and attach to.
+     * @return array
+     */
+    protected function _attachToArray($value, $arrayPath)
+    {
+        // As long as we have more levels
+        while ($arrayPos = strrpos($arrayPath, '[')) {
+            // Get the next key in the path
+            $arrayKey = trim(substr($arrayPath, $arrayPos + 1), ']');
+
+            // Attach
+            $value = array($arrayKey => $value);
+
+            // Set the next search point in the path
+            $arrayPath = trim(substr($arrayPath, 0, $arrayPos), ']');
+        }
+
+        $value = array($arrayPath => $value);
+
+        return $value;
+    }
+
+    /**
+     * Validate the form
+     *
+     * @param  array $data
+     * @return boolean
+     */
+    public function isValid($data)
+    {
+        if (!is_array($data)) {
+            require_once 'Zend/Form/Exception.php';
+            throw new Zend_Form_Exception(__CLASS__ . '::' . __METHOD__ . ' expects an array');
+        }
+        $translator = $this->getTranslator();
+        $valid      = true;
+
+        if ($this->isArray()) {
+            $data = $this->_dissolveArrayValue($data, $this->getElementsBelongTo());
+        }
+
+        foreach ($this->getElements() as $key => $element) {
+            $element->setTranslator($translator);
+            if (!isset($data[$key])) {
+                $valid = $element->isValid(null, $data) && $valid;
+            } else {
+                $valid = $element->isValid($data[$key], $data) && $valid;
+            }
+        }
+        foreach ($this->getSubForms() as $key => $form) {
+            $form->setTranslator($translator);
+            if (isset($data[$key])) {
+                $valid = $form->isValid($data[$key]) && $valid;
+            } else {
+                $valid = $form->isValid($data) && $valid;
+            }
+        }
+
+        $this->_errorsExist = !$valid;
+
+        // If manually flagged as an error, return invalid status
+        if ($this->_errorsForced) {
+            return false;
+        }
+
+        return $valid;
+    }
+
+    /**
+     * Validate a partial form
+     *
+     * Does not check for required flags.
+     *
+     * @param  array $data
+     * @return boolean
+     */
+    public function isValidPartial(array $data)
+    {
+        if ($this->isArray()) {
+            $data = $this->_dissolveArrayValue($data, $this->getElementsBelongTo());
+        }
+
+        $translator        = $this->getTranslator();
+        $valid             = true;
+        $validatedSubForms = array();
+
+        foreach ($data as $key => $value) {
+            if (null !== ($element = $this->getElement($key))) {
+                if (null !== $translator) {
+                    $element->setTranslator($translator);
+                }
+                $valid = $element->isValid($value, $data) && $valid;
+            } elseif (null !== ($subForm = $this->getSubForm($key))) {
+                if (null !== $translator) {
+                    $subForm->setTranslator($translator);
+                }
+                $valid = $subForm->isValidPartial($data[$key]) && $valid;
+                $validatedSubForms[] = $key;
+            }
+        }
+        foreach ($this->getSubForms() as $key => $subForm) {
+            if (!in_array($key, $validatedSubForms)) {
+                if (null !== $translator) {
+                    $subForm->setTranslator($translator);
+                }
+
+                $valid = $subForm->isValidPartial($data) && $valid;
+            }
+        }
+
+        $this->_errorsExist = !$valid;
+        return $valid;
+    }
+
+    /**
+     * Process submitted AJAX data
+     *
+     * Checks if provided $data is valid, via {@link isValidPartial()}. If so,
+     * it returns JSON-encoded boolean true. If not, it returns JSON-encoded
+     * error messages (as returned by {@link getMessages()}).
+     *
+     * @param  array $data
+     * @return string JSON-encoded boolean true or error messages
+     */
+    public function processAjax(array $data)
+    {
+        require_once 'Zend/Json.php';
+        if ($this->isValidPartial($data)) {
+            return Zend_Json::encode(true);
+        }
+        $messages = $this->getMessages();
+        return Zend_Json::encode($messages);
+    }
+
+    /**
+     * Add a custom error message to return in the event of failed validation
+     *
+     * @param  string $message
+     * @return Zend_Form
+     */
+    public function addErrorMessage($message)
+    {
+        $this->_errorMessages[] = (string) $message;
+        return $this;
+    }
+
+    /**
+     * Add multiple custom error messages to return in the event of failed validation
+     *
+     * @param  array $messages
+     * @return Zend_Form
+     */
+    public function addErrorMessages(array $messages)
+    {
+        foreach ($messages as $message) {
+            $this->addErrorMessage($message);
+        }
+        return $this;
+    }
+
+    /**
+     * Same as addErrorMessages(), but clears custom error message stack first
+     *
+     * @param  array $messages
+     * @return Zend_Form
+     */
+    public function setErrorMessages(array $messages)
+    {
+        $this->clearErrorMessages();
+        return $this->addErrorMessages($messages);
+    }
+
+    /**
+     * Retrieve custom error messages
+     *
+     * @return array
+     */
+    public function getErrorMessages()
+    {
+        return $this->_errorMessages;
+    }
+
+    /**
+     * Clear custom error messages stack
+     *
+     * @return Zend_Form
+     */
+    public function clearErrorMessages()
+    {
+        $this->_errorMessages = array();
+        return $this;
+    }
+
+    /**
+     * Mark the element as being in a failed validation state
+     *
+     * @return Zend_Form
+     */
+    public function markAsError()
+    {
+        $this->_errorsExist  = true;
+        $this->_errorsForced = true;
+        return $this;
+    }
+
+    /**
+     * Add an error message and mark element as failed validation
+     *
+     * @param  string $message
+     * @return Zend_Form
+     */
+    public function addError($message)
+    {
+        $this->addErrorMessage($message);
+        $this->markAsError();
+        return $this;
+    }
+
+    /**
+     * Add multiple error messages and flag element as failed validation
+     *
+     * @param  array $messages
+     * @return Zend_Form
+     */
+    public function addErrors(array $messages)
+    {
+        foreach ($messages as $message) {
+            $this->addError($message);
+        }
+        return $this;
+    }
+
+    /**
+     * Overwrite any previously set error messages and flag as failed validation
+     *
+     * @param  array $messages
+     * @return Zend_Form
+     */
+    public function setErrors(array $messages)
+    {
+        $this->clearErrorMessages();
+        return $this->addErrors($messages);
+    }
+
+
+    public function persistData()
+    {
+    }
+
+    /**
+     * Are there errors in the form?
+     *
+     * @return bool
+     */
+    public function isErrors()
+    {
+        return $this->_errorsExist;
+    }
+
+    /**
+     * Get error codes for all elements failing validation
+     *
+     * @param  string $name
+     * @return array
+     */
+    public function getErrors($name = null)
+    {
+        $errors = array();
+        if ((null !== $name) && isset($this->_elements[$name])) {
+            $errors = $this->getElement($name)->getErrors();
+        } elseif ((null !== $name) && isset($this->_subForms[$name])) {
+            $errors = $this->getSubForm($name)->getErrors();
+        } else {
+            foreach ($this->_elements as $key => $element) {
+                $errors[$key] = $element->getErrors();
+            }
+            foreach ($this->getSubForms() as $key => $subForm) {
+                $fErrors = $this->_attachToArray($subForm->getErrors(), $subForm->getElementsBelongTo());
+                $errors = array_merge($errors, $fErrors);
+            }
+        }
+        return $errors;
+    }
+
+    /**
+     * Retrieve error messages from elements failing validations
+     *
+     * @param  string $name
+     * @param  bool $suppressArrayNotation
+     * @return array
+     */
+    public function getMessages($name = null, $suppressArrayNotation = false)
+    {
+        if ((null !== $name) && isset($this->_elements[$name])) {
+            return $this->getElement($name)->getMessages();
+        }
+
+        if ((null !== $name) && isset($this->_subForms[$name])) {
+            return $this->getSubForm($name)->getMessages(null, true);
+        }
+
+        $arrayKeys = array();
+        foreach ($this->getSubForms() as $key => $subForm) {
+            $array = $this->_getArrayName($subForm->getElementsBelongTo());
+            if (!empty($array)) {
+                if ($name == $array) {
+                    return $subForm->getMessages(null, true);
+                }
+                $arrayKeys[$key] = $subForm->getElementsBelongTo();
+            }
+        }
+
+        $customMessages = $this->_getErrorMessages();
+        if ($this->isErrors() && !empty($customMessages)) {
+            return $customMessages;
+        }
+
+        $messages = array();
+
+        foreach ($this->getElements() as $name => $element) {
+            $eMessages = $element->getMessages();
+            if (!empty($eMessages)) {
+                $messages[$name] = $eMessages;
+            }
+        }
+
+        foreach ($this->getSubForms() as $key => $subForm) {
+            $fMessages = $subForm->getMessages(null, true);
+            if (!empty($fMessages)) {
+                if (array_key_exists($key, $arrayKeys)) {
+                    $fMessages = $this->_attachToArray($fMessages, $arrayKeys[$key]);
+                    $messages = array_merge($messages, $fMessages);
+                } else {
+                    $messages[$key] = $fMessages;
+                }
+            }
+        }
+
+        if (!$suppressArrayNotation && $this->isArray()) {
+            $messages = $this->_attachToArray($messages, $this->getElementsBelongTo());
+        }
+
+        return $messages;
+    }
+
+
+    // Rendering
+
+    /**
+     * Set view object
+     *
+     * @param  Zend_View_Interface $view
+     * @return Zend_Form
+     */
+    public function setView(Zend_View_Interface $view = null)
+    {
+        $this->_view = $view;
+        return $this;
+    }
+
+    /**
+     * Retrieve view object
+     *
+     * If none registered, attempts to pull from ViewRenderer.
+     *
+     * @return Zend_View_Interface|null
+     */
+    public function getView()
+    {
+        if (null === $this->_view) {
+            require_once 'Zend/Controller/Action/HelperBroker.php';
+            $viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
+            $this->setView($viewRenderer->view);
+        }
+
+        return $this->_view;
+    }
+
+    /**
+     * Instantiate a decorator based on class name or class name fragment
+     *
+     * @param  string $name
+     * @param  null|array $options
+     * @return Zend_Form_Decorator_Interface
+     */
+    protected function _getDecorator($name, $options)
+    {
+        $class = $this->getPluginLoader(self::DECORATOR)->load($name);
+        if (null === $options) {
+            $decorator = new $class;
+        } else {
+            $decorator = new $class($options);
+        }
+
+        return $decorator;
+    }
+
+    /**
+     * Add a decorator for rendering the element
+     *
+     * @param  string|Zend_Form_Decorator_Interface $decorator
+     * @param  array|Zend_Config $options Options with which to initialize decorator
+     * @return Zend_Form
+     */
+    public function addDecorator($decorator, $options = null)
+    {
+        if ($decorator instanceof Zend_Form_Decorator_Interface) {
+            $name = get_class($decorator);
+        } elseif (is_string($decorator)) {
+            $name      = $decorator;
+            $decorator = array(
+                'decorator' => $name,
+                'options'   => $options,
+            );
+        } elseif (is_array($decorator)) {
+            foreach ($decorator as $name => $spec) {
+                break;
+            }
+            if (is_numeric($name)) {
+                require_once 'Zend/Form/Exception.php';
+                throw new Zend_Form_Exception('Invalid alias provided to addDecorator; must be alphanumeric string');
+            }
+            if (is_string($spec)) {
+                $decorator = array(
+                    'decorator' => $spec,
+                    'options'   => $options,
+                );
+            } elseif ($spec instanceof Zend_Form_Decorator_Interface) {
+                $decorator = $spec;
+            }
+        } else {
+            require_once 'Zend/Form/Exception.php';
+            throw new Zend_Form_Exception('Invalid decorator provided to addDecorator; must be string or Zend_Form_Decorator_Interface');
+        }
+
+        $this->_decorators[$name] = $decorator;
+
+        return $this;
+    }
+
+    /**
+     * Add many decorators at once
+     *
+     * @param  array $decorators
+     * @return Zend_Form
+     */
+    public function addDecorators(array $decorators)
+    {
+        foreach ($decorators as $decoratorInfo) {
+            if (is_string($decoratorInfo)) {
+                $this->addDecorator($decoratorInfo);
+            } elseif ($decoratorInfo instanceof Zend_Form_Decorator_Interface) {
+                $this->addDecorator($decoratorInfo);
+            } elseif (is_array($decoratorInfo)) {
+                $argc    = count($decoratorInfo);
+                $options = array();
+                if (isset($decoratorInfo['decorator'])) {
+                    $decorator = $decoratorInfo['decorator'];
+                    if (isset($decoratorInfo['options'])) {
+                        $options = $decoratorInfo['options'];
+                    }
+                    $this->addDecorator($decorator, $options);
+                } else {
+                    switch (true) {
+                        case (0 == $argc):
+                            break;
+                        case (1 <= $argc):
+                            $decorator  = array_shift($decoratorInfo);
+                        case (2 <= $argc):
+                            $options = array_shift($decoratorInfo);
+                        default:
+                            $this->addDecorator($decorator, $options);
+                            break;
+                    }
+                }
+            } else {
+                require_once 'Zend/Form/Exception.php';
+                throw new Zend_Form_Exception('Invalid decorator passed to addDecorators()');
+            }
+        }
+
+        return $this;
+    }
+
+    /**
+     * Overwrite all decorators
+     *
+     * @param  array $decorators
+     * @return Zend_Form
+     */
+    public function setDecorators(array $decorators)
+    {
+        $this->clearDecorators();
+        return $this->addDecorators($decorators);
+    }
+
+    /**
+     * Retrieve a registered decorator
+     *
+     * @param  string $name
+     * @return false|Zend_Form_Decorator_Abstract
+     */
+    public function getDecorator($name)
+    {
+        if (!isset($this->_decorators[$name])) {
+            $len = strlen($name);
+            foreach ($this->_decorators as $localName => $decorator) {
+                if ($len > strlen($localName)) {
+                    continue;
+                }
+
+                if (0 === substr_compare($localName, $name, -$len, $len, true)) {
+                    if (is_array($decorator)) {
+                        return $this->_loadDecorator($decorator, $localName);
+                    }
+                    return $decorator;
+                }
+            }
+            return false;
+        }
+
+        if (is_array($this->_decorators[$name])) {
+            return $this->_loadDecorator($this->_decorators[$name], $name);
+        }
+
+        return $this->_decorators[$name];
+    }
+
+    /**
+     * Retrieve all decorators
+     *
+     * @return array
+     */
+    public function getDecorators()
+    {
+        foreach ($this->_decorators as $key => $value) {
+            if (is_array($value)) {
+                $this->_loadDecorator($value, $key);
+            }
+        }
+        return $this->_decorators;
+    }
+
+    /**
+     * Remove a single decorator
+     *
+     * @param  string $name
+     * @return bool
+     */
+    public function removeDecorator($name)
+    {
+        $decorator = $this->getDecorator($name);
+        if ($decorator) {
+            if (array_key_exists($name, $this->_decorators)) {
+                unset($this->_decorators[$name]);
+            } else {
+                $class = get_class($decorator);
+                if (!array_key_exists($class, $this->_decorators)) {
+                    return false;
+                }
+                unset($this->_decorators[$class]);
+            }
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Clear all decorators
+     *
+     * @return Zend_Form
+     */
+    public function clearDecorators()
+    {
+        $this->_decorators = array();
+        return $this;
+    }
+
+    /**
+     * Set all element decorators as specified
+     *
+     * @param  array $decorators
+     * @param  array|null $elements Specific elements to decorate or exclude from decoration
+     * @param  bool $include Whether $elements is an inclusion or exclusion list
+     * @return Zend_Form
+     */
+    public function setElementDecorators(array $decorators, array $elements = null, $include = true)
+    {
+        if (is_array($elements)) {
+            if ($include) {
+                $elementObjs = array();
+                foreach ($elements as $name) {
+                    if (null !== ($element = $this->getElement($name))) {
+                        $elementObjs[] = $element;
+                    }
+                }
+            } else {
+                $elementObjs = $this->getElements();
+                foreach ($elements as $name) {
+                    if (array_key_exists($name, $elementObjs)) {
+                        unset($elementObjs[$name]);
+                    }
+                }
+            }
+        } else {
+            $elementObjs = $this->getElements();
+        }
+
+        foreach ($elementObjs as $element) {
+            $element->setDecorators($decorators);
+        }
+
+        $this->_elementDecorators = $decorators;
+
+        return $this;
+    }
+
+    /**
+     * Set all display group decorators as specified
+     *
+     * @param  array $decorators
+     * @return Zend_Form
+     */
+    public function setDisplayGroupDecorators(array $decorators)
+    {
+        foreach ($this->getDisplayGroups() as $group) {
+            $group->setDecorators($decorators);
+        }
+
+        return $this;
+    }
+
+    /**
+     * Set all subform decorators as specified
+     *
+     * @param  array $decorators
+     * @return Zend_Form
+     */
+    public function setSubFormDecorators(array $decorators)
+    {
+        foreach ($this->getSubForms() as $form) {
+            $form->setDecorators($decorators);
+        }
+
+        return $this;
+    }
+
+    /**
+     * Render form
+     *
+     * @param  Zend_View_Interface $view
+     * @return string
+     */
+    public function render(Zend_View_Interface $view = null)
+    {
+        if (null !== $view) {
+            $this->setView($view);
+        }
+
+        $content = '';
+        foreach ($this->getDecorators() as $decorator) {
+            $decorator->setElement($this);
+            $content = $decorator->render($content);
+        }
+        return $content;
+    }
+
+    /**
+     * Serialize as string
+     *
+     * Proxies to {@link render()}.
+     *
+     * @return string
+     */
+    public function __toString()
+    {
+        try {
+            $return = $this->render();
+            return $return;
+        } catch (Exception $e) {
+            $message = "Exception caught by form: " . $e->getMessage()
+                     . "\nStack Trace:\n" . $e->getTraceAsString();
+            trigger_error($message, E_USER_WARNING);
+            return '';
+        }
+    }
+
+
+    // Localization:
+
+    /**
+     * Set translator object
+     *
+     * @param  Zend_Translate|Zend_Translate_Adapter|null $translator
+     * @return Zend_Form
+     */
+    public function setTranslator($translator = null)
+    {
+        if (null === $translator) {
+            $this->_translator = null;
+        } elseif ($translator instanceof Zend_Translate_Adapter) {
+            $this->_translator = $translator;
+        } elseif ($translator instanceof Zend_Translate) {
+            $this->_translator = $translator->getAdapter();
+        } else {
+            require_once 'Zend/Form/Exception.php';
+            throw new Zend_Form_Exception('Invalid translator specified');
+        }
+
+        return $this;
+    }
+
+    /**
+     * Set global default translator object
+     *
+     * @param  Zend_Translate|Zend_Translate_Adapter|null $translator
+     * @return void
+     */
+    public static function setDefaultTranslator($translator = null)
+    {
+        if (null === $translator) {
+            self::$_translatorDefault = null;
+        } elseif ($translator instanceof Zend_Translate_Adapter) {
+            self::$_translatorDefault = $translator;
+        } elseif ($translator instanceof Zend_Translate) {
+            self::$_translatorDefault = $translator->getAdapter();
+        } else {
+            require_once 'Zend/Form/Exception.php';
+            throw new Zend_Form_Exception('Invalid translator specified');
+        }
+    }
+
+    /**
+     * Retrieve translator object
+     *
+     * @return Zend_Translate|null
+     */
+    public function getTranslator()
+    {
+        if ($this->translatorIsDisabled()) {
+            return null;
+        }
+
+        if (null === $this->_translator) {
+            return self::getDefaultTranslator();
+        }
+
+        return $this->_translator;
+    }
+
+    /**
+     * Get global default translator object
+     *
+     * @return null|Zend_Translate
+     */
+    public static function getDefaultTranslator()
+    {
+        if (null === self::$_translatorDefault) {
+            require_once 'Zend/Registry.php';
+            if (Zend_Registry::isRegistered('Zend_Translate')) {
+                $translator = Zend_Registry::get('Zend_Translate');
+                if ($translator instanceof Zend_Translate_Adapter) {
+                    return $translator;
+                } elseif ($translator instanceof Zend_Translate) {
+                    return $translator->getAdapter();
+                }
+            }
+        }
+        return self::$_translatorDefault;
+    }
+
+    /**
+     * Indicate whether or not translation should be disabled
+     *
+     * @param  bool $flag
+     * @return Zend_Form
+     */
+    public function setDisableTranslator($flag)
+    {
+        $this->_translatorDisabled = (bool) $flag;
+        return $this;
+    }
+
+    /**
+     * Is translation disabled?
+     *
+     * @return bool
+     */
+    public function translatorIsDisabled()
+    {
+        return $this->_translatorDisabled;
+    }
+
+    /**
+     * Overloading: access to elements, form groups, and display groups
+     *
+     * @param  string $name
+     * @return Zend_Form_Element|Zend_Form|null
+     */
+    public function __get($name)
+    {
+        if (isset($this->_elements[$name])) {
+            return $this->_elements[$name];
+        } elseif (isset($this->_subForms[$name])) {
+            return $this->_subForms[$name];
+        } elseif (isset($this->_displayGroups[$name])) {
+            return $this->_displayGroups[$name];
+        }
+
+        return null;
+    }
+
+    /**
+     * Overloading: access to elements, form groups, and display groups
+     *
+     * @param  string $name
+     * @param  Zend_Form_Element|Zend_Form $value
+     * @return void
+     * @throws Zend_Form_Exception for invalid $value
+     */
+    public function __set($name, $value)
+    {
+        if ($value instanceof Zend_Form_Element) {
+            $this->addElement($value, $name);
+            return;
+        } elseif ($value instanceof Zend_Form) {
+            $this->addSubForm($value, $name);
+            return;
+        } elseif (is_array($value)) {
+            $this->addDisplayGroup($value, $name);
+            return;
+        }
+
+        require_once 'Zend/Form/Exception.php';
+        if (is_object($value)) {
+            $type = get_class($value);
+        } else {
+            $type = gettype($value);
+        }
+        throw new Zend_Form_Exception('Only form elements and groups may be overloaded; variable of type "' . $type . '" provided');
+    }
+
+    /**
+     * Overloading: access to elements, form groups, and display groups
+     *
+     * @param  string $name
+     * @return boolean
+     */
+    public function __isset($name)
+    {
+        if (isset($this->_elements[$name])
+            || isset($this->_subForms[$name])
+            || isset($this->_displayGroups[$name]))
+        {
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Overloading: access to elements, form groups, and display groups
+     *
+     * @param  string $name
+     * @return void
+     */
+    public function __unset($name)
+    {
+        if (isset($this->_elements[$name])) {
+            unset($this->_elements[$name]);
+        } elseif (isset($this->_subForms[$name])) {
+            unset($this->_subForms[$name]);
+        } elseif (isset($this->_displayGroups[$name])) {
+            unset($this->_displayGroups[$name]);
+        }
+    }
+
+    /**
+     * Overloading: allow rendering specific decorators
+     *
+     * Call renderDecoratorName() to render a specific decorator.
+     *
+     * @param  string $method
+     * @param  array $args
+     * @return string
+     * @throws Zend_Form_Exception for invalid decorator or invalid method call
+     */
+    public function __call($method, $args)
+    {
+        if ('render' == substr($method, 0, 6)) {
+            $decoratorName = substr($method, 6);
+            if (false !== ($decorator = $this->getDecorator($decoratorName))) {
+                $decorator->setElement($this);
+                $seed = '';
+                if (0 < count($args)) {
+                    $seed = array_shift($args);
+                }
+                return $decorator->render($seed);
+            }
+
+            require_once 'Zend/Form/Exception.php';
+            throw new Zend_Form_Exception(sprintf('Decorator by name %s does not exist', $decoratorName));
+        }
+
+        require_once 'Zend/Form/Exception.php';
+        throw new Zend_Form_Exception(sprintf('Method %s does not exist', $method));
+    }
+
+    // Interfaces: Iterator, Countable
+
+    /**
+     * Current element/subform/display group
+     *
+     * @return Zend_Form_Element|Zend_Form_DisplayGroup|Zend_Form
+     */
+    public function current()
+    {
+        $this->_sort();
+        current($this->_order);
+        $key = key($this->_order);
+
+        if (isset($this->_elements[$key])) {
+            return $this->getElement($key);
+        } elseif (isset($this->_subForms[$key])) {
+            return $this->getSubForm($key);
+        } elseif (isset($this->_displayGroups[$key])) {
+            return $this->getDisplayGroup($key);
+        } else {
+            require_once 'Zend/Form/Exception.php';
+            throw new Zend_Form_Exception(sprintf('Corruption detected in form; invalid key ("%s") found in internal iterator', (string) $key));
+        }
+    }
+
+    /**
+     * Current element/subform/display group name
+     *
+     * @return string
+     */
+    public function key()
+    {
+        $this->_sort();
+        return key($this->_order);
+    }
+
+    /**
+     * Move pointer to next element/subform/display group
+     *
+     * @return void
+     */
+    public function next()
+    {
+        $this->_sort();
+        next($this->_order);
+    }
+
+    /**
+     * Move pointer to beginning of element/subform/display group loop
+     *
+     * @return void
+     */
+    public function rewind()
+    {
+        $this->_sort();
+        reset($this->_order);
+    }
+
+    /**
+     * Determine if current element/subform/display group is valid
+     *
+     * @return bool
+     */
+    public function valid()
+    {
+        $this->_sort();
+        return (current($this->_order) !== false);
+    }
+
+    /**
+     * Count of elements/subforms that are iterable
+     *
+     * @return int
+     */
+    public function count()
+    {
+        return count($this->_order);
+    }
+
+    /**
+     * Set flag to disable loading default decorators
+     *
+     * @param  bool $flag
+     * @return Zend_Form
+     */
+    public function setDisableLoadDefaultDecorators($flag)
+    {
+        $this->_disableLoadDefaultDecorators = (bool) $flag;
+        return $this;
+    }
+
+    /**
+     * Should we load the default decorators?
+     *
+     * @return bool
+     */
+    public function loadDefaultDecoratorsIsDisabled()
+    {
+        return $this->_disableLoadDefaultDecorators;
+    }
+
+    /**
+     * Load the default decorators
+     *
+     * @return void
+     */
+    public function loadDefaultDecorators()
+    {
+        if ($this->loadDefaultDecoratorsIsDisabled()) {
+            return;
+        }
+
+        $decorators = $this->getDecorators();
+        if (empty($decorators)) {
+            $this->addDecorator('FormElements')
+                 ->addDecorator('HtmlTag', array('tag' => 'dl', 'class' => 'zend_form'))
+                 ->addDecorator('Form');
+        }
+    }
+
+    /**
+     * Sort items according to their order
+     *
+     * @return void
+     */
+    protected function _sort()
+    {
+        if ($this->_orderUpdated) {
+            $items = array();
+            $index = 0;
+            foreach ($this->_order as $key => $order) {
+                if (null === $order) {
+                    if (null === ($order = $this->{$key}->getOrder())) {
+                        while (array_search($index, $this->_order, true)) {
+                            ++$index;
+                        }
+                        $items[$index] = $key;
+                        ++$index;
+                    } else {
+                        $items[$order] = $key;
+                    }
+                } else {
+                    $items[$order] = $key;
+                }
+            }
+
+            $items = array_flip($items);
+            asort($items);
+            $this->_order = $items;
+            $this->_orderUpdated = false;
+        }
+    }
+
+    /**
+     * Lazy-load a decorator
+     *
+     * @param  array $decorator Decorator type and options
+     * @param  mixed $name Decorator name or alias
+     * @return Zend_Form_Decorator_Interface
+     */
+    protected function _loadDecorator(array $decorator, $name)
+    {
+        $sameName = false;
+        if ($name == $decorator['decorator']) {
+            $sameName = true;
+        }
+
+        $instance = $this->_getDecorator($decorator['decorator'], $decorator['options']);
+        if ($sameName) {
+            $newName            = get_class($instance);
+            $decoratorNames     = array_keys($this->_decorators);
+            $order              = array_flip($decoratorNames);
+            $order[$newName]    = $order[$name];
+            $decoratorsExchange = array();
+            unset($order[$name]);
+            asort($order);
+            foreach ($order as $key => $index) {
+                if ($key == $newName) {
+                    $decoratorsExchange[$key] = $instance;
+                    continue;
+                }
+                $decoratorsExchange[$key] = $this->_decorators[$key];
+            }
+            $this->_decorators = $decoratorsExchange;
+        } else {
+            $this->_decorators[$name] = $instance;
+        }
+
+        return $instance;
+    }
+
+    /**
+     * Retrieve optionally translated custom error messages
+     *
+     * @return array
+     */
+    protected function _getErrorMessages()
+    {
+        $messages   = $this->getErrorMessages();
+        $translator = $this->getTranslator();
+        if (null !== $translator) {
+            foreach ($messages as $key => $message) {
+                $messages[$key] = $translator->translate($message);
+            }
+        }
+        return $messages;
+    }
+}
index 9e63f88938b464c8d98a6e9f80e1e68e5c27c141..c9f73224dd37e7dcfbd1efaa48296ff05a19311a 100644 (file)
  *
  * @category   Zend
  * @package    Zend_Gdata
- * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @subpackage Gdata
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
  */
 
 /**
@@ -29,13 +31,14 @@ require_once 'Zend/Gdata/App.php';
  * Subclasses exist to implement service-specific features
  *
  * As the Google data API protocol is based upon the Atom Publishing Protocol
- * (APP), GData functionality extends the appropriate Zend_Gdata_App classes
+ * (APP), Gdata functionality extends the appropriate Zend_Gdata_App classes
  *
  * @link http://code.google.com/apis/gdata/overview.html
  *
  * @category   Zend
  * @package    Zend_Gdata
- * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @subpackage Gdata
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
  */
 class Zend_Gdata extends Zend_Gdata_App
@@ -68,14 +71,16 @@ class Zend_Gdata extends Zend_Gdata_App
             'Zend_Gdata_App');
 
     /**
-     * Namespaces used for GData data
+     * Namespaces used for Gdata data
      *
      * @var array
      */
     public static $namespaces = array(
-        'openSearch' => 'http://a9.com/-/spec/opensearchrss/1.0/',
-        'rss' => 'http://blogs.law.harvard.edu/tech/rss',
-        'gd' => 'http://schemas.google.com/g/2005');
+        array('gd', 'http://schemas.google.com/g/2005', 1, 0),
+        array('openSearch', 'http://a9.com/-/spec/opensearchrss/1.0/', 1, 0),
+        array('openSearch', 'http://a9.com/-/spec/opensearch/1.1/', 2, 0),
+        array('rss', 'http://blogs.law.harvard.edu/tech/rss', 1, 0)
+    );
 
     /**
      * Client object used to communicate
@@ -95,7 +100,8 @@ class Zend_Gdata extends Zend_Gdata_App
      * Create Gdata object
      *
      * @param Zend_Http_Client $client
-     * @param string $applicationId The identity of the app in the form of Company-AppName-Version
+     * @param string $applicationId The identity of the app in the form of
+     *          Company-AppName-Version
      */
     public function __construct($client = null, $applicationId = 'MyCompany-MyApp-1.0')
     {
@@ -109,15 +115,20 @@ class Zend_Gdata extends Zend_Gdata_App
      * @param  Zend_Http_Client $client The client used for communication
      * @param  string $className The class which is used as the return type
      * @throws Zend_Gdata_App_Exception
-     * @return Zend_Gdata_App_Feed
+     * @return string|Zend_Gdata_App_Feed Returns string only if the object
+     *                                    mapping has been disabled explicitly
+     *                                    by passing false to the
+     *                                    useObjectMapping() function.
      */
-    public static function import($uri, $client = null, $className='Zend_Gdata_Feed')
+    public static function import($uri, $client = null,
+        $className='Zend_Gdata_Feed')
     {
         $app = new Zend_Gdata($client);
         $requestData = $app->decodeRequest('GET', $uri);
         $response = $app->performHttpRequest($requestData['method'], $requestData['url']);
 
         $feedContent = $response->getBody();
+
         $feed = self::importString($feedContent, $className);
         if ($client != null) {
             $feed->setHttpClient($client);
@@ -126,12 +137,15 @@ class Zend_Gdata extends Zend_Gdata_App
     }
 
     /**
-     * Retreive feed object
+     * Retrieve feed as string or object
      *
      * @param mixed $location The location as string or Zend_Gdata_Query
      * @param string $className The class type to use for returning the feed
      * @throws Zend_Gdata_App_InvalidArgumentException
-     * @return Zend_Gdata_Feed
+     * @return string|Zend_Gdata_App_Feed Returns string only if the object
+     *                                    mapping has been disabled explicitly
+     *                                    by passing false to the
+     *                                    useObjectMapping() function.
      */
     public function getFeed($location, $className='Zend_Gdata_Feed')
     {
@@ -149,10 +163,14 @@ class Zend_Gdata extends Zend_Gdata_App
     }
 
     /**
-     * Retreive entry object
+     * Retrieve entry as string or object
      *
      * @param mixed $location The location as string or Zend_Gdata_Query
-     * @return Zend_Gdata_Feed
+     * @throws Zend_Gdata_App_InvalidArgumentException
+     * @return string|Zend_Gdata_App_Entry Returns string only if the object
+     *                                     mapping has been disabled explicitly
+     *                                     by passing false to the
+     *                                     useObjectMapping() function.
      */
     public function getEntry($location, $className='Zend_Gdata_Entry')
     {
@@ -171,11 +189,11 @@ class Zend_Gdata extends Zend_Gdata_App
 
     /**
      * Performs a HTTP request using the specified method.
-     * 
+     *
      * Overrides the definition in the parent (Zend_Gdata_App)
      * and uses the Zend_Gdata_HttpClient functionality
      * to filter the HTTP requests and responses.
-     *  
+     *
      * @param string $method The HTTP method for the request -
      *                       'GET', 'POST', 'PUT', 'DELETE'
      * @param string $url The URL to which this request is being performed,
@@ -204,4 +222,20 @@ class Zend_Gdata extends Zend_Gdata_App
         }
     }
 
+    /**
+     * Determines whether service object is authenticated.
+     *
+     * @return boolean True if service object is authenticated, false otherwise.
+     */
+    public function isAuthenticated()
+    {
+        $client = parent::getHttpClient();
+        if ($client->getClientLoginToken() ||
+            $client->getAuthSubToken()) {
+                return true;
+        }
+
+        return false;
+    }
+
 }
diff --git a/lib/zend/Zend/InfoCard.php b/lib/zend/Zend/InfoCard.php
new file mode 100644 (file)
index 0000000..25b84b3
--- /dev/null
@@ -0,0 +1,497 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_InfoCard
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/**
+ * Zend_InfoCard_Xml_EncryptedData
+ */
+require_once 'Zend/InfoCard/Xml/EncryptedData.php';
+
+/**
+ * Zend_InfoCard_Xml_Assertion
+ */
+require_once 'Zend/InfoCard/Xml/Assertion.php';
+
+/**
+ * Zend_InfoCard_Cipher
+ */
+require_once 'Zend/InfoCard/Cipher.php';
+
+/**
+ * Zend_InfoCard_Xml_Security
+ */
+require_once 'Zend/InfoCard/Xml/Security.php';
+
+/**
+ * Zend_InfoCard_Adapter_Interface
+ */
+require_once 'Zend/InfoCard/Adapter/Interface.php';
+
+/**
+ * Zend_InfoCard_Claims
+ */
+require_once 'Zend/InfoCard/Claims.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_InfoCard
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_InfoCard
+{
+    /**
+     * URI for XML Digital Signature SHA1 Digests
+     */
+    const DIGEST_SHA1        = 'http://www.w3.org/2000/09/xmldsig#sha1';
+
+    /**
+     * An array of certificate pair files and optional passwords for them to search
+     * when trying to determine which certificate was used to encrypt the transient key
+     *
+     * @var Array
+     */
+    protected $_keyPairs;
+
+    /**
+     * The instance to use to decrypt public-key encrypted data
+     *
+     * @var Zend_InfoCard_Cipher_Pki_Interface
+     */
+    protected $_pkiCipherObj;
+
+    /**
+     * The instance to use to decrypt symmetric encrypted data
+     *
+     * @var Zend_InfoCard_Cipher_Symmetric_Interface
+     */
+    protected $_symCipherObj;
+
+    /**
+     * The InfoCard Adapter to use for callbacks into the application using the component
+     * such as when storing assertions, etc.
+     *
+     * @var Zend_InfoCard_Adapter_Interface
+     */
+    protected $_adapter;
+
+
+    /**
+     * InfoCard Constructor
+     *
+     * @throws Zend_InfoCard_Exception
+     */
+    public function __construct()
+    {
+        $this->_keyPairs = array();
+
+        if(!extension_loaded('mcrypt')) {
+            require_once 'Zend/InfoCard/Exception.php';
+            throw new Zend_InfoCard_Exception("Use of the Zend_InfoCard component requires the mcrypt extension to be enabled in PHP");
+        }
+
+        if(!extension_loaded('openssl')) {
+            require_once 'Zend/InfoCard/Exception.php';
+            throw new Zend_InfoCard_Exception("Use of the Zend_InfoCard component requires the openssl extension to be enabled in PHP");
+        }
+    }
+
+    /**
+     * Sets the adapter uesd for callbacks into the application using the component, used
+     * when doing things such as storing / retrieving assertions, etc.
+     *
+     * @param Zend_InfoCard_Adapter_Interface $a The Adapter instance
+     * @return Zend_InfoCard The instnace
+     */
+    public function setAdapter(Zend_InfoCard_Adapter_Interface $a)
+    {
+        $this->_adapter = $a;
+        return $this;
+    }
+
+    /**
+     * Retrieves the adapter used for callbacks into the application using the component.
+     * If no adapter was set then an instance of Zend_InfoCard_Adapter_Default is used
+     *
+     * @return Zend_InfoCard_Adapter_Interface The Adapter instance
+     */
+    public function getAdapter()
+    {
+        if($this->_adapter === null) {
+            require_once 'Zend/InfoCard/Adapter/Default.php';
+            $this->setAdapter(new Zend_InfoCard_Adapter_Default());
+        }
+
+        return $this->_adapter;
+    }
+
+    /**
+     * Gets the Public Key Cipher object used in this instance
+     *
+     * @return Zend_InfoCard_Cipher_Pki_Interface
+     */
+    public function getPkiCipherObject()
+    {
+        return $this->_pkiCipherObj;
+    }
+
+    /**
+     * Sets the Public Key Cipher Object used in this instance
+     *
+     * @param Zend_InfoCard_Cipher_Pki_Interface $cipherObj
+     * @return Zend_InfoCard
+     */
+    public function setPkiCipherObject(Zend_InfoCard_Cipher_Pki_Interface $cipherObj)
+    {
+        $this->_pkiCipherObj = $cipherObj;
+        return $this;
+    }
+
+    /**
+     * Get the Symmetric Cipher Object used in this instance
+     *
+     * @return Zend_InfoCard_Cipher_Symmetric_Interface
+     */
+    public function getSymCipherObject()
+    {
+        return $this->_symCipherObj;
+    }
+
+    /**
+     * Sets the Symmetric Cipher Object used in this instance
+     *
+     * @param Zend_InfoCard_Cipher_Symmetric_Interface $cipherObj
+     * @return Zend_InfoCard
+     */
+    public function setSymCipherObject($cipherObj)
+    {
+        $this->_symCipherObj = $cipherObj;
+        return $this;
+    }
+
+    /**
+     * Remove a Certificate Pair by Key ID from the search list
+     *
+     * @throws Zend_InfoCard_Exception
+     * @param string $key_id The Certificate Key ID returned from adding the certificate pair
+     * @return Zend_InfoCard
+     */
+    public function removeCertificatePair($key_id)
+    {
+
+        if(!key_exists($key_id, $this->_keyPairs)) {
+            require_once 'Zend/InfoCard/Exception.php';
+            throw new Zend_InfoCard_Exception("Attempted to remove unknown key id: $key_id");
+        }
+
+        unset($this->_keyPairs[$key_id]);
+        return $this;
+    }
+
+    /**
+     * Add a Certificate Pair to the list of certificates searched by the component
+     *
+     * @throws Zend_InfoCard_Exception
+     * @param string $private_key_file The path to the private key file for the pair
+     * @param string $public_key_file The path to the certificate / public key for the pair
+     * @param string $type (optional) The URI for the type of key pair this is (default RSA with OAEP padding)
+     * @param string $password (optional) The password for the private key file if necessary
+     * @return string A key ID representing this key pair in the component
+     */
+    public function addCertificatePair($private_key_file, $public_key_file, $type = Zend_InfoCard_Cipher::ENC_RSA_OAEP_MGF1P, $password = null)
+    {
+        if(!file_exists($private_key_file) ||
+           !file_exists($public_key_file)) {
+            require_once 'Zend/InfoCard/Exception.php';
+            throw new Zend_InfoCard_Exception("Could not locate the public and private certificate pair files: $private_key_file, $public_key_file");
+        }
+
+        if(!is_readable($private_key_file) ||
+           !is_readable($public_key_file)) {
+            require_once 'Zend/InfoCard/Exception.php';
+            throw new Zend_InfoCard_Exception("Could not read the public and private certificate pair files (check permissions): $private_key_file, $public_key_file");
+        }
+
+        $key_id = md5($private_key_file.$public_key_file);
+
+        if(key_exists($key_id, $this->_keyPairs)) {
+            require_once 'Zend/InfoCard/Exception.php';
+            throw new Zend_InfoCard_Exception("Attempted to add previously existing certificate pair: $private_key_file, $public_key_file");
+        }
+
+        switch($type) {
+            case Zend_InfoCard_Cipher::ENC_RSA:
+            case Zend_InfoCard_Cipher::ENC_RSA_OAEP_MGF1P:
+                $this->_keyPairs[$key_id] = array('private' => $private_key_file,
+                                'public'      => $public_key_file,
+                                'type_uri'    => $type);
+
+                if($password !== null) {
+                    $this->_keyPairs[$key_id]['password'] = $password;
+                } else {
+                    $this->_keyPairs[$key_id]['password'] = null;
+                }
+
+                return $key_id;
+                break;
+            default:
+                require_once 'Zend/InfoCard/Exception.php';
+                throw new Zend_InfoCard_Exception("Invalid Certificate Pair Type specified: $type");
+        }
+    }
+
+    /**
+     * Return a Certificate Pair from a key ID
+     *
+     * @throws Zend_InfoCard_Exception
+     * @param string $key_id The Key ID of the certificate pair in the component
+     * @return array An array containing the path to the private/public key files,
+     *               the type URI and the password if provided
+     */
+    public function getCertificatePair($key_id)
+    {
+        if(key_exists($key_id, $this->_keyPairs)) {
+            return $this->_keyPairs[$key_id];
+        }
+
+        require_once 'Zend/InfoCard/Exception.php';
+        throw new Zend_InfoCard_Exception("Invalid Certificate Pair ID provided: $key_id");
+    }
+
+    /**
+     * Retrieve the digest of a given public key / certificate using the provided digest
+     * method
+     *
+     * @throws Zend_InfoCard_Exception
+     * @param string $key_id The certificate key id in the component
+     * @param string $digestMethod The URI of the digest method to use (default SHA1)
+     * @return string The digest value in binary format
+     */
+    protected function _getPublicKeyDigest($key_id, $digestMethod = self::DIGEST_SHA1)
+    {
+        $certificatePair = $this->getCertificatePair($key_id);
+
+        $temp = file($certificatePair['public']);
+        unset($temp[count($temp)-1]);
+        unset($temp[0]);
+        $certificateData = base64_decode(implode("\n", $temp));
+
+        switch($digestMethod) {
+            case self::DIGEST_SHA1:
+                $digest_retval = sha1($certificateData, true);
+                break;
+            default:
+                require_once 'Zend/InfoCard/Exception.php';
+                throw new Zend_InfoCard_Exception("Invalid Digest Type Provided: $digestMethod");
+        }
+
+        return $digest_retval;
+    }
+
+    /**
+     * Find a certificate pair based on a digest of its public key / certificate file
+     *
+     * @param string $digest The digest value of the public key wanted in binary form
+     * @param string $digestMethod The URI of the digest method used to calculate the digest
+     * @return mixed The Key ID of the matching certificate pair or false if not found
+     */
+    protected function _findCertifiatePairByDigest($digest, $digestMethod = self::DIGEST_SHA1)
+    {
+
+        foreach($this->_keyPairs as $key_id => $certificate_data) {
+
+            $cert_digest = $this->_getPublicKeyDigest($key_id, $digestMethod);
+
+            if($cert_digest == $digest) {
+                return $key_id;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Extracts the Signed Token from an EncryptedData block
+     *
+     * @throws Zend_InfoCard_Exception
+     * @param string $strXmlToken The EncryptedData XML block
+     * @return string The XML of the Signed Token inside of the EncryptedData block
+     */
+    protected function _extractSignedToken($strXmlToken)
+    {
+        $encryptedData = Zend_InfoCard_Xml_EncryptedData::getInstance($strXmlToken);
+
+        // Determine the Encryption Method used to encrypt the token
+
+        switch($encryptedData->getEncryptionMethod()) {
+            case Zend_InfoCard_Cipher::ENC_AES128CBC:
+            case Zend_InfoCard_Cipher::ENC_AES256CBC:
+                break;
+            default:
+                require_once 'Zend/InfoCard/Exception.php';
+                throw new Zend_InfoCard_Exception("Unknown Encryption Method used in the secure token");
+        }
+
+        // Figure out the Key we are using to decrypt the token
+
+        $keyinfo = $encryptedData->getKeyInfo();
+
+        if(!($keyinfo instanceof Zend_InfoCard_Xml_KeyInfo_XmlDSig)) {
+            require_once 'Zend/InfoCard/Exception.php';
+            throw new Zend_InfoCard_Exception("Expected a XML digital signature KeyInfo, but was not found");
+        }
+
+
+        $encryptedKey = $keyinfo->getEncryptedKey();
+
+        switch($encryptedKey->getEncryptionMethod()) {
+            case Zend_InfoCard_Cipher::ENC_RSA:
+            case Zend_InfoCard_Cipher::ENC_RSA_OAEP_MGF1P:
+                break;
+            default:
+                require_once 'Zend/InfoCard/Exception.php';
+                throw new Zend_InfoCard_Exception("Unknown Key Encryption Method used in secure token");
+        }
+
+        $securityTokenRef = $encryptedKey->getKeyInfo()->getSecurityTokenReference();
+
+        $key_id = $this->_findCertifiatePairByDigest($securityTokenRef->getKeyReference());
+
+        if(!$key_id) {
+            require_once 'Zend/InfoCard/Exception.php';
+            throw new Zend_InfoCard_Exception("Unable to find key pair used to encrypt symmetric InfoCard Key");
+        }
+
+        $certificate_pair = $this->getCertificatePair($key_id);
+
+        // Santity Check
+
+        if($certificate_pair['type_uri'] != $encryptedKey->getEncryptionMethod()) {
+            require_once 'Zend/InfoCard/Exception.php';
+            throw new Zend_InfoCard_Exception("Certificate Pair which matches digest is not of same algorithm type as document, check addCertificate()");
+        }
+
+        $PKcipher = Zend_InfoCard_Cipher::getInstanceByURI($encryptedKey->getEncryptionMethod());
+
+        $base64DecodeSupportsStrictParam = version_compare(PHP_VERSION, '5.2.0', '>=');
+
+        if ($base64DecodeSupportsStrictParam) {
+            $keyCipherValueBase64Decoded = base64_decode($encryptedKey->getCipherValue(), true);
+        } else {
+            $keyCipherValueBase64Decoded = base64_decode($encryptedKey->getCipherValue());
+        }
+
+        $symmetricKey = $PKcipher->decrypt(
+            $keyCipherValueBase64Decoded,
+            file_get_contents($certificate_pair['private']),
+            $certificate_pair['password']
+            );
+
+        $symCipher = Zend_InfoCard_Cipher::getInstanceByURI($encryptedData->getEncryptionMethod());
+
+        if ($base64DecodeSupportsStrictParam) {
+            $dataCipherValueBase64Decoded = base64_decode($encryptedData->getCipherValue(), true);
+        } else {
+            $dataCipherValueBase64Decoded = base64_decode($encryptedData->getCipherValue());
+        }
+
+        $signedToken = $symCipher->decrypt($dataCipherValueBase64Decoded, $symmetricKey);
+
+        return $signedToken;
+    }
+
+    /**
+     * Process an input Infomation Card EncryptedData block sent from the client,
+     * validate it, and return the claims contained within it on success or an error message on error
+     *
+     * @param string $strXmlToken The XML token sent to the server from the client
+     * @return Zend_Infocard_Claims The Claims object containing the claims, or any errors which occurred
+     */
+    public function process($strXmlToken)
+    {
+
+        $retval = new Zend_InfoCard_Claims();
+
+        require_once 'Zend/InfoCard/Exception.php';
+        try {
+            $signedAssertionsXml = $this->_extractSignedToken($strXmlToken);
+        } catch(Zend_InfoCard_Exception $e) {
+            $retval->setError('Failed to extract assertion document');
+            $retval->setCode(Zend_InfoCard_Claims::RESULT_PROCESSING_FAILURE);
+            return $retval;
+        }
+
+        try {
+            $assertions = Zend_InfoCard_Xml_Assertion::getInstance($signedAssertionsXml);
+        } catch(Zend_InfoCard_Exception $e) {
+            $retval->setError('Failure processing assertion document');
+            $retval->setCode(Zend_InfoCard_Claims::RESULT_PROCESSING_FAILURE);
+            return $retval;
+        }
+
+        if(!($assertions instanceof Zend_InfoCard_Xml_Assertion_Interface)) {
+            throw new Zend_InfoCard_Exception("Invalid Assertion Object returned");
+        }
+
+        if(!($reference_id = Zend_InfoCard_Xml_Security::validateXMLSignature($assertions->asXML()))) {
+            $retval->setError("Failure Validating the Signature of the assertion document");
+            $retval->setCode(Zend_InfoCard_Claims::RESULT_VALIDATION_FAILURE);
+            return $retval;
+        }
+
+        // The reference id should be locally scoped as far as I know
+        if($reference_id[0] == '#') {
+            $reference_id = substr($reference_id, 1);
+        } else {
+            $retval->setError("Reference of document signature does not reference the local document");
+            $retval->setCode(Zend_InfoCard_Claims::RESULT_VALIDATION_FAILURE);
+            return $retval;
+        }
+
+        // Make sure the signature is in reference to the same document as the assertions
+        if($reference_id != $assertions->getAssertionID()) {
+            $retval->setError("Reference of document signature does not reference the local document");
+            $retval->setCode(Zend_InfoCard_Claims::RESULT_VALIDATION_FAILURE);
+        }
+
+        // Validate we haven't seen this before and the conditions are acceptable
+        $conditions = $this->getAdapter()->retrieveAssertion($assertions->getAssertionURI(), $assertions->getAssertionID());
+
+        if($conditions === false) {
+            $conditions = $assertions->getConditions();
+        }
+
+
+        if(is_array($condition_error = $assertions->validateConditions($conditions))) {
+            $retval->setError("Conditions of assertion document are not met: {$condition_error[1]} ({$condition_error[0]})");
+            $retval->setCode(Zend_InfoCard_Claims::RESULT_VALIDATION_FAILURE);
+        }
+
+        $attributes = $assertions->getAttributes();
+
+        $retval->setClaims($attributes);
+
+        if($retval->getCode() == 0) {
+            $retval->setCode(Zend_InfoCard_Claims::RESULT_SUCCESS);
+        }
+
+        return $retval;
+    }
+}
diff --git a/lib/zend/Zend/Json.php b/lib/zend/Zend/Json.php
new file mode 100644 (file)
index 0000000..c3197d1
--- /dev/null
@@ -0,0 +1,339 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Json
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/**
+ * Zend_Json_Expr.
+ *
+ * @see Zend_Json_Expr
+ */
+require_once 'Zend/Json/Expr.php';
+
+
+/**
+ * Class for encoding to and decoding from JSON.
+ *
+ * @category   Zend
+ * @package    Zend_Json
+ * @uses       Zend_Json_Expr
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Json
+{
+    /**
+     * How objects should be encoded -- arrays or as StdClass. TYPE_ARRAY is 1
+     * so that it is a boolean true value, allowing it to be used with
+     * ext/json's functions.
+     */
+    const TYPE_ARRAY  = 1;
+    const TYPE_OBJECT = 0;
+
+     /**
+      * To check the allowed nesting depth of the XML tree during xml2json conversion.
+      *
+      * @var int
+      */
+    public static $maxRecursionDepthAllowed=25;
+
+    /**
+     * @var bool
+     */
+    public static $useBuiltinEncoderDecoder = false;
+
+    /**
+     * Decodes the given $encodedValue string which is
+     * encoded in the JSON format
+     *
+     * Uses ext/json's json_decode if available.
+     *
+     * @param string $encodedValue Encoded in JSON format
+     * @param int $objectDecodeType Optional; flag indicating how to decode
+     * objects. See {@link Zend_Json_Decoder::decode()} for details.
+     * @return mixed
+     */
+    public static function decode($encodedValue, $objectDecodeType = Zend_Json::TYPE_ARRAY)
+    {
+        if (function_exists('json_decode') && self::$useBuiltinEncoderDecoder !== true) {
+            return json_decode($encodedValue, $objectDecodeType);
+        }
+
+        require_once 'Zend/Json/Decoder.php';
+        return Zend_Json_Decoder::decode($encodedValue, $objectDecodeType);
+    }
+
+    /**
+     * Encode the mixed $valueToEncode into the JSON format
+     *
+     * Encodes using ext/json's json_encode() if available.
+     *
+     * NOTE: Object should not contain cycles; the JSON format
+     * does not allow object reference.
+     *
+     * NOTE: Only public variables will be encoded
+     *
+     * NOTE: Encoding native javascript expressions are possible using Zend_Json_Expr.
+     *       You can enable this by setting $options['enableJsonExprFinder'] = true
+     *
+     * @see Zend_Json_Expr
+     *
+     * @param  mixed $valueToEncode
+     * @param  boolean $cycleCheck Optional; whether or not to check for object recursion; off by default
+     * @param  array $options Additional options used during encoding
+     * @return string JSON encoded object
+     */
+    public static function encode($valueToEncode, $cycleCheck = false, $options = array())
+    {
+        if (is_object($valueToEncode) && method_exists($valueToEncode, 'toJson')) {
+            return $valueToEncode->toJson();
+        }
+
+        // Pre-encoding look for Zend_Json_Expr objects and replacing by tmp ids
+        $javascriptExpressions = array();
+        if(isset($options['enableJsonExprFinder'])
+           && ($options['enableJsonExprFinder'] == true)
+        ) {
+            /**
+             * @see Zend_Json_Encoder
+             */
+            require_once "Zend/Json/Encoder.php";
+            $valueToEncode = self::_recursiveJsonExprFinder($valueToEncode, $javascriptExpressions);
+        }
+
+        // Encoding
+        if (function_exists('json_encode') && self::$useBuiltinEncoderDecoder !== true) {
+            $encodedResult = json_encode($valueToEncode);
+        } else {
+            require_once 'Zend/Json/Encoder.php';
+            $encodedResult = Zend_Json_Encoder::encode($valueToEncode, $cycleCheck, $options);
+        }
+
+        //only do post-proccessing to revert back the Zend_Json_Expr if any.
+        if (count($javascriptExpressions) > 0) {
+            $count = count($javascriptExpressions);
+            for($i = 0; $i < $count; $i++) {
+                $magicKey = $javascriptExpressions[$i]['magicKey'];
+                $value    = $javascriptExpressions[$i]['value'];
+
+                $encodedResult = str_replace(
+                    //instead of replacing "key:magicKey", we replace directly magicKey by value because "key" never changes.
+                    '"' . $magicKey . '"',
+                    $value,
+                    $encodedResult
+                );
+            }
+        }
+
+         return $encodedResult;
+    }
+
+    /**
+     * Check & Replace Zend_Json_Expr for tmp ids in the valueToEncode
+     *
+     * Check if the value is a Zend_Json_Expr, and if replace its value
+     * with a magic key and save the javascript expression in an array.
+     *
+     * NOTE this method is recursive.
+     *
+     * NOTE: This method is used internally by the encode method.
+     *
+     * @see encode
+     * @param mixed $valueToCheck a string - object property to be encoded
+     * @return void
+     */
+    protected static function _recursiveJsonExprFinder(
+        &$value, array &$javascriptExpressions, $currentKey = null
+    ) {
+         if ($value instanceof Zend_Json_Expr) {
+            // TODO: Optimize with ascii keys, if performance is bad
+            $magicKey = "____" . $currentKey . "_" . (count($javascriptExpressions));
+            $javascriptExpressions[] = array(
+
+                //if currentKey is integer, encodeUnicodeString call is not required.
+                "magicKey" => (is_int($currentKey)) ? $magicKey : Zend_Json_Encoder::encodeUnicodeString($magicKey),
+                "value"    => $value->__toString(),
+            );
+            $value = $magicKey;
+        } elseif (is_array($value)) {
+            foreach ($value as $k => $v) {
+                $value[$k] = self::_recursiveJsonExprFinder($value[$k], $javascriptExpressions, $k);
+            }
+        } elseif (is_object($value)) {
+            foreach ($value as $k => $v) {
+                $value->$k = self::_recursiveJsonExprFinder($value->$k, $javascriptExpressions, $k);
+            }
+        }
+        return $value;
+    }
+
+    /**
+     * fromXml - Converts XML to JSON
+     *
+     * Converts a XML formatted string into a JSON formatted string.
+     * The value returned will be a string in JSON format.
+     *
+     * The caller of this function needs to provide only the first parameter,
+     * which is an XML formatted String. The second parameter is optional, which
+     * lets the user to select if the XML attributes in the input XML string
+     * should be included or ignored in xml2json conversion.
+     *
+     * This function converts the XML formatted string into a PHP array by
+     * calling a recursive (protected static) function in this class. Then, it
+     * converts that PHP array into JSON by calling the "encode" static funcion.
+     *
+     * Throws a Zend_Json_Exception if the input not a XML formatted string.
+     * NOTE: Encoding native javascript expressions via Zend_Json_Expr is not possible.
+     *
+     * @static
+     * @access public
+     * @param string $xmlStringContents XML String to be converted
+     * @param boolean $ignoreXmlAttributes Include or exclude XML attributes in
+     * the xml2json conversion process.
+     * @return mixed - JSON formatted string on success
+     * @throws Zend_Json_Exception
+     */
+    public static function fromXml ($xmlStringContents, $ignoreXmlAttributes=true) {
+        // Load the XML formatted string into a Simple XML Element object.
+        $simpleXmlElementObject = simplexml_load_string($xmlStringContents);
+
+        // If it is not a valid XML content, throw an exception.
+        if ($simpleXmlElementObject == null) {
+            require_once 'Zend/Json/Exception.php';
+            throw new Zend_Json_Exception('Function fromXml was called with an invalid XML formatted string.');
+        } // End of if ($simpleXmlElementObject == null)
+
+        $resultArray = null;
+
+        // Call the recursive function to convert the XML into a PHP array.
+        $resultArray = self::_processXml($simpleXmlElementObject, $ignoreXmlAttributes);
+
+        // Convert the PHP array to JSON using Zend_Json encode method.
+        // It is just that simple.
+        $jsonStringOutput = self::encode($resultArray);
+        return($jsonStringOutput);
+    } // End of function fromXml.
+
+    /**
+     * _processXml - Contains the logic for xml2json
+     *
+     * The logic in this function is a recursive one.
+     *
+     * The main caller of this function (i.e. fromXml) needs to provide
+     * only the first two parameters i.e. the SimpleXMLElement object and
+     * the flag for ignoring or not ignoring XML attributes. The third parameter
+     * will be used internally within this function during the recursive calls.
+     *
+     * This function converts the SimpleXMLElement object into a PHP array by
+     * calling a recursive (protected static) function in this class. Once all
+     * the XML elements are stored in the PHP array, it is returned to the caller.
+     *
+     * Throws a Zend_Json_Exception if the XML tree is deeper than the allowed limit.
+     *
+     * @static
+     * @access protected
+     * @param SimpleXMLElement $simpleXmlElementObject XML element to be converted
+     * @param boolean $ignoreXmlAttributes Include or exclude XML attributes in
+     * the xml2json conversion process.
+     * @param int $recursionDepth Current recursion depth of this function
+     * @return mixed - On success, a PHP associative array of traversed XML elements
+     * @throws Zend_Json_Exception
+     */
+    protected static function _processXml ($simpleXmlElementObject, $ignoreXmlAttributes, $recursionDepth=0) {
+        // Keep an eye on how deeply we are involved in recursion.
+        if ($recursionDepth > self::$maxRecursionDepthAllowed) {
+            // XML tree is too deep. Exit now by throwing an exception.
+            require_once 'Zend/Json/Exception.php';
+            throw new Zend_Json_Exception(
+                "Function _processXml exceeded the allowed recursion depth of " .
+                self::$maxRecursionDepthAllowed);
+        } // End of if ($recursionDepth > self::$maxRecursionDepthAllowed)
+
+        if ($recursionDepth == 0) {
+            // Store the original SimpleXmlElementObject sent by the caller.
+            // We will need it at the very end when we return from here for good.
+            $callerProvidedSimpleXmlElementObject = $simpleXmlElementObject;
+        } // End of if ($recursionDepth == 0)
+
+        if ($simpleXmlElementObject instanceof SimpleXMLElement) {
+            // Get a copy of the simpleXmlElementObject
+            $copyOfSimpleXmlElementObject = $simpleXmlElementObject;
+            // Get the object variables in the SimpleXmlElement object for us to iterate.
+            $simpleXmlElementObject = get_object_vars($simpleXmlElementObject);
+        } // End of if (get_class($simpleXmlElementObject) == "SimpleXMLElement")
+
+        // It needs to be an array of object variables.
+        if (is_array($simpleXmlElementObject)) {
+            // Initialize a result array.
+            $resultArray = array();
+            // Is the input array size 0? Then, we reached the rare CDATA text if any.
+            if (count($simpleXmlElementObject) <= 0) {
+                // Let us return the lonely CDATA. It could even be
+                // an empty element or just filled with whitespaces.
+                return (trim(strval($copyOfSimpleXmlElementObject)));
+            } // End of if (count($simpleXmlElementObject) <= 0)
+
+            // Let us walk through the child elements now.
+            foreach($simpleXmlElementObject as $key=>$value) {
+                // Check if we need to ignore the XML attributes.
+                // If yes, you can skip processing the XML attributes.
+                // Otherwise, add the XML attributes to the result array.
+                if(($ignoreXmlAttributes == true) && (is_string($key)) && ($key == "@attributes")) {
+                    continue;
+                } // End of if(($ignoreXmlAttributes == true) && ($key == "@attributes"))
+
+                // Let us recursively process the current XML element we just visited.
+                // Increase the recursion depth by one.
+                $recursionDepth++;
+                $resultArray[$key] = self::_processXml ($value, $ignoreXmlAttributes, $recursionDepth);
+
+                // Decrease the recursion depth by one.
+                $recursionDepth--;
+            } // End of foreach($simpleXmlElementObject as $key=>$value) {
+
+            if ($recursionDepth == 0) {
+                // That is it. We are heading to the exit now.
+                // Set the XML root element name as the root [top-level] key of
+                // the associative array that we are going to return to the original
+                // caller of this recursive function.
+                $tempArray = $resultArray;
+                $resultArray = array();
+                $resultArray[$callerProvidedSimpleXmlElementObject->getName()] = $tempArray;
+            } // End of if ($recursionDepth == 0)
+
+            return($resultArray);
+        } else {
+            // We are now looking at either the XML attribute text or
+            // the text between the XML tags.
+
+            // In order to allow Zend_Json_Expr from xml, we check if the node
+            // matchs the pattern that try to detect if it is a new Zend_Json_Expr
+            // if it matches, we return a new Zend_Json_Expr instead of a text node
+            $pattern = '/^[\s]*new Zend_Json_Expr[\s]*\([\s]*[\"\']{1}(.*)[\"\']{1}[\s]*\)[\s]*$/';
+            $matchings = array();
+            $match = preg_match ($pattern, $simpleXmlElementObject, $matchings);
+            if ($match) {
+                return new Zend_Json_Expr($matchings[1]);
+            } else {
+                return (trim(strval($simpleXmlElementObject)));
+            }
+
+        } // End of if (is_array($simpleXmlElementObject))
+    } // End of function _processXml.
+}
diff --git a/lib/zend/Zend/Layout.php b/lib/zend/Zend/Layout.php
new file mode 100644 (file)
index 0000000..e1cc310
--- /dev/null
@@ -0,0 +1,795 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Layout
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/**
+ * Provide Layout support for MVC applications
+ *
+ * @category   Zend
+ * @package    Zend_Layout
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Layout
+{
+    /**
+     * Placeholder container for layout variables
+     * @var Zend_View_Helper_Placeholder_Container
+     */
+    protected $_container;
+
+    /**
+     * Key used to store content from 'default' named response segment
+     * @var string
+     */
+    protected $_contentKey = 'content';
+
+    /**
+     * Are layouts enabled?
+     * @var bool
+     */
+    protected $_enabled = true;
+
+    /**
+     * Helper class
+     * @var string
+     */
+    protected $_helperClass = 'Zend_Layout_Controller_Action_Helper_Layout';
+    /**
+     * Inflector used to resolve layout script
+     * @var Zend_Filter_Inflector
+     */
+    protected $_inflector;
+
+    /**
+     * Flag: is inflector enabled?
+     * @var bool
+     */
+    protected $_inflectorEnabled = true;
+
+    /**
+     * Inflector target
+     * @var string
+     */
+    protected $_inflectorTarget = ':script.:suffix';
+
+    /**
+     * Layout view
+     * @var string
+     */
+    protected $_layout = 'layout';
+
+    /**
+     * Layout view script path
+     * @var string
+     */
+    protected $_viewScriptPath = null;
+    
+    protected $_viewBasePath = null;
+    protected $_viewBasePrefix = 'Layout_View';
+
+    /**
+     * Flag: is MVC integration enabled?
+     * @var bool
+     */
+    protected $_mvcEnabled = true;
+
+    /**
+     * Instance registered with MVC, if any
+     * @var Zend_Layout
+     */
+    protected static $_mvcInstance;
+
+    /**
+     * Flag: is MVC successful action only flag set?
+     * @var bool
+     */
+    protected $_mvcSuccessfulActionOnly = true;
+
+    /**
+     * Plugin class
+     * @var string
+     */
+    protected $_pluginClass = 'Zend_Layout_Controller_Plugin_Layout';
+    
+    /**
+     * @var Zend_View_Interface
+     */
+    protected $_view;
+
+    /**
+     * View script suffix for layout script
+     * @var string
+     */
+    protected $_viewSuffix = 'phtml';
+
+    /**
+     * Constructor
+     *
+     * Accepts either:
+     * - A string path to layouts
+     * - An array of options
+     * - A Zend_Config object with options
+     *
+     * Layout script path, either as argument or as key in options, is 
+     * required.
+     *
+     * If mvcEnabled flag is false from options, simply sets layout script path. 
+     * Otherwise, also instantiates and registers action helper and controller 
+     * plugin.
+     * 
+     * @param  string|array|Zend_Config $options 
+     * @return void
+     */ 
+    public function __construct($options = null, $initMvc = false) 
+    { 
+        if (null !== $options) {
+            if (is_string($options)) {
+                $this->setLayoutPath($options);
+            } elseif (is_array($options)) {
+                $this->setOptions($options);
+            } elseif ($options instanceof Zend_Config) {
+                $this->setConfig($options);
+            } else {
+                require_once 'Zend/Layout/Exception.php';
+                throw new Zend_Layout_Exception('Invalid option provided to constructor');
+            }
+        }
+
+        $this->_initVarContainer();
+
+        if ($initMvc) {
+            $this->_setMvcEnabled(true);
+            $this->_initMvc();
+        } else {
+            $this->_setMvcEnabled(false);
+        }
+    }
+
+    /**
+     * Static method for initialization with MVC support
+     * 
+     * @param  string|array|Zend_Config $options 
+     * @return Zend_Layout
+     */
+    public static function startMvc($options = null)
+    {
+        if (null === self::$_mvcInstance) {
+            self::$_mvcInstance = new self($options, true);
+        }
+        
+        if (is_string($options)) {
+            self::$_mvcInstance->setLayoutPath($options);
+        } elseif (is_array($options) || $options instanceof Zend_Config) {
+            self::$_mvcInstance->setOptions($options);
+        }
+
+        return self::$_mvcInstance;
+    }
+
+    /**
+     * Retrieve MVC instance of Zend_Layout object
+     * 
+     * @return Zend_Layout|null
+     */
+    public static function getMvcInstance()
+    {
+        return self::$_mvcInstance;
+    }
+
+    /**
+     * Reset MVC instance
+     *
+     * Unregisters plugins and helpers, and destroys MVC layout instance.
+     * 
+     * @return void
+     */
+    public static function resetMvcInstance()
+    {
+        if (null !== self::$_mvcInstance) {
+            $layout = self::$_mvcInstance;
+            $pluginClass = $layout->getPluginClass();
+            $front = Zend_Controller_Front::getInstance();
+            if ($front->hasPlugin($pluginClass)) {
+                $front->unregisterPlugin($pluginClass);
+            }
+
+            if (Zend_Controller_Action_HelperBroker::hasHelper('layout')) {
+                Zend_Controller_Action_HelperBroker::removeHelper('layout');
+            }
+
+            unset($layout);
+            self::$_mvcInstance = null;
+        }
+    }
+
+    /**
+     * Set options en masse
+     * 
+     * @param  array|Zend_Config $options 
+     * @return void
+     */
+    public function setOptions($options)
+    {
+        if ($options instanceof Zend_Config) {
+            $options = $options->toArray();
+        } elseif (!is_array($options)) {
+            require_once 'Zend/Layout/Exception.php';
+            throw new Zend_Layout_Exception('setOptions() expects either an array or a Zend_Config object');
+        }
+
+        foreach ($options as $key => $value) {
+            $method = 'set' . ucfirst($key);
+            if (method_exists($this, $method)) {
+                $this->$method($value);
+            }
+        }
+    }
+
+    /**
+     * Initialize MVC integration
+     * 
+     * @return void
+     */
+    protected function _initMvc()
+    {
+        $this->_initPlugin();
+        $this->_initHelper();
+    }
+
+    /**
+     * Initialize front controller plugin
+     * 
+     * @return void
+     */
+    protected function _initPlugin()
+    {
+        $pluginClass = $this->getPluginClass();
+        require_once 'Zend/Controller/Front.php';
+        $front = Zend_Controller_Front::getInstance();
+        if (!$front->hasPlugin($pluginClass)) {
+            if (!class_exists($pluginClass)) {
+                require_once 'Zend/Loader.php';
+                Zend_Loader::loadClass($pluginClass);
+            }
+            $front->registerPlugin(
+                // register to run last | BUT before the ErrorHandler (if its available)
+                new $pluginClass($this), 
+                99
+            );
+        }
+    }
+
+    /**
+     * Initialize action helper
+     * 
+     * @return void
+     */
+    protected function _initHelper()
+    {
+        $helperClass = $this->getHelperClass();
+        require_once 'Zend/Controller/Action/HelperBroker.php';
+        if (!Zend_Controller_Action_HelperBroker::hasHelper('layout')) {
+            if (!class_exists($helperClass)) {
+                require_once 'Zend/Loader.php';
+                Zend_Loader::loadClass($helperClass);
+            }
+            Zend_Controller_Action_HelperBroker::getStack()->offsetSet(-90, new $helperClass($this));
+        }
+    }
+
+    /**
+     * Set options from a config object
+     * 
+     * @param  Zend_Config $config 
+     * @return Zend_Layout
+     */
+    public function setConfig(Zend_Config $config)
+    {
+        $this->setOptions($config->toArray());
+        return $this;
+    }
+
+    /**
+     * Initialize placeholder container for layout vars
+     * 
+     * @return Zend_View_Helper_Placeholder_Container
+     */
+    protected function _initVarContainer()
+    {
+        if (null === $this->_container) {
+            require_once 'Zend/View/Helper/Placeholder/Registry.php';
+            $this->_container = Zend_View_Helper_Placeholder_Registry::getRegistry()->getContainer(__CLASS__);
+        }
+
+        return $this->_container;
+    }
+
+    /**
+     * Set layout script to use
+     *
+     * Note: enables layout.
+     * 
+     * @param  string $name 
+     * @return Zend_Layout
+     */ 
+    public function setLayout($name) 
+    {
+        $this->_layout = (string) $name;
+        $this->enableLayout();
+        return $this;
+    }
+    /**
+     * Get current layout script
+     * 
+     * @return string
+     */ 
+    public function getLayout() 
+    {
+        return $this->_layout;
+    } 
+    /**
+     * Disable layout
+     *
+     * @return Zend_Layout
+     */ 
+    public function disableLayout() 
+    {
+        $this->_enabled = false;
+        return $this;
+    } 
+
+    /**
+     * Enable layout 
+     * 
+     * @return Zend_Layout
+     */
+    public function enableLayout()
+    {
+        $this->_enabled = true;
+        return $this;
+    }
+
+    /**
+     * Is layout enabled?
+     * 
+     * @return bool
+     */
+    public function isEnabled()
+    {
+        return $this->_enabled;
+    }
+
+    
+    public function setViewBasePath($path, $prefix = 'Layout_View')
+    {
+        $this->_viewBasePath = $path;
+        $this->_viewBasePrefix = $prefix;
+        return $this;
+    }
+    
+    public function getViewBasePath()
+    {
+        return $this->_viewBasePath;
+    }
+    
+    public function setViewScriptPath($path)
+    {
+        $this->_viewScriptPath = $path;
+        return $this;
+    }
+    
+    public function getViewScriptPath()
+    {
+        return $this->_viewScriptPath;
+    }
+    
+    /**
+     * Set layout script path
+     * 
+     * @param  string $path 
+     * @return Zend_Layout
+     */ 
+    public function setLayoutPath($path) 
+    {
+        return $this->setViewScriptPath($path);
+    } 
+    
+    /**
+     * Get current layout script path
+     * 
+     * @return string
+     */ 
+    public function getLayoutPath() 
+    {
+        return $this->getViewScriptPath();
+    } 
+
+    /**
+     * Set content key
+     *
+     * Key in namespace container denoting default content
+     *
+     * @param  string $contentKey
+     * @return Zend_Layout
+     */
+    public function setContentKey($contentKey)
+    {
+        $this->_contentKey = (string) $contentKey;
+        return $this;
+    }
+
+    /**
+     * Retrieve content key
+     *
+     * @return string
+     */
+    public function getContentKey()
+    {
+        return $this->_contentKey;
+    }
+
+    /**
+     * Set MVC enabled flag
+     *
+     * @param  bool $mvcEnabled
+     * @return Zend_Layout
+     */
+    protected function _setMvcEnabled($mvcEnabled)
+    {
+        $this->_mvcEnabled = ($mvcEnabled) ? true : false;
+        return $this;
+    }
+
+    /**
+     * Retrieve MVC enabled flag
+     *
+     * @return bool
+     */
+    public function getMvcEnabled()
+    {
+        return $this->_mvcEnabled;
+    }
+
+    /**
+     * Set MVC Successful Action Only flag
+     *
+     * @param bool $successfulActionOnly
+     * @return Zend_Layout
+     */
+    public function setMvcSuccessfulActionOnly($successfulActionOnly)
+    {
+        $this->_mvcSuccessfulActionOnly = ($successfulActionOnly) ? true : false;
+        return $this;
+    }
+    
+    /**
+     * Get MVC Successful Action Only Flag
+     *
+     * @return bool
+     */
+    public function getMvcSuccessfulActionOnly()
+    {
+        return $this->_mvcSuccessfulActionOnly;
+    }
+    
+    /**
+     * Set view object
+     * 
+     * @param  Zend_View_Interface $view
+     * @return Zend_Layout
+     */ 
+    public function setView(Zend_View_Interface $view) 
+    {
+        $this->_view = $view;
+        return $this;
+    } 
+
+    /**
+     * Retrieve helper class
+     *
+     * @return string
+     */
+    public function getHelperClass()
+    {
+        return $this->_helperClass;
+    }
+
+    /**
+     * Set helper class
+     *
+     * @param  string $helperClass
+     * @return Zend_Layout
+     */
+    public function setHelperClass($helperClass)
+    {
+        $this->_helperClass = (string) $helperClass;
+        return $this;
+    }
+
+    /**
+     * Retrieve plugin class
+     *
+     * @return string
+     */
+    public function getPluginClass()
+    {
+        return $this->_pluginClass;
+    }
+
+    /**
+     * Set plugin class
+     *
+     * @param  string $pluginClass
+     * @return Zend_Layout
+     */
+    public function setPluginClass($pluginClass)
+    {
+        $this->_pluginClass = (string) $pluginClass;
+        return $this;
+    }
+    /**
+     * Get current view object
+     *
+     * If no view object currently set, retrieves it from the ViewRenderer.
+     * 
+     * @todo Set inflector from view renderer at same time
+     * @return Zend_View_Interface
+     */ 
+    public function getView() 
+    {
+        if (null === $this->_view) {
+            require_once 'Zend/Controller/Action/HelperBroker.php';
+            $viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
+            if (null === $viewRenderer->view) {
+                $viewRenderer->initView();
+            }
+            $this->setView($viewRenderer->view);
+        }
+        return $this->_view;
+    } 
+
+    /**
+     * Set layout view script suffix
+     *
+     * @param  string $viewSuffix
+     * @return Zend_Layout
+     */
+    public function setViewSuffix($viewSuffix)
+    {
+        $this->_viewSuffix = (string) $viewSuffix;
+        return $this;
+    }
+    /**
+     * Retrieve layout view script suffix
+     *
+     * @return string
+     */
+    public function getViewSuffix()
+    {
+        return $this->_viewSuffix;
+    }
+
+    /**
+     * Retrieve inflector target
+     *
+     * @return string
+     */
+    public function getInflectorTarget()
+    {
+        return $this->_inflectorTarget;
+    }
+
+    /**
+     * Set inflector target
+     *
+     * @param  string $inflectorTarget
+     * @return Zend_Layout
+     */
+    public function setInflectorTarget($inflectorTarget)
+    {
+        $this->_inflectorTarget = (string) $inflectorTarget;
+        return $this;
+    }
+
+    /**
+     * Set inflector to use when resolving layout names
+     *
+     * @param  Zend_Filter_Inflector $inflector
+     * @return Zend_Layout
+     */
+    public function setInflector(Zend_Filter_Inflector $inflector)
+    {
+        $this->_inflector = $inflector;
+        return $this;
+    }
+
+    /**
+     * Retrieve inflector
+     *
+     * @return Zend_Filter_Inflector
+     */
+    public function getInflector()
+    {
+        if (null === $this->_inflector) {
+            require_once 'Zend/Filter/Inflector.php';
+            $inflector = new Zend_Filter_Inflector();
+            $inflector->setTargetReference($this->_inflectorTarget)
+                      ->addRules(array(':script' => array('Word_CamelCaseToDash', 'StringToLower')))
+                      ->setStaticRuleReference('suffix', $this->_viewSuffix);
+            $this->setInflector($inflector);
+        }
+
+        return $this->_inflector;
+    }
+
+    /**
+     * Enable inflector
+     * 
+     * @return Zend_Layout
+     */
+    public function enableInflector()
+    {
+        $this->_inflectorEnabled = true;
+        return $this;
+    }
+
+    /**
+     * Disable inflector
+     * 
+     * @return Zend_Layout
+     */
+    public function disableInflector()
+    {
+        $this->_inflectorEnabled = false;
+        return $this;
+    }
+
+    /**
+     * Return status of inflector enabled flag
+     * 
+     * @return bool
+     */
+    public function inflectorEnabled()
+    {
+        return $this->_inflectorEnabled;
+    }
+
+    /**
+     * Set layout variable
+     * 
+     * @param  string $key 
+     * @param  mixed $value 
+     * @return void
+     */ 
+    public function __set($key, $value) 
+    {
+        $this->_container[$key] = $value;
+    }
+    /**
+     * Get layout variable
+     * 
+     * @param  string $key
+     * @return mixed
+     */ 
+    public function __get($key) 
+    {
+        if (isset($this->_container[$key])) {
+            return $this->_container[$key];
+        }
+
+        return null;
+    }
+    /**
+     * Is a layout variable set?
+     *
+     * @param  string $key
+     * @return bool
+     */ 
+    public function __isset($key) 
+    {
+        return (isset($this->_container[$key]));
+    } 
+    /**
+     * Unset a layout variable?
+     *
+     * @param  string $key
+     * @return void
+     */ 
+    public function __unset($key) 
+    {
+        if (isset($this->_container[$key])) {
+            unset($this->_container[$key]);
+        }
+    } 
+    /**
+     * Assign one or more layout variables
+     * 
+     * @param  mixed $spec Assoc array or string key; if assoc array, sets each
+     * key as a layout variable
+     * @param  mixed $value Value if $spec is a key
+     * @return Zend_Layout
+     * @throws Zend_Layout_Exception if non-array/string value passed to $spec
+     */ 
+    public function assign($spec, $value = null) 
+    {
+        if (is_array($spec)) {
+            $orig = $this->_container->getArrayCopy();
+            $merged = array_merge($orig, $spec);
+            $this->_container->exchangeArray($merged);
+            return $this;
+        }
+
+        if (is_string($spec)) {
+            $this->_container[$spec] = $value;
+            return $this;
+        }
+
+        require_once 'Zend/Layout/Exception.php';
+        throw new Zend_Layout_Exception('Invalid values passed to assign()');
+    }
+
+    /**
+     * Render layout
+     *
+     * Sets internal script path as last path on script path stack, assigns 
+     * layout variables to view, determines layout name using inflector, and 
+     * renders layout view script.
+     *
+     * $name will be passed to the inflector as the key 'script'.
+     * 
+     * @param  mixed $name 
+     * @return mixed
+     */ 
+    public function render($name = null) 
+    { 
+        if (null === $name) {
+            $name = $this->getLayout();
+        }
+
+        if ($this->inflectorEnabled() && (null !== ($inflector = $this->getInflector())))
+        {
+            $name = $this->_inflector->filter(array('script' => $name));
+        }
+
+        $view = $this->getView();
+
+        if (null !== ($path = $this->getViewScriptPath())) {
+            if (method_exists($view, 'addScriptPath')) {
+                $view->addScriptPath($path);
+            } else {
+                $view->setScriptPath($path);
+            }
+        } elseif (null !== ($path = $this->getViewBasePath())) {
+            $view->addBasePath($path, $this->_viewBasePrefix);
+        }
+
+        return $view->render($name);
+    }
+}
diff --git a/lib/zend/Zend/Ldap.php b/lib/zend/Zend/Ldap.php
new file mode 100644 (file)
index 0000000..cb74de3
--- /dev/null
@@ -0,0 +1,1476 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Ldap
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/**
+ * @category   Zend
+ * @package    Zend_Ldap
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Ldap
+{
+    const SEARCH_SCOPE_SUB  = 1;
+    const SEARCH_SCOPE_ONE  = 2;
+    const SEARCH_SCOPE_BASE = 3;
+
+    const ACCTNAME_FORM_DN        = 1;
+    const ACCTNAME_FORM_USERNAME  = 2;
+    const ACCTNAME_FORM_BACKSLASH = 3;
+    const ACCTNAME_FORM_PRINCIPAL = 4;
+
+    /**
+     * String used with ldap_connect for error handling purposes.
+     *
+     * @var string
+     */
+    private $_connectString;
+
+    /**
+     * The options used in connecting, binding, etc.
+     *
+     * @var array
+     */
+    protected $_options = null;
+
+    /**
+     * The raw LDAP extension resource.
+     *
+     * @var resource
+     */
+    protected $_resource = null;
+
+    /**
+     * Caches the RootDSE
+     *
+     * @var Zend_Ldap_Node
+     */
+    protected $_rootDse = null;
+
+    /**
+     * Caches the schema
+     *
+     * @var Zend_Ldap_Node
+     */
+    protected $_schema = null;
+
+    /**
+     * @deprecated will be removed, use {@see Zend_Ldap_Filter_Abstract::escapeValue()}
+     * @param  string $str The string to escape.
+     * @return string The escaped string
+     */
+    public static function filterEscape($str)
+    {
+        /**
+         * @see Zend_Ldap_Filter_Abstract
+         */
+        require_once 'Zend/Ldap/Filter/Abstract.php';
+        return Zend_Ldap_Filter_Abstract::escapeValue($str);
+    }
+
+    /**
+     * @deprecated will be removed, use {@see Zend_Ldap_Dn::checkDn()}
+     * @param  string $dn   The DN to parse
+     * @param  array  $keys An optional array to receive DN keys (e.g. CN, OU, DC, ...)
+     * @param  array  $vals An optional array to receive DN values
+     * @return boolean True if the DN was successfully parsed or false if the string is
+     * not a valid DN.
+     */
+    public static function explodeDn($dn, array &$keys = null, array &$vals = null)
+    {
+        /**
+         * @see Zend_Ldap_Dn
+         */
+        require_once 'Zend/Ldap/Dn.php';
+        return Zend_Ldap_Dn::checkDn($dn, $keys, $vals);
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param  array|Zend_Config $options Options used in connecting, binding, etc.
+     * @return void
+     */
+    public function __construct($options = array())
+    {
+        $this->setOptions($options);
+    }
+
+    /**
+     * Destructor.
+     *
+     * @return void
+     */
+    public function __destruct()
+    {
+        $this->disconnect();
+    }
+
+    /**
+     * @return resource The raw LDAP extension resource.
+     */
+    public function getResource()
+    {
+        return $this->_resource;
+    }
+
+    /**
+     * Return the LDAP error number of the last LDAP command
+     *
+     * @return int
+     */
+    public function getLastErrorCode()
+    {
+        $ret = @ldap_get_option($this->getResource(), LDAP_OPT_ERROR_NUMBER, $err);
+        if ($ret === true) {
+            if ($err <= -1 && $err >= -17) {
+                /**
+                 * @see Zend_Ldap_Exception
+                 */
+                require_once 'Zend/Ldap/Exception.php';
+                /* For some reason draft-ietf-ldapext-ldap-c-api-xx.txt error
+                 * codes in OpenLDAP are negative values from -1 to -17.
+                 */
+                $err = Zend_Ldap_Exception::LDAP_SERVER_DOWN + (-$err - 1);
+            }
+            return $err;
+        }
+        return 0;
+    }
+
+    /**
+     * Return the LDAP error message of the last LDAP command
+     *
+     * @param  int   $errorCode
+     * @param  array $errorMessages
+     * @return string
+     */
+    public function getLastError(&$errorCode = null, array &$errorMessages = null)
+    {
+        $errorCode = $this->getLastErrorCode();
+        $errorMessages = array();
+
+        /* The various error retrieval functions can return
+         * different things so we just try to collect what we
+         * can and eliminate dupes.
+         */
+        $estr1 = @ldap_error($this->getResource());
+        if ($errorCode !== 0 && $estr1 === 'Success') {
+            $estr1 = @ldap_err2str($errorCode);
+        }
+        if (!empty($estr1)) {
+            $errorMessages[] = $estr1;
+        }
+
+        @ldap_get_option($this->getResource(), LDAP_OPT_ERROR_STRING, $estr2);
+        if (!empty($estr2) && !in_array($estr2, $errorMessages)) {
+            $errorMessages[] = $estr2;
+        }
+
+        $message = '';
+        if ($errorCode > 0) {
+            $message = '0x' . dechex($errorCode) . ' ';
+        } else {
+            $message = '';
+        }
+        if (count($errorMessages) > 0) {
+            $message .= '(' . implode('; ', $errorMessages) . ')';
+        } else {
+            $message .= '(no error message from LDAP)';
+        }
+        return $message;
+    }
+
+    /**
+     * Sets the options used in connecting, binding, etc.
+     *
+     * Valid option keys:
+     *  host
+     *  port
+     *  useSsl
+     *  username
+     *  password
+     *  bindRequiresDn
+     *  baseDn
+     *  accountCanonicalForm
+     *  accountDomainName
+     *  accountDomainNameShort
+     *  accountFilterFormat
+     *  allowEmptyPassword
+     *  useStartTls
+     *  optRefferals
+     *  tryUsernameSplit
+     *
+     * @param  array|Zend_Config $options Options used in connecting, binding, etc.
+     * @return Zend_Ldap Provides a fluent interface
+     * @throws Zend_Ldap_Exception
+     */
+    public function setOptions($options)
+    {
+        if ($options instanceof Zend_Config) {
+            $options = $options->toArray();
+        }
+
+        $permittedOptions = array(
+            'host'                   => null,
+            'port'                   => 0,
+            'useSsl'                 => false,
+            'username'               => null,
+            'password'               => null,
+            'bindRequiresDn'         => false,
+            'baseDn'                 => null,
+            'accountCanonicalForm'   => null,
+            'accountDomainName'      => null,
+            'accountDomainNameShort' => null,
+            'accountFilterFormat'    => null,
+            'allowEmptyPassword'     => false,
+            'useStartTls'            => false,
+            'optReferrals'           => false,
+            'tryUsernameSplit'       => true,
+        );
+
+        foreach ($permittedOptions as $key => $val) {
+            if (array_key_exists($key, $options)) {
+                $val = $options[$key];
+                unset($options[$key]);
+                /* Enforce typing. This eliminates issues like Zend_Config_Ini
+                 * returning '1' as a string (ZF-3163).
+                 */
+                switch ($key) {
+                    case 'port':
+                    case 'accountCanonicalForm':
+                        $permittedOptions[$key] = (int)$val;
+                        break;
+                    case 'useSsl':
+                    case 'bindRequiresDn':
+                    case 'allowEmptyPassword':
+                    case 'useStartTls':
+                    case 'optReferrals':
+                    case 'tryUsernameSplit':
+                        $permittedOptions[$key] = ($val === true ||
+                                $val === '1' || strcasecmp($val, 'true') == 0);
+                        break;
+                    default:
+                        $permittedOptions[$key] = trim($val);
+                        break;
+                }
+            }
+        }
+        if (count($options) > 0) {
+            $key = key($options);
+            /**
+             * @see Zend_Ldap_Exception
+             */
+            require_once 'Zend/Ldap/Exception.php';
+            throw new Zend_Ldap_Exception(null, "Unknown Zend_Ldap option: $key");
+        }
+        $this->_options = $permittedOptions;
+        return $this;
+    }
+
+    /**
+     * @return array The current options.
+     */
+    public function getOptions()
+    {
+        return $this->_options;
+    }
+
+    /**
+     * @return string The hostname of the LDAP server being used to authenticate accounts
+     */
+    protected function _getHost()
+    {
+        return $this->_options['host'];
+    }
+
+    /**
+     * @return int The port of the LDAP server or 0 to indicate that no port value is set
+     */
+    protected function _getPort()
+    {
+        return $this->_options['port'];
+    }
+
+    /**
+     * @return boolean The default SSL / TLS encrypted transport control
+     */
+    protected function _getUseSsl()
+    {
+        return $this->_options['useSsl'];
+    }
+
+    /**
+     * @return string The default acctname for binding
+     */
+    protected function _getUsername()
+    {
+        return $this->_options['username'];
+    }
+
+    /**
+     * @return string The default password for binding
+     */
+    protected function _getPassword()
+    {
+        return $this->_options['password'];
+    }
+
+    /**
+     * @return boolean Bind requires DN
+     */
+    protected function _getBindRequiresDn()
+    {
+        return $this->_options['bindRequiresDn'];
+    }
+
+    /**
+     * Gets the base DN under which objects of interest are located
+     *
+     * @return string
+     */
+    public function getBaseDn()
+    {
+        return $this->_options['baseDn'];
+    }
+
+    /**
+     * @return integer Either ACCTNAME_FORM_BACKSLASH, ACCTNAME_FORM_PRINCIPAL or
+     * ACCTNAME_FORM_USERNAME indicating the form usernames should be canonicalized to.
+     */
+    protected function _getAccountCanonicalForm()
+    {
+        /* Account names should always be qualified with a domain. In some scenarios
+         * using non-qualified account names can lead to security vulnerabilities. If
+         * no account canonical form is specified, we guess based in what domain
+         * names have been supplied.
+         */
+
+        $accountCanonicalForm = $this->_options['accountCanonicalForm'];
+        if (!$accountCanonicalForm) {
+            $accountDomainName = $this->_getAccountDomainName();
+            $accountDomainNameShort = $this->_getAccountDomainNameShort();
+            if ($accountDomainNameShort) {
+                $accountCanonicalForm = Zend_Ldap::ACCTNAME_FORM_BACKSLASH;
+            } else if ($accountDomainName) {
+                $accountCanonicalForm = Zend_Ldap::ACCTNAME_FORM_PRINCIPAL;
+            } else {
+                $accountCanonicalForm = Zend_Ldap::ACCTNAME_FORM_USERNAME;
+            }
+        }
+
+        return $accountCanonicalForm;
+    }
+
+    /**
+     * @return string The account domain name
+     */
+    protected function _getAccountDomainName()
+    {
+        return $this->_options['accountDomainName'];
+    }
+
+    /**
+     * @return string The short account domain name
+     */
+    protected function _getAccountDomainNameShort()
+    {
+        return $this->_options['accountDomainNameShort'];
+    }
+
+    /**
+     * @return string A format string for building an LDAP search filter to match
+     * an account
+     */
+    protected function _getAccountFilterFormat()
+    {
+        return $this->_options['accountFilterFormat'];
+    }
+
+    /**
+     * @return boolean Allow empty passwords
+     */
+    protected function _getAllowEmptyPassword()
+    {
+        return $this->_options['allowEmptyPassword'];
+    }
+
+    /**
+     * @return boolean The default SSL / TLS encrypted transport control
+     */
+    protected function _getUseStartTls()
+    {
+        return $this->_options['useStartTls'];
+    }
+
+    /**
+     * @return boolean Opt. Referrals
+     */
+    protected function _getOptReferrals()
+    {
+        return $this->_options['optReferrals'];
+    }
+
+    /**
+     * @return boolean Try splitting the username into username and domain
+     */
+    protected function _getTryUsernameSplit()
+    {
+        return $this->_options['tryUsernameSplit'];
+    }
+
+    /**
+     * @return string The LDAP search filter for matching directory accounts
+     */
+    protected function _getAccountFilter($acctname)
+    {
+        /**
+         * @see Zend_Ldap_Filter_Abstract
+         */
+        require_once 'Zend/Ldap/Filter/Abstract.php';
+        $this->_splitName($acctname, $dname, $aname);
+        $accountFilterFormat = $this->_getAccountFilterFormat();
+        $aname = Zend_Ldap_Filter_Abstract::escapeValue($aname);
+        if ($accountFilterFormat) {
+            return sprintf($accountFilterFormat, $aname);
+        }
+        if (!$this->_getBindRequiresDn()) {
+            // is there a better way to detect this?
+            return sprintf("(&(objectClass=user)(sAMAccountName=%s))", $aname);
+        }
+        return sprintf("(&(objectClass=posixAccount)(uid=%s))", $aname);
+    }
+
+    /**
+     * @param string $name  The name to split
+     * @param string $dname The resulting domain name (this is an out parameter)
+     * @param string $aname The resulting account name (this is an out parameter)
+     * @return void
+     */
+    protected function _splitName($name, &$dname, &$aname)
+    {
+        $dname = null;
+        $aname = $name;
+
+        if (!$this->_getTryUsernameSplit()) {
+            return;
+        }
+
+        $pos = strpos($name, '@');
+        if ($pos) {
+            $dname = substr($name, $pos + 1);
+            $aname = substr($name, 0, $pos);
+        } else {
+            $pos = strpos($name, '\\');
+            if ($pos) {
+                $dname = substr($name, 0, $pos);
+                $aname = substr($name, $pos + 1);
+            }
+        }
+    }
+
+    /**
+     * @param  string $acctname The name of the account
+     * @return string The DN of the specified account
+     * @throws Zend_Ldap_Exception
+     */
+    protected function _getAccountDn($acctname)
+    {
+        /**
+         * @see Zend_Ldap_Dn
+         */
+        require_once 'Zend/Ldap/Dn.php';
+        if (Zend_Ldap_Dn::checkDn($acctname)) return $acctname;
+        $acctname = $this->getCanonicalAccountName($acctname, Zend_Ldap::ACCTNAME_FORM_USERNAME);
+        $acct = $this->_getAccount($acctname, array('dn'));
+        return $acct['dn'];
+    }
+
+    /**
+     * @param  string $dname The domain name to check
+     * @return boolean
+     */
+    protected function _isPossibleAuthority($dname)
+    {
+        if ($dname === null) {
+            return true;
+        }
+        $accountDomainName = $this->_getAccountDomainName();
+        $accountDomainNameShort = $this->_getAccountDomainNameShort();
+        if ($accountDomainName === null && $accountDomainNameShort === null) {
+            return true;
+        }
+        if (strcasecmp($dname, $accountDomainName) == 0) {
+            return true;
+        }
+        if (strcasecmp($dname, $accountDomainNameShort) == 0) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * @param  string $acctname The name to canonicalize
+     * @param  int    $type     The desired form of canonicalization
+     * @return string The canonicalized name in the desired form
+     * @throws Zend_Ldap_Exception
+     */
+    public function getCanonicalAccountName($acctname, $form = 0)
+    {
+        $this->_splitName($acctname, $dname, $uname);
+
+        if (!$this->_isPossibleAuthority($dname)) {
+            /**
+             * @see Zend_Ldap_Exception
+             */
+            require_once 'Zend/Ldap/Exception.php';
+            throw new Zend_Ldap_Exception(null,
+                "Binding domain is not an authority for user: $acctname",
+                Zend_Ldap_Exception::LDAP_X_DOMAIN_MISMATCH);
+        }
+
+        if (!$uname) {
+            /**
+             * @see Zend_Ldap_Exception
+             */
+            require_once 'Zend/Ldap/Exception.php';
+            throw new Zend_Ldap_Exception(null, "Invalid account name syntax: $acctname");
+        }
+
+        if (function_exists('mb_strtolower')) {
+            $uname = mb_strtolower($uname, 'UTF-8');
+        } else {
+            $uname = strtolower($uname);
+        }
+
+        if ($form === 0) {
+            $form = $this->_getAccountCanonicalForm();
+        }
+
+        switch ($form) {
+            case Zend_Ldap::ACCTNAME_FORM_DN:
+                return $this->_getAccountDn($acctname);
+            case Zend_Ldap::ACCTNAME_FORM_USERNAME:
+                return $uname;
+            case Zend_Ldap::ACCTNAME_FORM_BACKSLASH:
+                $accountDomainNameShort = $this->_getAccountDomainNameShort();
+                if (!$accountDomainNameShort) {
+                    /**
+                     * @see Zend_Ldap_Exception
+                     */
+                    require_once 'Zend/Ldap/Exception.php';
+                    throw new Zend_Ldap_Exception(null, 'Option required: accountDomainNameShort');
+                }
+                return "$accountDomainNameShort\\$uname";
+            case Zend_Ldap::ACCTNAME_FORM_PRINCIPAL:
+                $accountDomainName = $this->_getAccountDomainName();
+                if (!$accountDomainName) {
+                    /**
+                     * @see Zend_Ldap_Exception
+                     */
+                    require_once 'Zend/Ldap/Exception.php';
+                    throw new Zend_Ldap_Exception(null, 'Option required: accountDomainName');
+                }
+                return "$uname@$accountDomainName";
+            default:
+                /**
+                 * @see Zend_Ldap_Exception
+                 */
+                require_once 'Zend/Ldap/Exception.php';
+                throw new Zend_Ldap_Exception(null, "Unknown canonical name form: $form");
+        }
+    }
+
+    /**
+     * @param  array $attrs An array of names of desired attributes
+     * @return array An array of the attributes representing the account
+     * @throws Zend_Ldap_Exception
+     */
+    protected function _getAccount($acctname, array $attrs = null)
+    {
+        $baseDn = $this->getBaseDn();
+        if (!$baseDn) {
+            /**
+             * @see Zend_Ldap_Exception
+             */
+            require_once 'Zend/Ldap/Exception.php';
+            throw new Zend_Ldap_Exception(null, 'Base DN not set');
+        }
+
+        $accountFilter = $this->_getAccountFilter($acctname);
+        if (!$accountFilter) {
+            /**
+             * @see Zend_Ldap_Exception
+             */
+            require_once 'Zend/Ldap/Exception.php';
+            throw new Zend_Ldap_Exception(null, 'Invalid account filter');
+        }
+
+        if (!is_resource($this->getResource())) {
+            $this->bind();
+        }
+
+        $accounts = $this->search($accountFilter, $baseDn, self::SEARCH_SCOPE_SUB, $attrs);
+        $count = $accounts->count();
+        if ($count === 1) {
+            $acct = $accounts->getFirst();
+            $accounts->close();
+            return $acct;
+        } else if ($count === 0) {
+            /**
+             * @see Zend_Ldap_Exception
+             */
+            require_once 'Zend/Ldap/Exception.php';
+            $code = Zend_Ldap_Exception::LDAP_NO_SUCH_OBJECT;
+            $str = "No object found for: $accountFilter";
+        } else {
+            /**
+             * @see Zend_Ldap_Exception
+             */
+            require_once 'Zend/Ldap/Exception.php';
+            $code = Zend_Ldap_Exception::LDAP_OPERATIONS_ERROR;
+            $str = "Unexpected result count ($count) for: $accountFilter";
+        }
+        $accounts->close();
+        /**
+         * @see Zend_Ldap_Exception
+         */
+        require_once 'Zend/Ldap/Exception.php';
+        throw new Zend_Ldap_Exception($this, $str, $code);
+    }
+
+    /**
+     * @return Zend_Ldap Provides a fluent interface
+     */
+    public function disconnect()
+    {
+        if (is_resource($this->getResource())) {
+            if (!extension_loaded('ldap')) {
+                /**
+                 * @see Zend_Ldap_Exception
+                 */
+                require_once 'Zend/Ldap/Exception.php';
+                throw new Zend_Ldap_Exception(null, 'LDAP extension not loaded',
+                    Zend_Ldap_Exception::LDAP_X_EXTENSION_NOT_LOADED);
+            }
+            @ldap_unbind($this->getResource());
+        }
+        $this->_resource = null;
+        return $this;
+    }
+
+    /**
+     * @param  string  $host        The hostname of the LDAP server to connect to
+     * @param  int     $port        The port number of the LDAP server to connect to
+     * @param  boolean $useSsl      Use SSL
+     * @param  boolean $useStartTls Use STARTTLS
+     * @return Zend_Ldap Provides a fluent interface
+     * @throws Zend_Ldap_Exception
+     */
+    public function connect($host = null, $port = null, $useSsl = null, $useStartTls = null)
+    {
+        if ($host === null) {
+            $host = $this->_getHost();
+        }
+        if ($port === null) {
+            $port = $this->_getPort();
+        } else {
+            $port = (int)$port;
+        }
+        if ($useSsl === null) {
+            $useSsl = $this->_getUseSsl();
+        } else {
+            $useSsl = (bool)$useSsl;
+        }
+        if ($useStartTls === null) {
+            $useStartTls = $this->_getUseStartTls();
+        } else {
+            $useStartTls = (bool)$useStartTls;
+        }
+
+        if (!$host) {
+            /**
+             * @see Zend_Ldap_Exception
+             */
+            require_once 'Zend/Ldap/Exception.php';
+            throw new Zend_Ldap_Exception(null, 'A host parameter is required');
+        }
+
+        /* To connect using SSL it seems the client tries to verify the server
+         * certificate by default. One way to disable this behavior is to set
+         * 'TLS_REQCERT never' in OpenLDAP's ldap.conf and restarting Apache. Or,
+         * if you really care about the server's cert you can put a cert on the
+         * web server.
+         */
+        $url = ($useSsl) ? "ldaps://$host" : "ldap://$host";
+        if ($port) {
+            $url .= ":$port";
+        }
+
+        /* Because ldap_connect doesn't really try to connect, any connect error
+         * will actually occur during the ldap_bind call. Therefore, we save the
+         * connect string here for reporting it in error handling in bind().
+         */
+        $this->_connectString = $url;
+
+        $this->disconnect();
+
+        if (!extension_loaded('ldap')) {
+            /**
+             * @see Zend_Ldap_Exception
+             */
+            require_once 'Zend/Ldap/Exception.php';
+            throw new Zend_Ldap_Exception(null, 'LDAP extension not loaded',
+                Zend_Ldap_Exception::LDAP_X_EXTENSION_NOT_LOADED);
+        }
+
+        /* Only OpenLDAP 2.2 + supports URLs so if SSL is not requested, just
+         * use the old form.
+         */
+        $resource = ($useSsl) ? @ldap_connect($url) : @ldap_connect($host, $port);
+
+        if (is_resource($resource) === true) {
+            $this->_resource = $resource;
+
+            $optReferrals = ($this->_getOptReferrals()) ? 1 : 0;
+            if (@ldap_set_option($resource, LDAP_OPT_PROTOCOL_VERSION, 3) &&
+                        @ldap_set_option($resource, LDAP_OPT_REFERRALS, $optReferrals)) {
+                if ($useSsl || !$useStartTls || @ldap_start_tls($resource)) {
+                    return $this;
+                }
+            }
+
+            /**
+             * @see Zend_Ldap_Exception
+             */
+            require_once 'Zend/Ldap/Exception.php';
+            $zle = new Zend_Ldap_Exception($this, "$host:$port");
+            $this->disconnect();
+            throw $zle;
+        }
+        /**
+         * @see Zend_Ldap_Exception
+         */
+        require_once 'Zend/Ldap/Exception.php';
+        throw new Zend_Ldap_Exception(null, "Failed to connect to LDAP server: $host:$port");
+    }
+
+    /**
+     * @param  string $username The username for authenticating the bind
+     * @param  string $password The password for authenticating the bind
+     * @return Zend_Ldap Provides a fluent interface
+     * @throws Zend_Ldap_Exception
+     */
+    public function bind($username = null, $password = null)
+    {
+        $moreCreds = true;
+
+        if ($username === null) {
+            $username = $this->_getUsername();
+            $password = $this->_getPassword();
+            $moreCreds = false;
+        }
+
+        if ($username === null) {
+            /* Perform anonymous bind
+             */
+            $password = null;
+        } else {
+            /* Check to make sure the username is in DN form.
+             */
+            /**
+             * @see Zend_Ldap_Dn
+             */
+            require_once 'Zend/Ldap/Dn.php';
+            if (!Zend_Ldap_Dn::checkDn($username)) {
+                if ($this->_getBindRequiresDn()) {
+                    /* moreCreds stops an infinite loop if _getUsername does not
+                     * return a DN and the bind requires it
+                     */
+                    if ($moreCreds) {
+                        try {
+                            $username = $this->_getAccountDn($username);
+                        } catch (Zend_Ldap_Exception $zle) {
+                            switch ($zle->getCode()) {
+                                case Zend_Ldap_Exception::LDAP_NO_SUCH_OBJECT:
+                                case Zend_Ldap_Exception::LDAP_X_DOMAIN_MISMATCH:
+                                case Zend_Ldap_Exception::LDAP_X_EXTENSION_NOT_LOADED:
+                                    throw $zle;
+                            }
+                            throw new Zend_Ldap_Exception(null,
+                                'Failed to retrieve DN for account: ' . $username .
+                                ' [' . $zle->getMessage() . ']',
+                                Zend_Ldap_Exception::LDAP_OPERATIONS_ERROR);
+                        }
+                    } else {
+                        /**
+                         * @see Zend_Ldap_Exception
+                         */
+                        require_once 'Zend/Ldap/Exception.php';
+                        throw new Zend_Ldap_Exception(null, 'Binding requires username in DN form');
+                    }
+                } else {
+                    $username = $this->getCanonicalAccountName($username,
+                        $this->_getAccountCanonicalForm());
+                }
+            }
+        }
+
+        if (!is_resource($this->getResource())) {
+            $this->connect();
+        }
+
+        if ($username !== null && $password === '' && $this->_getAllowEmptyPassword() !== true) {
+            /**
+             * @see Zend_Ldap_Exception
+             */
+            require_once 'Zend/Ldap/Exception.php';
+            $zle = new Zend_Ldap_Exception(null,
+                'Empty password not allowed - see allowEmptyPassword option.');
+        } else {
+            if (@ldap_bind($this->getResource(), $username, $password)) {
+                return $this;
+            }
+
+            $message = ($username === null) ? $this->_connectString : $username;
+            /**
+             * @see Zend_Ldap_Exception
+             */
+            require_once 'Zend/Ldap/Exception.php';
+            switch ($this->getLastErrorCode()) {
+                case Zend_Ldap_Exception::LDAP_SERVER_DOWN:
+                    /* If the error is related to establishing a connection rather than binding,
+                     * the connect string is more informative than the username.
+                     */
+                    $message = $this->_connectString;
+            }
+
+            $zle = new Zend_Ldap_Exception($this, $message);
+        }
+        $this->disconnect();
+        throw $zle;
+    }
+
+    /**
+     * A global LDAP search routine for finding information.
+     *
+     * @param  string|Zend_Ldap_Filter_Abstract $filter
+     * @param  string|Zend_Ldap_Dn|null         $basedn
+     * @param  integer                          $scope
+     * @param  array                            $attributes
+     * @param  string|null                      $sort
+     * @param  string|null                      $collectionClass
+     * @return Zend_Ldap_Collection
+     * @throws Zend_Ldap_Exception
+     */
+    public function search($filter, $basedn = null, $scope = self::SEARCH_SCOPE_SUB,
+        array $attributes = array(), $sort = null, $collectionClass = null)
+    {
+        if ($basedn === null) {
+            $basedn = $this->getBaseDn();
+        }
+        else if ($basedn instanceof Zend_Ldap_Dn) {
+            $basedn = $basedn->toString();
+        }
+
+        if ($filter instanceof Zend_Ldap_Filter_Abstract) {
+            $filter = $filter->toString();
+        }
+
+        switch ($scope) {
+            case self::SEARCH_SCOPE_ONE:
+                $search = @ldap_list($this->getResource(), $basedn, $filter, $attributes);
+                break;
+            case self::SEARCH_SCOPE_BASE:
+                $search = @ldap_read($this->getResource(), $basedn, $filter, $attributes);
+                break;
+            case self::SEARCH_SCOPE_SUB:
+            default:
+                $search = @ldap_search($this->getResource(), $basedn, $filter, $attributes);
+                break;
+        }
+
+        if($search === false) {
+            /**
+             * @see Zend_Ldap_Exception
+             */
+            require_once 'Zend/Ldap/Exception.php';
+            throw new Zend_Ldap_Exception($this, 'searching: ' . $filter);
+        }
+        if (!is_null($sort) && is_string($sort)) {
+            $isSorted = @ldap_sort($this->getResource(), $search, $sort);
+            if($search === false) {
+                /**
+                 * @see Zend_Ldap_Exception
+                 */
+                require_once 'Zend/Ldap/Exception.php';
+                throw new Zend_Ldap_Exception($this, 'sorting: ' . $sort);
+            }
+        }
+
+        /**
+         * Zend_Ldap_Collection_Iterator_Default
+         */
+        require_once 'Zend/Ldap/Collection/Iterator/Default.php';
+        $iterator = new Zend_Ldap_Collection_Iterator_Default($this, $search);
+        if ($collectionClass === null) {
+            /**
+             * Zend_Ldap_Collection
+             */
+            require_once 'Zend/Ldap/Collection.php';
+            return new Zend_Ldap_Collection($iterator);
+        } else {
+            $collectionClass = (string)$collectionClass;
+            if (!class_exists($collectionClass)) {
+                /**
+                 * @see Zend_Ldap_Exception
+                 */
+                require_once 'Zend/Ldap/Exception.php';
+                throw new Zend_Ldap_Exception(null,
+                    "Class '$collectionClass' can not be found");
+            }
+            if (!is_subclass_of($collectionClass, 'Zend_Ldap_Collection')) {
+                /**
+                 * @see Zend_Ldap_Exception
+                 */
+                require_once 'Zend/Ldap/Exception.php';
+                throw new Zend_Ldap_Exception(null,
+                    "Class '$collectionClass' must subclass 'Zend_Ldap_Collection'");
+            }
+            return new $collectionClass($iterator);
+        }
+    }
+
+    /**
+     * Count items found by given filter.
+     *
+     * @param  string|Zend_Ldap_Filter_Abstract $filter
+     * @param  string|Zend_Ldap_Dn|null         $basedn
+     * @param  integer                          $scope
+     * @return integer
+     * @throws Zend_Ldap_Exception
+     */
+    public function count($filter, $basedn = null, $scope = self::SEARCH_SCOPE_SUB)
+    {
+        try {
+            $result = $this->search($filter, $basedn, $scope, array('dn'), null);
+        } catch (Zend_Ldap_Exception $e) {
+            if ($e->getCode() === Zend_Ldap_Exception::LDAP_NO_SUCH_OBJECT) return 0;
+            else throw $e;
+        }
+        return $result->count();
+    }
+
+    /**
+     * Count children for a given DN.
+     *
+     * @param  string|Zend_Ldap_Dn $dn
+     * @return integer
+     * @throws Zend_Ldap_Exception
+     */
+    public function countChildren($dn)
+    {
+        return $this->count('(objectClass=*)', $dn, self::SEARCH_SCOPE_ONE);
+    }
+
+    /**
+     * Check if a given DN exists.
+     *
+     * @param  string|Zend_Ldap_Dn $dn
+     * @return boolean
+     * @throws Zend_Ldap_Exception
+     */
+    public function exists($dn)
+    {
+        return ($this->count('(objectClass=*)', $dn, self::SEARCH_SCOPE_BASE) == 1);
+    }
+
+    /**
+     * Search LDAP registry for entries matching filter and optional attributes
+     *
+     * @param  string|Zend_Ldap_Filter_Abstract $filter
+     * @param  string|Zend_Ldap_Dn|null         $basedn
+     * @param  integer                          $scope
+     * @param  array                            $attributes
+     * @param  string|null                      $sort
+     * @return array
+     * @throws Zend_Ldap_Exception
+     */
+    public function searchEntries($filter, $basedn = null, $scope = self::SEARCH_SCOPE_SUB,
+        array $attributes = array(), $sort = null)
+    {
+        $result = $this->search($filter, $basedn, $scope, $attributes, $sort);
+        return $result->toArray();
+    }
+
+    /**
+     * Get LDAP entry by DN
+     *
+     * @param  string|Zend_Ldap_Dn $dn
+     * @param  array               $attributes
+     * @param  boolean             $throwOnNotFound
+     * @return array
+     * @throws Zend_Ldap_Exception
+     */
+    public function getEntry($dn, array $attributes = array(), $throwOnNotFound = false)
+    {
+        try {
+            $result = $this->search("(objectClass=*)", $dn, self::SEARCH_SCOPE_BASE,
+                $attributes, null);
+            return $result->getFirst();
+        } catch (Zend_Ldap_Exception $e){
+            if ($throwOnNotFound !== false) throw $e;
+        }
+        return null;
+    }
+
+    /**
+     * Prepares an ldap data entry array for insert/update operation
+     *
+     * @param  array $entry
+     * @return void
+     * @throws InvalidArgumentException
+     */
+    public static function prepareLdapEntryArray(array &$entry)
+    {
+        if (array_key_exists('dn', $entry)) unset($entry['dn']);
+        foreach ($entry as $key => $value) {
+            if (is_array($value)) {
+                foreach ($value as $i => $v) {
+                    if (is_null($v)) unset($value[$i]);
+                    else if (!is_scalar($v)) {
+                        throw new InvalidArgumentException('Only scalar values allowed in LDAP data');
+                    } else {
+                        $v = (string)$v;
+                        if (strlen($v) == 0) {
+                            unset($value[$i]);
+                        } else {
+                            $value[$i] = $v;
+                        }
+                    }
+                }
+                $entry[$key] = array_values($value);
+            } else {
+                if (is_null($value)) $entry[$key] = array();
+                else if (!is_scalar($value)) {
+                    throw new InvalidArgumentException('Only scalar values allowed in LDAP data');
+                } else {
+                    $value = (string)$value;
+                    if (strlen($value) == 0) {
+                        $entry[$key] = array();
+                    } else {
+                        $entry[$key] = array($value);
+                    }
+                }
+            }
+        }
+        $entry = array_change_key_case($entry, CASE_LOWER);
+    }
+
+    /**
+     * Add new information to the LDAP repository
+     *
+     * @param  string|Zend_Ldap_Dn $dn
+     * @param  array               $entry
+     * @return Zend_Ldap                  Provides a fluid interface
+     * @throws Zend_Ldap_Exception
+     */
+    public function add($dn, array $entry)
+    {
+        if (!($dn instanceof Zend_Ldap_Dn)) {
+            $dn = Zend_Ldap_Dn::factory($dn, null);
+        }
+        self::prepareLdapEntryArray($entry);
+        foreach ($entry as $key => $value) {
+            if (is_array($value) && count($value) === 0) {
+                unset($entry[$key]);
+            }
+        }
+
+        $rdnParts = $dn->getRdn(Zend_Ldap_Dn::ATTR_CASEFOLD_LOWER);
+        foreach ($rdnParts as $key => $value) {
+            $value = Zend_Ldap_Dn::unescapeValue($value);
+            if (!array_key_exists($key, $entry) ||
+                    !in_array($value, $entry[$key]) ||
+                    count($entry[$key]) !== 1) {
+                $entry[$key] = array($value);
+            }
+        }
+        $adAttributes = array('distinguishedname', 'instancetype', 'name', 'objectcategory',
+            'objectguid', 'usnchanged', 'usncreated', 'whenchanged', 'whencreated');
+        foreach ($adAttributes as $attr) {
+            if (array_key_exists($attr, $entry)) {
+                unset($entry[$attr]);
+            }
+        }
+
+        $isAdded = @ldap_add($this->getResource(), $dn->toString(), $entry);
+        if($isAdded === false) {
+            /**
+             * @see Zend_Ldap_Exception
+             */
+            require_once 'Zend/Ldap/Exception.php';
+            throw new Zend_Ldap_Exception($this, 'adding: ' . $dn->toString());
+        }
+        return $this;
+    }
+
+    /**
+     * Update LDAP registry
+     *
+     * @param  string|Zend_Ldap_Dn $dn
+     * @param  array               $entry
+     * @return Zend_Ldap                  Provides a fluid interface
+     * @throws Zend_Ldap_Exception
+     */
+    public function update($dn, array $entry)
+    {
+        if (!($dn instanceof Zend_Ldap_Dn)) {
+            $dn = Zend_Ldap_Dn::factory($dn, null);
+        }
+        self::prepareLdapEntryArray($entry);
+
+        $rdnParts = $dn->getRdn(Zend_Ldap_Dn::ATTR_CASEFOLD_LOWER);
+        $adAttributes = array('distinguishedname', 'instancetype', 'name', 'objectcategory',
+            'objectguid', 'usnchanged', 'usncreated', 'whenchanged', 'whencreated');
+        $stripAttributes = array_merge(array_keys($rdnParts), $adAttributes);
+        foreach ($stripAttributes as $attr) {
+            if (array_key_exists($attr, $entry)) {
+                unset($entry[$attr]);
+            }
+        }
+
+        if (count($entry) > 0) {
+            $isModified = @ldap_modify($this->getResource(), $dn->toString(), $entry);
+            if($isModified === false) {
+                /**
+                 * @see Zend_Ldap_Exception
+                 */
+                require_once 'Zend/Ldap/Exception.php';
+                throw new Zend_Ldap_Exception($this, 'updating: ' . $dn->toString());
+            }
+        }
+        return $this;
+    }
+
+    /**
+     * Save entry to LDAP registry.
+     *
+     * Internally decides if entry will be updated to added by calling
+     * {@link exists()}.
+     *
+     * @param  string|Zend_Ldap_Dn $dn
+     * @param  array               $entry
+     * @return Zend_Ldap Provides a fluid interface
+     * @throws Zend_Ldap_Exception
+     */
+    public function save($dn, array $entry)
+    {
+        if ($dn instanceof Zend_Ldap_Dn) {
+            $dn = $dn->toString();
+        }
+        if ($this->exists($dn)) $this->update($dn, $entry);
+        else $this->add($dn, $entry);
+        return $this;
+    }
+
+    /**
+     * Delete an LDAP entry
+     *
+     * @param  string|Zend_Ldap_Dn $dn
+     * @param  boolean             $recursively
+     * @return Zend_Ldap Provides a fluid interface
+     * @throws Zend_Ldap_Exception
+     */
+    public function delete($dn, $recursively = false)
+    {
+        if ($dn instanceof Zend_Ldap_Dn) {
+            $dn = $dn->toString();
+        }
+        if ($recursively === true) {
+            if ($this->countChildren($dn)>0) {
+                $children = $this->_getChildrenDns($dn);
+                foreach ($children as $c) {
+                    $this->delete($c, true);
+                }
+            }
+        }
+        $isDeleted = @ldap_delete($this->getResource(), $dn);
+        if($isDeleted === false) {
+            /**
+             * @see Zend_Ldap_Exception
+             */
+            require_once 'Zend/Ldap/Exception.php';
+            throw new Zend_Ldap_Exception($this, 'deleting: ' . $dn);
+        }
+        return $this;
+    }
+
+    /**
+     * Retrieve the immediate children DNs of the given $parentDn
+     *
+     * This method is used in recursive methods like {@see delete()}
+     * or {@see copy()}
+     *
+     * @param  string|Zend_Ldap_Dn $parentDn
+     * @return array of DNs
+     */
+    protected function _getChildrenDns($parentDn)
+    {
+        if ($parentDn instanceof Zend_Ldap_Dn) {
+            $parentDn = $parentDn->toString();
+        }
+        $children = array();
+        $search = @ldap_list($this->getResource(), $parentDn, '(objectClass=*)', array('dn'));
+        for ($entry = @ldap_first_entry($this->getResource(), $search);
+                $entry !== false;
+                $entry = @ldap_next_entry($this->getResource(), $entry)) {
+            $childDn = @ldap_get_dn($this->getResource(), $entry);
+            if ($childDn === false) {
+                /**
+                 * @see Zend_Ldap_Exception
+                 */
+                require_once 'Zend/Ldap/Exception.php';
+                throw new Zend_Ldap_Exception($this, 'getting dn');
+            }
+            $children[] = $childDn;
+        }
+        @ldap_free_result($search);
+        return $children;
+    }
+
+    /**
+     * Moves a LDAP entry from one DN to another subtree.
+     *
+     * @param  string|Zend_Ldap_Dn $from
+     * @param  string|Zend_Ldap_Dn $to
+     * @param  boolean             $recursively
+     * @param  boolean             $alwaysEmulate
+     * @return Zend_Ldap Provides a fluid interface
+     * @throws Zend_Ldap_Exception
+     */
+    public function moveToSubtree($from, $to, $recursively = false, $alwaysEmulate = false)
+    {
+        if ($from instanceof Zend_Ldap_Dn) {
+            $orgDnParts = $from->toArray();
+        } else {
+            $orgDnParts = Zend_Ldap_Dn::explodeDn($from);
+        }
+
+        if ($to instanceof Zend_Ldap_Dn) {
+            $newParentDnParts = $to->toArray();
+        } else {
+            $newParentDnParts = Zend_Ldap_Dn::explodeDn($to);
+        }
+
+        $newDnParts = array_merge(array(array_shift($orgDnParts)), $newParentDnParts);
+        $newDn = Zend_Ldap_Dn::fromArray($newDnParts);
+        return $this->rename($from, $newDn, $recursively, $alwaysEmulate);
+    }
+
+    /**
+     * Moves a LDAP entry from one DN to another DN.
+     *
+     * This is an alias for {@link rename()}
+     *
+     * @param  string|Zend_Ldap_Dn $from
+     * @param  string|Zend_Ldap_Dn $to
+     * @param  boolean             $recursively
+     * @param  boolean             $alwaysEmulate
+     * @return Zend_Ldap Provides a fluid interface
+     * @throws Zend_Ldap_Exception
+     */
+    public function move($from, $to, $recursively = false, $alwaysEmulate = false)
+    {
+        return $this->rename($from, $to, $recursively, $alwaysEmulate);
+    }
+
+    /**
+     * Renames a LDAP entry from one DN to another DN.
+     *
+     * This method implicitely moves the entry to another location within the tree.
+     *
+     * @param  string|Zend_Ldap_Dn $from
+     * @param  string|Zend_Ldap_Dn $to
+     * @param  boolean             $recursively
+     * @param  boolean             $alwaysEmulate
+     * @return Zend_Ldap Provides a fluid interface
+     * @throws Zend_Ldap_Exception
+     */
+    public function rename($from, $to, $recursively = false, $alwaysEmulate = false)
+    {
+        $emulate = (bool)$alwaysEmulate;
+        if (!function_exists('ldap_rename')) $emulate = true;
+        else if ($recursively) $emulate = true;
+
+        if ($emulate === false) {
+            if ($from instanceof Zend_Ldap_Dn) {
+                $from = $from->toString();
+            }
+
+            if ($to instanceof Zend_Ldap_Dn) {
+                $newDnParts = $to->toArray();
+            } else {
+                $newDnParts = Zend_Ldap_Dn::explodeDn($to);
+            }
+
+            $newRdn = Zend_Ldap_Dn::implodeRdn(array_shift($newDnParts));
+            $newParent = Zend_Ldap_Dn::implodeDn($newDnParts);
+            $isOK = @ldap_rename($this->getResource(), $from, $newRdn, $newParent, true);
+            if($isOK === false) {
+                /**
+                 * @see Zend_Ldap_Exception
+                 */
+                require_once 'Zend/Ldap/Exception.php';
+                throw new Zend_Ldap_Exception($this, 'renaming ' . $from . ' to ' . $to);
+            }
+            else if (!$this->exists($to)) $emulate = true;
+        }
+        if ($emulate) {
+            $this->copy($from, $to, $recursively);
+            $this->delete($from, $recursively);
+        }
+        return $this;
+    }
+
+    /**
+     * Copies a LDAP entry from one DN to another subtree.
+     *
+     * @param  string|Zend_Ldap_Dn $from
+     * @param  string|Zend_Ldap_Dn $to
+     * @param  boolean             $recursively
+     * @return Zend_Ldap Provides a fluid interface
+     * @throws Zend_Ldap_Exception
+     */
+    public function copyToSubtree($from, $to, $recursively = false)
+    {
+        if ($from instanceof Zend_Ldap_Dn) {
+            $orgDnParts = $from->toArray();
+        } else {
+            $orgDnParts = Zend_Ldap_Dn::explodeDn($from);
+        }
+
+        if ($to instanceof Zend_Ldap_Dn) {
+            $newParentDnParts = $to->toArray();
+        } else {
+            $newParentDnParts = Zend_Ldap_Dn::explodeDn($to);
+        }
+
+        $newDnParts = array_merge(array(array_shift($orgDnParts)), $newParentDnParts);
+        $newDn = Zend_Ldap_Dn::fromArray($newDnParts);
+        return $this->copy($from, $newDn, $recursively);
+    }
+
+    /**
+     * Copies a LDAP entry from one DN to another DN.
+     *
+     * @param  string|Zend_Ldap_Dn $from
+     * @param  string|Zend_Ldap_Dn $to
+     * @param  boolean             $recursively
+     * @return Zend_Ldap Provides a fluid interface
+     * @throws Zend_Ldap_Exception
+     */
+    public function copy($from, $to, $recursively = false)
+    {
+        $entry = $this->getEntry($from, array(), true);
+
+        if ($to instanceof Zend_Ldap_Dn) {
+            $toDnParts = $to->toArray();
+        } else {
+            $toDnParts = Zend_Ldap_Dn::explodeDn($to);
+        }
+        $this->add($to, $entry);
+
+        if ($recursively === true && $this->countChildren($from)>0) {
+            $children = $this->_getChildrenDns($from);
+            foreach ($children as $c) {
+                $cDnParts = Zend_Ldap_Dn::explodeDn($c);
+                $newChildParts = array_merge(array(array_shift($cDnParts)), $toDnParts);
+                $newChild = Zend_Ldap_Dn::implodeDn($newChildParts);
+                $this->copy($c, $newChild, true);
+            }
+        }
+        return $this;
+    }
+
+    /**
+     * Returns the specified DN as a Zend_Ldap_Node
+     *
+     * @param  string|Zend_Ldap_Dn $dn
+     * @return Zend_Ldap_Node
+     * @throws Zend_Ldap_Exception
+     */
+    public function getNode($dn)
+    {
+        /**
+         * Zend_Ldap_Node
+         */
+        require_once 'Zend/Ldap/Node.php';
+        return Zend_Ldap_Node::fromLdap($dn, $this);
+    }
+
+    /**
+     * Returns the base node as a Zend_Ldap_Node
+     *
+     * @return Zend_Ldap_Node
+     * @throws Zend_Ldap_Exception
+     */
+    public function getBaseNode()
+    {
+        return $this->getNode($this->getBaseDn(), $this);
+    }
+
+    /**
+     * Returns the RootDSE
+     *
+     * @return Zend_Ldap_Node_RootDse
+     * @throws Zend_Ldap_Exception
+     */
+    public function getRootDse()
+    {
+        if ($this->_rootDse === null) {
+            /**
+             * @see Zend_Ldap_Node_Schema
+             */
+            require_once 'Zend/Ldap/Node/RootDse.php';
+            $this->_rootDse = Zend_Ldap_Node_RootDse::create($this);
+        }
+        return $this->_rootDse;
+    }
+
+    /**
+     * Returns the schema
+     *
+     * @return Zend_Ldap_Node_Schema
+     * @throws Zend_Ldap_Exception
+     */
+    public function getSchema()
+    {
+        if ($this->_schema === null) {
+            /**
+             * @see Zend_Ldap_Node_Schema
+             */
+            require_once 'Zend/Ldap/Node/Schema.php';
+            $this->_schema = Zend_Ldap_Node_Schema::create($this);
+        }
+        return $this->_schema;
+    }
+}
index d140684cfb6721c95c0e4de1cfb17ea00bd5b973..9532aa44189f851c9e3548563f470cfc9efbeed2 100644 (file)
@@ -14,7 +14,7 @@
  *
  * @category   Zend
  * @package    Zend_Loader
- * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
  * @version    $Id$
  */
@@ -24,7 +24,7 @@
  *
  * @category   Zend
  * @package    Zend_Loader
- * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
  */
 class Zend_Loader
@@ -80,7 +80,7 @@ class Zend_Loader
             self::loadFile($file, $dirs, true);
         } else {
             self::_securityCheck($file);
-            include_once $file;
+            include $file;
         }
 
         if (!class_exists($class, false) && !interface_exists($class, false)) {
@@ -177,13 +177,15 @@ class Zend_Loader
      * spl_autoload_register(array('Zend_Loader', 'autoload'));
      * </code>
      *
-     * @param string $class
+     * @deprecated Since 1.8.0
+     * @param  string $class
      * @return string|false Class name on success; false on failure
      */
     public static function autoload($class)
     {
+        trigger_error(__CLASS__ . '::' . __METHOD__ . ' is deprecated as of 1.8.0 and will be removed with 2.0.0; use Zend_Loader_Autoloader instead', E_USER_NOTICE);
         try {
-            self::loadClass($class);
+            @self::loadClass($class);
             return $class;
         } catch (Exception $e) {
             return false;
@@ -193,6 +195,7 @@ class Zend_Loader
     /**
      * Register {@link autoload()} with spl_autoload()
      *
+     * @deprecated Since 1.8.0
      * @param string $class (optional)
      * @param boolean $enabled (optional)
      * @return void
@@ -201,22 +204,26 @@ class Zend_Loader
      */
     public static function registerAutoload($class = 'Zend_Loader', $enabled = true)
     {
-        if (!function_exists('spl_autoload_register')) {
-            require_once 'Zend/Exception.php';
-            throw new Zend_Exception('spl_autoload does not exist in this PHP installation');
-        }
+        trigger_error(__CLASS__ . '::' . __METHOD__ . ' is deprecated as of 1.8.0 and will be removed with 2.0.0; use Zend_Loader_Autoloader instead', E_USER_NOTICE);
+        require_once 'Zend/Loader/Autoloader.php';
+        $autoloader = Zend_Loader_Autoloader::getInstance();
+        $autoloader->setFallbackAutoloader(true);
 
-        self::loadClass($class);
-        $methods = get_class_methods($class);
-        if (!in_array('autoload', (array) $methods)) {
-            require_once 'Zend/Exception.php';
-            throw new Zend_Exception("The class \"$class\" does not have an autoload() method");
-        }
+        if ('Zend_Loader' != $class) {
+            self::loadClass($class);
+            $methods = get_class_methods($class);
+            if (!in_array('autoload', (array) $methods)) {
+                require_once 'Zend/Exception.php';
+                throw new Zend_Exception("The class \"$class\" does not have an autoload() method");
+            }
 
-        if ($enabled === true) {
-            spl_autoload_register(array($class, 'autoload'));
-        } else {
-            spl_autoload_unregister(array($class, 'autoload'));
+            $callback = array($class, 'autoload');
+
+            if ($enabled) {
+                $autoloader->pushAutoloader($callback);
+            } else {
+                $autoloader->removeAutoloader($callback);
+            }
         }
     }
 
@@ -232,7 +239,7 @@ class Zend_Loader
         /**
          * Security check
          */
-        if (preg_match('/[^a-z0-9\\/\\\\_.-]/i', $filename)) {
+        if (preg_match('/[^a-z0-9\\/\\\\_.:-]/i', $filename)) {
             require_once 'Zend/Exception.php';
             throw new Zend_Exception('Security check: Illegal character in filename');
         }
diff --git a/lib/zend/Zend/Locale.php b/lib/zend/Zend/Locale.php
new file mode 100644 (file)
index 0000000..669313d
--- /dev/null
@@ -0,0 +1,1019 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category  Zend
+ * @package   Zend_Locale
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license   http://framework.zend.com/license/new-bsd     New BSD License
+ * @version   $Id$
+ */
+
+/**
+ * Base class for localization
+ *
+ * @category  Zend
+ * @package   Zend_Locale
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license   http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Locale
+{
+    /**
+     * Class wide Locale Constants
+     *
+     * @var array $_localeData
+     */
+    private static $_localeData = array(
+        'root'  => true, 'aa_DJ' => true, 'aa_ER' => true, 'aa_ET' => true, 'aa'    => true,
+        'af_NA' => true, 'af_ZA' => true, 'af'    => true, 'ak_GH' => true, 'ak'    => true,
+        'am_ET' => true, 'am'    => true, 'ar_AE' => true, 'ar_BH' => true, 'ar_DZ' => true,
+        'ar_EG' => true, 'ar_IQ' => true, 'ar_JO' => true, 'ar_KW' => true, 'ar_LB' => true,
+        'ar_LY' => true, 'ar_MA' => true, 'ar_OM' => true, 'ar_QA' => true, 'ar_SA' => true,
+        'ar_SD' => true, 'ar_SY' => true, 'ar_TN' => true, 'ar_YE' => true, 'ar'    => true,
+        'as_IN' => true, 'as'    => true, 'az_AZ' => true, 'az'    => true, 'be_BY' => true,
+        'be'    => true, 'bg_BG' => true, 'bg'    => true, 'bn_BD' => true, 'bn_IN' => true,
+        'bn'    => true, 'bo_CN' => true, 'bo_IN' => true, 'bo'    => true, 'bs_BA' => true,
+        'bs'    => true, 'byn_ER'=> true, 'byn'   => true, 'ca_ES' => true, 'ca'    => true,
+        'cch_NG'=> true, 'cch'   => true, 'cop'   => true, 'cs_CZ' => true, 'cs'    => true,
+        'cy_GB' => true, 'cy'    => true, 'da_DK' => true, 'da'    => true, 'de_AT' => true,
+        'de_BE' => true, 'de_CH' => true, 'de_DE' => true, 'de_LI' => true, 'de_LU' => true,
+        'de'    => true, 'dv_MV' => true, 'dv'    => true, 'dz_BT' => true, 'dz'    => true,
+        'ee_GH' => true, 'ee_TG' => true, 'ee'    => true, 'el_CY' => true, 'el_GR' => true,
+        'el'    => true, 'en_AS' => true, 'en_AU' => true, 'en_BE' => true, 'en_BW' => true,
+        'en_BZ' => true, 'en_CA' => true, 'en_GB' => true, 'en_GU' => true, 'en_HK' => true,
+        'en_IE' => true, 'en_IN' => true, 'en_JM' => true, 'en_MH' => true, 'en_MP' => true,
+        'en_MT' => true, 'en_NA' => true, 'en_NZ' => true, 'en_PH' => true, 'en_PK' => true,
+        'en_SG' => true, 'en_TT' => true, 'en_UM' => true, 'en_US' => true, 'en_VI' => true,
+        'en_ZA' => true, 'en_ZW' => true, 'en'    => true, 'eo'    => true, 'es_AR' => true,
+        'es_BO' => true, 'es_CL' => true, 'es_CO' => true, 'es_CR' => true, 'es_DO' => true,
+        'es_EC' => true, 'es_ES' => true, 'es_GT' => true, 'es_HN' => true, 'es_MX' => true,
+        'es_NI' => true, 'es_PA' => true, 'es_PE' => true, 'es_PR' => true, 'es_PY' => true,
+        'es_SV' => true, 'es_US' => true, 'es_UY' => true, 'es_VE' => true, 'es'    => true,
+        'et_EE' => true, 'et'    => true, 'eu_ES' => true, 'eu'    => true, 'fa_AF' => true,
+        'fa_IR' => true, 'fa'    => true, 'fi_FI' => true, 'fi'    => true, 'fil_PH'=> true,
+        'fil'   => true, 'fo_FO' => true, 'fo'    => true, 'fr_BE' => true, 'fr_CA' => true,
+        'fr_CH' => true, 'fr_FR' => true, 'fr_LU' => true, 'fr_MC' => true, 'fr_SN' => true,
+        'fr'    => true, 'fur_IT'=> true, 'fur'   => true, 'ga_IE' => true, 'ga'    => true,
+        'gaa_GH'=> true, 'gaa'   => true, 'gez_ER'=> true, 'gez_ET'=> true, 'gez'   => true,
+        'gl_ES' => true, 'gl'    => true, 'gsw_CH'=> true, 'gsw'   => true, 'gu_IN' => true,
+        'gu'    => true, 'gv_GB' => true, 'gv'    => true, 'ha_GH' => true, 'ha_NE' => true,
+        'ha_NG' => true, 'ha_SD' => true, 'ha'    => true, 'haw_US'=> true, 'haw'   => true,
+        'he_IL' => true, 'he'    => true, 'hi_IN' => true, 'hi'    => true, 'hr_HR' => true,
+        'hr'    => true, 'hu_HU' => true, 'hu'    => true, 'hy_AM' => true, 'hy'    => true,
+        'ia'    => true, 'id_ID' => true, 'id'    => true, 'ig_NG' => true, 'ig'    => true,
+        'ii_CN' => true, 'ii'    => true, 'in'    => true, 'is_IS' => true, 'is'    => true,
+        'it_CH' => true, 'it_IT' => true, 'it'    => true, 'iu'    => true, 'iw'    => true,
+        'ja_JP' => true, 'ja'    => true, 'ka_GE' => true, 'ka'    => true, 'kaj_NG'=> true,
+        'kaj'   => true, 'kam_KE'=> true, 'kam'   => true, 'kcg_NG'=> true, 'kcg'   => true,
+        'kfo_CI'=> true, 'kfo'   => true, 'kk_KZ' => true, 'kk'    => true, 'kl_GL' => true,
+        'kl'    => true, 'km_KH' => true, 'km'    => true, 'kn_IN' => true, 'kn'    => true,
+        'ko_KR' => true, 'ko'    => true, 'kok_IN'=> true, 'kok'   => true, 'kpe_GN'=> true,
+        'kpe_LR'=> true, 'kpe'   => true, 'ku_IQ' => true, 'ku_IR' => true, 'ku_SY' => true,
+        'ku_TR' => true, 'ku'    => true, 'kw_GB' => true, 'kw'    => true, 'ky_KG' => true,
+        'ky'    => true, 'ln_CD' => true, 'ln_CG' => true, 'ln'    => true, 'lo_LA' => true,
+        'lo'    => true, 'lt_LT' => true, 'lt'    => true, 'lv_LV' => true, 'lv'    => true,
+        'mk_MK' => true, 'mk'    => true, 'ml_IN' => true, 'ml'    => true, 'mn_CN' => true,
+        'mn_MN' => true, 'mn'    => true, 'mo'    => true, 'mr_IN' => true, 'mr'    => true,
+        'ms_BN' => true, 'ms_MY' => true, 'ms'    => true, 'mt_MT' => true, 'mt'    => true,
+        'my_MM' => true, 'my'    => true, 'nb_NO' => true, 'nb'    => true, 'nds_DE'=> true,
+        'nds'   => true, 'ne_IN' => true, 'ne_NP' => true, 'ne'    => true, 'nl_BE' => true,
+        'nl_NL' => true, 'nl'    => true, 'nn_NO' => true, 'nn'    => true, 'no'    => true,
+        'nr_ZA' => true, 'nr'    => true, 'nso_ZA'=> true, 'nso'   => true, 'ny_MW' => true,
+        'ny'    => true, 'oc_FR' => true, 'oc'    => true, 'om_ET' => true, 'om_KE' => true,
+        'om'    => true, 'or_IN' => true, 'or'    => true, 'pa_IN' => true, 'pa_PK' => true,
+        'pa'    => true, 'pl_PL' => true, 'pl'    => true, 'ps_AF' => true, 'ps'    => true,
+        'pt_BR' => true, 'pt_PT' => true, 'pt'    => true, 'ro_MD' => true, 'ro_RO' => true,
+        'ro'    => true, 'ru_RU' => true, 'ru_UA' => true, 'ru'    => true, 'rw_RW' => true,
+        'rw'    => true, 'sa_IN' => true, 'sa'    => true, 'se_FI' => true, 'se_NO' => true,
+        'se'    => true, 'sh_BA' => true, 'sh_CS' => true, 'sh_YU' => true, 'sh'    => true,
+        'si_LK' => true, 'si'    => true, 'sid_ET'=> true, 'sid'   => true, 'sk_SK' => true,
+        'sk'    => true, 'sl_SI' => true, 'sl'    => true, 'so_DJ' => true, 'so_ET' => true,
+        'so_KE' => true, 'so_SO' => true, 'so'    => true, 'sq_AL' => true, 'sq'    => true,
+        'sr_BA' => true, 'sr_CS' => true, 'sr_ME' => true, 'sr_RS' => true, 'sr_YU' => true,
+        'sr'    => true, 'ss_SZ' => true, 'ss_ZA' => true, 'ss'    => true, 'st_LS' => true,
+        'st_ZA' => true, 'st'    => true, 'sv_FI' => true, 'sv_SE' => true, 'sv'    => true,
+        'sw_KE' => true, 'sw_TZ' => true, 'sw'    => true, 'syr_SY'=> true, 'syr'   => true,
+        'ta_IN' => true, 'ta'    => true, 'te_IN' => true, 'te'    => true, 'tg_TJ' => true,
+        'tg'    => true, 'th_TH' => true, 'th'    => true, 'ti_ER' => true, 'ti_ET' => true,
+        'ti'    => true, 'tig_ER'=> true, 'tig'   => true, 'tl'    => true, 'tn_ZA' => true,
+        'tn'    => true, 'to_TO' => true, 'to'    => true, 'tr_TR' => true, 'tr'    => true,
+        'trv_TW'=> true, 'trv'   => true, 'ts_ZA' => true, 'ts'    => true, 'tt_RU' => true,
+        'tt'    => true, 'ug_CN' => true, 'ug'    => true, 'uk_UA' => true, 'uk'    => true,
+        'ur_IN' => true, 'ur_PK' => true, 'ur'    => true, 'uz_AF' => true, 'uz_UZ' => true,
+        'uz'    => true, 've_ZA' => true, 've'    => true, 'vi_VN' => true, 'vi'    => true,
+        'wal_ET'=> true, 'wal'   => true, 'wo_SN' => true, 'wo'    => true, 'xh_ZA' => true,
+        'xh'    => true, 'yo_NG' => true, 'yo'    => true, 'zh_CN' => true, 'zh_HK' => true,
+        'zh_MO' => true, 'zh_SG' => true, 'zh_TW' => true, 'zh'    => true, 'zu_ZA' => true,
+        'zu'    => true
+    );
+
+    /**
+     * Autosearch constants
+     */
+    const BROWSER     = 'browser';
+    const ENVIRONMENT = 'environment';
+    const ZFDEFAULT   = 'default';
+
+    /**
+     * Defines if old behaviour should be supported
+     * Old behaviour throws notices and will be deleted in future releases
+     *
+     * @var boolean
+     */
+    public static $compatibilityMode = false;
+
+    /**
+     * Internal variable
+     *
+     * @var boolean
+     */
+    private static $_breakChain = false;
+
+    /**
+     * Actual set locale
+     *
+     * @var string Locale
+     */
+    protected $_locale;
+
+    /**
+     * Automatic detected locale
+     *
+     * @var string Locales
+     */
+    protected static $_auto;
+
+    /**
+     * Browser detected locale
+     *
+     * @var string Locales
+     */
+    protected static $_browser;
+
+    /**
+     * Environment detected locale
+     *
+     * @var string Locales
+     */
+    protected static $_environment;
+
+    /**
+     * Default locale
+     *
+     * @var string Locales
+     */
+    protected static $_default = array('en' => true);
+
+    /**
+     * Generates a locale object
+     * If no locale is given a automatic search is done
+     * Then the most probable locale will be automatically set
+     * Search order is
+     *  1. Given Locale
+     *  2. HTTP Client
+     *  3. Server Environment
+     *  4. Framework Standard
+     *
+     * @param  string|Zend_Locale $locale (Optional) Locale for parsing input
+     * @throws Zend_Locale_Exception When autodetection has been failed
+     */
+    public function __construct($locale = null)
+    {
+        $locale = self::_prepareLocale($locale);
+        $this->setLocale((string) $locale);
+    }
+
+    /**
+     * Serialization Interface
+     *
+     * @return string
+     */
+    public function serialize()
+    {
+        return serialize($this);
+    }
+
+    /**
+     * Returns a string representation of the object
+     *
+     * @return string
+     */
+    public function toString()
+    {
+        return (string) $this->_locale;
+    }
+
+    /**
+     * Returns a string representation of the object
+     * Alias for toString
+     *
+     * @return string
+     */
+    public function __toString()
+    {
+        return $this->toString();
+    }
+
+    /**
+     * Return the default locale
+     *
+     * @return array Returns an array of all locale string
+     */
+    public static function getDefault()
+    {
+        if ((self::$compatibilityMode === true) or (func_num_args() > 0)) {
+            if (!self::$_breakChain) {
+                self::$_breakChain = true;
+                trigger_error('You are running Zend_Locale in compatibility mode... please migrate your scripts', E_USER_NOTICE);
+                $params = func_get_args();
+                $param = null;
+                if (isset($params[0])) {
+                    $param = $params[0];
+                }
+                return self::getOrder($param);
+            }
+
+            self::$_breakChain = false;
+        }
+
+        return self::$_default;
+    }
+
+    /**
+     * Sets a new default locale which will be used when no locale can be detected
+     * If provided you can set a quality between 0 and 1 (or 2 and 100)
+     * which represents the percent of quality the browser
+     * requested within HTTP
+     *
+     * @param  string|Zend_Locale $locale  Locale to set
+     * @param  float              $quality The quality to set from 0 to 1
+     * @throws Zend_Locale_Exception When a autolocale was given
+     * @throws Zend_Locale_Exception When a unknown locale was given
+     * @return void
+     */
+    public static function setDefault($locale, $quality = 1)
+    {
+        if (($locale === 'auto') or ($locale === 'root') or ($locale === 'default') or
+            ($locale === 'environment') or ($locale === 'browser')) {
+            require_once 'Zend/Locale/Exception.php';
+            throw new Zend_Locale_Exception('Only full qualified locales can be used as default!');
+        }
+
+        if (($quality < 0.1) or ($quality > 100)) {
+            require_once 'Zend/Locale/Exception.php';
+            throw new Zend_Locale_Exception("Quality must be between 0.1 and 100");
+        }
+
+        if ($quality > 1) {
+            $quality /= 100;
+        }
+
+        $locale = self::_prepareLocale($locale);
+        if (isset(self::$_localeData[(string) $locale]) === true) {
+            self::$_default = array((string) $locale => $quality);
+        } else {
+            $elocale = explode('_', (string) $locale);
+            if (isset(self::$_localeData[$elocale[0]]) === true) {
+                self::$_default = array($elocale[0] => $quality);
+            } else {
+                require_once 'Zend/Locale/Exception.php';
+                throw new Zend_Locale_Exception("Unknown locale '" . (string) $locale . "' can not be set as default!");
+            }
+        }
+    }
+
+    /**
+     * Expects the Systems standard locale
+     *
+     * For Windows:
+     * f.e.: LC_COLLATE=C;LC_CTYPE=German_Austria.1252;LC_MONETARY=C
+     * would be recognised as de_AT
+     *
+     * @return array
+     */
+    public static function getEnvironment()
+    {
+        if (self::$_environment !== null) {
+            return self::$_environment;
+        }
+
+        require_once 'Zend/Locale/Data/Translation.php';
+
+        $language      = setlocale(LC_ALL, 0);
+        $languages     = explode(';', $language);
+        $languagearray = array();
+
+        foreach ($languages as $locale) {
+            if (strpos($locale, '=') !== false) {
+                $language = substr($locale, strpos($locale, '='));
+                $language = substr($language, 1);
+            }
+
+            if ($language !== 'C') {
+                if (strpos($language, '.') !== false) {
+                    $language = substr($language, 0, (strpos($language, '.') - 1));
+                } else if (strpos($language, '@') !== false) {
+                    $language = substr($language, 0, (strpos($language, '@') - 1));
+                }
+
+                $splitted = explode('_', $language);
+                $language = (string) $language;
+                if (isset(self::$_localeData[$language]) === true) {
+                    $languagearray[$language] = 1;
+                    if (strlen($language) > 4) {
+                        $languagearray[substr($language, 0, 2)] = 1;
+                    }
+
+                    continue;
+                }
+
+                if (empty(Zend_Locale_Data_Translation::$localeTranslation[$splitted[0]]) === false) {
+                    if (empty(Zend_Locale_Data_Translation::$localeTranslation[$splitted[1]]) === false) {
+                        $languagearray[Zend_Locale_Data_Translation::$localeTranslation[$splitted[0]] . '_' .
+                        Zend_Locale_Data_Translation::$localeTranslation[$splitted[1]]] = 1;
+                    }
+
+                    $languagearray[Zend_Locale_Data_Translation::$localeTranslation[$splitted[0]]] = 1;
+                }
+            }
+        }
+
+        self::$_environment = $languagearray;
+        return $languagearray;
+    }
+
+    /**
+     * Return an array of all accepted languages of the client
+     * Expects RFC compilant Header !!
+     *
+     * The notation can be :
+     * de,en-UK-US;q=0.5,fr-FR;q=0.2
+     *
+     * @return array - list of accepted languages including quality
+     */
+    public static function getBrowser()
+    {
+        if (self::$_browser !== null) {
+            return self::$_browser;
+        }
+
+        $httplanguages = getenv('HTTP_ACCEPT_LANGUAGE');
+        $languages     = array();
+        if (empty($httplanguages) === true) {
+            return $languages;
+        }
+
+        $accepted = preg_split('/,\s*/', $httplanguages);
+
+        foreach ($accepted as $accept) {
+            $match  = null;
+            $result = preg_match('/^([a-z]{1,8}(?:[-_][a-z]{1,8})*)(?:;\s*q=(0(?:\.[0-9]{1,3})?|1(?:\.0{1,3})?))?$/i',
+                                 $accept, $match);
+
+            if ($result < 1) {
+                continue;
+            }
+
+            if (isset($match[2]) === true) {
+                $quality = (float) $match[2];
+            } else {
+                $quality = 1.0;
+            }
+
+            $countrys = explode('-', $match[1]);
+            $region   = array_shift($countrys);
+
+            $country2 = explode('_', $region);
+            $region   = array_shift($country2);
+
+            foreach ($countrys as $country) {
+                $languages[$region . '_' . strtoupper($country)] = $quality;
+            }
+
+            foreach ($country2 as $country) {
+                $languages[$region . '_' . strtoupper($country)] = $quality;
+            }
+
+            if ((isset($languages[$region]) === false) || ($languages[$region] < $quality)) {
+                $languages[$region] = $quality;
+            }
+        }
+
+        self::$_browser = $languages;
+        return $languages;
+    }
+
+    /**
+     * Sets a new locale
+     *
+     * @param  string|Zend_Locale $locale (Optional) New locale to set
+     * @return void
+     */
+    public function setLocale($locale = null)
+    {
+        $locale = self::_prepareLocale($locale);
+
+        if (isset(self::$_localeData[(string) $locale]) === false) {
+            $region = substr((string) $locale, 0, 3);
+            if (isset($region[2]) === true) {
+                if (($region[2] === '_') or ($region[2] === '-')) {
+                    $region = substr($region, 0, 2);
+                }
+            }
+
+            if (isset(self::$_localeData[(string) $region]) === true) {
+                $this->_locale = $region;
+            } else {
+                $this->_locale = 'root';
+            }
+        } else {
+            $this->_locale = $locale;
+        }
+    }
+
+    /**
+     * Returns the language part of the locale
+     *
+     * @return string
+     */
+    public function getLanguage()
+    {
+        $locale = explode('_', $this->_locale);
+        return $locale[0];
+    }
+
+    /**
+     * Returns the region part of the locale if available
+     *
+     * @return string|false - Regionstring
+     */
+    public function getRegion()
+    {
+        $locale = explode('_', $this->_locale);
+        if (isset($locale[1]) === true) {
+            return $locale[1];
+        }
+
+        return false;
+    }
+
+    /**
+     * Return the accepted charset of the client
+     *
+     * @return string
+     */
+    public static function getHttpCharset()
+    {
+        $httpcharsets = getenv('HTTP_ACCEPT_CHARSET');
+
+        $charsets = array();
+        if ($httpcharsets === false) {
+            return $charsets;
+        }
+
+        $accepted = preg_split('/,\s*/', $httpcharsets);
+        foreach ($accepted as $accept) {
+            if (empty($accept) === true) {
+                continue;
+            }
+
+            if (strpos($accept, ';') !== false) {
+                $quality        = (float) substr($accept, (strpos($accept, '=') + 1));
+                $pos            = substr($accept, 0, strpos($accept, ';'));
+                $charsets[$pos] = $quality;
+            } else {
+                $quality           = 1.0;
+                $charsets[$accept] = $quality;
+            }
+        }
+
+        return $charsets;
+    }
+
+    /**
+     * Returns true if both locales are equal
+     *
+     * @param  Zend_Locale $object Locale to check for equality
+     * @return boolean
+     */
+    public function equals(Zend_Locale $object)
+    {
+        if ($object->toString() === $this->toString()) {
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Returns localized informations as array, supported are several
+     * types of informations.
+     * For detailed information about the types look into the documentation
+     *
+     * @param  string             $path   (Optional) Type of information to return
+     * @param  string|Zend_Locale $locale (Optional) Locale|Language for which this informations should be returned
+     * @param  string             $value  (Optional) Value for detail list
+     * @return array Array with the wished information in the given language
+     */
+    public static function getTranslationList($path = null, $locale = null, $value = null)
+    {
+        require_once 'Zend/Locale/Data.php';
+        $locale = self::_prepareLocale($locale);
+        $result = Zend_Locale_Data::getList($locale, $path, $value);
+        if (empty($result) === true) {
+            return false;
+        }
+
+        return $result;
+    }
+
+    /**
+     * Returns an array with the name of all languages translated to the given language
+     *
+     * @param  string|Zend_Locale $locale (Optional) Locale for language translation
+     * @return array
+     * @deprecated
+     */
+    public static function getLanguageTranslationList($locale = null)
+    {
+        trigger_error("The method getLanguageTranslationList is deprecated. Use getTranslationList('language', $locale) instead", E_USER_NOTICE);
+        return self::getTranslationList('language', $locale);
+    }
+
+    /**
+     * Returns an array with the name of all scripts translated to the given language
+     *
+     * @param  string|Zend_Locale $locale (Optional) Locale for script translation
+     * @return array
+     * @deprecated
+     */
+    public static function getScriptTranslationList($locale = null)
+    {
+        trigger_error("The method getScriptTranslationList is deprecated. Use getTranslationList('script', $locale) instead", E_USER_NOTICE);
+        return self::getTranslationList('script', $locale);
+    }
+
+    /**
+     * Returns an array with the name of all countries translated to the given language
+     *
+     * @param  string|Zend_Locale $locale (Optional) Locale for country translation
+     * @return array
+     * @deprecated
+     */
+    public static function getCountryTranslationList($locale = null)
+    {
+        trigger_error("The method getCountryTranslationList is deprecated. Use getTranslationList('territory', $locale, 2) instead", E_USER_NOTICE);
+        return self::getTranslationList('territory', $locale, 2);
+    }
+
+    /**
+     * Returns an array with the name of all territories translated to the given language
+     * All territories contains other countries.
+     *
+     * @param  string|Zend_Locale $locale (Optional) Locale for territory translation
+     * @return array
+     * @deprecated
+     */
+    public static function getTerritoryTranslationList($locale = null)
+    {
+        trigger_error("The method getTerritoryTranslationList is deprecated. Use getTranslationList('territory', $locale, 1) instead", E_USER_NOTICE);
+        return self::getTranslationList('territory', $locale, 1);
+    }
+
+    /**
+     * Returns a localized information string, supported are several types of informations.
+     * For detailed information about the types look into the documentation
+     *
+     * @param  string             $value  Name to get detailed information about
+     * @param  string             $path   (Optional) Type of information to return
+     * @param  string|Zend_Locale $locale (Optional) Locale|Language for which this informations should be returned
+     * @return string|false The wished information in the given language
+     */
+    public static function getTranslation($value = null, $path = null, $locale = null)
+    {
+        require_once 'Zend/Locale/Data.php';
+        $locale = self::_prepareLocale($locale);
+        $result = Zend_Locale_Data::getContent($locale, $path, $value);
+        if (empty($result) === true) {
+            return false;
+        }
+
+        return $result;
+    }
+
+    /**
+     * Returns the localized language name
+     *
+     * @param  string $value  Name to get detailed information about
+     * @param  string $locale (Optional) Locale for language translation
+     * @return array
+     * @deprecated
+     */
+    public static function getLanguageTranslation($value, $locale = null)
+    {
+        trigger_error("The method getLanguageTranslation is deprecated. Use getTranslation($value, 'language', $locale) instead", E_USER_NOTICE);
+        return self::getTranslation($value, 'language', $locale);
+    }
+
+    /**
+     * Returns the localized script name
+     *
+     * @param  string $value  Name to get detailed information about
+     * @param  string $locale (Optional) locale for script translation
+     * @return array
+     * @deprecated
+     */
+    public static function getScriptTranslation($value, $locale = null)
+    {
+        trigger_error("The method getScriptTranslation is deprecated. Use getTranslation($value, 'script', $locale) instead", E_USER_NOTICE);
+        return self::getTranslation($value, 'script', $locale);
+    }
+
+    /**
+     * Returns the localized country name
+     *
+     * @param  string             $value  Name to get detailed information about
+     * @param  string|Zend_Locale $locale (Optional) Locale for country translation
+     * @return array
+     * @deprecated
+     */
+    public static function getCountryTranslation($value, $locale = null)
+    {
+        trigger_error("The method getCountryTranslation is deprecated. Use getTranslation($value, 'country', $locale) instead", E_USER_NOTICE);
+        return self::getTranslation($value, 'country', $locale);
+    }
+
+    /**
+     * Returns the localized territory name
+     * All territories contains other countries.
+     *
+     * @param  string             $value  Name to get detailed information about
+     * @param  string|Zend_Locale $locale (Optional) Locale for territory translation
+     * @return array
+     * @deprecated
+     */
+    public static function getTerritoryTranslation($value, $locale = null)
+    {
+        trigger_error("The method getTerritoryTranslation is deprecated. Use getTranslation($value, 'territory', $locale) instead", E_USER_NOTICE);
+        return self::getTranslation($value, 'territory', $locale);
+    }
+
+    /**
+     * Returns an array with translated yes strings
+     *
+     * @param  string|Zend_Locale $locale (Optional) Locale for language translation (defaults to $this locale)
+     * @return array
+     */
+    public static function getQuestion($locale = null)
+    {
+        require_once 'Zend/Locale/Data.php';
+        $locale            = self::_prepareLocale($locale);
+        $quest             = Zend_Locale_Data::getList($locale, 'question');
+        $yes               = explode(':', $quest['yes']);
+        $no                = explode(':', $quest['no']);
+        $quest['yes']      = $yes[0];
+        $quest['yesarray'] = $yes;
+        $quest['no']       = $no[0];
+        $quest['noarray']  = $no;
+        $quest['yesexpr']  = self::_prepareQuestionString($yes);
+        $quest['noexpr']   = self::_prepareQuestionString($no);
+
+        return $quest;
+    }
+
+    /**
+     * Internal function for preparing the returned question regex string
+     *
+     * @param  string $input Regex to parse
+     * @return string
+     */
+    private static function _prepareQuestionString($input)
+    {
+        $regex = '';
+        if (is_array($input) === true) {
+            $regex = '^';
+            $start = true;
+            foreach ($input as $row) {
+                if ($start === false) {
+                    $regex .= '|';
+                }
+
+                $start  = false;
+                $regex .= '(';
+                $one    = null;
+                if (strlen($row) > 2) {
+                    $one = true;
+                }
+
+                foreach (str_split($row, 1) as $char) {
+                    $regex .= '[' . $char;
+                    $regex .= strtoupper($char) . ']';
+                    if ($one === true) {
+                        $one    = false;
+                        $regex .= '(';
+                    }
+                }
+
+                if ($one === false) {
+                    $regex .= ')';
+                }
+
+                $regex .= '?)';
+            }
+        }
+
+        return $regex;
+    }
+
+    /**
+     * Checks if a locale identifier is a real locale or not
+     * Examples:
+     * "en_XX" refers to "en", which returns true
+     * "XX_yy" refers to "root", which returns false
+     *
+     * @param  string|Zend_Locale $locale     Locale to check for
+     * @param  boolean            $strict     (Optional) If true, no rerouting will be done when checking
+     * @param  boolean            $compatible (DEPRECIATED) Only for internal usage, brakes compatibility mode
+     * @return boolean If the locale is known dependend on the settings
+     */
+    public static function isLocale($locale, $strict = false, $compatible = true)
+    {
+        if ($locale instanceof Zend_Locale) {
+            return true;
+        }
+
+        if (($locale !== null) and !is_string($locale) and !is_array($locale)) {
+            return false;
+        }
+
+        try {
+            $locale = self::_prepareLocale($locale, $strict);
+        } catch (Zend_Locale_Exception $e) {
+            return false;
+        }
+
+        if (($compatible === true) and (self::$compatibilityMode === true)) {
+            trigger_error('You are running Zend_Locale in compatibility mode... please migrate your scripts', E_USER_NOTICE);
+            if (isset(self::$_localeData[$locale]) === true) {
+                return $locale;
+            } else if (!$strict) {
+                $locale = explode('_', $locale);
+                if (isset(self::$_localeData[$locale[0]]) === true) {
+                    return $locale[0];
+                }
+            }
+        } else {
+            if (isset(self::$_localeData[$locale]) === true) {
+                return true;
+            } else if (!$strict) {
+                $locale = explode('_', $locale);
+                if (isset(self::$_localeData[$locale[0]]) === true) {
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Finds the proper locale based on the input
+     * Checks if it exists, degrades it when necessary
+     * Detects registry locale and when all fails tries to detect a automatic locale
+     * Returns the found locale as string
+     *
+     * @param string $locale
+     * @throws Zend_Locale_Exception When the given locale is no locale or the autodetection fails
+     * @return string
+     */
+    public static function findLocale($locale = null)
+    {
+        if ($locale === null) {
+            require_once 'Zend/Registry.php';
+            if (Zend_Registry::isRegistered('Zend_Locale')) {
+                $locale = Zend_Registry::get('Zend_Locale');
+            }
+        }
+
+        require_once 'Zend/Locale.php';
+        if ($locale === null) {
+            $locale = new Zend_Locale();
+        }
+
+        if (!Zend_Locale::isLocale($locale, true, false)) {
+            if (!Zend_Locale::isLocale($locale, false, false)) {
+                require_once 'Zend/Locale/Exception.php';
+                throw new Zend_Locale_Exception("The locale '$locale' is no known locale");
+            }
+
+            $locale = new Zend_Locale($locale);
+        }
+
+        if ($locale instanceof Zend_Locale) {
+            $locale = $locale->toString();
+        }
+
+        return $locale;
+    }
+
+    /**
+     * Returns a list of all known locales where the locale is the key
+     * Only real locales are returned, the internal locales 'root', 'auto', 'browser'
+     * and 'environment' are suppressed
+     *
+     * @return array List of all Locales
+     */
+    public static function getLocaleList()
+    {
+        $list = self::$_localeData;
+        unset($list['root']);
+        unset($list['auto']);
+        unset($list['browser']);
+        unset($list['environment']);
+        return $list;
+    }
+
+    /**
+     * Returns the set cache
+     *
+     * @return Zend_Cache_Core The set cache
+     */
+    public static function getCache()
+    {
+        require_once 'Zend/Locale/Data.php';
+        $cache = Zend_Locale_Data::getCache();
+
+        return $cache;
+    }
+
+    /**
+     * Sets a cache
+     *
+     * @param  Zend_Cache_Core $cache Cache to set
+     * @return void
+     */
+    public static function setCache(Zend_Cache_Core $cache)
+    {
+        require_once 'Zend/Locale/Data.php';
+        Zend_Locale_Data::setCache($cache);
+    }
+
+    /**
+     * Returns true when a cache is set
+     *
+     * @return boolean
+     */
+    public static function hasCache()
+    {
+        require_once 'Zend/Locale/Data.php';
+        return Zend_Locale_Data::hasCache();
+    }
+
+    /**
+     * Removes any set cache
+     *
+     * @return void
+     */
+    public static function removeCache()
+    {
+        require_once 'Zend/Locale/Data.php';
+        Zend_Locale_Data::removeCache();
+    }
+
+    /**
+     * Clears all set cache data
+     *
+     * @return void
+     */
+    public static function clearCache()
+    {
+        require_once 'Zend/Locale/Data.php';
+        Zend_Locale_Data::clearCache();
+    }
+
+    /**
+     * Disables the set cache
+     *
+     * @param  boolean $flag True disables any set cache, default is false
+     * @return void
+     */
+    public static function disableCache($flag)
+    {
+        require_once 'Zend/Locale/Data.php';
+        Zend_Locale_Data::disableCache($flag);
+    }
+
+    /**
+     * Internal function, returns a single locale on detection
+     *
+     * @param  string|Zend_Locale $locale (Optional) Locale to work on
+     * @param  boolean            $strict (Optional) Strict preparation
+     * @throws Zend_Locale_Exception When no locale is set which is only possible when the class was wrong extended
+     * @return string
+     */
+    private static function _prepareLocale($locale, $strict = false)
+    {
+        if ($locale instanceof Zend_Locale) {
+            $locale = $locale->toString();
+        }
+
+        if (is_array($locale)) {
+            return '';
+        }
+
+        if (empty(self::$_auto) === true) {
+            self::$_browser     = self::getBrowser();
+            self::$_environment = self::getEnvironment();
+            self::$_breakChain  = true;
+            self::$_auto        = self::getBrowser() + self::getEnvironment() + self::getDefault();
+        }
+
+        if (!$strict) {
+            if ($locale === 'browser') {
+                $locale = self::$_browser;
+            }
+
+            if ($locale === 'environment') {
+                $locale = self::$_environment;
+            }
+
+            if ($locale === 'default') {
+                $locale = self::$_default;
+            }
+
+            if (($locale === 'auto') or ($locale === null)) {
+                $locale = self::$_auto;
+            }
+
+            if (is_array($locale) === true) {
+                $locale = key($locale);
+            }
+        }
+
+        // This can only happen when someone extends Zend_Locale and erases the default
+        if ($locale === null) {
+            require_once 'Zend/Locale/Exception.php';
+            throw new Zend_Locale_Exception('Autodetection of Locale has been failed!');
+        }
+
+        if (strpos($locale, '-') !== false) {
+            $locale = strtr($locale, '-', '_');
+        }
+
+        $parts = explode('_', $locale);
+        if (!isset(self::$_localeData[$parts[0]])) {
+            return '';
+        }
+
+        foreach($parts as $key => $value) {
+            if ((strlen($value) < 2) || (strlen($value) > 3)) {
+                unset($parts[$key]);
+            }
+        }
+
+        $locale = implode('_', $parts);
+        return (string) $locale;
+    }
+
+    /**
+     * Search the locale automatically and return all used locales
+     * ordered by quality
+     *
+     * Standard Searchorder is Browser, Environment, Default
+     *
+     * @param  string  $searchorder (Optional) Searchorder
+     * @return array Returns an array of all detected locales
+     */
+    public static function getOrder($order = null)
+    {
+        switch ($order) {
+            case self::ENVIRONMENT:
+                self::$_breakChain = true;
+                $languages         = self::getEnvironment() + self::getBrowser() + self::getDefault();
+                break;
+
+            case self::ZFDEFAULT:
+                self::$_breakChain = true;
+                $languages         = self::getDefault() + self::getEnvironment() + self::getBrowser();
+                break;
+
+            default:
+                self::$_breakChain = true;
+                $languages         = self::getBrowser() + self::getEnvironment() + self::getDefault();
+                break;
+        }
+
+        return $languages;
+    }
+}
diff --git a/lib/zend/Zend/Log.php b/lib/zend/Zend/Log.php
new file mode 100644 (file)
index 0000000..b0dd790
--- /dev/null
@@ -0,0 +1,222 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Log
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/**
+ * @category   Zend
+ * @package    Zend_Log
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+class Zend_Log
+{
+    const EMERG   = 0;  // Emergency: system is unusable
+    const ALERT   = 1;  // Alert: action must be taken immediately
+    const CRIT    = 2;  // Critical: critical conditions
+    const ERR     = 3;  // Error: error conditions
+    const WARN    = 4;  // Warning: warning conditions
+    const NOTICE  = 5;  // Notice: normal but significant condition
+    const INFO    = 6;  // Informational: informational messages
+    const DEBUG   = 7;  // Debug: debug messages
+
+    /**
+     * @var array of priorities where the keys are the
+     * priority numbers and the values are the priority names
+     */
+    protected $_priorities = array();
+
+    /**
+     * @var array of Zend_Log_Writer_Abstract
+     */
+    protected $_writers = array();
+
+    /**
+     * @var array of Zend_Log_Filter_Interface
+     */
+    protected $_filters = array();
+
+    /**
+     * @var array of extra log event
+     */
+    protected $_extras = array();
+
+    /**
+     * Class constructor.  Create a new logger
+     *
+     * @param Zend_Log_Writer_Abstract|null  $writer  default writer
+     */
+    public function __construct(Zend_Log_Writer_Abstract $writer = null)
+    {
+        $r = new ReflectionClass($this);
+        $this->_priorities = array_flip($r->getConstants());
+
+        if ($writer !== null) {
+            $this->addWriter($writer);
+        }
+    }
+
+    /**
+     * Class destructor.  Shutdown log writers
+     *
+     * @return void
+     */
+    public function __destruct()
+    {
+        foreach($this->_writers as $writer) {
+            $writer->shutdown();
+        }
+    }
+
+    /**
+     * Undefined method handler allows a shortcut:
+     *   $log->priorityName('message')
+     *     instead of
+     *   $log->log('message', Zend_Log::PRIORITY_NAME)
+     *
+     * @param  string  $method  priority name
+     * @param  string  $params  message to log
+     * @return void
+     * @throws Zend_Log_Exception
+     */
+    public function __call($method, $params)
+    {
+        $priority = strtoupper($method);
+        if (($priority = array_search($priority, $this->_priorities)) !== false) {
+            $this->log(array_shift($params), $priority);
+        } else {
+            /** @see Zend_Log_Exception */
+            require_once 'Zend/Log/Exception.php';
+            throw new Zend_Log_Exception('Bad log priority');
+        }
+    }
+
+    /**
+     * Log a message at a priority
+     *
+     * @param  string   $message   Message to log
+     * @param  integer  $priority  Priority of message
+     * @return void
+     * @throws Zend_Log_Exception
+     */
+    public function log($message, $priority)
+    {
+        // sanity checks
+        if (empty($this->_writers)) {
+            /** @see Zend_Log_Exception */
+            require_once 'Zend/Log/Exception.php';
+            throw new Zend_Log_Exception('No writers were added');
+        }
+
+        if (! isset($this->_priorities[$priority])) {
+            /** @see Zend_Log_Exception */
+            require_once 'Zend/Log/Exception.php';
+            throw new Zend_Log_Exception('Bad log priority');
+        }
+
+        // pack into event required by filters and writers
+        $event = array_merge(array('timestamp'    => date('c'),
+                                    'message'      => $message,
+                                    'priority'     => $priority,
+                                    'priorityName' => $this->_priorities[$priority]),
+                              $this->_extras);
+
+        // abort if rejected by the global filters
+        foreach ($this->_filters as $filter) {
+            if (! $filter->accept($event)) {
+                return;
+            }
+        }
+
+        // send to each writer
+        foreach ($this->_writers as $writer) {
+            $writer->write($event);
+        }
+    }
+
+    /**
+     * Add a custom priority
+     *
+     * @param  string   $name      Name of priority
+     * @param  integer  $priority  Numeric priority
+     * @throws Zend_Log_InvalidArgumentException
+     */
+    public function addPriority($name, $priority)
+    {
+        // Priority names must be uppercase for predictability.
+        $name = strtoupper($name);
+
+        if (isset($this->_priorities[$priority])
+            || array_search($name, $this->_priorities)) {
+            /** @see Zend_Log_Exception */
+            require_once 'Zend/Log/Exception.php';
+            throw new Zend_Log_Exception('Existing priorities cannot be overwritten');
+        }
+
+        $this->_priorities[$priority] = $name;
+    }
+
+    /**
+     * Add a filter that will be applied before all log writers.
+     * Before a message will be received by any of the writers, it
+     * must be accepted by all filters added with this method.
+     *
+     * @param  int|Zend_Log_Filter_Interface $filter
+     * @return void
+     */
+    public function addFilter($filter)
+    {
+        if (is_integer($filter)) {
+               /** @see Zend_Log_Filter_Priority */
+            require_once 'Zend/Log/Filter/Priority.php';
+            $filter = new Zend_Log_Filter_Priority($filter);
+        } elseif(!is_object($filter) || ! $filter instanceof Zend_Log_Filter_Interface) {
+            /** @see Zend_Log_Exception */
+            require_once 'Zend/Log/Exception.php';
+            throw new Zend_Log_Exception('Invalid filter provided');
+        }
+
+        $this->_filters[] = $filter;
+    }
+
+    /**
+     * Add a writer.  A writer is responsible for taking a log
+     * message and writing it out to storage.
+     *
+     * @param  Zend_Log_Writer_Abstract $writer
+     * @return void
+     */
+    public function addWriter(Zend_Log_Writer_Abstract $writer)
+    {
+        $this->_writers[] = $writer;
+    }
+
+    /**
+     * Set an extra item to pass to the log writers.
+     *
+     * @param  $name    Name of the field
+     * @param  $value   Value of the field
+     * @return void
+     */
+    public function setEventItem($name, $value) {
+        $this->_extras = array_merge($this->_extras, array($name => $value));
+    }
+
+}
diff --git a/lib/zend/Zend/Mail.php b/lib/zend/Zend/Mail.php
new file mode 100644 (file)
index 0000000..4a5153a
--- /dev/null
@@ -0,0 +1,1055 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Mail
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+
+/**
+ * @see Zend_Mail_Transport_Abstract
+ */
+require_once 'Zend/Mail/Transport/Abstract.php';
+
+/**
+ * @see Zend_Mime
+ */
+require_once 'Zend/Mime.php';
+
+/**
+ * @see Zend_Mime_Message
+ */
+require_once 'Zend/Mime/Message.php';
+
+/**
+ * @see Zend_Mime_Part
+ */
+require_once 'Zend/Mime/Part.php';
+
+
+/**
+ * Class for sending an email.
+ *
+ * @category   Zend
+ * @package    Zend_Mail
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Mail extends Zend_Mime_Message
+{
+    /**#@+
+     * @access protected
+     */
+
+    /**
+     * @var Zend_Mail_Transport_Abstract
+     * @static
+     */
+    protected static $_defaultTransport = null;
+
+    /**
+     * Mail character set
+     * @var string
+     */
+    protected $_charset = null;
+
+    /**
+     * Mail headers
+     * @var array
+     */
+    protected $_headers = array();
+
+    /**
+     * Encoding of Mail headers
+     * @var string
+     */
+    protected $_headerEncoding = Zend_Mime::ENCODING_QUOTEDPRINTABLE;
+
+    /**
+     * From: address
+     * @var string
+     */
+    protected $_from = null;
+
+    /**
+     * To: addresses
+     * @var array
+     */
+    protected $_to = array();
+
+    /**
+     * Array of all recipients
+     * @var array
+     */
+    protected $_recipients = array();
+
+    /**
+     * Return-Path header
+     * @var string
+     */
+    protected $_returnPath = null;
+
+    /**
+     * Subject: header
+     * @var string
+     */
+    protected $_subject = null;
+
+    /**
+     * Date: header
+     * @var string
+     */
+    protected $_date = null;
+
+    /**
+     * Message-ID: header
+     * @var string
+     */
+    protected $_messageId = null;
+
+    /**
+     * text/plain MIME part
+     * @var false|Zend_Mime_Part
+     */
+    protected $_bodyText = false;
+
+    /**
+     * text/html MIME part
+     * @var false|Zend_Mime_Part
+     */
+    protected $_bodyHtml = false;
+
+    /**
+     * MIME boundary string
+     * @var string
+     */
+    protected $_mimeBoundary = null;
+
+    /**
+     * Content type of the message
+     * @var string
+     */
+    protected $_type = null;
+
+    /**#@-*/
+
+    /**
+     * Flag: whether or not email has attachments
+     * @var boolean
+     */
+    public $hasAttachments = false;
+
+
+    /**
+     * Sets the default mail transport for all following uses of
+     * Zend_Mail::send();
+     *
+     * @todo Allow passing a string to indicate the transport to load
+     * @todo Allow passing in optional options for the transport to load
+     * @param  Zend_Mail_Transport_Abstract $transport
+     */
+    public static function setDefaultTransport(Zend_Mail_Transport_Abstract $transport)
+    {
+        self::$_defaultTransport = $transport;
+    }
+
+    /**
+     * Public constructor
+     *
+     * @param string $charset
+     */
+    public function __construct($charset = 'iso-8859-1')
+    {
+        $this->_charset = $charset;
+    }
+
+    /**
+     * Return charset string
+     *
+     * @return string
+     */
+    public function getCharset()
+    {
+        return $this->_charset;
+    }
+
+    /**
+     * Set content type
+     *
+     * Should only be used for manually setting multipart content types.
+     *
+     * @param  string $type Content type
+     * @return Zend_Mail Implements fluent interface
+     * @throws Zend_Mail_Exception for types not supported by Zend_Mime
+     */
+    public function setType($type)
+    {
+        $allowed = array(
+            Zend_Mime::MULTIPART_ALTERNATIVE,
+            Zend_Mime::MULTIPART_MIXED,
+            Zend_Mime::MULTIPART_RELATED,
+        );
+        if (!in_array($type, $allowed)) {
+            /**
+             * @see Zend_Mail_Exception
+             */
+            require_once 'Zend/Mail/Exception.php';
+            throw new Zend_Mail_Exception('Invalid content type "' . $type . '"');
+        }
+
+        $this->_type = $type;
+        return $this;
+    }
+
+    /**
+     * Get content type of the message
+     *
+     * @return string
+     */
+    public function getType()
+    {
+        return $this->_type;
+    }
+
+    /**
+     * Set an arbitrary mime boundary for the message
+     *
+     * If not set, Zend_Mime will generate one.
+     *
+     * @param  string    $boundary
+     * @return Zend_Mail Provides fluent interface
+     */
+    public function setMimeBoundary($boundary)
+    {
+        $this->_mimeBoundary = $boundary;
+
+        return $this;
+    }
+
+    /**
+     * Return the boundary string used for the message
+     *
+     * @return string
+     */
+    public function getMimeBoundary()
+    {
+        return $this->_mimeBoundary;
+    }
+
+    /**
+     * Return encoding of mail headers
+     *
+     * @deprecated use {@link getHeaderEncoding()} instead
+     * @return string
+     */
+    public function getEncodingOfHeaders()
+    {
+        return $this->getHeaderEncoding();
+    }
+
+    /**
+     * Return the encoding of mail headers
+     *
+     * Either Zend_Mime::ENCODING_QUOTEDPRINTABLE or Zend_Mime::ENCODING_BASE64
+     *
+     * @return string
+     */
+    public function getHeaderEncoding()
+    {
+        return $this->_headerEncoding;
+    }
+
+    /**
+     * Set the encoding of mail headers
+     *
+     * @deprecated Use {@link setHeaderEncoding()} instead.
+     * @param  string $encoding
+     * @return Zend_Mail
+     */
+    public function setEncodingOfHeaders($encoding)
+    {
+        return $this->setHeaderEncoding($encoding);
+    }
+
+    /**
+     * Set the encoding of mail headers
+     *
+     * @param  string $encoding Zend_Mime::ENCODING_QUOTEDPRINTABLE or Zend_Mime::ENCODING_BASE64
+     * @return Zend_Mail Provides fluent interface
+     */
+    public function setHeaderEncoding($encoding)
+    {
+        $allowed = array(
+            Zend_Mime::ENCODING_BASE64,
+            Zend_Mime::ENCODING_QUOTEDPRINTABLE
+        );
+        if (!in_array($encoding, $allowed)) {
+            /**
+             * @see Zend_Mail_Exception
+             */
+            require_once 'Zend/Mail/Exception.php';
+            throw new Zend_Mail_Exception('Invalid encoding "' . $encoding . '"');
+        }
+        $this->_headerEncoding = $encoding;
+
+        return $this;
+    }
+
+    /**
+     * Sets the text body for the message.
+     *
+     * @param  string $txt
+     * @param  string $charset
+     * @param  string $encoding
+     * @return Zend_Mail Provides fluent interface
+    */
+    public function setBodyText($txt, $charset = null, $encoding = Zend_Mime::ENCODING_QUOTEDPRINTABLE)
+    {
+        if ($charset === null) {
+            $charset = $this->_charset;
+        }
+
+        $mp = new Zend_Mime_Part($txt);
+        $mp->encoding = $encoding;
+        $mp->type = Zend_Mime::TYPE_TEXT;
+        $mp->disposition = Zend_Mime::DISPOSITION_INLINE;
+        $mp->charset = $charset;
+
+        $this->_bodyText = $mp;
+
+        return $this;
+    }
+
+    /**
+     * Return text body Zend_Mime_Part or string
+     *
+     * @param  bool textOnly Whether to return just the body text content or the MIME part; defaults to false, the MIME part
+     * @return false|Zend_Mime_Part|string
+     */
+    public function getBodyText($textOnly = false)
+    {
+        if ($textOnly && $this->_bodyText) {
+            $body = $this->_bodyText;
+            return $body->getContent();
+        }
+
+        return $this->_bodyText;
+    }
+
+    /**
+     * Sets the HTML body for the message
+     *
+     * @param  string    $html
+     * @param  string    $charset
+     * @param  string    $encoding
+     * @return Zend_Mail Provides fluent interface
+     */
+    public function setBodyHtml($html, $charset = null, $encoding = Zend_Mime::ENCODING_QUOTEDPRINTABLE)
+    {
+        if ($charset === null) {
+            $charset = $this->_charset;
+        }
+
+        $mp = new Zend_Mime_Part($html);
+        $mp->encoding = $encoding;
+        $mp->type = Zend_Mime::TYPE_HTML;
+        $mp->disposition = Zend_Mime::DISPOSITION_INLINE;
+        $mp->charset = $charset;
+
+        $this->_bodyHtml = $mp;
+
+        return $this;
+    }
+
+    /**
+     * Return Zend_Mime_Part representing body HTML
+     *
+     * @param  bool $htmlOnly Whether to return the body HTML only, or the MIME part; defaults to false, the MIME part
+     * @return false|Zend_Mime_Part|string
+     */
+    public function getBodyHtml($htmlOnly = false)
+    {
+        if ($htmlOnly && $this->_bodyHtml) {
+            $body = $this->_bodyHtml;
+            return $body->getContent();
+        }
+
+        return $this->_bodyHtml;
+    }
+
+    /**
+     * Adds an existing attachment to the mail message
+     *
+     * @param  Zend_Mime_Part $attachment
+     * @return Zend_Mail Provides fluent interface
+     */
+    public function addAttachment(Zend_Mime_Part $attachment)
+    {
+        $this->addPart($attachment);
+        $this->hasAttachments = true;
+
+        return $this;
+    }
+
+    /**
+     * Creates a Zend_Mime_Part attachment
+     *
+     * Attachment is automatically added to the mail object after creation. The
+     * attachment object is returned to allow for further manipulation.
+     *
+     * @param  string         $body
+     * @param  string         $mimeType
+     * @param  string         $disposition
+     * @param  string         $encoding
+     * @param  string         $filename OPTIONAL A filename for the attachment
+     * @return Zend_Mime_Part Newly created Zend_Mime_Part object (to allow
+     * advanced settings)
+     */
+    public function createAttachment($body,
+                                     $mimeType    = Zend_Mime::TYPE_OCTETSTREAM,
+                                     $disposition = Zend_Mime::DISPOSITION_ATTACHMENT,
+                                     $encoding    = Zend_Mime::ENCODING_BASE64,
+                                     $filename    = null)
+    {
+
+        $mp = new Zend_Mime_Part($body);
+        $mp->encoding = $encoding;
+        $mp->type = $mimeType;
+        $mp->disposition = $disposition;
+        $mp->filename = $filename;
+
+        $this->addAttachment($mp);
+
+        return $mp;
+    }
+
+    /**
+     * Return a count of message parts
+     *
+     * @return integer
+     */
+    public function getPartCount()
+    {
+        return count($this->_parts);
+    }
+
+    /**
+     * Encode header fields
+     *
+     * Encodes header content according to RFC1522 if it contains non-printable
+     * characters.
+     *
+     * @param  string $value
+     * @return string
+     */
+    protected function _encodeHeader($value)
+    {
+       if (Zend_Mime::isPrintable($value) === false) {
+            if ($this->getHeaderEncoding() === Zend_Mime::ENCODING_QUOTEDPRINTABLE) {
+                $value = Zend_Mime::encodeQuotedPrintableHeader($value, $this->getCharset(), Zend_Mime::LINELENGTH, Zend_Mime::LINEEND);
+            } else {
+                $value = Zend_Mime::encodeBase64Header($value, $this->getCharset(), Zend_Mime::LINELENGTH, Zend_Mime::LINEEND);
+            }
+        }
+
+        return $value;
+    }
+
+    /**
+     * Add a header to the message
+     *
+     * Adds a header to this message. If append is true and the header already
+     * exists, raises a flag indicating that the header should be appended.
+     *
+     * @param string  $headerName
+     * @param string  $value
+     * @param bool $append
+     */
+    protected function _storeHeader($headerName, $value, $append = false)
+    {
+        if (isset($this->_headers[$headerName])) {
+            $this->_headers[$headerName][] = $value;
+        } else {
+            $this->_headers[$headerName] = array($value);
+        }
+
+        if ($append) {
+            $this->_headers[$headerName]['append'] = true;
+        }
+
+    }
+
+    /**
+     * Clear header from the message
+     *
+     * @param string $headerName
+     */
+    protected function _clearHeader($headerName)
+    {
+        if (isset($this->_headers[$headerName])){
+            unset($this->_headers[$headerName]);
+        }
+    }
+
+    /**
+     * Helper function for adding a recipient and the corresponding header
+     *
+     * @param string $headerName
+     * @param string $email
+     * @param string $name
+     */
+    protected function _addRecipientAndHeader($headerName, $email, $name)
+    {
+        $email = $this->_filterEmail($email);
+        $name  = $this->_filterName($name);
+        // prevent duplicates
+        $this->_recipients[$email] = 1;
+        $this->_storeHeader($headerName, $this->_formatAddress($email, $name), true);
+    }
+
+    /**
+     * Adds To-header and recipient
+     *
+     * @param  string $email
+     * @param  string $name
+     * @return Zend_Mail Provides fluent interface
+     */
+    public function addTo($email, $name='')
+    {
+        $this->_addRecipientAndHeader('To', $email, $name);
+        $this->_to[] = $email;
+        return $this;
+    }
+
+    /**
+     * Adds Cc-header and recipient
+     *
+     * @param  string    $email
+     * @param  string    $name
+     * @return Zend_Mail Provides fluent interface
+     */
+    public function addCc($email, $name='')
+    {
+        $this->_addRecipientAndHeader('Cc', $email, $name);
+        return $this;
+    }
+
+    /**
+     * Adds Bcc recipient
+     *
+     * @param  string    $email
+     * @return Zend_Mail Provides fluent interface
+     */
+    public function addBcc($email)
+    {
+        $this->_addRecipientAndHeader('Bcc', $email, '');
+        return $this;
+    }
+
+    /**
+     * Return list of recipient email addresses
+     *
+     * @return array (of strings)
+     */
+    public function getRecipients()
+    {
+        return array_keys($this->_recipients);
+    }
+
+    /**
+     * Clears list of recipient email addresses
+     *
+     * @return Zend_Mail Provides fluent interface
+     */
+    public function clearRecipients()
+    {
+        $this->_recipients = array();
+        $this->_to = array();
+
+        $this->_clearHeader('To');
+        $this->_clearHeader('Cc');
+        $this->_clearHeader('Bcc');
+
+        return $this;
+    }
+
+    /**
+     * Sets From-header and sender of the message
+     *
+     * @param  string    $email
+     * @param  string    $name
+     * @return Zend_Mail Provides fluent interface
+     * @throws Zend_Mail_Exception if called subsequent times
+     */
+    public function setFrom($email, $name = null)
+    {
+        if ($this->_from === null) {
+            $email = $this->_filterEmail($email);
+            $name  = $this->_filterName($name);
+            $this->_from = $email;
+            $this->_storeHeader('From', $this->_formatAddress($email, $name), true);
+        } else {
+            /**
+             * @see Zend_Mail_Exception
+             */
+            require_once 'Zend/Mail/Exception.php';
+            throw new Zend_Mail_Exception('From Header set twice');
+        }
+        return $this;
+    }
+
+    /**
+     * Set Reply-To Header
+     *
+     * @param string $email
+     * @param string $name
+     * @return Zend_Mail
+     */
+    public function setReplyTo($email, $name=null)
+    {
+        $this->_addRecipientAndHeader('Reply-To', $email, $name);
+        return $this;
+    }
+
+    /**
+     * Returns the sender of the mail
+     *
+     * @return string
+     */
+    public function getFrom()
+    {
+        return $this->_from;
+    }
+
+    /**
+     * Clears the sender from the mail
+     *
+     * @return Zend_Mail Provides fluent interface
+     */
+    public function clearFrom()
+    {
+        $this->_from = null;
+        $this->_clearHeader('From');
+
+        return $this;
+    }
+
+    /**
+     * Sets the Return-Path header of the message
+     *
+     * @param  string    $email
+     * @return Zend_Mail Provides fluent interface
+     * @throws Zend_Mail_Exception if set multiple times
+     */
+    public function setReturnPath($email)
+    {
+        if ($this->_returnPath === null) {
+            $email = $this->_filterEmail($email);
+            $this->_returnPath = $email;
+            $this->_storeHeader('Return-Path', $email, false);
+        } else {
+            /**
+             * @see Zend_Mail_Exception
+             */
+            require_once 'Zend/Mail/Exception.php';
+            throw new Zend_Mail_Exception('Return-Path Header set twice');
+        }
+        return $this;
+    }
+
+    /**
+     * Returns the current Return-Path address of the message
+     *
+     * If no Return-Path header is set, returns the value of {@link $_from}.
+     *
+     * @return string
+     */
+    public function getReturnPath()
+    {
+        if (null !== $this->_returnPath) {
+            return $this->_returnPath;
+        }
+
+        return $this->_from;
+    }
+
+    /**
+     * Clears the current Return-Path address from the message
+     *
+     * @return Zend_Mail Provides fluent interface
+     */
+    public function clearReturnPath()
+    {
+        $this->_returnPath = null;
+        $this->_clearHeader('Return-Path');
+
+        return $this;
+    }
+
+    /**
+     * Sets the subject of the message
+     *
+     * @param   string    $subject
+     * @return  Zend_Mail Provides fluent interface
+     * @throws  Zend_Mail_Exception
+     */
+    public function setSubject($subject)
+    {
+        if ($this->_subject === null) {
+            $subject = $this->_filterOther($subject);
+            $this->_subject = $this->_encodeHeader($subject);
+            $this->_storeHeader('Subject', $this->_subject);
+        } else {
+            /**
+             * @see Zend_Mail_Exception
+             */
+            require_once 'Zend/Mail/Exception.php';
+            throw new Zend_Mail_Exception('Subject set twice');
+        }
+        return $this;
+    }
+
+    /**
+     * Returns the encoded subject of the message
+     *
+     * @return string
+     */
+    public function getSubject()
+    {
+        return $this->_subject;
+    }
+
+    /**
+     * Clears the encoded subject from the message
+     *
+     * @return  Zend_Mail Provides fluent interface
+     */
+    public function clearSubject()
+    {
+        $this->_subject = null;
+        $this->_clearHeader('Subject');
+
+        return $this;
+    }
+
+    /**
+     * Sets Date-header
+     *
+     * @param  string    $date
+     * @return Zend_Mail Provides fluent interface
+     * @throws Zend_Mail_Exception if called subsequent times
+     */
+    public function setDate($date = null)
+    {
+        if ($this->_date === null) {
+            if ($date === null) {
+                $date = date('r');
+            } else if (is_int($date)) {
+                $date = date('r', $date);
+            } else if (is_string($date)) {
+                $date = strtotime($date);
+                if ($date === false || $date < 0) {
+                           /**
+                            * @see Zend_Mail_Exception
+                            */
+                           require_once 'Zend/Mail/Exception.php';
+                       throw new Zend_Mail_Exception('String representations of Date Header must be ' .
+                                                  'strtotime()-compatible');
+                }
+                $date = date('r', $date);
+            } else if ($date instanceof Zend_Date) {
+                $date = $date->get(Zend_Date::RFC_2822);
+            } else {
+                   /**
+                    * @see Zend_Mail_Exception
+                    */
+                   require_once 'Zend/Mail/Exception.php';
+               throw new Zend_Mail_Exception(__METHOD__ . ' only accepts UNIX timestamps, Zend_Date objects, ' .
+                                              ' and strtotime()-compatible strings');
+            }
+            $this->_date = $date;
+            $this->_storeHeader('Date', $date);
+        } else {
+            /**
+             * @see Zend_Mail_Exception
+             */
+               require_once 'Zend/Mail/Exception.php';
+               throw new Zend_Mail_Exception('Date Header set twice');
+        }
+        return $this;
+    }
+
+    /**
+     * Returns the formatted date of the message
+     *
+     * @return string
+     */
+    public function getDate()
+    {
+        return $this->_date;
+    }
+
+    /**
+     * Clears the formatted date from the message
+     *
+     * @return Zend_Mail Provides fluent interface
+     */
+    public function clearDate()
+    {
+        $this->_date = null;
+        $this->_clearHeader('Date');
+
+        return $this;
+    }
+
+    /**
+     * Sets the Message-ID of the message
+     *
+     * @param   boolean|string  $id
+     * true  :Auto
+     * false :No set
+     * null  :No set
+     * string:Sets string
+     * @return  Zend_Mail Provides fluent interface
+     * @throws  Zend_Mail_Exception
+     */
+    public function setMessageId($id = true)
+    {
+       if ($id === null || $id === false) {
+               return $this;
+       } elseif ($id === true) {
+            $id = $this->createMessageId();
+       }
+
+        if ($this->_messageId === null) {
+               $id = $this->_filterOther($id);
+            $this->_messageId = $id;
+            $this->_storeHeader('Message-Id', $this->_messageId);
+        } else {
+            /**
+             * @see Zend_Mail_Exception
+             */
+            require_once 'Zend/Mail/Exception.php';
+            throw new Zend_Mail_Exception('Message-ID set twice');
+        }
+
+        return $this;
+    }
+
+    /**
+     * Returns the Message-ID of the message
+     *
+     * @return string
+     */
+    public function getMessageId()
+    {
+        return $this->_messageId;
+    }
+
+
+    /**
+     * Clears the Message-ID from the message
+     *
+     * @return Zend_Mail Provides fluent interface
+     */
+    public function clearMessageId()
+    {
+        $this->_messageId = null;
+        $this->_clearHeader('Message-Id');
+
+        return $this;
+    }
+
+    /**
+     * Creates the Message-ID
+     *
+     * @return string
+     */
+    public function createMessageId() {
+
+        $time = time();
+
+        if ($this->_from !== null) {
+               $user = $this->_from;
+        } elseif (isset($_SERVER['REMOTE_ADDR'])) {
+               $user = $_SERVER['REMOTE_ADDR'];
+        } else {
+               $user = getmypid();
+        }
+
+       $rand = mt_rand();
+
+       if ($this->_recipients !== array()) {
+            $recipient = array_rand($this->_recipients);
+       } else {
+               $recipient = 'unknown';
+       }
+
+       if (isset($_SERVER["SERVER_NAME"])) {
+            $hostName = $_SERVER["SERVER_NAME"];
+        } else {
+               $hostName = php_uname('n');
+        }
+
+        return sha1($time . $user . $rand . $recipient) . '@' . $hostName;
+    }
+
+    /**
+     * Add a custom header to the message
+     *
+     * @param  string              $name
+     * @param  string              $value
+     * @param  boolean             $append
+     * @return Zend_Mail           Provides fluent interface
+     * @throws Zend_Mail_Exception on attempts to create standard headers
+     */
+    public function addHeader($name, $value, $append = false)
+    {
+        $prohibit = array('to', 'cc', 'bcc', 'from', 'subject',
+                          'return-path', 'date', 'message-id',
+                         );
+        if (in_array(strtolower($name), $prohibit)) {
+            /**
+             * @see Zend_Mail_Exception
+             */
+            require_once 'Zend/Mail/Exception.php';
+            throw new Zend_Mail_Exception('Cannot set standard header from addHeader()');
+        }
+
+        $value = $this->_filterOther($value);
+        $value = $this->_encodeHeader($value);
+        $this->_storeHeader($name, $value, $append);
+
+        return $this;
+    }
+
+    /**
+     * Return mail headers
+     *
+     * @return void
+     */
+    public function getHeaders()
+    {
+        return $this->_headers;
+    }
+
+    /**
+     * Sends this email using the given transport or a previously
+     * set DefaultTransport or the internal mail function if no
+     * default transport had been set.
+     *
+     * @param  Zend_Mail_Transport_Abstract $transport
+     * @return Zend_Mail                    Provides fluent interface
+     */
+    public function send($transport = null)
+    {
+        if ($transport === null) {
+            if (! self::$_defaultTransport instanceof Zend_Mail_Transport_Abstract) {
+                require_once 'Zend/Mail/Transport/Sendmail.php';
+                $transport = new Zend_Mail_Transport_Sendmail();
+            } else {
+                $transport = self::$_defaultTransport;
+            }
+        }
+
+        if ($this->_date === null) {
+            $this->setDate();
+        }
+
+        $transport->send($this);
+
+        return $this;
+    }
+
+    /**
+     * Filter of email data
+     *
+     * @param string $email
+     * @return string
+     */
+    protected function _filterEmail($email)
+    {
+       $rule = array("\r" => '',
+                     "\n" => '',
+                     "\t" => '',
+                      '"'  => '',
+                     ','  => '',
+                      '<'  => '',
+                      '>'  => '',
+       );
+
+        return strtr($email, $rule);
+    }
+
+    /**
+     * Filter of name data
+     *
+     * @param string $name
+     * @return string
+     */
+    protected function _filterName($name)
+    {
+       $rule = array("\r" => '',
+                      "\n" => '',
+                      "\t" => '',
+                      '"'  => "'",
+                      '<'  => '[',
+                     '>'  => ']',
+       );
+
+        return trim(strtr($name, $rule));
+    }
+
+    /**
+     * Filter of other data
+     *
+     * @param string $data
+     * @return string
+     */
+    protected function _filterOther($data)
+    {
+        $rule = array("\r" => '',
+                      "\n" => '',
+                      "\t" => '',
+        );
+
+        return strtr($data, $rule);
+    }
+
+    /**
+     * Formats e-mail address
+     *
+     * @param string $email
+     * @param string $name
+     * @return string
+     */
+    protected function _formatAddress($email, $name)
+    {
+        if ($name === '' || $name === null || $name === $email) {
+            return $email;
+        } else {
+            $encodedName = $this->_encodeHeader($name);
+            if ($encodedName === $name && strpos($name, ',') !== false) {
+                $format = '"%s" <%s>';
+            } else {
+                $format = '%s <%s>';
+            }
+            return sprintf($format, $encodedName, $email);
+        }
+    }
+
+}
diff --git a/lib/zend/Zend/Memory.php b/lib/zend/Zend/Memory.php
new file mode 100644 (file)
index 0000000..1ed9d3f
--- /dev/null
@@ -0,0 +1,73 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @package    Zend_Memory
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/** Zend_Memory_Exception */
+require_once 'Zend/Memory/Manager.php';
+
+/** Zend_Memory_Value */
+require_once 'Zend/Memory/Value.php';
+
+/** Zend_Memory_Container */
+require_once 'Zend/Memory/Container.php';
+
+/** Zend_Memory_Exception */
+require_once 'Zend/Cache.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Memory
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Memory
+{
+    /**
+     * Factory
+     *
+     * @param string $backend backend name
+     * @param array $backendOptions associative array of options for the corresponding backend constructor
+     * @return Zend_Memory_Manager
+     * @throws Zend_Memory_Exception
+     */
+    public static function factory($backend, $backendOptions = array())
+    {
+        if (strcasecmp($backend, 'none') == 0) {
+            return new Zend_Memory_Manager();
+        }
+
+        // because lowercase will fail
+        $backend = @ucfirst(strtolower($backend));
+
+        if (!in_array($backend, Zend_Cache::$availableBackends)) {
+            require_once 'Zend/Memory/Exception.php';
+            throw new Zend_Memory_Exception("Incorrect backend ($backend)");
+        }
+
+        $backendClass = 'Zend_Cache_Backend_' . $backend;
+
+        // For perfs reasons, we do not use the Zend_Loader::loadClass() method
+        // (security controls are explicit)
+        require_once str_replace('_', DIRECTORY_SEPARATOR, $backendClass) . '.php';
+
+        $backendObject = new $backendClass($backendOptions);
+
+        return new Zend_Memory_Manager($backendObject);
+    }
+}
index 499ff21b6a69220f46e7334184c22601f9f9a974..9072f9d0c521d9ed1a70c919b83b45b52201c646 100644 (file)
@@ -14,8 +14,9 @@
  *
  * @category   Zend
  * @package    Zend_Mime
- * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
  */
 
 
@@ -24,7 +25,7 @@
  *
  * @category   Zend
  * @package    Zend_Mime
- * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
  */
 class Zend_Mime
@@ -38,7 +39,7 @@ class Zend_Mime
     const ENCODING_BASE64 = 'base64';
     const DISPOSITION_ATTACHMENT = 'attachment';
     const DISPOSITION_INLINE = 'inline';
-    const LINELENGTH = 74;
+    const LINELENGTH = 72;
     const LINEEND = "\n";
     const MULTIPART_ALTERNATIVE = 'multipart/alternative';
     const MULTIPART_MIXED = 'multipart/mixed';
@@ -114,7 +115,7 @@ class Zend_Mime
     }
 
     /**
-     * Encode a given string with the QUOTED_PRINTABLE mechanism
+     * Encode a given string with the QUOTED_PRINTABLE mechanism and wrap the lines.
      *
      * @param string $str
      * @param int $lineLength Defaults to {@link LINELENGTH}
@@ -126,9 +127,7 @@ class Zend_Mime
         $lineEnd = self::LINEEND)
     {
         $out = '';
-        $str = str_replace('=', '=3D', $str);
-        $str = str_replace(self::$qpKeys, self::$qpReplaceValues, $str);
-        $str = rtrim($str);
+        $str = self::_encodeQuotedPrintable($str);
 
         // Split encoded text into separate lines
         while ($str) {
@@ -158,6 +157,120 @@ class Zend_Mime
         return $out;
     }
 
+    /**
+     * Converts a string into quoted printable format.
+     *
+     * @param  string $str
+     * @return string
+     */
+    private static function _encodeQuotedPrintable($str)
+    {
+        $str = str_replace('=', '=3D', $str);
+        $str = str_replace(self::$qpKeys, self::$qpReplaceValues, $str);
+        $str = rtrim($str);
+        return $str;
+    }
+
+    /**
+     * Encode a given string with the QUOTED_PRINTABLE mechanism for Mail Headers.
+     *
+     * Mail headers depend on an extended quoted printable algorithm otherwise
+     * a range of bugs can occur.
+     *
+     * @param string $str
+     * @param string $charset
+     * @param int $lineLength Defaults to {@link LINELENGTH}
+     * @param int $lineEnd Defaults to {@link LINEEND}
+     * @return string
+     */
+    public static function encodeQuotedPrintableHeader($str, $charset,
+        $lineLength = self::LINELENGTH,
+        $lineEnd = self::LINEEND)
+    {
+        // Reduce line-length by the length of the required delimiter, charsets and encoding
+        $prefix = sprintf('=?%s?Q?', $charset);
+        $lineLength = $lineLength-strlen($prefix)-3;
+
+        $str = self::_encodeQuotedPrintable($str);
+
+        // Mail-Header required chars have to be encoded also:
+        $str = str_replace(array('?', ' ', '_'), array('=3F', '=20', '=5F'), $str);
+
+        // initialize first line, we need it anyways
+        $lines = array(0 => "");
+
+        // Split encoded text into separate lines
+        $tmp = "";
+        while(strlen($str) > 0) {
+            $currentLine = max(count($lines)-1, 0);
+            $token       = self::getNextQuotedPrintableToken($str);
+            $str         = substr($str, strlen($token));
+
+            $tmp .= $token;
+            if($token == '=20') {
+                // only if we have a single char token or space, we can append the
+                // tempstring it to the current line or start a new line if necessary.
+                if(strlen($lines[$currentLine].$tmp) > $lineLength) {
+                    $lines[$currentLine+1] = $tmp;
+                } else {
+                    $lines[$currentLine] .= $tmp;
+                }
+                $tmp = "";
+            }
+            // don't forget to append the rest to the last line
+            if(strlen($str) == 0) {
+                $lines[$currentLine] .= $tmp;
+            }
+        }
+
+        // assemble the lines together by pre- and appending delimiters, charset, encoding.
+        for($i = 0; $i < count($lines); $i++) {
+            $lines[$i] = " ".$prefix.$lines[$i]."?=";
+        }
+        $str = trim(implode($lineEnd, $lines));
+        return $str;
+    }
+
+    /**
+     * Retrieves the first token from a quoted printable string.
+     *
+     * @param  string $str
+     * @return string
+     */
+    private static function getNextQuotedPrintableToken($str)
+    {
+        if(substr($str, 0, 1) == "=") {
+            $token = substr($str, 0, 3);
+        } else {
+            $token = substr($str, 0, 1);
+        }
+        return $token;
+    }
+
+    /**
+     * Encode a given string in mail header compatible base64 encoding.
+     *
+     * @param string $str
+     * @param string $charset
+     * @param int $lineLength Defaults to {@link LINELENGTH}
+     * @param int $lineEnd Defaults to {@link LINEEND}
+     * @return string
+     */
+    public static function encodeBase64Header($str,
+        $charset,
+        $lineLength = self::LINELENGTH,
+        $lineEnd = self::LINEEND)
+    {
+        $prefix = '=?' . $charset . '?B?';
+        $suffix = '?=';
+        $remainingLength = $lineLength - strlen($prefix) - strlen($suffix);
+
+        $encodedValue = self::encodeBase64($str, $remainingLength, $lineEnd);
+        $encodedValue = str_replace($lineEnd, $suffix . $lineEnd . ' ' . $prefix, $encodedValue);
+        $encodedValue = $prefix . $encodedValue . $suffix;
+        return $encodedValue;
+    }
+
     /**
      * Encode a given string in base64 encoding and break lines
      * according to the maximum linelength.
diff --git a/lib/zend/Zend/Navigation.php b/lib/zend/Zend/Navigation.php
new file mode 100644 (file)
index 0000000..0915f55
--- /dev/null
@@ -0,0 +1,54 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category  Zend
+ * @package   Zend_Navigation
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license   http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/**
+ * @see Zend_Navigation_Container
+ */
+require_once 'Zend/Navigation/Container.php';
+
+/**
+ * A simple container class for {@link Zend_Navigation_Page} pages
+ *
+ * @category  Zend
+ * @package   Zend_Navigation
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license   http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Navigation extends Zend_Navigation_Container
+{
+    /**
+     * Creates a new navigation container
+     *
+     * @param array|Zend_Config $pages    [optional] pages to add
+     * @throws Zend_Navigation_Exception  if $pages is invalid
+     */
+    public function __construct($pages = null)
+    {
+        if (is_array($pages) || $pages instanceof Zend_Config) {
+            $this->addPages($pages);
+        } elseif (null !== $pages) {
+            require_once 'Zend/Navigation/Exception.php';
+            throw new Zend_Navigation_Exception(
+                    'Invalid argument: $pages must be an array, an ' .
+                    'instance of Zend_Config, or null');
+        }
+    }
+}
diff --git a/lib/zend/Zend/OpenId.php b/lib/zend/Zend/OpenId.php
new file mode 100644 (file)
index 0000000..55a0fea
--- /dev/null
@@ -0,0 +1,753 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_OpenId
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/**
+ * @see Zend_Controller_Response_Abstract
+ */
+require_once "Zend/Controller/Response/Abstract.php";
+
+/**
+ * Static class that contains common utility functions for
+ * {@link Zend_OpenId_Consumer} and {@link Zend_OpenId_Provider}.
+ *
+ * This class implements common utility functions that are used by both
+ * Consumer and Provider. They include functions for Diffie-Hellman keys
+ * generation and exchange, URL normalization, HTTP redirection and some others.
+ *
+ * @category   Zend
+ * @package    Zend_OpenId
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_OpenId
+{
+    /**
+     * Default Diffie-Hellman key generator (1024 bit)
+     */
+    const DH_P   = 'dcf93a0b883972ec0e19989ac5a2ce310e1d37717e8d9571bb7623731866e61ef75a2e27898b057f9891c2e27a639c3f29b60814581cd3b2ca3986d2683705577d45c2e7e52dc81c7a171876e5cea74b1448bfdfaf18828efd2519f14e45e3826634af1949e5b535cc829a483b8a76223e5d490a257f05bdff16f2fb22c583ab';
+
+    /**
+     * Default Diffie-Hellman prime number (should be 2 or 5)
+     */
+    const DH_G   = '02';
+
+    /**
+     * OpenID 2.0 namespace. All OpenID 2.0 messages MUST contain variable
+     * openid.ns with its value.
+     */
+    const NS_2_0 = 'http://specs.openid.net/auth/2.0';
+
+    /**
+     * Allows enable/disable stoping execution of PHP script after redirect()
+     */
+    static public $exitOnRedirect = true;
+
+    /**
+     * Alternative request URL that can be used to override the default
+     * selfUrl() response
+     */
+    static public $selfUrl = null;
+
+    /**
+     * Sets alternative request URL that can be used to override the default
+     * selfUrl() response
+     *
+     * @param string $selfUrl the URL to be set
+     * @return string the old value of overriding URL
+     */
+    static public function setSelfUrl($selfUrl = null)
+    {
+        $ret = self::$selfUrl;
+        self::$selfUrl = $selfUrl;
+        return $ret;
+    }
+
+    /**
+     * Returns a full URL that was requested on current HTTP request.
+     *
+     * @return string
+     */
+    static public function selfUrl()
+    {
+        if (self::$selfUrl !== null) {
+            return self::$selfUrl;
+        } if (isset($_SERVER['SCRIPT_URI'])) {
+            return $_SERVER['SCRIPT_URI'];
+        }
+        $url = '';
+        $port = '';
+        if (isset($_SERVER['HTTP_HOST'])) {
+            if (($pos = strpos($_SERVER['HTTP_HOST'], ':')) === false) {
+                if (isset($_SERVER['SERVER_PORT'])) {
+                    $port = ':' . $_SERVER['SERVER_PORT'];
+                }
+                $url = $_SERVER['HTTP_HOST'];
+            } else {
+                $url = substr($_SERVER['HTTP_HOST'], 0, $pos);
+                $port = substr($_SERVER['HTTP_HOST'], $pos);
+            }
+        } else if (isset($_SERVER['SERVER_NAME'])) {
+            $url = $_SERVER['SERVER_NAME'];
+            if (isset($_SERVER['SERVER_PORT'])) {
+                $port = ':' . $_SERVER['SERVER_PORT'];
+            }
+        }
+        if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
+            $url = 'https://' . $url;
+            if ($port == ':443') {
+                $port = '';
+            }
+        } else {
+            $url = 'http://' . $url;
+            if ($port == ':80') {
+                $port = '';
+            }
+        }
+
+        $url .= $port;
+        if (isset($_SERVER['HTTP_X_REWRITE_URL'])) {
+            $url .= $_SERVER['HTTP_X_REWRITE_URL'];
+        } elseif (isset($_SERVER['REQUEST_URI'])) {
+            $query = strpos($_SERVER['REQUEST_URI'], '?');
+            if ($query === false) {
+                $url .= $_SERVER['REQUEST_URI'];
+            } else {
+                $url .= substr($_SERVER['REQUEST_URI'], 0, $query);
+            }
+        } else if (isset($_SERVER['SCRIPT_URL'])) {
+            $url .= $_SERVER['SCRIPT_URL'];
+        } else if (isset($_SERVER['REDIRECT_URL'])) {
+            $url .= $_SERVER['REDIRECT_URL'];
+        } else if (isset($_SERVER['PHP_SELF'])) {
+            $url .= $_SERVER['PHP_SELF'];
+        } else if (isset($_SERVER['SCRIPT_NAME'])) {
+            $url .= $_SERVER['SCRIPT_NAME'];
+            if (isset($_SERVER['PATH_INFO'])) {
+                $url .= $_SERVER['PATH_INFO'];
+            }
+        }
+        return $url;
+    }
+
+    /**
+     * Returns an absolute URL for the given one
+     *
+     * @param string $url absilute or relative URL
+     * @return string
+     */
+    static public function absoluteUrl($url)
+    {
+        if (empty($url)) {
+            return Zend_OpenId::selfUrl();
+        } else if (!preg_match('|^([^:]+)://|', $url)) {
+            if (preg_match('|^([^:]+)://([^:@]*(?:[:][^@]*)?@)?([^/:@?#]*)(?:[:]([^/?#]*))?(/[^?]*)?((?:[?](?:[^#]*))?(?:#.*)?)$|', Zend_OpenId::selfUrl(), $reg)) {
+                $scheme = $reg[1];
+                $auth = $reg[2];
+                $host = $reg[3];
+                $port = $reg[4];
+                $path = $reg[5];
+                $query = $reg[6];
+                if ($url[0] == '/') {
+                    return $scheme
+                        . '://'
+                        . $auth
+                        . $host
+                        . (empty($port) ? '' : (':' . $port))
+                        . $url;
+                } else {
+                    $dir = dirname($path);
+                    return $scheme
+                        . '://'
+                        . $auth
+                        . $host
+                        . (empty($port) ? '' : (':' . $port))
+                        . (strlen($dir) > 1 ? $dir : '')
+                        . '/'
+                        . $url;
+                }
+            }
+        }
+        return $url;
+    }
+
+    /**
+     * Converts variable/value pairs into URL encoded query string
+     *
+     * @param array $params variable/value pairs
+     * @return string URL encoded query string
+     */
+    static public function paramsToQuery($params)
+    {
+        foreach($params as $key => $value) {
+            if (isset($query)) {
+                $query .= '&' . $key . '=' . urlencode($value);
+            } else {
+                $query = $key . '=' . urlencode($value);
+            }
+        }
+        return isset($query) ? $query : '';
+    }
+
+    /**
+     * Normalizes URL according to RFC 3986 to use it in comparison operations.
+     * The function gets URL argument by reference and modifies it.
+     * It returns true on success and false of failure.
+     *
+     * @param string &$id url to be normalized
+     * @return bool
+     */
+    static public function normalizeUrl(&$id)
+    {
+        // RFC 3986, 6.2.2.  Syntax-Based Normalization
+
+        // RFC 3986, 6.2.2.2 Percent-Encoding Normalization
+        $i = 0;
+        $n = strlen($id);
+        $res = '';
+        while ($i < $n) {
+            if ($id[$i] == '%') {
+                if ($i + 2 >= $n) {
+                    return false;
+                }
+                ++$i;
+                if ($id[$i] >= '0' && $id[$i] <= '9') {
+                    $c = ord($id[$i]) - ord('0');
+                } else if ($id[$i] >= 'A' && $id[$i] <= 'F') {
+                    $c = ord($id[$i]) - ord('A') + 10;
+                } else if ($id[$i] >= 'a' && $id[$i] <= 'f') {
+                    $c = ord($id[$i]) - ord('a') + 10;
+                } else {
+                    return false;
+                }
+                ++$i;
+                if ($id[$i] >= '0' && $id[$i] <= '9') {
+                    $c = ($c << 4) | (ord($id[$i]) - ord('0'));
+                } else if ($id[$i] >= 'A' && $id[$i] <= 'F') {
+                    $c = ($c << 4) | (ord($id[$i]) - ord('A') + 10);
+                } else if ($id[$i] >= 'a' && $id[$i] <= 'f') {
+                    $c = ($c << 4) | (ord($id[$i]) - ord('a') + 10);
+                } else {
+                    return false;
+                }
+                ++$i;
+                $ch = chr($c);
+                if (($ch >= 'A' && $ch <= 'Z') ||
+                    ($ch >= 'a' && $ch <= 'z') ||
+                    $ch == '-' ||
+                    $ch == '.' ||
+                    $ch == '_' ||
+                    $ch == '~') {
+                    $res .= $ch;
+                } else {
+                    $res .= '%';
+                    if (($c >> 4) < 10) {
+                        $res .= chr(($c >> 4) + ord('0'));
+                    } else {
+                        $res .= chr(($c >> 4) - 10 + ord('A'));
+                    }
+                    $c = $c & 0xf;
+                    if ($c < 10) {
+                        $res .= chr($c + ord('0'));
+                    } else {
+                        $res .= chr($c - 10 + ord('A'));
+                    }
+                }
+            } else {
+                $res .= $id[$i++];
+            }
+        }
+
+        if (!preg_match('|^([^:]+)://([^:@]*(?:[:][^@]*)?@)?([^/:@?#]*)(?:[:]([^/?#]*))?(/[^?#]*)?((?:[?](?:[^#]*))?)((?:#.*)?)$|', $res, $reg)) {
+            return false;
+        }
+        $scheme = $reg[1];
+        $auth = $reg[2];
+        $host = $reg[3];
+        $port = $reg[4];
+        $path = $reg[5];
+        $query = $reg[6];
+        $fragment = $reg[7]; /* strip it */
+
+        if (empty($scheme) || empty($host)) {
+            return false;
+        }
+
+        // RFC 3986, 6.2.2.1.  Case Normalization
+        $scheme = strtolower($scheme);
+        $host = strtolower($host);
+
+        // RFC 3986, 6.2.2.3.  Path Segment Normalization
+        if (!empty($path)) {
+            $i = 0;
+            $n = strlen($path);
+            $res = "";
+            while ($i < $n) {
+                if ($path[$i] == '/') {
+                    ++$i;
+                    while ($i < $n && $path[$i] == '/') {
+                        ++$i;
+                    }
+                    if ($i < $n && $path[$i] == '.') {
+                        ++$i;
+                        if ($i < $n && $path[$i] == '.') {
+                            ++$i;
+                            if ($i == $n || $path[$i] == '/') {
+                                if (($pos = strrpos($res, '/')) !== false) {
+                                    $res = substr($res, 0, $pos);
+                                }
+                            } else {
+                                    $res .= '/..';
+                            }
+                        } else if ($i != $n && $path[$i] != '/') {
+                            $res .= '/.';
+                        }
+                    } else {
+                        $res .= '/';
+                    }
+                } else {
+                    $res .= $path[$i++];
+                }
+            }
+            $path = $res;
+        }
+
+        // RFC 3986,6.2.3.  Scheme-Based Normalization
+        if ($scheme == 'http') {
+            if ($port == 80) {
+                $port = '';
+            }
+        } else if ($scheme == 'https') {
+            if ($port == 443) {
+                $port = '';
+            }
+        }
+        if (empty($path)) {
+            $path = '/';
+        }
+
+        $id = $scheme
+            . '://'
+            . $auth
+            . $host
+            . (empty($port) ? '' : (':' . $port))
+            . $path
+            . $query;
+        return true;
+    }
+
+    /**
+     * Normalizes OpenID identifier that can be URL or XRI name.
+     * Returns true on success and false of failure.
+     *
+     * Normalization is performed according to the following rules:
+     * 1. If the user's input starts with one of the "xri://", "xri://$ip*",
+     *    or "xri://$dns*" prefixes, they MUST be stripped off, so that XRIs
+     *    are used in the canonical form, and URI-authority XRIs are further
+     *    considered URL identifiers.
+     * 2. If the first character of the resulting string is an XRI Global
+     *    Context Symbol ("=", "@", "+", "$", "!"), then the input SHOULD be
+     *    treated as an XRI.
+     * 3. Otherwise, the input SHOULD be treated as an http URL; if it does
+     *    not include a "http" or "https" scheme, the Identifier MUST be
+     *    prefixed with the string "http://".
+     * 4. URL identifiers MUST then be further normalized by both following
+     *    redirects when retrieving their content and finally applying the
+     *    rules in Section 6 of [RFC3986] to the final destination URL.
+     * @param string &$id identifier to be normalized
+     * @return bool
+     */
+    static public function normalize(&$id)
+    {
+        $id = trim($id);
+        if (strlen($id) === 0) {
+            return true;
+        }
+
+        // 7.2.1
+        if (strpos($id, 'xri://$ip*') === 0) {
+            $id = substr($id, strlen('xri://$ip*'));
+        } else if (strpos($id, 'xri://$dns*') === 0) {
+            $id = substr($id, strlen('xri://$dns*'));
+        } else if (strpos($id, 'xri://') === 0) {
+            $id = substr($id, strlen('xri://'));
+        }
+
+        // 7.2.2
+        if ($id[0] == '=' ||
+            $id[0] == '@' ||
+            $id[0] == '+' ||
+            $id[0] == '$' ||
+            $id[0] == '!') {
+            return true;
+        }
+
+        // 7.2.3
+        if (strpos($id, "://") === false) {
+            $id = 'http://' . $id;
+        }
+
+        // 7.2.4
+        return self::normalizeURL($id);
+    }
+
+    /**
+     * Performs a HTTP redirection to specified URL with additional data.
+     * It may generate redirected request using GET or POST HTTP method.
+     * The function never returns.
+     *
+     * @param string $url URL to redirect to
+     * @param array $params additional variable/value pairs to send
+     * @param Zend_Controller_Response_Abstract $response
+     * @param string $method redirection method ('GET' or 'POST')
+     */
+    static public function redirect($url, $params = null,
+        Zend_Controller_Response_Abstract $response = null, $method = 'GET')
+    {
+        $url = Zend_OpenId::absoluteUrl($url);
+        $body = "";
+        if (null === $response) {
+            require_once "Zend/Controller/Response/Http.php";
+            $response = new Zend_Controller_Response_Http();
+        }
+
+        if ($method == 'POST') {
+            $body = "<html><body onLoad=\"document.forms[0].submit();\">\n";
+            $body .= "<form method=\"POST\" action=\"$url\">\n";
+            if (is_array($params) && count($params) > 0) {
+                foreach($params as $key => $value) {
+                    $body .= '<input type="hidden" name="' . $key . '" value="' . $value . "\">\n";
+                }
+            }
+            $body .= "<input type=\"submit\" value=\"Continue OpenID transaction\">\n";
+            $body .= "</form></body></html>\n";
+        } else if (is_array($params) && count($params) > 0) {
+            if (strpos($url, '?') === false) {
+                $url .= '?' . self::paramsToQuery($params);
+            } else {
+                $url .= '&' . self::paramsToQuery($params);
+            }
+        }
+        if (!empty($body)) {
+            $response->setBody($body);
+        } else if (!$response->canSendHeaders()) {
+            $response->setBody("<script language=\"JavaScript\"" .
+                 " type=\"text/javascript\">window.location='$url';" .
+                 "</script>");
+        } else {
+            $response->setRedirect($url);
+        }
+        $response->sendResponse();
+        if (self::$exitOnRedirect) {
+            exit();
+        }
+    }
+
+    /**
+     * Produces string of random byte of given length.
+     *
+     * @param integer $len length of requested string
+     * @return string RAW random binary string
+     */
+    static public function randomBytes($len)
+    {
+        $key = '';
+        for($i=0; $i < $len; $i++) {
+            $key .= chr(mt_rand(0, 255));
+        }
+        return $key;
+    }
+
+    /**
+     * Generates a hash value (message digest) according to given algorithm.
+     * It returns RAW binary string.
+     *
+     * This is a wrapper function that uses one of available internal function
+     * dependent on given PHP configuration. It may use various functions from
+     *  ext/openssl, ext/hash, ext/mhash or ext/standard.
+     *
+     * @param string $func digest algorithm
+     * @param string $data data to sign
+     * @return string RAW digital signature
+     * @throws Zend_OpenId_Exception
+     */
+    static public function digest($func, $data)
+    {
+        if (function_exists('openssl_digest')) {
+            return openssl_digest($data, $func, true);
+        } else if (function_exists('hash')) {
+            return hash($func, $data, true);
+        } else if ($func === 'sha1') {
+            return sha1($data, true);
+        } else if ($func === 'sha256') {
+            if (function_exists('mhash')) {
+                return mhash(MHASH_SHA256 , $data);
+            }
+        }
+        require_once "Zend/OpenId/Exception.php";
+        throw new Zend_OpenId_Exception(
+            'Unsupported digest algorithm "' . $func . '".',
+            Zend_OpenId_Exception::UNSUPPORTED_DIGEST);
+    }
+
+    /**
+     * Generates a keyed hash value using the HMAC method. It uses ext/hash
+     * if available or user-level PHP implementation, that is not significantly
+     * slower.
+     *
+     * @param string $macFunc name of selected hashing algorithm (sha1, sha256)
+     * @param string $data data to sign
+     * @param string $secret shared secret key used for generating the HMAC
+     *  variant of the message digest
+     * @return string RAW HMAC value
+     */
+    static public function hashHmac($macFunc, $data, $secret)
+    {
+//        require_once "Zend/Crypt/Hmac.php";
+//        return Zend_Crypt_Hmac::compute($secret, $macFunc, $data, Zend_Crypt_Hmac::BINARY);
+        if (function_exists('hash_hmac')) {
+            return hash_hmac($macFunc, $data, $secret, 1);
+        } else {
+            if (Zend_OpenId::strlen($secret) > 64) {
+                $secret = self::digest($macFunc, $secret);
+            }
+            $secret = str_pad($secret, 64, chr(0x00));
+            $ipad = str_repeat(chr(0x36), 64);
+            $opad = str_repeat(chr(0x5c), 64);
+            $hash1 = self::digest($macFunc, ($secret ^ $ipad) . $data);
+            return self::digest($macFunc, ($secret ^ $opad) . $hash1);
+        }
+    }
+
+    /**
+     * Converts binary representation into ext/gmp or ext/bcmath big integer
+     * representation.
+     *
+     * @param string $bin binary representation of big number
+     * @return mixed
+     * @throws Zend_OpenId_Exception
+     */
+    static protected function binToBigNum($bin)
+    {
+        if (extension_loaded('gmp')) {
+            return gmp_init(bin2hex($bin), 16);
+        } else if (extension_loaded('bcmath')) {
+            $bn = 0;
+            $len = Zend_OpenId::strlen($bin);
+            for ($i = 0; $i < $len; $i++) {
+                $bn = bcmul($bn, 256);
+                $bn = bcadd($bn, ord($bin[$i]));
+            }
+            return $bn;
+        }
+        require_once "Zend/OpenId/Exception.php";
+        throw new Zend_OpenId_Exception(
+            'The system doesn\'t have proper big integer extension',
+            Zend_OpenId_Exception::UNSUPPORTED_LONG_MATH);
+    }
+
+    /**
+     * Converts internal ext/gmp or ext/bcmath big integer representation into
+     * binary string.
+     *
+     * @param mixed $bn big number
+     * @return string
+     * @throws Zend_OpenId_Exception
+     */
+    static protected function bigNumToBin($bn)
+    {
+        if (extension_loaded('gmp')) {
+            $s = gmp_strval($bn, 16);
+            if (strlen($s) % 2 != 0) {
+                $s = '0' . $s;
+            } else if ($s[0] > '7') {
+                $s = '00' . $s;
+            }
+            return pack("H*", $s);
+        } else if (extension_loaded('bcmath')) {
+            $cmp = bccomp($bn, 0);
+            if ($cmp == 0) {
+                return (chr(0));
+            } else if ($cmp < 0) {
+                require_once "Zend/OpenId/Exception.php";
+                throw new Zend_OpenId_Exception(
+                    'Big integer arithmetic error',
+                    Zend_OpenId_Exception::ERROR_LONG_MATH);
+            }
+            $bin = "";
+            while (bccomp($bn, 0) > 0) {
+                $bin = chr(bcmod($bn, 256)) . $bin;
+                $bn = bcdiv($bn, 256);
+            }
+            if (ord($bin[0]) > 127) {
+                $bin = chr(0) . $bin;
+            }
+            return $bin;
+        }
+        require_once "Zend/OpenId/Exception.php";
+        throw new Zend_OpenId_Exception(
+            'The system doesn\'t have proper big integer extension',
+            Zend_OpenId_Exception::UNSUPPORTED_LONG_MATH);
+    }
+
+    /**
+     * Performs the first step of a Diffie-Hellman key exchange by generating
+     * private and public DH values based on given prime number $p and
+     * generator $g. Both sides of key exchange MUST have the same prime number
+     * and generator. In this case they will able to create a random shared
+     * secret that is never send from one to the other.
+     *
+     * @param string $p prime number in binary representation
+     * @param string $g generator in binary representation
+     * @param string $priv_key private key in binary representation
+     * @return mixed
+     */
+    static public function createDhKey($p, $g, $priv_key = null)
+    {
+        if (function_exists('openssl_dh_compute_key')) {
+            $dh_details = array(
+                    'p' => $p,
+                    'g' => $g
+                );
+            if ($priv_key !== null) {
+                $dh_details['priv_key'] = $priv_key;
+            }
+            return openssl_pkey_new(array('dh'=>$dh_details));
+        } else {
+            $bn_p        = self::binToBigNum($p);
+            $bn_g        = self::binToBigNum($g);
+            if ($priv_key === null) {
+                $priv_key    = self::randomBytes(Zend_OpenId::strlen($p));
+            }
+            $bn_priv_key = self::binToBigNum($priv_key);
+            if (extension_loaded('gmp')) {
+                $bn_pub_key  = gmp_powm($bn_g, $bn_priv_key, $bn_p);
+            } else if (extension_loaded('bcmath')) {
+                $bn_pub_key  = bcpowmod($bn_g, $bn_priv_key, $bn_p);
+            }
+            $pub_key     = self::bigNumToBin($bn_pub_key);
+
+            return array(
+                'p'        => $bn_p,
+                'g'        => $bn_g,
+                'priv_key' => $bn_priv_key,
+                'pub_key'  => $bn_pub_key,
+                'details'  => array(
+                    'p'        => $p,
+                    'g'        => $g,
+                    'priv_key' => $priv_key,
+                    'pub_key'  => $pub_key));
+        }
+    }
+
+    /**
+     * Returns an associative array with Diffie-Hellman key components in
+     * binary representation. The array includes original prime number 'p' and
+     * generator 'g', random private key 'priv_key' and corresponding public
+     * key 'pub_key'.
+     *
+     * @param mixed $dh Diffie-Hellman key
+     * @return array
+     */
+    static public function getDhKeyDetails($dh)
+    {
+        if (function_exists('openssl_dh_compute_key')) {
+            $details = openssl_pkey_get_details($dh);
+            if (isset($details['dh'])) {
+                return $details['dh'];
+            }
+        } else {
+            return $dh['details'];
+        }
+    }
+
+    /**
+     * Computes the shared secret from the private DH value $dh and the other
+     * party's public value in $pub_key
+     *
+     * @param string $pub_key other party's public value
+     * @param mixed $dh Diffie-Hellman key
+     * @return string
+     * @throws Zend_OpenId_Exception
+     */
+    static public function computeDhSecret($pub_key, $dh)
+    {
+        if (function_exists('openssl_dh_compute_key')) {
+            $ret = openssl_dh_compute_key($pub_key, $dh);
+            if (ord($ret[0]) > 127) {
+                $ret = chr(0) . $ret;
+            }
+            return $ret;
+        } else if (extension_loaded('gmp')) {
+            $bn_pub_key = self::binToBigNum($pub_key);
+            $bn_secret  = gmp_powm($bn_pub_key, $dh['priv_key'], $dh['p']);
+            return self::bigNumToBin($bn_secret);
+        } else if (extension_loaded('bcmath')) {
+            $bn_pub_key = self::binToBigNum($pub_key);
+            $bn_secret  = bcpowmod($bn_pub_key, $dh['priv_key'], $dh['p']);
+            return self::bigNumToBin($bn_secret);
+        }
+        require_once "Zend/OpenId/Exception.php";
+        throw new Zend_OpenId_Exception(
+            'The system doesn\'t have proper big integer extension',
+            Zend_OpenId_Exception::UNSUPPORTED_LONG_MATH);
+    }
+
+    /**
+     * Takes an arbitrary precision integer and returns its shortest big-endian
+     * two's complement representation.
+     *
+     * Arbitrary precision integers MUST be encoded as big-endian signed two's
+     * complement binary strings. Henceforth, "btwoc" is a function that takes
+     * an arbitrary precision integer and returns its shortest big-endian two's
+     * complement representation. All integers that are used with
+     * Diffie-Hellman Key Exchange are positive. This means that the left-most
+     * bit of the two's complement representation MUST be zero. If it is not,
+     * implementations MUST add a zero byte at the front of the string.
+     *
+     * @param string $str binary representation of arbitrary precision integer
+     * @return string big-endian signed representation
+     */
+    static public function btwoc($str)
+    {
+        if (ord($str[0]) > 127) {
+            return chr(0) . $str;
+        }
+        return $str;
+    }
+
+    /**
+     * Returns lenght of binary string in bytes
+     *
+     * @param string $str
+     * @return int the string lenght
+     */
+    static public function strlen($str)
+    {
+        if (extension_loaded('mbstring') &&
+            (((int)ini_get('mbstring.func_overload')) & 2)) {
+            return mb_strlen($str, 'latin1');
+        } else {
+            return strlen($str);
+        }
+    }
+
+}
diff --git a/lib/zend/Zend/Paginator.php b/lib/zend/Zend/Paginator.php
new file mode 100644 (file)
index 0000000..6e1db3d
--- /dev/null
@@ -0,0 +1,1107 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Paginator
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/**
+ * @see Zend_Loader_PluginLoader
+ */
+require_once 'Zend/Loader/PluginLoader.php';
+
+/**
+ * @see Zend_Json
+ */
+require_once 'Zend/Json.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Paginator
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Paginator implements Countable, IteratorAggregate
+{
+    /**
+     * Specifies that the factory should try to detect the proper adapter type first
+     *
+     * @var string
+     */
+    const INTERNAL_ADAPTER = 'Zend_Paginator_Adapter_Internal';
+
+    /**
+     * The cache tag prefix used to namespace Paginator results in the cache
+     *
+     */
+    const CACHE_TAG_PREFIX = 'Zend_Paginator_';
+
+    /**
+     * Adapter plugin loader
+     *
+     * @var Zend_Loader_PluginLoader
+     */
+    protected static $_adapterLoader = null;
+
+    /**
+     * Configuration file
+     *
+     * @var Zend_Config
+     */
+    protected static $_config = null;
+
+    /**
+     * Default scrolling style
+     *
+     * @var string
+     */
+    protected static $_defaultScrollingStyle = 'Sliding';
+
+    /**
+     * Default item count per page
+     *
+     * @var int
+     */
+    protected static $_defaultItemCountPerPage = 10;
+
+    /**
+     * Scrolling style plugin loader
+     *
+     * @var Zend_Loader_PluginLoader
+     */
+    protected static $_scrollingStyleLoader = null;
+
+    /**
+     * Cache object
+     *
+     * @var Zend_Cache_Core
+     */
+    protected static $_cache;
+
+    /**
+     * Enable or desable the cache by Zend_Paginator instance
+     *
+     * @var bool
+     */
+    protected $_cacheEnabled = true;
+
+    /**
+     * Adapter
+     *
+     * @var Zend_Paginator_Adapter_Interface
+     */
+    protected $_adapter = null;
+
+    /**
+     * Number of items in the current page
+     *
+     * @var integer
+     */
+    protected $_currentItemCount = null;
+
+    /**
+     * Current page items
+     *
+     * @var Traversable
+     */
+    protected $_currentItems = null;
+
+    /**
+     * Current page number (starting from 1)
+     *
+     * @var integer
+     */
+    protected $_currentPageNumber = 1;
+
+    /**
+     * Result filter
+     *
+     * @var Zend_Filter_Interface
+     */
+    protected $_filter = null;
+
+    /**
+     * Number of items per page
+     *
+     * @var integer
+     */
+    protected $_itemCountPerPage = null;
+
+    /**
+     * Number of pages
+     *
+     * @var integer
+     */
+    protected $_pageCount = null;
+
+    /**
+     * Number of local pages (i.e., the number of discrete page numbers
+     * that will be displayed, including the current page number)
+     *
+     * @var integer
+     */
+    protected $_pageRange = 10;
+
+    /**
+     * Pages
+     *
+     * @var array
+     */
+    protected $_pages = null;
+
+    /**
+     * View instance used for self rendering
+     *
+     * @var Zend_View_Interface
+     */
+    protected $_view = null;
+
+    /**
+     * Adds an adapter prefix path to the plugin loader.
+     *
+     * @param string $prefix
+     * @param string $path
+     */
+    public static function addAdapterPrefixPath($prefix, $path)
+    {
+        self::getAdapterLoader()->addPrefixPath($prefix, $path);
+    }
+
+    /**
+     * Adds an array of adapter prefix paths to the plugin
+     * loader.
+     *
+     * <code>
+     * $prefixPaths = array(
+     *     'My_Paginator_Adapter'   => 'My/Paginator/Adapter/',
+     *     'Your_Paginator_Adapter' => 'Your/Paginator/Adapter/'
+     * );
+     * </code>
+     *
+     * @param array $prefixPaths
+     */
+    public static function addAdapterPrefixPaths(array $prefixPaths)
+    {
+        if (isset($prefixPaths['prefix']) && isset($prefixPaths['path'])) {
+            self::addAdapterPrefixPath($prefixPaths['prefix'], $prefixPaths['path']);
+        } else {
+            foreach ($prefixPaths as $prefix => $path) {
+                if (is_array($path) && isset($path['prefix']) && isset($path['path'])) {
+                    $prefix = $path['prefix'];
+                    $path   = $path['path'];
+                }
+
+                self::addAdapterPrefixPath($prefix, $path);
+            }
+        }
+    }
+
+    /**
+     * Adds a scrolling style prefix path to the plugin loader.
+     *
+     * @param string $prefix
+     * @param string $path
+     */
+    public static function addScrollingStylePrefixPath($prefix, $path)
+    {
+        self::getScrollingStyleLoader()->addPrefixPath($prefix, $path);
+    }
+
+    /**
+     * Adds an array of scrolling style prefix paths to the plugin
+     * loader.
+     *
+     * <code>
+     * $prefixPaths = array(
+     *     'My_Paginator_ScrollingStyle'   => 'My/Paginator/ScrollingStyle/',
+     *     'Your_Paginator_ScrollingStyle' => 'Your/Paginator/ScrollingStyle/'
+     * );
+     * </code>
+     *
+     * @param array $prefixPaths
+     */
+    public static function addScrollingStylePrefixPaths(array $prefixPaths)
+    {
+        if (isset($prefixPaths['prefix']) && isset($prefixPaths['path'])) {
+            self::addScrollingStylePrefixPath($prefixPaths['prefix'], $prefixPaths['path']);
+        } else {
+            foreach ($prefixPaths as $prefix => $path) {
+                if (is_array($path) && isset($path['prefix']) && isset($path['path'])) {
+                    $prefix = $path['prefix'];
+                    $path   = $path['path'];
+                }
+
+                self::addScrollingStylePrefixPath($prefix, $path);
+            }
+        }
+    }
+
+    /**
+     * Factory.
+     *
+     * @param  mixed $data
+     * @param  string $adapter
+     * @param  array $prefixPaths
+     * @return Zend_Paginator
+     */
+    public static function factory($data, $adapter = self::INTERNAL_ADAPTER,
+                                   array $prefixPaths = null)
+    {
+        if ($data instanceof Zend_Paginator_AdapterAggregate) {
+            return new self($data->getPaginatorAdapter());
+        } else {
+            if ($adapter == self::INTERNAL_ADAPTER) {
+                if (is_array($data)) {
+                    $adapter = 'Array';
+                } else if ($data instanceof Zend_Db_Table_Select) {
+                    $adapter = 'DbTableSelect';
+                } else if ($data instanceof Zend_Db_Select) {
+                    $adapter = 'DbSelect';
+                } else if ($data instanceof Iterator) {
+                    $adapter = 'Iterator';
+                } else if (is_integer($data)) {
+                    $adapter = 'Null';
+                } else {
+                    $type = (is_object($data)) ? get_class($data) : gettype($data);
+
+                    /**
+                     * @see Zend_Paginator_Exception
+                     */
+                    require_once 'Zend/Paginator/Exception.php';
+
+                    throw new Zend_Paginator_Exception('No adapter for type ' . $type);
+                }
+            }
+
+            $pluginLoader = self::getAdapterLoader();
+
+            if (null !== $prefixPaths) {
+                foreach ($prefixPaths as $prefix => $path) {
+                    $pluginLoader->addPrefixPath($prefix, $path);
+                }
+            }
+
+            $adapterClassName = $pluginLoader->load($adapter);
+
+            return new self(new $adapterClassName($data));
+        }
+    }
+
+    /**
+     * Returns the adapter loader.  If it doesn't exist it's created.
+     *
+     * @return Zend_Loader_PluginLoader
+     */
+    public static function getAdapterLoader()
+    {
+        if (self::$_adapterLoader === null) {
+            self::$_adapterLoader = new Zend_Loader_PluginLoader(
+                array('Zend_Paginator_Adapter' => 'Zend/Paginator/Adapter')
+            );
+        }
+
+        return self::$_adapterLoader;
+    }
+
+    /**
+     * Set a global config
+     *
+     * @param Zend_Config $config
+     */
+    public static function setConfig(Zend_Config $config)
+    {
+        self::$_config = $config;
+
+        $adapterPaths = $config->get('adapterpaths');
+
+        if ($adapterPaths != null) {
+            self::addAdapterPrefixPaths($adapterPaths->adapterpath->toArray());
+        }
+
+        $prefixPaths = $config->get('prefixpaths');
+
+        if ($prefixPaths != null) {
+            self::addScrollingStylePrefixPaths($prefixPaths->prefixpath->toArray());
+        }
+
+        $scrollingStyle = $config->get('scrollingstyle');
+
+        if ($scrollingStyle != null) {
+            self::setDefaultScrollingStyle($scrollingStyle);
+        }
+    }
+
+    /**
+     * Returns the default scrolling style.
+     *
+     * @return  string
+     */
+    public static function getDefaultScrollingStyle()
+    {
+        return self::$_defaultScrollingStyle;
+    }
+
+    /**
+     * Get the default item count per page
+     *
+     * @return int
+     */
+    public static function getDefaultItemCountPerPage()
+    {
+        return self::$_defaultItemCountPerPage;
+    }
+
+    /**
+     * Set the default item count per page
+     *
+     * @param int $count
+     */
+    public static function setDefaultItemCountPerPage($count)
+    {
+        self::$_defaultItemCountPerPage = (int) $count;
+    }
+
+    /**
+     * Sets a cache object
+     *
+     * @param Zend_Cache_Core $cache
+     */
+    public static function setCache(Zend_Cache_Core $cache)
+    {
+        self::$_cache = $cache;
+    }
+
+    /**
+     * Sets the default scrolling style.
+     *
+     * @param  string $scrollingStyle
+     */
+    public static function setDefaultScrollingStyle($scrollingStyle = 'Sliding')
+    {
+        self::$_defaultScrollingStyle = $scrollingStyle;
+    }
+
+    /**
+     * Returns the scrolling style loader.  If it doesn't exist it's
+     * created.
+     *
+     * @return Zend_Loader_PluginLoader
+     */
+    public static function getScrollingStyleLoader()
+    {
+        if (self::$_scrollingStyleLoader === null) {
+            self::$_scrollingStyleLoader = new Zend_Loader_PluginLoader(
+                array('Zend_Paginator_ScrollingStyle' => 'Zend/Paginator/ScrollingStyle')
+            );
+        }
+
+        return self::$_scrollingStyleLoader;
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param Zend_Paginator_Adapter_Interface|Zend_Paginator_AdapterAggregate $adapter
+     */
+    public function __construct($adapter)
+    {
+        if ($adapter instanceof Zend_Paginator_Adapter_Interface) {
+            $this->_adapter = $adapter;
+        } else if ($adapter instanceof Zend_Paginator_AdapterAggregate) {
+            $this->_adapter = $adapter->getPaginatorAdapter();
+        } else {
+            /**
+             * @see Zend_Paginator_Exception
+             */
+            require_once 'Zend/Paginator/Exception.php';
+
+            throw new Zend_Paginator_Exception(
+                'Zend_Paginator only accepts instances of the type ' .
+                'Zend_Paginator_Adapter_Interface or Zend_Paginator_AdapterAggregate.'
+            );
+        }
+
+        $config = self::$_config;
+
+        if ($config != null) {
+            $setupMethods = array('ItemCountPerPage', 'PageRange');
+
+            foreach ($setupMethods as $setupMethod) {
+                $value = $config->get(strtolower($setupMethod));
+
+                if ($value != null) {
+                    $setupMethod = 'set' . $setupMethod;
+                    $this->$setupMethod($value);
+                }
+            }
+        }
+    }
+
+    /**
+     * Serializes the object as a string.  Proxies to {@link render()}.
+     *
+     * @return string
+     */
+    public function __toString()
+    {
+        try {
+            $return = $this->render();
+            return $return;
+        } catch (Exception $e) {
+            trigger_error($e->getMessage(), E_USER_WARNING);
+        }
+
+        return '';
+    }
+
+    /**
+     * Enables/Disables the cache for this instance
+     *
+     * @param bool $enable
+     * @return Zend_Paginator
+     */
+    public function setCacheEnabled($enable)
+    {
+        $this->_cacheEnabled = (bool)$enable;
+        return $this;
+    }
+
+    /**
+     * Returns the number of pages.
+     *
+     * @return integer
+     */
+    public function count()
+    {
+        if (!$this->_pageCount) {
+            $this->_pageCount = $this->_calculatePageCount();
+        }
+
+        return $this->_pageCount;
+    }
+
+    /**
+     * Returns the total number of items available.
+     *
+     * @return integer
+     */
+    public function getTotalItemCount()
+    {
+        return count($this->getAdapter());
+    }
+
+    /**
+     * Clear the page item cache.
+     *
+     * @param int $pageNumber
+     * @return Zend_Paginator
+     */
+    public function clearPageItemCache($pageNumber = null)
+    {
+        if (!$this->_cacheEnabled()) {
+            return $this;
+        }
+
+        if (null === $pageNumber) {
+            $cleanTags = self::CACHE_TAG_PREFIX;
+            foreach (self::$_cache->getIdsMatchingTags(array($this->_getCacheInternalId())) as $id) {
+                if (preg_match('|'.self::CACHE_TAG_PREFIX."(\d+)_.*|", $id, $page)) {
+                    self::$_cache->remove($this->_getCacheId($page[1]));
+                }
+            }
+        } else {
+            $cleanId = $this->_getCacheId($pageNumber);
+            self::$_cache->remove($cleanId);
+        }
+        return $this;
+    }
+
+    /**
+     * Returns the absolute item number for the specified item.
+     *
+     * @param  integer $relativeItemNumber Relative item number
+     * @param  integer $pageNumber Page number
+     * @return integer
+     */
+    public function getAbsoluteItemNumber($relativeItemNumber, $pageNumber = null)
+    {
+        $relativeItemNumber = $this->normalizeItemNumber($relativeItemNumber);
+
+        if ($pageNumber == null) {
+            $pageNumber = $this->getCurrentPageNumber();
+        }
+
+        $pageNumber = $this->normalizePageNumber($pageNumber);
+
+        return (($pageNumber - 1) * $this->getItemCountPerPage()) + $relativeItemNumber;
+    }
+
+    /**
+     * Returns the adapter.
+     *
+     * @return Zend_Paginator_Adapter_Interface
+     */
+    public function getAdapter()
+    {
+        return $this->_adapter;
+    }
+
+    /**
+     * Returns the number of items for the current page.
+     *
+     * @return integer
+     */
+    public function getCurrentItemCount()
+    {
+        if ($this->_currentItemCount === null) {
+            $this->_currentItemCount = $this->getItemCount($this->getCurrentItems());
+        }
+
+        return $this->_currentItemCount;
+    }
+
+    /**
+     * Returns the items for the current page.
+     *
+     * @return Traversable
+     */
+    public function getCurrentItems()
+    {
+        if ($this->_currentItems === null) {
+            $this->_currentItems = $this->getItemsByPage($this->getCurrentPageNumber());
+        }
+
+        return $this->_currentItems;
+    }
+
+    /**
+     * Returns the current page number.
+     *
+     * @return integer
+     */
+    public function getCurrentPageNumber()
+    {
+        return $this->normalizePageNumber($this->_currentPageNumber);
+    }
+
+    /**
+     * Sets the current page number.
+     *
+     * @param  integer $pageNumber Page number
+     * @return Zend_Paginator $this
+     */
+    public function setCurrentPageNumber($pageNumber)
+    {
+        $this->_currentPageNumber = (integer) $pageNumber;
+        $this->_currentItems      = null;
+        $this->_currentItemCount  = null;
+
+        return $this;
+    }
+
+    /**
+     * Get the filter
+     *
+     * @return Zend_Filter_Interface
+     */
+    public function getFilter()
+    {
+        return $this->_filter;
+    }
+
+    /**
+     * Set a filter chain
+     *
+     * @param Zend_Filter_Interface $filter
+     * @return Zend_Paginator
+     */
+    public function setFilter(Zend_Filter_Interface $filter)
+    {
+        $this->_filter = $filter;
+
+        return $this;
+    }
+
+    /**
+     * Returns an item from a page.  The current page is used if there's no
+     * page sepcified.
+     *
+     * @param  integer $itemNumber Item number (1 to itemCountPerPage)
+     * @param  integer $pageNumber
+     * @return mixed
+     */
+    public function getItem($itemNumber, $pageNumber = null)
+    {
+        $itemNumber = $this->normalizeItemNumber($itemNumber);
+
+        if ($pageNumber == null) {
+            $pageNumber = $this->getCurrentPageNumber();
+        }
+
+        $page = $this->getItemsByPage($pageNumber);
+        $itemCount = $this->getItemCount($page);
+
+        if ($itemCount == 0) {
+            /**
+             * @see Zend_Paginator_Exception
+             */
+            require_once 'Zend/Paginator/Exception.php';
+
+            throw new Zend_Paginator_Exception('Page ' . $pageNumber . ' does not exist');
+        }
+
+        if ($itemNumber > $itemCount) {
+            /**
+             * @see Zend_Paginator_Exception
+             */
+            require_once 'Zend/Paginator/Exception.php';
+
+            throw new Zend_Paginator_Exception('Page ' . $pageNumber . ' does not'
+                                             . ' contain item number ' . $itemNumber);
+        }
+
+        return $page[$itemNumber - 1];
+    }
+
+    /**
+     * Returns the number of items per page.
+     *
+     * @return integer
+     */
+    public function getItemCountPerPage()
+    {
+        if (empty($this->_itemCountPerPage)) {
+            $this->_itemCountPerPage = self::getDefaultItemCountPerPage();
+        }
+
+        return $this->_itemCountPerPage;
+    }
+
+    /**
+     * Sets the number of items per page.
+     *
+     * @param  integer $itemCountPerPage
+     * @return Zend_Paginator $this
+     */
+    public function setItemCountPerPage($itemCountPerPage)
+    {
+        $this->_itemCountPerPage = (integer) $itemCountPerPage;
+        if ($this->_itemCountPerPage < 1) {
+            $this->_itemCountPerPage = $this->getItemCountPerPage();
+        }
+        $this->_pageCount        = $this->_calculatePageCount();
+        $this->_currentItems     = null;
+        $this->_currentItemCount = null;
+
+        return $this;
+    }
+
+    /**
+     * Returns the number of items in a collection.
+     *
+     * @param  mixed $items Items
+     * @return integer
+     */
+    public function getItemCount($items)
+    {
+        $itemCount = 0;
+
+        if (is_array($items) || $items instanceof Countable) {
+            $itemCount = count($items);
+        } else { // $items is something like LimitIterator
+            $itemCount = iterator_count($items);
+        }
+
+        return $itemCount;
+    }
+
+    /**
+     * Returns the items for a given page.
+     *
+     * @return Traversable
+     */
+    public function getItemsByPage($pageNumber)
+    {
+        $pageNumber = $this->normalizePageNumber($pageNumber);
+
+        if ($this->_cacheEnabled()) {
+            $data = self::$_cache->load($this->_getCacheId($pageNumber));
+            if ($data !== false) {
+                return $data;
+            }
+        }
+
+        $offset = ($pageNumber - 1) * $this->getItemCountPerPage();
+
+        $items = $this->_adapter->getItems($offset, $this->getItemCountPerPage());
+
+        $filter = $this->getFilter();
+
+        if ($filter !== null) {
+            $items = $filter->filter($items);
+        }
+
+        if (!$items instanceof Traversable) {
+            $items = new ArrayIterator($items);
+        }
+
+        if ($this->_cacheEnabled()) {
+            self::$_cache->save($items, $this->_getCacheId($pageNumber), array($this->_getCacheInternalId()));
+        }
+
+        return $items;
+    }
+
+    /**
+     * Returns a foreach-compatible iterator.
+     *
+     * @return Traversable
+     */
+    public function getIterator()
+    {
+        return $this->getCurrentItems();
+    }
+
+    /**
+     * Returns the page range (see property declaration above).
+     *
+     * @return integer
+     */
+    public function getPageRange()
+    {
+        return $this->_pageRange;
+    }
+
+    /**
+     * Sets the page range (see property declaration above).
+     *
+     * @param  integer $pageRange
+     * @return Zend_Paginator $this
+     */
+    public function setPageRange($pageRange)
+    {
+        $this->_pageRange = (integer) $pageRange;
+
+        return $this;
+    }
+
+    /**
+     * Returns the page collection.
+     *
+     * @param  string $scrollingStyle Scrolling style
+     * @return array
+     */
+    public function getPages($scrollingStyle = null)
+    {
+        if ($this->_pages === null) {
+            $this->_pages = $this->_createPages($scrollingStyle);
+        }
+
+        return $this->_pages;
+    }
+
+    /**
+     * Returns a subset of pages within a given range.
+     *
+     * @param  integer $lowerBound Lower bound of the range
+     * @param  integer $upperBound Upper bound of the range
+     * @return array
+     */
+    public function getPagesInRange($lowerBound, $upperBound)
+    {
+        $lowerBound = $this->normalizePageNumber($lowerBound);
+        $upperBound = $this->normalizePageNumber($upperBound);
+
+        $pages = array();
+
+        for ($pageNumber = $lowerBound; $pageNumber <= $upperBound; $pageNumber++) {
+            $pages[$pageNumber] = $pageNumber;
+        }
+
+        return $pages;
+    }
+
+    /**
+     * Returns the page item cache.
+     *
+     * @return array
+     */
+    public function getPageItemCache()
+    {
+        $data = array();
+        if ($this->_cacheEnabled()) {
+            foreach (self::$_cache->getIdsMatchingTags(array($this->_getCacheInternalId())) as $id) {
+                    if (preg_match('|'.self::CACHE_TAG_PREFIX."(\d+)_.*|", $id, $page)) {
+                        $data[$page[1]] = self::$_cache->load($this->_getCacheId($page[1]));
+                    }
+            }
+        }
+        return $data;
+    }
+
+    /**
+     * Retrieves the view instance.  If none registered, attempts to pull f
+     * rom ViewRenderer.
+     *
+     * @return Zend_View_Interface|null
+     */
+    public function getView()
+    {
+        if ($this->_view === null) {
+            /**
+             * @see Zend_Controller_Action_HelperBroker
+             */
+            require_once 'Zend/Controller/Action/HelperBroker.php';
+
+            $viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
+            if ($viewRenderer->view === null) {
+                $viewRenderer->initView();
+            }
+            $this->_view = $viewRenderer->view;
+        }
+
+        return $this->_view;
+    }
+
+    /**
+     * Sets the view object.
+     *
+     * @param  Zend_View_Interface $view
+     * @return Zend_Paginator
+     */
+    public function setView(Zend_View_Interface $view = null)
+    {
+        $this->_view = $view;
+
+        return $this;
+    }
+
+    /**
+     * Brings the item number in range of the page.
+     *
+     * @param  integer $itemNumber
+     * @return integer
+     */
+    public function normalizeItemNumber($itemNumber)
+    {
+        if ($itemNumber < 1) {
+            $itemNumber = 1;
+        }
+
+        if ($itemNumber > $this->getItemCountPerPage()) {
+            $itemNumber = $this->getItemCountPerPage();
+        }
+
+        return $itemNumber;
+    }
+
+    /**
+     * Brings the page number in range of the paginator.
+     *
+     * @param  integer $pageNumber
+     * @return integer
+     */
+    public function normalizePageNumber($pageNumber)
+    {
+        if ($pageNumber < 1) {
+            $pageNumber = 1;
+        }
+
+        $pageCount = $this->count();
+
+        if ($pageCount > 0 && $pageNumber > $pageCount) {
+            $pageNumber = $pageCount;
+        }
+
+        return $pageNumber;
+    }
+
+    /**
+     * Renders the paginator.
+     *
+     * @param  Zend_View_Interface $view
+     * @return string
+     */
+    public function render(Zend_View_Interface $view = null)
+    {
+        if (null !== $view) {
+            $this->setView($view);
+        }
+
+        $view = $this->getView();
+
+        return $view->paginationControl($this);
+    }
+
+    /**
+     * Returns the items of the current page as JSON.
+     *
+     * @return string
+     */
+    public function toJson()
+    {
+        $currentItems = $this->getCurrentItems();
+
+        if ($currentItems instanceof Zend_Db_Table_Rowset_Abstract) {
+            return Zend_Json::encode($currentItems->toArray());
+        } else {
+            return Zend_Json::encode($currentItems);
+        }
+    }
+
+    /**
+     * Tells if there is an active cache object
+     * and if the cache has not been desabled
+     *
+     * @return bool
+     */
+    protected function _cacheEnabled()
+    {
+        return ((self::$_cache !== null) && $this->_cacheEnabled);
+    }
+
+    /**
+     * Makes an Id for the cache
+     * Depends on the adapter object and the page number
+     *
+     * Used to store item in cache from that Paginator instance
+     *  and that current page
+     *
+     * @param int $page
+     * @return string
+     */
+    protected function _getCacheId($page = null)
+    {
+        if ($page === null) {
+            $page = $this->getCurrentPageNumber();
+        }
+        return self::CACHE_TAG_PREFIX . $page . '_' . $this->_getCacheInternalId();
+    }
+
+    /**
+     * Get the internal cache id
+     * Depends on the adapter and the item count per page
+     *
+     * Used to tag that unique Paginator instance in cache
+     *
+     * @return string
+     */
+    protected function _getCacheInternalId()
+    {
+        return md5(serialize($this->getAdapter()) . $this->getItemCountPerPage());
+    }
+
+    /**
+     * Calculates the page count.
+     *
+     * @return integer
+     */
+    protected function _calculatePageCount()
+    {
+        return (integer) ceil($this->getAdapter()->count() / $this->getItemCountPerPage());
+    }
+
+    /**
+     * Creates the page collection.
+     *
+     * @param  string $scrollingStyle Scrolling style
+     * @return stdClass
+     */
+    protected function _createPages($scrollingStyle = null)
+    {
+        $pageCount         = $this->count();
+        $currentPageNumber = $this->getCurrentPageNumber();
+
+        $pages = new stdClass();
+        $pages->pageCount        = $pageCount;
+        $pages->itemCountPerPage = $this->getItemCountPerPage();
+        $pages->first            = 1;
+        $pages->current          = $currentPageNumber;
+        $pages->last             = $pageCount;
+
+        // Previous and next
+        if ($currentPageNumber - 1 > 0) {
+            $pages->previous = $currentPageNumber - 1;
+        }
+
+        if ($currentPageNumber + 1 <= $pageCount) {
+            $pages->next = $currentPageNumber + 1;
+        }
+
+        // Pages in range
+        $scrollingStyle = $this->_loadScrollingStyle($scrollingStyle);
+        $pages->pagesInRange     = $scrollingStyle->getPages($this);
+        $pages->firstPageInRange = min($pages->pagesInRange);
+        $pages->lastPageInRange  = max($pages->pagesInRange);
+
+        // Item numbers
+        if ($this->getCurrentItems() !== null) {
+            $pages->currentItemCount = $this->getCurrentItemCount();
+            $pages->itemCountPerPage = $this->getItemCountPerPage();
+            $pages->totalItemCount   = $this->getTotalItemCount();
+            $pages->firstItemNumber  = (($currentPageNumber - 1) * $this->getItemCountPerPage()) + 1;
+            $pages->lastItemNumber   = $pages->firstItemNumber + $pages->currentItemCount - 1;
+        }
+
+        return $pages;
+    }
+
+    /**
+     * Loads a scrolling style.
+     *
+     * @param string $scrollingStyle
+     * @return Zend_Paginator_ScrollingStyle_Interface
+     */
+    protected function _loadScrollingStyle($scrollingStyle = null)
+    {
+        if ($scrollingStyle === null) {
+            $scrollingStyle = self::$_defaultScrollingStyle;
+        }
+
+        switch (strtolower(gettype($scrollingStyle))) {
+            case 'object':
+                if (!$scrollingStyle instanceof Zend_Paginator_ScrollingStyle_Interface) {
+                    /**
+                     * @see Zend_View_Exception
+                     */
+                    require_once 'Zend/View/Exception.php';
+
+                    throw new Zend_View_Exception('Scrolling style must implement ' .
+                        'Zend_Paginator_ScrollingStyle_Interface');
+                }
+
+                return $scrollingStyle;
+
+            case 'string':
+                $className = self::getScrollingStyleLoader()->load($scrollingStyle);
+
+                return new $className();
+
+            case 'null':
+                // Fall through to default case
+
+            default:
+                /**
+                 * @see Zend_View_Exception
+                 */
+                require_once 'Zend/View/Exception.php';
+
+                throw new Zend_View_Exception('Scrolling style must be a class ' .
+                    'name or object implementing Zend_Paginator_ScrollingStyle_Interface');
+        }
+    }
+}
diff --git a/lib/zend/Zend/Pdf.php b/lib/zend/Zend/Pdf.php
new file mode 100644 (file)
index 0000000..cdebe5e
--- /dev/null
@@ -0,0 +1,1429 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Pdf
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/** Zend_Pdf_Page */
+require_once 'Zend/Pdf/Page.php';
+
+/** Zend_Pdf_Cmap */
+require_once 'Zend/Pdf/Cmap.php';
+
+/** Zend_Pdf_Font */
+require_once 'Zend/Pdf/Font.php';
+
+/** Zend_Pdf_Style */
+require_once 'Zend/Pdf/Style.php';
+
+/** Zend_Pdf_Parser */
+require_once 'Zend/Pdf/Parser.php';
+
+/** Zend_Pdf_Trailer */
+require_once 'Zend/Pdf/Trailer.php';
+
+/** Zend_Pdf_Trailer_Generator */
+require_once 'Zend/Pdf/Trailer/Generator.php';
+
+/** Zend_Pdf_Color */
+require_once 'Zend/Pdf/Color.php';
+
+/** Zend_Pdf_Color_GrayScale */
+require_once 'Zend/Pdf/Color/GrayScale.php';
+
+/** Zend_Pdf_Color_Rgb */
+require_once 'Zend/Pdf/Color/Rgb.php';
+
+/** Zend_Pdf_Color_Cmyk */
+require_once 'Zend/Pdf/Color/Cmyk.php';
+
+/** Zend_Pdf_Color_Html */
+require_once 'Zend/Pdf/Color/Html.php';
+
+/** Zend_Pdf_Image */
+require_once 'Zend/Pdf/Resource/Image.php';
+
+/** Zend_Pdf_Image */
+require_once 'Zend/Pdf/Image.php';
+
+/** Zend_Pdf_Image_Jpeg */
+require_once 'Zend/Pdf/Resource/Image/Jpeg.php';
+
+/** Zend_Pdf_Image_Tiff */
+require_once 'Zend/Pdf/Resource/Image/Tiff.php';
+
+/** Zend_Pdf_Image_Png */
+require_once 'Zend/Pdf/Resource/Image/Png.php';
+
+/** Zend_Memory */
+require_once 'Zend/Memory.php';
+
+/** Zend_Pdf_Action */
+require_once 'Zend/Pdf/Action.php';
+
+/** Zend_Pdf_Destination */
+require_once 'Zend/Pdf/Destination.php';
+
+/** Zend_Pdf_Destination_Explicit */
+require_once 'Zend/Pdf/Destination/Explicit.php';
+
+/** Zend_Pdf_Destination_Named */
+require_once 'Zend/Pdf/Destination/Named.php';
+
+/** Zend_Pdf_Outline_Created */
+require_once 'Zend/Pdf/Outline/Created.php';
+
+/** Zend_Pdf_Outline_Loaded */
+require_once 'Zend/Pdf/Outline/Loaded.php';
+
+/** Zend_Pdf_RecursivelyIteratableObjectsContainer */
+require_once 'Zend/Pdf/RecursivelyIteratableObjectsContainer.php';
+
+/** Zend_Pdf_NameTree */
+require_once 'Zend/Pdf/NameTree.php';
+
+/** Zend_Pdf_Destination */
+require_once 'Zend/Pdf/Exception.php';
+
+/**
+ * General entity which describes PDF document.
+ * It implements document abstraction with a document level operations.
+ *
+ * Class is used to create new PDF document or load existing document.
+ * See details in a class constructor description
+ *
+ * Class agregates document level properties and entities (pages, bookmarks,
+ * document level actions, attachments, form object, etc)
+ *
+ * @category   Zend
+ * @package    Zend_Pdf
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Pdf
+{
+  /**** Class Constants ****/
+
+    /**
+     * Version number of generated PDF documents.
+     */
+    const PDF_VERSION = '1.4';
+
+    /**
+     * PDF file header.
+     */
+    const PDF_HEADER  = "%PDF-1.4\n%\xE2\xE3\xCF\xD3\n";
+
+
+
+    /**
+     * Pages collection
+     *
+     * @todo implement it as a class, which supports ArrayAccess and Iterator interfaces,
+     *       to provide incremental parsing and pages tree updating.
+     *       That will give good performance and memory (PDF size) benefits.
+     *
+     * @var array   - array of Zend_Pdf_Page object
+     */
+    public $pages = array();
+
+    /**
+     * Document properties
+     *
+     * It's an associative array with PDF meta information, values may
+     * be string, boolean or float.
+     * Returned array could be used directly to access, add, modify or remove
+     * document properties.
+     *
+     * Standard document properties: Title (must be set for PDF/X documents), Author,
+     * Subject, Keywords (comma separated list), Creator (the name of the application,
+     * that created document, if it was converted from other format), Trapped (must be
+     * true, false or null, can not be null for PDF/X documents)
+     *
+     * @var array
+     */
+    public $properties = array();
+
+    /**
+     * Original properties set.
+     *
+     * Used for tracking properties changes
+     *
+     * @var array
+     */
+    protected $_originalProperties = array();
+
+    /**
+     * Document level javascript
+     *
+     * @var string
+     */
+    protected $_javaScript = null;
+
+    /**
+     * Document named destinations or "GoTo..." actions, used to refer
+     * document parts from outside PDF
+     *
+     * @var array   - array of Zend_Pdf_Target objects
+     */
+    protected $_namedTargets = array();
+
+    /**
+     * Document outlines
+     *
+     * @var array - array of Zend_Pdf_Outline objects
+     */
+    public $outlines = array();
+
+    /**
+     * Original document outlines list
+     * Used to track outlines update
+     *
+     * @var array - array of Zend_Pdf_Outline objects
+     */
+    protected $_originalOutlines = array();
+
+    /**
+     * Original document outlines open elements count
+     * Used to track outlines update
+     *
+     * @var integer
+     */
+    protected $_originalOpenOutlinesCount = 0;
+
+    /**
+     * Pdf trailer (last or just created)
+     *
+     * @var Zend_Pdf_Trailer
+     */
+    protected $_trailer = null;
+
+    /**
+     * PDF objects factory.
+     *
+     * @var Zend_Pdf_ElementFactory_Interface
+     */
+    protected $_objFactory = null;
+
+    /**
+     * Memory manager for stream objects
+     *
+     * @var Zend_Memory_Manager|null
+     */
+    protected static $_memoryManager = null;
+
+    /**
+     * Pdf file parser.
+     * It's not used, but has to be destroyed only with Zend_Pdf object
+     *
+     * @var Zend_Pdf_Parser
+     */
+    protected $_parser;
+
+
+    /**
+     * List of inheritable attributesfor pages tree
+     *
+     * @var array
+     */
+    protected static $_inheritableAttributes = array('Resources', 'MediaBox', 'CropBox', 'Rotate');
+
+    /**
+     * Request used memory manager
+     *
+     * @return Zend_Memory_Manager
+     */
+    static public function getMemoryManager()
+    {
+        if (self::$_memoryManager === null) {
+            self::$_memoryManager = Zend_Memory::factory('none');
+        }
+
+        return self::$_memoryManager;
+    }
+
+    /**
+     * Set user defined memory manager
+     *
+     * @param Zend_Memory_Manager $memoryManager
+     */
+    static public function setMemoryManager(Zend_Memory_Manager $memoryManager)
+    {
+        self::$_memoryManager = $memoryManager;
+    }
+
+
+    /**
+     * Create new PDF document from a $source string
+     *
+     * @param string $source
+     * @param integer $revision
+     * @return Zend_Pdf
+     */
+    public static function parse(&$source = null, $revision = null)
+    {
+        return new Zend_Pdf($source, $revision);
+    }
+
+    /**
+     * Load PDF document from a file
+     *
+     * @param string $source
+     * @param integer $revision
+     * @return Zend_Pdf
+     */
+    public static function load($source = null, $revision = null)
+    {
+        return new Zend_Pdf($source, $revision, true);
+    }
+
+    /**
+     * Render PDF document and save it.
+     *
+     * If $updateOnly is true, then it only appends new section to the end of file.
+     *
+     * @param string $filename
+     * @param boolean $updateOnly
+     * @throws Zend_Pdf_Exception
+     */
+    public function save($filename, $updateOnly = false)
+    {
+        if (($file = @fopen($filename, $updateOnly ? 'ab':'wb')) === false ) {
+            require_once 'Zend/Pdf/Exception.php';
+            throw new Zend_Pdf_Exception( "Can not open '$filename' file for writing." );
+        }
+
+        $this->render($updateOnly, $file);
+
+        fclose($file);
+    }
+
+    /**
+     * Creates or loads PDF document.
+     *
+     * If $source is null, then it creates a new document.
+     *
+     * If $source is a string and $load is false, then it loads document
+     * from a binary string.
+     *
+     * If $source is a string and $load is true, then it loads document
+     * from a file.
+
+     * $revision used to roll back document to specified version
+     * (0 - currtent version, 1 - previous version, 2 - ...)
+     *
+     * @param string  $source - PDF file to load
+     * @param integer $revision
+     * @throws Zend_Pdf_Exception
+     * @return Zend_Pdf
+     */
+    public function __construct($source = null, $revision = null, $load = false)
+    {
+        $this->_objFactory = Zend_Pdf_ElementFactory::createFactory(1);
+
+        if ($source !== null) {
+            $this->_parser           = new Zend_Pdf_Parser($source, $this->_objFactory, $load);
+            $this->_pdfHeaderVersion = $this->_parser->getPDFVersion();
+            $this->_trailer          = $this->_parser->getTrailer();
+            if ($this->_trailer->Encrypt !== null) {
+                require_once 'Zend/Pdf/Exception.php';
+                throw new Zend_Pdf_Exception('Encrypted document modification is not supported');
+            }
+            if ($revision !== null) {
+                $this->rollback($revision);
+            } else {
+                $this->_loadPages($this->_trailer->Root->Pages);
+            }
+
+            $this->_loadNamedDestinations($this->_trailer->Root, $this->_parser->getPDFVersion());
+            $this->_loadOutlines($this->_trailer->Root);
+
+            if ($this->_trailer->Info !== null) {
+                $this->properties = $this->_trailer->Info->toPhp();
+
+                if (isset($this->properties['Trapped'])) {
+                    switch ($this->properties['Trapped']) {
+                        case 'True':
+                            $this->properties['Trapped'] = true;
+                            break;
+
+                        case 'False':
+                            $this->properties['Trapped'] = false;
+                            break;
+
+                        case 'Unknown':
+                            $this->properties['Trapped'] = null;
+                            break;
+
+                        default:
+                            // Wrong property value
+                            // Do nothing
+                            break;
+                    }
+                }
+
+                $this->_originalProperties = $this->properties;
+            }
+        } else {
+            $this->_pdfHeaderVersion = Zend_Pdf::PDF_VERSION;
+
+            $trailerDictionary = new Zend_Pdf_Element_Dictionary();
+
+            /**
+             * Document id
+             */
+            $docId = md5(uniqid(rand(), true));   // 32 byte (128 bit) identifier
+            $docIdLow  = substr($docId,  0, 16);  // first 16 bytes
+            $docIdHigh = substr($docId, 16, 16);  // second 16 bytes
+
+            $trailerDictionary->ID = new Zend_Pdf_Element_Array();
+            $trailerDictionary->ID->items[] = new Zend_Pdf_Element_String_Binary($docIdLow);
+            $trailerDictionary->ID->items[] = new Zend_Pdf_Element_String_Binary($docIdHigh);
+
+            $trailerDictionary->Size = new Zend_Pdf_Element_Numeric(0);
+
+            $this->_trailer    = new Zend_Pdf_Trailer_Generator($trailerDictionary);
+
+            /**
+             * Document catalog indirect object.
+             */
+            $docCatalog = $this->_objFactory->newObject(new Zend_Pdf_Element_Dictionary());
+            $docCatalog->Type    = new Zend_Pdf_Element_Name('Catalog');
+            $docCatalog->Version = new Zend_Pdf_Element_Name(Zend_Pdf::PDF_VERSION);
+            $this->_trailer->Root = $docCatalog;
+
+            /**
+             * Pages container
+             */
+            $docPages = $this->_objFactory->newObject(new Zend_Pdf_Element_Dictionary());
+            $docPages->Type  = new Zend_Pdf_Element_Name('Pages');
+            $docPages->Kids  = new Zend_Pdf_Element_Array();
+            $docPages->Count = new Zend_Pdf_Element_Numeric(0);
+            $docCatalog->Pages = $docPages;
+        }
+    }
+
+    /**
+     * Retrive number of revisions.
+     *
+     * @return integer
+     */
+    public function revisions()
+    {
+        $revisions = 1;
+        $currentTrailer = $this->_trailer;
+
+        while ($currentTrailer->getPrev() !== null && $currentTrailer->getPrev()->Root !== null ) {
+            $revisions++;
+            $currentTrailer = $currentTrailer->getPrev();
+        }
+
+        return $revisions++;
+    }
+
+    /**
+     * Rollback document $steps number of revisions.
+     * This method must be invoked before any changes, applied to the document.
+     * Otherwise behavior is undefined.
+     *
+     * @param integer $steps
+     */
+    public function rollback($steps)
+    {
+        for ($count = 0; $count < $steps; $count++) {
+            if ($this->_trailer->getPrev() !== null && $this->_trailer->getPrev()->Root !== null) {
+                $this->_trailer = $this->_trailer->getPrev();
+            } else {
+                break;
+            }
+        }
+        $this->_objFactory->setObjectCount($this->_trailer->Size->value);
+
+        // Mark content as modified to force new trailer generation at render time
+        $this->_trailer->Root->touch();
+
+        $this->pages = array();
+        $this->_loadPages($this->_trailer->Root->Pages);
+    }
+
+
+    /**
+     * Load pages recursively
+     *
+     * @param Zend_Pdf_Element_Reference $pages
+     * @param array|null $attributes
+     */
+    protected function _loadPages(Zend_Pdf_Element_Reference $pages, $attributes = array())
+    {
+        if ($pages->getType() != Zend_Pdf_Element::TYPE_DICTIONARY) {
+            require_once 'Zend/Pdf/Exception.php';
+            throw new Zend_Pdf_Exception('Wrong argument');
+        }
+
+        foreach ($pages->getKeys() as $property) {
+            if (in_array($property, self::$_inheritableAttributes)) {
+                $attributes[$property] = $pages->$property;
+                $pages->$property = null;
+            }
+        }
+
+
+        foreach ($pages->Kids->items as $child) {
+            if ($child->Type->value == 'Pages') {
+                $this->_loadPages($child, $attributes);
+            } else if ($child->Type->value == 'Page') {
+                foreach (self::$_inheritableAttributes as $property) {
+                    if ($child->$property === null && array_key_exists($property, $attributes)) {
+                        /**
+                         * Important note.
+                         * If any attribute or dependant object is an indirect object, then it's still
+                         * shared between pages.
+                         */
+                        if ($attributes[$property] instanceof Zend_Pdf_Element_Object  ||
+                            $attributes[$property] instanceof Zend_Pdf_Element_Reference) {
+                            $child->$property = $attributes[$property];
+                        } else {
+                            $child->$property = $this->_objFactory->newObject($attributes[$property]);
+                        }
+                    }
+                }
+                $this->pages[] = new Zend_Pdf_Page($child, $this->_objFactory);
+            }
+        }
+    }
+
+    /**
+     * Load named destinations recursively
+     *
+     * @param Zend_Pdf_Element_Reference $root Document catalog entry
+     * @param string $pdfHeaderVersion
+     * @throws Zend_Pdf_Exception
+     */
+    protected function _loadNamedDestinations(Zend_Pdf_Element_Reference $root, $pdfHeaderVersion)
+    {
+        if ($root->Version !== null  &&  version_compare($root->Version->value, $pdfHeaderVersion, '>')) {
+            $versionIs_1_2_plus = version_compare($root->Version->value,    '1.1', '>');
+        } else {
+            $versionIs_1_2_plus = version_compare($pdfHeaderVersion, '1.1', '>');
+        }
+
+        if ($versionIs_1_2_plus) {
+            // PDF version is 1.2+
+            // Look for Destinations structure at Name dictionary
+            if ($root->Names !== null  &&  $root->Names->Dests !== null) {
+                foreach (new Zend_Pdf_NameTree($root->Names->Dests) as $name => $destination) {
+                    $this->_namedTargets[$name] = Zend_Pdf_Target::load($destination);
+                }
+            }
+        } else {
+            // PDF version is 1.1 (or earlier)
+            // Look for Destinations sructure at Dest entry of document catalog
+            if ($root->Dests !== null) {
+                if ($root->Dests->getType() != Zend_Pdf_Element::TYPE_DICTIONARY) {
+                    require_once 'Zend/Pdf/Exception.php';
+                    throw new Zend_Pdf_Exception('Document catalog Dests entry must be a dictionary.');
+                }
+
+                foreach ($root->Dests->getKeys() as $destKey) {
+                    $this->_namedTargets[$destKey] = Zend_Pdf_Target::load($root->Dests->$destKey);
+                }
+            }
+        }
+    }
+
+    /**
+     * Load outlines recursively
+     *
+     * @param Zend_Pdf_Element_Reference $root Document catalog entry
+     */
+    protected function _loadOutlines(Zend_Pdf_Element_Reference $root)
+    {
+        if ($root->Outlines === null) {
+            return;
+        }
+
+        if ($root->Outlines->getType() != Zend_Pdf_Element::TYPE_DICTIONARY) {
+            require_once 'Zend/Pdf/Exception.php';
+            throw new Zend_Pdf_Exception('Document catalog Outlines entry must be a dictionary.');
+        }
+
+        if ($root->Outlines->Type !== null  &&  $root->Outlines->Type->value != 'Outlines') {
+            require_once 'Zend/Pdf/Exception.php';
+            throw new Zend_Pdf_Exception('Outlines Type entry must be an \'Outlines\' string.');
+        }
+
+        if ($root->Outlines->First === null) {
+            return;
+        }
+
+        $outlineDictionary = $root->Outlines->First;
+        $processedDictionaries = new SplObjectStorage();
+        while ($outlineDictionary !== null  &&  !$processedDictionaries->contains($outlineDictionary)) {
+            $processedDictionaries->attach($outlineDictionary);
+
+            $this->outlines[] = new Zend_Pdf_Outline_Loaded($outlineDictionary);
+
+            $outlineDictionary = $outlineDictionary->Next;
+        }
+
+        $this->_originalOutlines = $this->outlines;
+
+        if ($root->Outlines->Count !== null) {
+            $this->_originalOpenOutlinesCount = $root->Outlines->Count->value;
+        }
+    }
+
+    /**
+     * Orginize pages to tha pages tree structure.
+     *
+     * @todo atomatically attach page to the document, if it's not done yet.
+     * @todo check, that page is attached to the current document
+     *
+     * @todo Dump pages as a balanced tree instead of a plain set.
+     */
+    protected function _dumpPages()
+    {
+        $root = $this->_trailer->Root;
+        $pagesContainer = $root->Pages;
+
+        $pagesContainer->touch();
+        $pagesContainer->Kids->items = array();
+
+        foreach ($this->pages as $page ) {
+            $page->render($this->_objFactory);
+
+            $pageDictionary = $page->getPageDictionary();
+            $pageDictionary->touch();
+            $pageDictionary->Parent = $pagesContainer;
+
+            $pagesContainer->Kids->items[] = $pageDictionary;
+        }
+
+        $this->_refreshPagesHash();
+
+        $pagesContainer->Count->touch();
+        $pagesContainer->Count->value = count($this->pages);
+
+
+        // Refresh named destinations list
+        foreach ($this->_namedTargets as $name => $namedTarget) {
+            if ($namedTarget instanceof Zend_Pdf_Destination_Explicit) {
+                // Named target is an explicit destination
+                if ($this->resolveDestination($namedTarget, false) === null) {
+                    unset($this->_namedTargets[$name]);
+                }
+            } else if ($namedTarget instanceof Zend_Pdf_Action) {
+                // Named target is an action
+                if ($this->_cleanUpAction($namedTarget, false) === null) {
+                    // Action is a GoTo action with an unresolved destination
+                    unset($this->_namedTargets[$name]);
+                }
+            } else {
+                require_once 'Zend/Pdf/Exception.php';
+                throw new Zend_Pdf_Exception('Wrong type of named targed (\'' . get_class($namedTarget) . '\').');
+            }
+        }
+
+        // Refresh outlines
+        $iterator = new RecursiveIteratorIterator(new Zend_Pdf_RecursivelyIteratableObjectsContainer($this->outlines), RecursiveIteratorIterator::SELF_FIRST);
+        foreach ($iterator as $outline) {
+            $target = $outline->getTarget();
+
+            if ($target !== null) {
+                if ($target instanceof Zend_Pdf_Destination) {
+                    // Outline target is a destination
+                    if ($this->resolveDestination($target, false) === null) {
+                        $outline->setTarget(null);
+                    }
+                } else if ($target instanceof Zend_Pdf_Action) {
+                    // Outline target is an action
+                    if ($this->_cleanUpAction($target, false) === null) {
+                        // Action is a GoTo action with an unresolved destination
+                        $outline->setTarget(null);
+                    }
+                } else {
+                    require_once 'Zend/Pdf/Exception.php';
+                    throw new Zend_Pdf_Exception('Wrong outline target.');
+                }
+            }
+        }
+
+        $openAction = $this->getOpenAction();
+        if ($openAction !== null) {
+            if ($openAction instanceof Zend_Pdf_Action) {
+                // OpenAction is an action
+                if ($this->_cleanUpAction($openAction, false) === null) {
+                    // Action is a GoTo action with an unresolved destination
+                    $this->setOpenAction(null);
+                }
+            } else if ($openAction instanceof Zend_Pdf_Destination) {
+                // OpenAction target is a destination
+                if ($this->resolveDestination($openAction, false) === null) {
+                    $this->setOpenAction(null);
+                }
+            } else {
+                require_once 'Zend/Pdf/Exception.php';
+                throw new Zend_Pdf_Exception('OpenAction has to be either PDF Action or Destination.');
+            }
+        }
+    }
+
+    /**
+     * Dump named destinations
+     *
+     * @todo Create a balanced tree instead of plain structure.
+     */
+    protected function _dumpNamedDestinations()
+    {
+        ksort($this->_namedTargets, SORT_STRING);
+
+        $destArrayItems = array();
+        foreach ($this->_namedTargets as $name => $destination) {
+            $destArrayItems[] = new Zend_Pdf_Element_String($name);
+
+            if ($destination instanceof Zend_Pdf_Target) {
+                $destArrayItems[] = $destination->getResource();
+            } else {
+                require_once 'Zend/Pdf/Exception.php';
+                throw new Zend_Pdf_Exception('PDF named destinations must be a Zend_Pdf_Target object.');
+            }
+        }
+        $destArray = $this->_objFactory->newObject(new Zend_Pdf_Element_Array($destArrayItems));
+
+        $DestTree = $this->_objFactory->newObject(new Zend_Pdf_Element_Dictionary());
+        $DestTree->Names = $destArray;
+
+        $root = $this->_trailer->Root;
+
+        if ($root->Names === null) {
+            $root->touch();
+            $root->Names = $this->_objFactory->newObject(new Zend_Pdf_Element_Dictionary());
+        } else {
+            $root->Names->touch();
+        }
+        $root->Names->Dests = $DestTree;
+    }
+
+    /**
+     * Dump outlines recursively
+     */
+    protected function _dumpOutlines()
+    {
+        $root = $this->_trailer->Root;
+
+        if ($root->Outlines === null) {
+            if (count($this->outlines) == 0) {
+                return;
+            } else {
+                $root->Outlines = $this->_objFactory->newObject(new Zend_Pdf_Element_Dictionary());
+                $root->Outlines->Type = new Zend_Pdf_Element_Name('Outlines');
+                $updateOutlinesNavigation = true;
+            }
+        } else {
+            $updateOutlinesNavigation = false;
+            if (count($this->_originalOutlines) != count($this->outlines)) {
+                // If original and current outlines arrays have different size then outlines list was updated
+                $updateOutlinesNavigation = true;
+            } else if ( !(array_keys($this->_originalOutlines) === array_keys($this->outlines)) ) {
+                // If original and current outlines arrays have different keys (with a glance to an order) then outlines list was updated
+                $updateOutlinesNavigation = true;
+            } else {
+                foreach ($this->outlines as $key => $outline) {
+                    if ($this->_originalOutlines[$key] !== $outline) {
+                        $updateOutlinesNavigation = true;
+                    }
+                }
+            }
+        }
+
+        $lastOutline = null;
+        $openOutlinesCount = 0;
+        if ($updateOutlinesNavigation) {
+            $root->Outlines->touch();
+            $root->Outlines->First = null;
+
+            foreach ($this->outlines as $outline) {
+                if ($lastOutline === null) {
+                    // First pass. Update Outlines dictionary First entry using corresponding value
+                    $lastOutline = $outline->dumpOutline($this->_objFactory, $updateOutlinesNavigation, $root->Outlines);
+                    $root->Outlines->First = $lastOutline;
+                } else {
+                    // Update previous outline dictionary Next entry (Prev is updated within dumpOutline() method)
+                    $currentOutlineDictionary = $outline->dumpOutline($this->_objFactory, $updateOutlinesNavigation, $root->Outlines, $lastOutline);
+                    $lastOutline->Next = $currentOutlineDictionary;
+                    $lastOutline       = $currentOutlineDictionary;
+                }
+                $openOutlinesCount += $outline->openOutlinesCount();
+            }
+
+            $root->Outlines->Last  = $lastOutline;
+        } else {
+            foreach ($this->outlines as $outline) {
+                $lastOutline = $outline->dumpOutline($this->_objFactory, $updateOutlinesNavigation, $root->Outlines, $lastOutline);
+                $openOutlinesCount += $outline->openOutlinesCount();
+            }
+        }
+
+        if ($openOutlinesCount != $this->_originalOpenOutlinesCount) {
+            $root->Outlines->touch;
+            $root->Outlines->Count = new Zend_Pdf_Element_Numeric($openOutlinesCount);
+        }
+    }
+
+    /**
+     * Create page object, attached to the PDF document.
+     * Method signatures:
+     *
+     * 1. Create new page with a specified pagesize.
+     *    If $factory is null then it will be created and page must be attached to the document to be
+     *    included into output.
+     * ---------------------------------------------------------
+     * new Zend_Pdf_Page(string $pagesize);
+     * ---------------------------------------------------------
+     *
+     * 2. Create new page with a specified pagesize (in default user space units).
+     *    If $factory is null then it will be created and page must be attached to the document to be
+     *    included into output.
+     * ---------------------------------------------------------
+     * new Zend_Pdf_Page(numeric $width, numeric $height);
+     * ---------------------------------------------------------
+     *
+     * @param mixed $param1
+     * @param mixed $param2
+     * @return Zend_Pdf_Page
+     */
+    public function newPage($param1, $param2 = null)
+    {
+        if ($param2 === null) {
+            return new Zend_Pdf_Page($param1, $this->_objFactory);
+        } else {
+            return new Zend_Pdf_Page($param1, $param2, $this->_objFactory);
+        }
+    }
+
+    /**
+     * Return the document-level Metadata
+     * or null Metadata stream is not presented
+     *
+     * @return string
+     */
+    public function getMetadata()
+    {
+        if ($this->_trailer->Root->Metadata !== null) {
+            return $this->_trailer->Root->Metadata->value;
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Sets the document-level Metadata (mast be valid XMP document)
+     *
+     * @param string $metadata
+     */
+    public function setMetadata($metadata)
+    {
+        $metadataObject = $this->_objFactory->newStreamObject($metadata);
+        $metadataObject->dictionary->Type    = new Zend_Pdf_Element_Name('Metadata');
+        $metadataObject->dictionary->Subtype = new Zend_Pdf_Element_Name('XML');
+
+        $this->_trailer->Root->Metadata = $metadataObject;
+        $this->_trailer->Root->touch();
+    }
+
+    /**
+     * Return the document-level JavaScript
+     * or null if there is no JavaScript for this document
+     *
+     * @return string
+     */
+    public function getJavaScript()
+    {
+        return $this->_javaScript;
+    }
+
+    /**
+     * Get open Action
+     * Returns Zend_Pdf_Target (Zend_Pdf_Destination or Zend_Pdf_Action object)
+     *
+     * @return Zend_Pdf_Target
+     */
+    public function getOpenAction()
+    {
+        if ($this->_trailer->Root->OpenAction !== null) {
+            return Zend_Pdf_Target::load($this->_trailer->Root->OpenAction);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Set open Action which is actually Zend_Pdf_Destination or Zend_Pdf_Action object
+     *
+     * @param Zend_Pdf_Target $openAction
+     * @returns Zend_Pdf
+     */
+    public function setOpenAction(Zend_Pdf_Target $openAction = null)
+    {
+        $root = $this->_trailer->Root;
+        $root->touch();
+
+        if ($openAction === null) {
+            $root->OpenAction = null;
+        } else {
+            $root->OpenAction = $openAction->getResource();
+
+            if ($openAction instanceof Zend_Pdf_Action)  {
+                $openAction->dumpAction($this->_objFactory);
+            }
+        }
+
+        return $this;
+    }
+
+    /**
+     * Return an associative array containing all the named destinations (or GoTo actions) in the PDF.
+     * Named targets can be used to reference from outside
+     * the PDF, ex: 'http://www.something.com/mydocument.pdf#MyAction'
+     *
+     * @return array
+     */
+    public function getNamedDestinations()
+    {
+        return $this->_namedTargets;
+    }
+
+    /**
+     * Return specified named destination
+     *
+     * @param string $name
+     * @return Zend_Pdf_Destination_Explicit|Zend_Pdf_Action_GoTo
+     */
+    public function getNamedDestination($name)
+    {
+        if (isset($this->_namedTargets[$name])) {
+            return $this->_namedTargets[$name];
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Set specified named destination
+     *
+     * @param string $name
+     * @param Zend_Pdf_Destination_Explicit|Zend_Pdf_Action_GoTo $target
+     */
+    public function setNamedDestination($name, $destination = null)
+    {
+        if ($destination !== null  &&
+            !$destination instanceof Zend_Pdf_Action_GoTo  &&
+            !$destination instanceof Zend_Pdf_Destination_Explicit) {
+            require_once 'Zend/Pdf/Exception.php';
+            throw new Zend_Pdf_Exception('PDF named destination must refer an explicit destination or a GoTo PDF action.');
+        }
+
+        if ($destination !== null) {
+           $this->_namedTargets[$name] = $destination;
+        } else {
+            unset($this->_namedTargets[$name]);
+        }
+    }
+
+    /**
+     * Pages collection hash:
+     * <page dictionary object hash id> => Zend_Pdf_Page
+     *
+     * @var SplObjectStorage
+     */
+    protected $_pageReferences = null;
+
+    /**
+     * Pages collection hash:
+     * <page number> => Zend_Pdf_Page
+     *
+     * @var array
+     */
+    protected $_pageNumbers = null;
+
+    /**
+     * Refresh page collection hashes
+     *
+     * @return Zend_Pdf
+     */
+    protected function _refreshPagesHash()
+    {
+        $this->_pageReferences = array();
+        $this->_pageNumbers    = array();
+        $count = 1;
+        foreach ($this->pages as $page) {
+            $pageDictionaryHashId = spl_object_hash($page->getPageDictionary()->getObject());
+            $this->_pageReferences[$pageDictionaryHashId] = $page;
+            $this->_pageNumbers[$count++]                 = $page;
+        }
+
+        return $this;
+    }
+
+    /**
+     * Resolve destination.
+     *
+     * Returns Zend_Pdf_Page page object or null if destination is not found within PDF document.
+     *
+     * @param Zend_Pdf_Destination $destination  Destination to resolve
+     * @param boolean $refreshPagesHash  Refresh page collection hashes before processing
+     * @return Zend_Pdf_Page|null
+     * @throws Zend_Pdf_Exception
+     */
+    public function resolveDestination(Zend_Pdf_Destination $destination, $refreshPageCollectionHashes = true)
+    {
+        if ($this->_pageReferences === null  ||  $refreshPageCollectionHashes) {
+            $this->_refreshPagesHash();
+        }
+
+        if ($destination instanceof Zend_Pdf_Destination_Named) {
+            if (!isset($this->_namedTargets[$destination->getName()])) {
+                return null;
+            }
+            $destination = $this->getNamedDestination($destination->getName());
+
+            if ($destination instanceof Zend_Pdf_Action) {
+                if (!$destination instanceof Zend_Pdf_Action_GoTo) {
+                    return null;
+                }
+                $destination = $destination->getDestination();
+            }
+
+            if (!$destination instanceof Zend_Pdf_Destination_Explicit) {
+                require_once 'Zend/Pdf/Exception.php';
+                throw new Zend_Pdf_Exception('Named destination target has to be an explicit destination.');
+            }
+        }
+
+        // Named target is an explicit destination
+        $pageElement = $destination->getResource()->items[0];
+
+        if ($pageElement->getType() == Zend_Pdf_Element::TYPE_NUMERIC) {
+            // Page reference is a PDF number
+            if (!isset($this->_pageNumbers[$pageElement->value])) {
+                return null;
+            }
+
+            return $this->_pageNumbers[$pageElement->value];
+        }
+
+        // Page reference is a PDF page dictionary reference
+        $pageDictionaryHashId = spl_object_hash($pageElement->getObject());
+        if (!isset($this->_pageReferences[$pageDictionaryHashId])) {
+            return null;
+        }
+        return $this->_pageReferences[$pageDictionaryHashId];
+    }
+
+    /**
+     * Walk through action and its chained actions tree and remove nodes
+     * if they are GoTo actions with an unresolved target.
+     *
+     * Returns null if root node is deleted or updated action overwise.
+     *
+     * @todo Give appropriate name and make method public
+     *
+     * @param $action
+     * @param boolean $refreshPagesHash  Refresh page collection hashes before processing
+     * @return Zend_Pdf_Action|null
+     */
+    protected function _cleanUpAction(Zend_Pdf_Action $action, $refreshPageCollectionHashes = true)
+    {
+        if ($this->_pageReferences === null  ||  $refreshPageCollectionHashes) {
+            $this->_refreshPagesHash();
+        }
+
+        // Named target is an action
+        if ($action instanceof Zend_Pdf_Action_GoTo  &&
+            $this->resolveDestination($action->getDestination(), false) === null) {
+            // Action itself is a GoTo action with an unresolved destination
+            return null;
+        }
+
+        // Walk through child actions
+        $iterator = new RecursiveIteratorIterator($action, RecursiveIteratorIterator::SELF_FIRST);
+
+        $actionsToClean        = array();
+        $deletionCandidateKeys = array();
+        foreach ($iterator as $chainedAction) {
+            if ($chainedAction instanceof Zend_Pdf_Action_GoTo  &&
+                $this->resolveDestination($chainedAction->getDestination(), false) === null) {
+                // Some child action is a GoTo action with an unresolved destination
+                // Mark it as a candidate for deletion
+                $actionsToClean[]        = $iterator->getSubIterator();
+                $deletionCandidateKeys[] = $iterator->getSubIterator()->key();
+            }
+        }
+        foreach ($actionsToClean as $id => $action) {
+            unset($action->next[$deletionCandidateKeys[$id]]);
+        }
+
+        return $action;
+    }
+
+    /**
+     * Extract fonts attached to the document
+     *
+     * returns array of Zend_Pdf_Resource_Font_Extracted objects
+     *
+     * @return array
+     * @throws Zend_Pdf_Exception
+     */
+    public function extractFonts()
+    {
+        $fontResourcesUnique = array();
+        foreach ($this->pages as $page) {
+            $pageResources = $page->extractResources();
+
+            if ($pageResources->Font === null) {
+                // Page doesn't contain have any font reference
+                continue;
+            }
+
+            $fontResources = $pageResources->Font;
+
+            foreach ($fontResources->getKeys() as $fontResourceName) {
+                $fontDictionary = $fontResources->$fontResourceName;
+
+                if (! ($fontDictionary instanceof Zend_Pdf_Element_Reference  ||
+                       $fontDictionary instanceof Zend_Pdf_Element_Object) ) {
+                    require_once 'Zend/Pdf/Exception.php';
+                    throw new Zend_Pdf_Exception('Font dictionary has to be an indirect object or object reference.');
+                }
+
+                $fontResourcesUnique[spl_object_hash($fontDictionary->getObject())] = $fontDictionary;
+            }
+        }
+
+        $fonts = array();
+        require_once 'Zend/Pdf/Exception.php';
+        foreach ($fontResourcesUnique as $resourceId => $fontDictionary) {
+            try {
+                // Try to extract font
+                $extractedFont = new Zend_Pdf_Resource_Font_Extracted($fontDictionary);
+
+                $fonts[$resourceId] = $extractedFont;
+            } catch (Zend_Pdf_Exception $e) {
+                if ($e->getMessage() != 'Unsupported font type.') {
+                    throw $e;
+                }
+            }
+        }
+
+        return $fonts;
+    }
+
+    /**
+     * Extract font attached to the page by specific font name
+     *
+     * $fontName should be specified in UTF-8 encoding
+     *
+     * @return Zend_Pdf_Resource_Font_Extracted|null
+     * @throws Zend_Pdf_Exception
+     */
+    public function extractFont($fontName)
+    {
+        $fontResourcesUnique = array();
+        require_once 'Zend/Pdf/Exception.php';
+        foreach ($this->pages as $page) {
+            $pageResources = $page->extractResources();
+
+            if ($pageResources->Font === null) {
+                // Page doesn't contain have any font reference
+                continue;
+            }
+
+            $fontResources = $pageResources->Font;
+
+            foreach ($fontResources->getKeys() as $fontResourceName) {
+                $fontDictionary = $fontResources->$fontResourceName;
+
+                if (! ($fontDictionary instanceof Zend_Pdf_Element_Reference  ||
+                       $fontDictionary instanceof Zend_Pdf_Element_Object) ) {
+                    require_once 'Zend/Pdf/Exception.php';
+                    throw new Zend_Pdf_Exception('Font dictionary has to be an indirect object or object reference.');
+                }
+
+                $resourceId = spl_object_hash($fontDictionary->getObject());
+                if (isset($fontResourcesUnique[$resourceId])) {
+                    continue;
+                } else {
+                    // Mark resource as processed
+                    $fontResourcesUnique[$resourceId] = 1;
+                }
+
+                if ($fontDictionary->BaseFont->value != $fontName) {
+                    continue;
+                }
+
+                try {
+                    // Try to extract font
+                    return new Zend_Pdf_Resource_Font_Extracted($fontDictionary);
+                } catch (Zend_Pdf_Exception $e) {
+                    if ($e->getMessage() != 'Unsupported font type.') {
+                        throw $e;
+                    }
+                    // Continue searhing
+                }
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Render the completed PDF to a string.
+     * If $newSegmentOnly is true, then only appended part of PDF is returned.
+     *
+     * @param boolean $newSegmentOnly
+     * @param resource $outputStream
+     * @return string
+     * @throws Zend_Pdf_Exception
+     */
+    public function render($newSegmentOnly = false, $outputStream = null)
+    {
+        // Save document properties if necessary
+        if ($this->properties != $this->_originalProperties) {
+            $docInfo = $this->_objFactory->newObject(new Zend_Pdf_Element_Dictionary());
+
+            foreach ($this->properties as $key => $value) {
+                switch ($key) {
+                    case 'Trapped':
+                        switch ($value) {
+                            case true:
+                                $docInfo->$key = new Zend_Pdf_Element_Name('True');
+                                break;
+
+                            case false:
+                                $docInfo->$key = new Zend_Pdf_Element_Name('False');
+                                break;
+
+                            case null:
+                                $docInfo->$key = new Zend_Pdf_Element_Name('Unknown');
+                                break;
+
+                            default:
+                                require_once 'Zend/Pdf/Exception.php';
+                                throw new Zend_Pdf_Exception('Wrong Trapped document property vale: \'' . $value . '\'. Only true, false and null values are allowed.');
+                                break;
+                        }
+
+                    case 'CreationDate':
+                        // break intentionally omitted
+                    case 'ModDate':
+                        $docInfo->$key = new Zend_Pdf_Element_String((string)$value);
+                        break;
+
+                    case 'Title':
+                        // break intentionally omitted
+                    case 'Author':
+                        // break intentionally omitted
+                    case 'Subject':
+                        // break intentionally omitted
+                    case 'Keywords':
+                        // break intentionally omitted
+                    case 'Creator':
+                        // break intentionally omitted
+                    case 'Producer':
+                        if (extension_loaded('mbstring') === true) {
+                            $detected = mb_detect_encoding($value);
+                            if ($detected !== 'ASCII') {
+                                $value = chr(254) . chr(255) . mb_convert_encoding($value, 'UTF-16', $detected);
+                            }
+                        }
+                        $docInfo->$key = new Zend_Pdf_Element_String((string)$value);
+                        break;
+
+                    default:
+                        // Set property using PDF type based on PHP type
+                        $docInfo->$key = Zend_Pdf_Element::phpToPdf($value);
+                        break;
+                }
+            }
+
+            $this->_trailer->Info = $docInfo;
+        }
+
+        $this->_dumpPages();
+        $this->_dumpNamedDestinations();
+        $this->_dumpOutlines();
+
+        // Check, that PDF file was modified
+        // File is always modified by _dumpPages() now, but future implementations may eliminate this.
+        if (!$this->_objFactory->isModified()) {
+            if ($newSegmentOnly) {
+                // Do nothing, return
+                return '';
+            }
+
+            if ($outputStream === null) {
+                return $this->_trailer->getPDFString();
+            } else {
+                $pdfData = $this->_trailer->getPDFString();
+                while ( strlen($pdfData) > 0 && ($byteCount = fwrite($outputStream, $pdfData)) != false ) {
+                    $pdfData = substr($pdfData, $byteCount);
+                }
+
+                return '';
+            }
+        }
+
+        // offset (from a start of PDF file) of new PDF file segment
+        $offset = $this->_trailer->getPDFLength();
+        // Last Object number in a list of free objects
+        $lastFreeObject = $this->_trailer->getLastFreeObject();
+
+        // Array of cross-reference table subsections
+        $xrefTable = array();
+        // Object numbers of first objects in each subsection
+        $xrefSectionStartNums = array();
+
+        // Last cross-reference table subsection
+        $xrefSection = array();
+        // Dummy initialization of the first element (specail case - header of linked list of free objects).
+        $xrefSection[] = 0;
+        $xrefSectionStartNums[] = 0;
+        // Object number of last processed PDF object.
+        // Used to manage cross-reference subsections.
+        // Initialized by zero (specail case - header of linked list of free objects).
+        $lastObjNum = 0;
+
+        if ($outputStream !== null) {
+            if (!$newSegmentOnly) {
+                $pdfData = $this->_trailer->getPDFString();
+                while ( strlen($pdfData) > 0 && ($byteCount = fwrite($outputStream, $pdfData)) != false ) {
+                    $pdfData = substr($pdfData, $byteCount);
+                }
+            }
+        } else {
+            $pdfSegmentBlocks = ($newSegmentOnly) ? array() : array($this->_trailer->getPDFString());
+        }
+
+        // Iterate objects to create new reference table
+        foreach ($this->_objFactory->listModifiedObjects() as $updateInfo) {
+            $objNum = $updateInfo->getObjNum();
+
+            if ($objNum - $lastObjNum != 1) {
+                // Save cross-reference table subsection and start new one
+                $xrefTable[] = $xrefSection;
+                $xrefSection = array();
+                $xrefSectionStartNums[] = $objNum;
+            }
+
+            if ($updateInfo->isFree()) {
+                // Free object cross-reference table entry
+                $xrefSection[]  = sprintf("%010d %05d f \n", $lastFreeObject, $updateInfo->getGenNum());
+                $lastFreeObject = $objNum;
+            } else {
+                // In-use object cross-reference table entry
+                $xrefSection[]  = sprintf("%010d %05d n \n", $offset, $updateInfo->getGenNum());
+
+                $pdfBlock = $updateInfo->getObjectDump();
+                $offset += strlen($pdfBlock);
+
+                if ($outputStream === null) {
+                    $pdfSegmentBlocks[] = $pdfBlock;
+                } else {
+                    while ( strlen($pdfBlock) > 0 && ($byteCount = fwrite($outputStream, $pdfBlock)) != false ) {
+                        $pdfBlock = substr($pdfBlock, $byteCount);
+                    }
+                }
+            }
+            $lastObjNum = $objNum;
+        }
+        // Save last cross-reference table subsection
+        $xrefTable[] = $xrefSection;
+
+        // Modify first entry (specail case - header of linked list of free objects).
+        $xrefTable[0][0] = sprintf("%010d 65535 f \n", $lastFreeObject);
+
+        $xrefTableStr = "xref\n";
+        foreach ($xrefTable as $sectId => $xrefSection) {
+            $xrefTableStr .= sprintf("%d %d \n", $xrefSectionStartNums[$sectId], count($xrefSection));
+            foreach ($xrefSection as $xrefTableEntry) {
+                $xrefTableStr .= $xrefTableEntry;
+            }
+        }
+
+        $this->_trailer->Size->value = $this->_objFactory->getObjectCount();
+
+        $pdfBlock = $xrefTableStr
+                 .  $this->_trailer->toString()
+                 . "startxref\n" . $offset . "\n"
+                 . "%%EOF\n";
+
+        $this->_objFactory->cleanEnumerationShiftCache();
+
+        if ($outputStream === null) {
+            $pdfSegmentBlocks[] = $pdfBlock;
+
+            return implode('', $pdfSegmentBlocks);
+        } else {
+            while ( strlen($pdfBlock) > 0 && ($byteCount = fwrite($outputStream, $pdfBlock)) != false ) {
+                $pdfBlock = substr($pdfBlock, $byteCount);
+            }
+
+            return '';
+        }
+    }
+
+
+    /**
+     * Set the document-level JavaScript
+     *
+     * @param string $javascript
+     */
+    public function setJavaScript($javascript)
+    {
+        $this->_javaScript = $javascript;
+    }
+
+
+    /**
+     * Convert date to PDF format (it's close to ASN.1 (Abstract Syntax Notation
+     * One) defined in ISO/IEC 8824).
+     *
+     * @todo This really isn't the best location for this method. It should
+     *   probably actually exist as Zend_Pdf_Element_Date or something like that.
+     *
+     * @todo Address the following E_STRICT issue:
+     *   PHP Strict Standards:  date(): It is not safe to rely on the system's
+     *   timezone settings. Please use the date.timezone setting, the TZ
+     *   environment variable or the date_default_timezone_set() function. In
+     *   case you used any of those methods and you are still getting this
+     *   warning, you most likely misspelled the timezone identifier.
+     *
+     * @param integer $timestamp (optional) If omitted, uses the current time.
+     * @return string
+     */
+    public static function pdfDate($timestamp = null)
+    {
+        if ($timestamp === null) {
+            $date = date('\D\:YmdHisO');
+        } else {
+            $date = date('\D\:YmdHisO', $timestamp);
+        }
+        return substr_replace($date, '\'', -2, 0) . '\'';
+    }
+
+}
diff --git a/lib/zend/Zend/ProgressBar.php b/lib/zend/Zend/ProgressBar.php
new file mode 100644 (file)
index 0000000..bb7141a
--- /dev/null
@@ -0,0 +1,209 @@
+<?php
+/**
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_ProgressBar
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/**
+ * Zend_ProgressBar offers an interface for multiple enviroments.
+ *
+ * @category  Zend
+ * @package   Zend_ProgressBar
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license   http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_ProgressBar
+{
+    /**
+     * Min value
+     *
+     * @var float
+     */
+    protected $_min;
+
+    /**
+     * Max value
+     *
+     * @var float
+     */
+    protected $_max;
+
+    /**
+     * Current value
+     *
+     * @var float
+     */
+    protected $_current;
+
+    /**
+     * Start time of the progressbar, required for ETA
+     *
+     * @var integer
+     */
+    protected $_startTime;
+
+    /**
+     * Current status text
+     *
+     * @var string
+     */
+    protected $_statusText = null;
+
+    /**
+     * Adapter for the output
+     *
+     * @var Zend_ProgressBar_Adapter
+     */
+    protected $_adapter;
+
+    /**
+     * Namespace for keeping the progressbar persistent
+     *
+     * @var string
+     */
+    protected $_persistenceNamespace = null;
+
+    /**
+     * Create a new progressbar backend.
+     *
+     * @param  Zend_ProgressBar_Adapter $adapter
+     * @param  float                    $min
+     * @param  float                    $max
+     * @param  string                   $persistenceNamespace
+     * @throws Zend_ProgressBar_Exception When $min is greater than $max
+     */
+    public function __construct(Zend_ProgressBar_Adapter $adapter, $min = 0, $max = 100, $persistenceNamespace = null)
+    {
+        // Check min/max values and set them
+        if ($min > $max) {
+            require_once 'Zend/ProgressBar/Exception.php';
+            throw new Zend_ProgressBar_Exception('$max must be greater than $min');
+        }
+
+        $this->_min     = (float) $min;
+        $this->_max     = (float) $max;
+        $this->_current = (float) $min;
+
+        // See if we have to open a session namespace
+        if ($persistenceNamespace !== null) {
+            require_once 'Zend/Session/Namespace.php';
+
+            $this->_persistenceNamespace = new Zend_Session_Namespace($persistenceNamespace);
+        }
+
+        // Set adapter
+        $this->_adapter = $adapter;
+
+        // Track the start time
+        $this->_startTime = time();
+
+        // See If a persistenceNamespace exists and handle accordingly
+        if ($this->_persistenceNamespace !== null) {
+            if (isset($this->_persistenceNamespace->isSet)) {
+                $this->_startTime  = $this->_persistenceNamespace->startTime;
+                $this->_current    = $this->_persistenceNamespace->current;
+                $this->_statusText = $this->_persistenceNamespace->statusText;
+            } else {
+                $this->_persistenceNamespace->isSet      = true;
+                $this->_persistenceNamespace->startTime  = $this->_startTime;
+                $this->_persistenceNamespace->current    = $this->_current;
+                $this->_persistenceNamespace->statusText = $this->_statusText;
+            }
+        } else {
+            $this->update();
+        }
+    }
+
+    /**
+     * Get the current adapter
+     *
+     * @return Zend_ProgressBar_Adapter
+     */
+    public function getAdapter()
+    {
+        return $this->_adapter;
+    }
+
+    /**
+     * Update the progressbar
+     *
+     * @param  float  $value
+     * @param  string $text
+     * @return void
+     */
+    public function update($value = null, $text = null)
+    {
+        // Update value if given
+        if ($value !== null) {
+            $this->_current = min($this->_max, max($this->_min, $value));
+        }
+
+        // Update text if given
+        if ($text !== null) {
+            $this->_statusText = $text;
+        }
+
+        // See if we have to update a namespace
+        if ($this->_persistenceNamespace !== null) {
+            $this->_persistenceNamespace->current    = $this->_current;
+            $this->_persistenceNamespace->statusText = $this->_statusText;
+        }
+
+        // Calculate percent
+        if ($this->_min === $this->_max) {
+            $percent = false;
+        } else {
+            $percent = (float) ($this->_current - $this->_min) / ($this->_max - $this->_min);
+        }
+
+        // Calculate ETA
+        $timeTaken = time() - $this->_startTime;
+
+        if ($percent === .0 || $percent === false) {
+            $timeRemaining = null;
+        } else {
+            $timeRemaining = round(((1 / $percent) * $timeTaken) - $timeTaken);
+        }
+
+        // Poll the adapter
+        $this->_adapter->notify($this->_current, $this->_max, $percent, $timeTaken, $timeRemaining, $this->_statusText);
+    }
+
+    /**
+     * Update the progressbar to the next value
+     *
+     * @param  string $text
+     * @return void
+     */
+    public function next($diff = 1, $text = null)
+    {
+        $this->update(max($this->_min, min($this->_max, $this->_current + $diff)), $text);
+    }
+
+    /**
+     * Call the adapters finish() behaviour
+     *
+     * @return void
+     */
+    public function finish()
+    {
+        if ($this->_persistenceNamespace !== null) {
+            unset($this->_persistenceNamespace->isSet);
+        }
+
+        $this->_adapter->finish();
+    }
+}
diff --git a/lib/zend/Zend/Queue.php b/lib/zend/Zend/Queue.php
new file mode 100644 (file)
index 0000000..181f317
--- /dev/null
@@ -0,0 +1,569 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/**
+ * Class for connecting to queues performing common operations.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Queue implements Countable
+{
+    /**
+     * Use the TIMEOUT constant in the config of a Zend_Queue
+     */
+    const TIMEOUT = 'timeout';
+
+    /**
+     * Default visibility passed to count
+     */
+    const VISIBILITY_TIMEOUT = 30;
+
+    /**
+     * Use the NAME constant in the config of Zend_Queue
+     */
+    const NAME = 'name';
+
+    /**
+     * @var Zend_Queue_Adapter_AdapterInterface
+     */
+    protected $_adapter = null;
+
+    /**
+     * User-provided configuration
+     *
+     * @var array
+     */
+    protected $_options = array();
+
+    /**
+     * Zend_Queue_Message class
+     *
+     * @var string
+     */
+    protected $_messageClass = 'Zend_Queue_Message';
+
+    /**
+     * Zend_Queue_Message_Iterator class
+     *
+     * @var string
+     */
+    protected $_messageSetClass = 'Zend_Queue_Message_Iterator';
+
+    /**
+     * @var Zend_Log
+     */
+    protected $_logger = null;
+
+    /**
+     * Constructor
+     *
+     * Can be called as
+     * $queue = new Zend_Queue($config);
+     * - or -
+     * $queue = new Zend_Queue('array', $config);
+     * - or -
+     * $queue = new Zend_Queue(null, $config); // Zend_Queue->createQueue();
+     *
+     * @param  string|Zend_Queue_Adapter|array|Zend_Config|null String or adapter instance, or options array or Zend_Config instance
+     * @param  Zend_Config|array $options Zend_Config or a configuration array
+     * @return void
+     */
+    public function __construct($spec, $options = array())
+    {
+        $adapter = null;
+        if ($spec instanceof Zend_Queue_Adapter_AdapterInterface) {
+            $adapter = $spec;
+        } elseif (is_string($spec)) {
+            $adapter = $spec;
+        } elseif ($spec instanceof Zend_Config) {
+            $options = $spec->toArray();
+        } elseif (is_array($spec)) {
+            $options = $spec;
+        }
+
+        // last minute error checking
+        if ((null === $adapter)
+            && (!is_array($options) && (!$options instanceof Zend_Config))
+        ) {
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception('No valid params passed to constructor');
+        }
+
+        // Now continue as we would if we were a normal constructor
+        if ($options instanceof Zend_Config) {
+            $options = $options->toArray();
+        } elseif (!is_array($options)) {
+            $options = array();
+        }
+
+        // Make sure we have some defaults to work with
+        if (!isset($options[self::TIMEOUT])) {
+            $options[self::TIMEOUT] = self::VISIBILITY_TIMEOUT;
+        }
+
+        // Make sure all defaults are appropriately set.
+        if (!array_key_exists('timeout', $options)) {
+            $options[self::TIMEOUT] = self::VISIBILITY_TIMEOUT;
+        }
+        if (array_key_exists('messageClass', $options)) {
+            $this->setMessageClass($options['messageClass']);
+        }
+        if (array_key_exists('messageSetClass', $options)) {
+            $this->setMessageSetClass($options['messageSetClass']);
+        }
+
+        $this->setOptions($options);
+
+        // if we were passed an adapter we either build the $adapter or use it
+        if (null !== $adapter) {
+            $this->setAdapter($adapter);
+        }
+    }
+
+    /**
+     * Set queue options 
+     * 
+     * @param  array $options 
+     * @return Zend_Queue
+     */
+    public function setOptions(array $options)
+    {
+        $this->_options = array_merge($this->_options, $options);
+        return $this;
+    }
+
+    /**
+     * Set an individual configuration option
+     * 
+     * @param  string $name 
+     * @param  mixed $value 
+     * @return Zend_Queue
+     */
+    public function setOption($name, $value)
+    {
+        $this->_options[(string) $name] = $value;
+        return $this;
+    }
+
+    /**
+     * Returns the configuration options for the queue
+     *
+     * @return array
+     */
+    public function getOptions()
+    {
+        return $this->_options;
+    }
+
+    /**
+     * Determine if a requested option has been defined
+     * 
+     * @param  string $name 
+     * @return bool
+     */
+    public function hasOption($name)
+    {
+        return array_key_exists($name, $this->_options);
+    }
+
+    /**
+     * Retrieve a single option
+     * 
+     * @param  string $name 
+     * @return null|mixed Returns null if option does not exist; option value otherwise
+     */
+    public function getOption($name)
+    {
+        if ($this->hasOption($name)) {
+            return $this->_options[$name];
+        }
+        return null;
+    }
+
+    /**
+     * Set the adapter for this queue
+     *
+     * @param  string|Zend_Queue_Adapter_AdapterInterface $adapter
+     * @return Zend_Queue Provides a fluent interface
+     */
+    public function setAdapter($adapter)
+    {
+        if (is_string($adapter)) {
+            if (null === ($adapterNamespace = $this->getOption('adapterNamespace'))) {
+                $adapterNamespace = 'Zend_Queue_Adapter';
+            }
+
+            $adapterName = str_replace(
+                ' ', 
+                '_',
+                ucwords(
+                    str_replace(
+                        '_', 
+                        ' ',
+                        strtolower($adapterNamespace . '_' . $adapter)
+                    )
+                )
+            );
+
+            if (!class_exists($adapterName)) {
+                require_once 'Zend/Loader.php';
+                Zend_Loader::loadClass($adapterName);
+            }
+
+            /*
+             * Create an instance of the adapter class.
+             * Pass the configuration to the adapter class constructor.
+             */
+            $adapter = new $adapterName($this->getOptions(), $this);
+        } 
+        
+        if (!$adapter instanceof Zend_Queue_Adapter_AdapterInterface) {
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception("Adapter class '" . get_class($adapterName) . "' does not implement Zend_Queue_Adapter_AdapterInterface");
+        }
+
+        $this->_adapter = $adapter;
+
+        $this->_adapter->setQueue($this);
+
+        if (null !== ($name = $this->getOption(self::NAME))) {
+            $this->_setName($name);
+        }
+
+        return $this;
+    }
+
+    /**
+     * Get the adapter for this queue
+     *
+     * @return Zend_Queue_Adapter_AdapterInterface
+     */
+    public function getAdapter()
+    {
+        return $this->_adapter;
+    }
+
+    /**
+     * @param  string $className
+     * @return Zend_Queue Provides a fluent interface
+     */
+    public function setMessageClass($className)
+    {
+        $this->_messageClass = (string) $className;
+        return $this;
+    }
+
+    /**
+     * @return string
+     */
+    public function getMessageClass()
+    {
+        return $this->_messageClass;
+    }
+
+    /**
+     * @param  string $className
+     * @return Zend_Queue Provides a fluent interface
+     */
+    public function setMessageSetClass($className)
+    {
+        $this->_messageSetClass = (string) $className;
+        return $this;
+    }
+
+    /**
+     * @return string
+     */
+    public function getMessageSetClass()
+    {
+        return $this->_messageSetClass;
+    }
+
+    /**
+     * Get the name of the queue
+     *
+     * Note: _setName() used to exist, but it caused confusion with createQueue
+     * Will evaluate later to see if we should add it back in.
+     *
+     * @return string
+     */
+    public function getName()
+    {
+        return $this->getOption(self::NAME);
+    }
+
+    /**
+     * Create a new queue
+     *
+     * @param  string           $name    queue name
+     * @param  integer          $timeout default visibility timeout
+     * @return Zend_Queue|false
+     * @throws Zend_Queue_Exception
+     */
+    public function createQueue($name, $timeout = null)
+    {
+        if (!is_string($name)) {
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception('$name is not a string');
+        }
+
+        if ((null !== $timeout) && !is_integer($timeout)) {
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception('$timeout must be an integer');
+        }
+
+        // Default to standard timeout
+        if (null === $timeout) {
+            $timeout = $this->getOption(self::TIMEOUT);
+        }
+
+        // Some queues allow you to create on the fly, but cannot return
+        // a list of queues.  Stomp protocol for example.
+        if ($this->isSupported('create')) {
+            if ($this->getAdapter()->isExists($name)) {
+                return false;
+            }
+
+            if (!$this->getAdapter()->create($name, $timeout)) {
+                return false;
+            }
+        }
+
+        $options = array(
+            self::NAME  => $name,
+            'timeout'   => $timeout
+        );
+
+        return new self($this->getAdapter(), $options);
+    }
+
+    /**
+     * Delete the queue this object is working on.
+     *
+     * This queue is disabled, regardless of the outcome of the deletion
+     * of the queue, because the programmers intent is to disable this queue.
+     *
+     * @return boolean
+     */
+    public function deleteQueue()
+    {
+        if ($this->isSupported('delete')) {
+            $deleted = $this->getAdapter()->delete($this->getName());
+        }
+        else {
+            $deleted = true;
+        }
+
+        /**
+         * @see Zend_Queue_Adapter_Null
+         */
+        require_once('Zend/Queue/Adapter/Null.php');
+        $this->setAdapter(new Zend_Queue_Adapter_Null($this->getOptions()));
+
+        return $deleted;
+    }
+
+    /**
+     * Delete a message from the queue
+     *
+     * Returns true if the message is deleted, false if the deletion is
+     * unsuccessful.
+     *
+     * Returns true if the adapter doesn't support message deletion.
+     *
+     * @param  Zend_Queue_Message $message
+     * @return boolean
+     * @throws Zend_Queue_Exception
+     */
+    public function deleteMessage(Zend_Queue_Message $message)
+    {
+        if ($this->getAdapter()->isSupported('deleteMessage')) {
+            return $this->getAdapter()->deleteMessage($message);
+        }
+        return true;
+    }
+
+    /**
+     * Send a message to the queue
+     *
+     * @param  mixed $message message
+     * @return Zend_Queue_Message
+     * @throws Zend_Queue_Exception
+     */
+    public function send($message)
+    {
+        return $this->getAdapter()->send($message);
+    }
+
+    /**
+     * Returns the approximate number of messages in the queue
+     *
+     * @return integer
+     */
+    public function count()
+    {
+        if ($this->getAdapter()->isSupported('count')) {
+            return $this->getAdapter()->count();
+        }
+        return 0;
+    }
+
+    /**
+     * Return the first element in the queue
+     *
+     * @param  integer $maxMessages
+     * @param  integer $timeout
+     * @return Zend_Queue_Message_Iterator
+     */
+    public function receive($maxMessages=null, $timeout=null)
+    {
+        if (($maxMessages !== null) && !is_integer($maxMessages)) {
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception('$maxMessages must be an integer or null');
+        }
+
+        if (($timeout !== null) && !is_integer($timeout)) {
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception('$timeout must be an integer or null');
+        }
+
+        // Default to returning only one message
+        if ($maxMessages === null) {
+            $maxMessages = 1;
+        }
+
+        // Default to standard timeout
+        if ($timeout === null) {
+            $timeout = $this->getOption(self::TIMEOUT);
+        }
+
+        return $this->getAdapter()->receive($maxMessages, $timeout);
+    }
+
+    /**
+     * Return a list of queue capabilities functions
+     *
+     * $array['function name'] = true or false
+     * true is supported, false is not supported.
+     *
+     * @param  string $name
+     * @return array
+     */
+    public function getCapabilities()
+    {
+        return $this->getAdapter()->getCapabilities();
+    }
+
+    /**
+     * Indicates if a function is supported or not.
+     *
+     * @param  string $name
+     * @return boolean
+     */
+    public function isSupported($name)
+    {
+        $translation = array(
+            'deleteQueue' => 'delete',
+            'createQueue' => 'create'
+        );
+
+        if (isset($translation[$name])) {
+            $name = $translation[$name];
+        }
+
+        return $this->getAdapter()->isSupported($name);
+    }
+
+    /**
+     * Get an array of all available queues
+     *
+     * @return array
+     * @throws Zend_Queue_Exception
+     */
+    public function getQueues()
+    {
+        if (!$this->isSupported('getQueues')) {
+            throw new Zend_Queue_Exception( __FUNCTION__ . '() is not supported by ' . get_class($this->getAdapter()));
+        }
+
+        return $this->getAdapter()->getQueues();
+    }
+
+    /**
+     * Set the name of the queue
+     *
+     * This is AN UNSUPPORTED FUNCTION
+     *
+     * @param  string           $name
+     * @return Zend_Queue|false Provides a fluent interface
+     */
+    protected function _setName($name)
+    {
+        if (!is_string($name)) {
+            /**
+             * @see Zend_Queue_Exception
+             */
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception("$name is not a string");
+        }
+
+        if ($this->getAdapter()->isSupported('create')) {
+            if (!$this->getAdapter()->isExists($name)) {
+                $timeout = $this->getOption(self::TIMEOUT);
+
+                if (!$this->getAdapter()->create($name, $timeout)) {
+                    // Unable to create the new queue
+                    return false;
+                }
+            }
+        }
+
+        $this->setOption(self::NAME, $name);
+
+        return $this;
+    }
+
+    /**
+     * returns a listing of Zend_Queue details.
+     * useful for debugging
+     *
+     * @return array
+     */
+    public function debugInfo()
+    {
+        $info = array();
+        $info['self']                     = get_class($this);
+        $info['adapter']                  = get_class($this->getAdapter());
+        foreach ($this->getAdapter()->getCapabilities() as $feature => $supported) {
+            $info['adapter-' . $feature]  = ($supported) ? 'yes' : 'no';
+        }
+        $info['options']                  = $this->getOptions();
+        $info['options']['driverOptions'] = '[hidden]';
+        $info['currentQueue']             = $this->getName();
+        $info['messageClass']             = $this->getMessageClass();
+        $info['messageSetClass']          = $this->getMessageSetClass();
+
+        return $info;
+    }
+}
index 11bba274b74bb3982ce3d0b7e323e7d769d70c6e..3c3cf496523c6ce61c2c104c3e3821c4a395571f 100644 (file)
@@ -14,7 +14,7 @@
  *
  * @category   Zend
  * @package    Zend_Registry
- * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
  * @version    $Id$
  */
@@ -24,7 +24,7 @@
  *
  * @category   Zend
  * @package    Zend_Registry
- * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
  */
 class Zend_Registry extends ArrayObject
@@ -109,8 +109,10 @@ class Zend_Registry extends ArrayObject
         /**
          * @see Zend_Loader
          */
-        require_once 'Zend/Loader.php';
-        Zend_Loader::loadClass($registryClassName);
+        if (!class_exists($registryClassName)) {
+            require_once 'Zend/Loader.php';
+            Zend_Loader::loadClass($registryClassName);
+        }
 
         self::$_registryClassName = $registryClassName;
     }
@@ -181,6 +183,18 @@ class Zend_Registry extends ArrayObject
         return self::$_registry->offsetExists($index);
     }
 
+    /**
+     * Constructs a parent ArrayObject with default
+     * ARRAY_AS_PROPS to allow acces as an object
+     *
+     * @param array $array data array
+     * @param integer $flags ArrayObject flags
+     */
+    public function __construct($array = array(), $flags = parent::ARRAY_AS_PROPS)
+    {
+        parent::__construct($array, $flags);
+    }
+
     /**
      * @param string $index
      * @returns mixed
diff --git a/lib/zend/Zend/Session.php b/lib/zend/Zend/Session.php
new file mode 100644 (file)
index 0000000..157547b
--- /dev/null
@@ -0,0 +1,878 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Session
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ * @since      Preview Release 0.2
+ */
+
+
+/**
+ * @see Zend_Session_Abstract
+ */
+require_once 'Zend/Session/Abstract.php';
+
+/**
+ * @see Zend_Session_Namespace
+ */
+require_once 'Zend/Session/Namespace.php';
+
+/**
+ * @see Zend_Session_SaveHandler_Interface
+ */
+require_once 'Zend/Session/SaveHandler/Interface.php';
+
+
+/**
+ * Zend_Session
+ *
+ * @category   Zend
+ * @package    Zend_Session
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Session extends Zend_Session_Abstract
+{
+    /**
+     * Whether or not Zend_Session is being used with unit tests
+     *
+     * @internal
+     * @var bool
+     */
+    public static $_unitTestEnabled = false;
+
+    /**
+     * $_throwStartupException
+     *
+     * @var bool|bitset This could also be a combiniation of error codes to catch
+     */
+    protected static $_throwStartupExceptions = true;
+    
+    /**
+     * Check whether or not the session was started
+     *
+     * @var bool
+     */
+    private static $_sessionStarted = false;
+
+    /**
+     * Whether or not the session id has been regenerated this request.
+     *
+     * Id regeneration state
+     * <0 - regenerate requested when session is started
+     * 0  - do nothing
+     * >0 - already called session_regenerate_id()
+     *
+     * @var int
+     */
+    private static $_regenerateIdState = 0;
+
+    /**
+     * Private list of php's ini values for ext/session
+     * null values will default to the php.ini value, otherwise
+     * the value below will overwrite the default ini value, unless
+     * the user has set an option explicity with setOptions()
+     *
+     * @var array
+     */
+    private static $_defaultOptions = array(
+        'save_path'                 => null,
+        'name'                      => null, /* this should be set to a unique value for each application */
+        'save_handler'              => null,
+        //'auto_start'                => null, /* intentionally excluded (see manual) */
+        'gc_probability'            => null,
+        'gc_divisor'                => null,
+        'gc_maxlifetime'            => null,
+        'serialize_handler'         => null,
+        'cookie_lifetime'           => null,
+        'cookie_path'               => null,
+        'cookie_domain'             => null,
+        'cookie_secure'             => null,
+        'cookie_httponly'           => null,
+        'use_cookies'               => null,
+        'use_only_cookies'          => 'on',
+        'referer_check'             => null,
+        'entropy_file'              => null,
+        'entropy_length'            => null,
+        'cache_limiter'             => null,
+        'cache_expire'              => null,
+        'use_trans_sid'             => null,
+        'bug_compat_42'             => null,
+        'bug_compat_warn'           => null,
+        'hash_function'             => null,
+        'hash_bits_per_character'   => null
+    );
+
+    /**
+     * List of options pertaining to Zend_Session that can be set by developers
+     * using Zend_Session::setOptions(). This list intentionally duplicates
+     * the individual declaration of static "class" variables by the same names.
+     *
+     * @var array
+     */
+    private static $_localOptions = array(
+        'strict'                => '_strict',
+        'remember_me_seconds'   => '_rememberMeSeconds',
+        'throw_startup_exceptions' => '_throwStartupExceptions'
+    );
+
+    /**
+     * Whether or not write close has been performed.
+     *
+     * @var bool
+     */
+    private static $_writeClosed = false;
+
+    /**
+     * Whether or not session id cookie has been deleted
+     *
+     * @var bool
+     */
+    private static $_sessionCookieDeleted = false;
+
+    /**
+     * Whether or not session has been destroyed via session_destroy()
+     *
+     * @var bool
+     */
+    private static $_destroyed = false;
+
+    /**
+     * Whether or not session must be initiated before usage
+     *
+     * @var bool
+     */
+    private static $_strict = false;
+
+    /**
+     * Default number of seconds the session will be remembered for when asked to be remembered
+     *
+     * @var int
+     */
+    private static $_rememberMeSeconds = 1209600; // 2 weeks
+
+    /**
+     * Whether the default options listed in Zend_Session::$_localOptions have been set
+     *
+     * @var bool
+     */
+    private static $_defaultOptionsSet = false;
+
+    /**
+     * A reference to the set session save handler
+     *
+     * @var Zend_Session_SaveHandler_Interface
+     */
+    private static $_saveHandler = null;
+
+
+    /**
+     * Constructor overriding - make sure that a developer cannot instantiate
+     */
+    protected function __construct()
+    {
+    }
+
+
+    /**
+     * setOptions - set both the class specified
+     *
+     * @param  array $userOptions - pass-by-keyword style array of <option name, option value> pairs
+     * @throws Zend_Session_Exception
+     * @return void
+     */
+    public static function setOptions(array $userOptions = array())
+    {
+        // set default options on first run only (before applying user settings)
+        if (!self::$_defaultOptionsSet) {
+            foreach (self::$_defaultOptions as $defaultOptionName => $defaultOptionValue) {
+                if (isset(self::$_defaultOptions[$defaultOptionName])) {
+                    ini_set("session.$defaultOptionName", $defaultOptionValue);
+                }
+            }
+
+            self::$_defaultOptionsSet = true;
+        }
+
+        // set the options the user has requested to set
+        foreach ($userOptions as $userOptionName => $userOptionValue) {
+
+            $userOptionName = strtolower($userOptionName);
+
+            // set the ini based values
+            if (array_key_exists($userOptionName, self::$_defaultOptions)) {
+                ini_set("session.$userOptionName", $userOptionValue);
+            }
+            elseif (isset(self::$_localOptions[$userOptionName])) {
+                self::${self::$_localOptions[$userOptionName]} = $userOptionValue;
+            }
+            else {
+                /** @see Zend_Session_Exception */
+                require_once 'Zend/Session/Exception.php';
+                throw new Zend_Session_Exception("Unknown option: $userOptionName = $userOptionValue");
+            }
+        }
+    }
+
+    /**
+     * getOptions()
+     *
+     * @param string $optionName OPTIONAL
+     * @return array|string
+     */
+    public static function getOptions($optionName = null)
+    {
+        $options = array();
+        foreach (ini_get_all('session') as $sysOptionName => $sysOptionValues) {
+            $options[substr($sysOptionName, 8)] = $sysOptionValues['local_value'];
+        }
+        foreach (self::$_localOptions as $localOptionName => $localOptionMemberName) {
+            $options[$localOptionName] = self::${$localOptionMemberName};
+        }
+        
+        if ($optionName) {
+            if (array_key_exists($optionName, $options)) {
+                return $options[$optionName];
+            }
+            return null;
+        }
+        
+        return $options;
+    }
+
+    /**
+     * setSaveHandler() - Session Save Handler assignment
+     *
+     * @param Zend_Session_SaveHandler_Interface $interface
+     * @return void
+     */
+    public static function setSaveHandler(Zend_Session_SaveHandler_Interface $saveHandler)
+    {
+        self::$_saveHandler = $saveHandler;
+
+        if (self::$_unitTestEnabled) {
+            return;
+        }
+
+        session_set_save_handler(
+            array(&$saveHandler, 'open'),
+            array(&$saveHandler, 'close'),
+            array(&$saveHandler, 'read'),
+            array(&$saveHandler, 'write'),
+            array(&$saveHandler, 'destroy'),
+            array(&$saveHandler, 'gc')
+            );
+    }
+
+
+    /**
+     * getSaveHandler() - Get the session Save Handler
+     *
+     * @return Zend_Session_SaveHandler_Interface
+     */
+    public static function getSaveHandler()
+    {
+        return self::$_saveHandler;
+    }
+
+
+    /**
+     * regenerateId() - Regenerate the session id.  Best practice is to call this after
+     * session is started.  If called prior to session starting, session id will be regenerated
+     * at start time.
+     *
+     * @throws Zend_Session_Exception
+     * @return void
+     */
+    public static function regenerateId()
+    {
+        if (!self::$_unitTestEnabled && headers_sent($filename, $linenum)) {
+            /** @see Zend_Session_Exception */
+            require_once 'Zend/Session/Exception.php';
+            throw new Zend_Session_Exception("You must call " . __CLASS__ . '::' . __FUNCTION__ .
+                "() before any output has been sent to the browser; output started in {$filename}/{$linenum}");
+        }
+
+        if (self::$_sessionStarted && self::$_regenerateIdState <= 0) {
+            if (!self::$_unitTestEnabled) {
+                session_regenerate_id(true);
+            }
+            self::$_regenerateIdState = 1;
+        } else {
+            /**
+             * @todo If we can detect that this requester had no session previously,
+             *       then why regenerate the id before the session has started?
+             *       Feedback wanted for:
+             //
+            if (isset($_COOKIE[session_name()]) || (!use only cookies && isset($_REQUEST[session_name()]))) {
+                self::$_regenerateIdState = 1;
+            } else {
+                self::$_regenerateIdState = -1;
+            }
+            //*/
+            self::$_regenerateIdState = -1;
+        }
+    }
+
+
+    /**
+     * rememberMe() - Write a persistent cookie that expires after a number of seconds in the future. If no number of
+     * seconds is specified, then this defaults to self::$_rememberMeSeconds.  Due to clock errors on end users' systems,
+     * large values are recommended to avoid undesirable expiration of session cookies.
+     *
+     * @param $seconds integer - OPTIONAL specifies TTL for cookie in seconds from present time
+     * @return void
+     */
+    public static function rememberMe($seconds = null)
+    {
+        $seconds = (int) $seconds;
+        $seconds = ($seconds > 0) ? $seconds : self::$_rememberMeSeconds;
+
+        self::rememberUntil($seconds);
+    }
+
+
+    /**
+     * forgetMe() - Write a volatile session cookie, removing any persistent cookie that may have existed. The session
+     * would end upon, for example, termination of a web browser program.
+     *
+     * @return void
+     */
+    public static function forgetMe()
+    {
+        self::rememberUntil(0);
+    }
+
+
+    /**
+     * rememberUntil() - This method does the work of changing the state of the session cookie and making
+     * sure that it gets resent to the browser via regenerateId()
+     *
+     * @param int $seconds
+     * @return void
+     */
+    public static function rememberUntil($seconds = 0)
+    {
+        if (self::$_unitTestEnabled) {
+            self::regenerateId();
+            return;
+        }
+
+        $cookieParams = session_get_cookie_params();
+
+        session_set_cookie_params(
+            $seconds,
+            $cookieParams['path'],
+            $cookieParams['domain'],
+            $cookieParams['secure']
+            );
+
+        // normally "rememberMe()" represents a security context change, so should use new session id
+        self::regenerateId();
+    }
+
+
+    /**
+     * sessionExists() - whether or not a session exists for the current request
+     *
+     * @return bool
+     */
+    public static function sessionExists()
+    {
+        if (ini_get('session.use_cookies') == '1' && isset($_COOKIE[session_name()])) {
+            return true;
+        } elseif (!empty($_REQUEST[session_name()])) {
+            return true;
+        } elseif (self::$_unitTestEnabled) {
+            return true;
+        }
+
+        return false;
+    }
+
+
+    /**
+     * Whether or not session has been destroyed via session_destroy()
+     *
+     * @return bool
+     */
+    public static function isDestroyed()
+    {
+        return self::$_destroyed;
+    }
+
+
+    /**
+     * start() - Start the session.
+     *
+     * @param bool|array $options  OPTIONAL Either user supplied options, or flag indicating if start initiated automatically
+     * @throws Zend_Session_Exception
+     * @return void
+     */
+    public static function start($options = false)
+    {
+        if (self::$_sessionStarted && self::$_destroyed) {
+            require_once 'Zend/Session/Exception.php';
+            throw new Zend_Session_Exception('The session was explicitly destroyed during this request, attempting to re-start is not allowed.');
+        }
+
+        if (self::$_sessionStarted) {
+            return; // already started
+        }
+
+        // make sure our default options (at the least) have been set
+        if (!self::$_defaultOptionsSet) {
+            self::setOptions(is_array($options) ? $options : array());
+        }
+
+        // In strict mode, do not allow auto-starting Zend_Session, such as via "new Zend_Session_Namespace()"
+        if (self::$_strict && $options === true) {
+            /** @see Zend_Session_Exception */
+            require_once 'Zend/Session/Exception.php';
+            throw new Zend_Session_Exception('You must explicitly start the session with Zend_Session::start() when session options are set to strict.');
+        }
+
+        $filename = $linenum = null;
+        if (!self::$_unitTestEnabled && headers_sent($filename, $linenum)) {
+            /** @see Zend_Session_Exception */
+            require_once 'Zend/Session/Exception.php';
+            throw new Zend_Session_Exception("Session must be started before any output has been sent to the browser;"
+               . " output started in {$filename}/{$linenum}");
+        }
+
+        // See http://www.php.net/manual/en/ref.session.php for explanation
+        if (!self::$_unitTestEnabled && defined('SID')) {
+            /** @see Zend_Session_Exception */
+            require_once 'Zend/Session/Exception.php';
+            throw new Zend_Session_Exception('session has already been started by session.auto-start or session_start()');
+        }
+
+        /**
+         * Hack to throw exceptions on start instead of php errors
+         * @see http://framework.zend.com/issues/browse/ZF-1325
+         */
+        
+        $errorLevel = (is_int(self::$_throwStartupExceptions)) ? self::$_throwStartupExceptions : E_ALL;
+        
+        /** @see Zend_Session_Exception */
+        if (!self::$_unitTestEnabled) {
+            
+            if (self::$_throwStartupExceptions) {
+                require_once 'Zend/Session/Exception.php';
+                set_error_handler(array('Zend_Session_Exception', 'handleSessionStartError'), $errorLevel);
+            }
+            
+            $startedCleanly = session_start();
+            
+            if (self::$_throwStartupExceptions) {
+                restore_error_handler();
+            }
+            
+            if (!$startedCleanly || Zend_Session_Exception::$sessionStartError != null) {
+                if (self::$_throwStartupExceptions) {
+                    set_error_handler(array('Zend_Session_Exception', 'handleSilentWriteClose'), $errorLevel);
+                }
+                session_write_close();
+                if (self::$_throwStartupExceptions) {
+                    restore_error_handler();
+                    throw new Zend_Session_Exception(__CLASS__ . '::' . __FUNCTION__ . '() - ' . Zend_Session_Exception::$sessionStartError);
+                }
+            }
+        }
+
+        parent::$_readable = true;
+        parent::$_writable = true;
+        self::$_sessionStarted = true;
+        if (self::$_regenerateIdState === -1) {
+            self::regenerateId();
+        }
+
+        // run validators if they exist
+        if (isset($_SESSION['__ZF']['VALID'])) {
+            self::_processValidators();
+        }
+
+        self::_processStartupMetadataGlobal();
+    }
+
+
+    /**
+     * _processGlobalMetadata() - this method initizes the sessions GLOBAL
+     * metadata, mostly global data expiration calculations.
+     *
+     * @return void
+     */
+    private static function _processStartupMetadataGlobal()
+    {
+        // process global metadata
+        if (isset($_SESSION['__ZF'])) {
+
+            // expire globally expired values
+            foreach ($_SESSION['__ZF'] as $namespace => $namespace_metadata) {
+
+                // Expire Namespace by Time (ENT)
+                if (isset($namespace_metadata['ENT']) && ($namespace_metadata['ENT'] > 0) && (time() > $namespace_metadata['ENT']) ) {
+                    unset($_SESSION[$namespace]);
+                    unset($_SESSION['__ZF'][$namespace]['ENT']);
+                }
+
+                // Expire Namespace by Global Hop (ENGH)
+                if (isset($namespace_metadata['ENGH']) && $namespace_metadata['ENGH'] >= 1) {
+                    $_SESSION['__ZF'][$namespace]['ENGH']--;
+
+                    if ($_SESSION['__ZF'][$namespace]['ENGH'] === 0) {
+                        if (isset($_SESSION[$namespace])) {
+                            parent::$_expiringData[$namespace] = $_SESSION[$namespace];
+                            unset($_SESSION[$namespace]);
+                        }
+                        unset($_SESSION['__ZF'][$namespace]['ENGH']);
+                    }
+                }
+
+                // Expire Namespace Variables by Time (ENVT)
+                if (isset($namespace_metadata['ENVT'])) {
+                    foreach ($namespace_metadata['ENVT'] as $variable => $time) {
+                        if (time() > $time) {
+                            unset($_SESSION[$namespace][$variable]);
+                            unset($_SESSION['__ZF'][$namespace]['ENVT'][$variable]);
+
+                            if (empty($_SESSION['__ZF'][$namespace]['ENVT'])) {
+                                unset($_SESSION['__ZF'][$namespace]['ENVT']);
+                            }
+                        }
+                    }
+                }
+
+                // Expire Namespace Variables by Global Hop (ENVGH)
+                if (isset($namespace_metadata['ENVGH'])) {
+                    foreach ($namespace_metadata['ENVGH'] as $variable => $hops) {
+                        $_SESSION['__ZF'][$namespace]['ENVGH'][$variable]--;
+
+                        if ($_SESSION['__ZF'][$namespace]['ENVGH'][$variable] === 0) {
+                            if (isset($_SESSION[$namespace][$variable])) {
+                                parent::$_expiringData[$namespace][$variable] = $_SESSION[$namespace][$variable];
+                                unset($_SESSION[$namespace][$variable]);
+                            }
+                            unset($_SESSION['__ZF'][$namespace]['ENVGH'][$variable]);
+                        }
+                    }
+                }
+            }
+
+            if (isset($namespace) && empty($_SESSION['__ZF'][$namespace])) {
+                unset($_SESSION['__ZF'][$namespace]);
+            }
+        }
+
+        if (isset($_SESSION['__ZF']) && empty($_SESSION['__ZF'])) {
+            unset($_SESSION['__ZF']);
+        }
+    }
+
+
+    /**
+     * isStarted() - convenience method to determine if the session is already started.
+     *
+     * @return bool
+     */
+    public static function isStarted()
+    {
+        return self::$_sessionStarted;
+    }
+
+
+    /**
+     * isRegenerated() - convenience method to determine if session_regenerate_id()
+     * has been called during this request by Zend_Session.
+     *
+     * @return bool
+     */
+    public static function isRegenerated()
+    {
+        return ( (self::$_regenerateIdState > 0) ? true : false );
+    }
+
+
+    /**
+     * getId() - get the current session id
+     *
+     * @return string
+     */
+    public static function getId()
+    {
+        return session_id();
+    }
+
+
+    /**
+     * setId() - set an id to a user specified id
+     *
+     * @throws Zend_Session_Exception
+     * @param string $id
+     * @return void
+     */
+    public static function setId($id)
+    {
+        if (!self::$_unitTestEnabled && defined('SID')) {
+            /** @see Zend_Session_Exception */
+            require_once 'Zend/Session/Exception.php';
+            throw new Zend_Session_Exception('The session has already been started.  The session id must be set first.');
+        }
+
+        if (!self::$_unitTestEnabled && headers_sent($filename, $linenum)) {
+            /** @see Zend_Session_Exception */
+            require_once 'Zend/Session/Exception.php';
+            throw new Zend_Session_Exception("You must call ".__CLASS__.'::'.__FUNCTION__.
+                "() before any output has been sent to the browser; output started in {$filename}/{$linenum}");
+        }
+
+        if (!is_string($id) || $id === '') {
+            /** @see Zend_Session_Exception */
+            require_once 'Zend/Session/Exception.php';
+            throw new Zend_Session_Exception('You must provide a non-empty string as a session identifier.');
+        }
+
+        session_id($id);
+    }
+
+
+    /**
+     * registerValidator() - register a validator that will attempt to validate this session for
+     * every future request
+     *
+     * @param Zend_Session_Validator_Interface $validator
+     * @return void
+     */
+    public static function registerValidator(Zend_Session_Validator_Interface $validator)
+    {
+        $validator->setup();
+    }
+
+
+    /**
+     * stop() - Disable write access.  Optionally disable read (not implemented).
+     *
+     * @return void
+     */
+    public static function stop()
+    {
+        parent::$_writable = false;
+    }
+
+
+    /**
+     * writeClose() - Shutdown the sesssion, close writing and detach $_SESSION from the back-end storage mechanism.
+     * This will complete the internal data transformation on this request.
+     *
+     * @param bool $readonly - OPTIONAL remove write access (i.e. throw error if Zend_Session's attempt writes)
+     * @return void
+     */
+    public static function writeClose($readonly = true)
+    {
+        if (self::$_unitTestEnabled) {
+            return;
+        }
+
+        if (self::$_writeClosed) {
+            return;
+        }
+
+        if ($readonly) {
+            parent::$_writable = false;
+        }
+
+        session_write_close();
+        self::$_writeClosed = true;
+    }
+
+
+    /**
+     * destroy() - This is used to destroy session data, and optionally, the session cookie itself
+     *
+     * @param bool $remove_cookie - OPTIONAL remove session id cookie, defaults to true (remove cookie)
+     * @param bool $readonly - OPTIONAL remove write access (i.e. throw error if Zend_Session's attempt writes)
+     * @return void
+     */
+    public static function destroy($remove_cookie = true, $readonly = true)
+    {
+        if (self::$_unitTestEnabled) {
+            return;
+        }
+
+        if (self::$_destroyed) {
+            return;
+        }
+
+        if ($readonly) {
+            parent::$_writable = false;
+        }
+
+        session_destroy();
+        self::$_destroyed = true;
+
+        if ($remove_cookie) {
+            self::expireSessionCookie();
+        }
+    }
+
+
+    /**
+     * expireSessionCookie() - Sends an expired session id cookie, causing the client to delete the session cookie
+     *
+     * @return void
+     */
+    public static function expireSessionCookie()
+    {
+        if (self::$_unitTestEnabled) {
+            return;
+        }
+
+        if (self::$_sessionCookieDeleted) {
+            return;
+        }
+
+        self::$_sessionCookieDeleted = true;
+
+        if (isset($_COOKIE[session_name()])) {
+            $cookie_params = session_get_cookie_params();
+
+            setcookie(
+                session_name(),
+                false,
+                315554400, // strtotime('1980-01-01'),
+                $cookie_params['path'],
+                $cookie_params['domain'],
+                $cookie_params['secure']
+                );
+        }
+    }
+
+
+    /**
+     * _processValidator() - internal function that is called in the existence of VALID metadata
+     *
+     * @throws Zend_Session_Exception
+     * @return void
+     */
+    private static function _processValidators()
+    {
+        foreach ($_SESSION['__ZF']['VALID'] as $validator_name => $valid_data) {
+            if (!class_exists($validator_name)) {
+                require_once 'Zend/Loader.php';
+                Zend_Loader::loadClass($validator_name);
+            }
+            $validator = new $validator_name;
+            if ($validator->validate() === false) {
+                /** @see Zend_Session_Exception */
+                require_once 'Zend/Session/Exception.php';
+                throw new Zend_Session_Exception("This session is not valid according to {$validator_name}.");
+            }
+        }
+    }
+
+
+    /**
+     * namespaceIsset() - check to see if a namespace is set
+     *
+     * @param string $namespace
+     * @return bool
+     */
+    public static function namespaceIsset($namespace)
+    {
+        return parent::_namespaceIsset($namespace);
+    }
+
+
+    /**
+     * namespaceUnset() - unset a namespace or a variable within a namespace
+     *
+     * @param string $namespace
+     * @throws Zend_Session_Exception
+     * @return void
+     */
+    public static function namespaceUnset($namespace)
+    {
+        parent::_namespaceUnset($namespace);
+        Zend_Session_Namespace::resetSingleInstance($namespace);
+    }
+
+
+    /**
+     * namespaceGet() - get all variables in a namespace
+     * Deprecated: Use getIterator() in Zend_Session_Namespace.
+     *
+     * @param string $namespace
+     * @return array
+     */
+    public static function namespaceGet($namespace)
+    {
+        return parent::_namespaceGetAll($namespace);
+    }
+
+
+    /**
+     * getIterator() - return an iteratable object for use in foreach and the like,
+     * this completes the IteratorAggregate interface
+     *
+     * @throws Zend_Session_Exception
+     * @return ArrayObject
+     */
+    public static function getIterator()
+    {
+        if (parent::$_readable === false) {
+            /** @see Zend_Session_Exception */
+            require_once 'Zend/Session/Exception.php';
+            throw new Zend_Session_Exception(parent::_THROW_NOT_READABLE_MSG);
+        }
+
+        $spaces  = array();
+        if (isset($_SESSION)) {
+            $spaces = array_keys($_SESSION);
+            foreach($spaces as $key => $space) {
+                if (!strncmp($space, '__', 2) || !is_array($_SESSION[$space])) {
+                    unset($spaces[$key]);
+                }
+            }
+        }
+
+        return new ArrayObject(array_merge($spaces, array_keys(parent::$_expiringData)));
+    }
+
+
+    /**
+     * isWritable() - returns a boolean indicating if namespaces can write (use setters)
+     *
+     * @return bool
+     */
+    public static function isWritable()
+    {
+        return parent::$_writable;
+    }
+
+
+    /**
+     * isReadable() - returns a boolean indicating if namespaces can write (use setters)
+     *
+     * @return bool
+     */
+    public static function isReadable()
+    {
+        return parent::$_readable;
+    }
+
+}
diff --git a/lib/zend/Zend/TimeSync.php b/lib/zend/Zend/TimeSync.php
new file mode 100644 (file)
index 0000000..b274dc2
--- /dev/null
@@ -0,0 +1,304 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_TimeSync
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @version    $Id$
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+
+/**
+ * Zend_Date
+ */
+require_once 'Zend/Date.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_TimeSync
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_TimeSync implements IteratorAggregate
+{
+    /**
+     * Set the default timeserver protocol to "Ntp". This will be called
+     * when no protocol is specified
+     */
+    const DEFAULT_PROTOCOL = 'Ntp';
+
+    /**
+     * Contains array of timeserver objects
+     *
+     * @var array
+     */
+    protected $_timeservers = array();
+
+    /**
+     * Holds a reference to the timeserver that is currently being used
+     *
+     * @var object
+     */
+    protected $_current;
+
+    /**
+     * Allowed timeserver schemes
+     *
+     * @var array
+     */
+    protected $_allowedSchemes = array(
+        'Ntp',
+        'Sntp'
+    );
+
+    /**
+     * Configuration array, set using the constructor or using
+     * ::setOptions() or ::setOption()
+     *
+     * @var array
+     */
+    public static $options = array(
+        'timeout' => 1
+    );
+
+    /**
+     * Zend_TimeSync constructor
+     *
+     * @param  string|array $target - OPTIONAL single timeserver, or an array of timeservers.
+     * @param  string       $alias  - OPTIONAL an alias for this timeserver
+     * @return  object
+     */
+    public function __construct($target = null, $alias = null)
+    {
+        if ($target !== null) {
+            $this->addServer($target, $alias);
+        }
+    }
+
+    /**
+     * getIterator() - return an iteratable object for use in foreach and the like,
+     * this completes the IteratorAggregate interface
+     *
+     * @return ArrayObject
+     */
+    public function getIterator()
+    {
+        return new ArrayObject($this->_timeservers);
+    }
+
+    /**
+     * Add a timeserver or multiple timeservers
+     *
+     * Server should be a single string representation of a timeserver,
+     * or a structured array listing multiple timeservers.
+     *
+     * If you provide an array of timeservers in the $target variable,
+     * $alias will be ignored. you can enter these as the array key
+     * in the provided array, which should be structured as follows:
+     *
+     * <code>
+     * $example = array(
+     *   'server_a' => 'ntp://127.0.0.1',
+     *   'server_b' => 'ntp://127.0.0.1:123',
+     *   'server_c' => 'ntp://[2000:364:234::2.5]',
+     *   'server_d' => 'ntp://[2000:364:234::2.5]:123'
+     * );
+     * </code>
+     *
+     * If no port number has been suplied, the default matching port
+     * number will be used.
+     *
+     * Supported protocols are:
+     * - ntp
+     * - sntp
+     *
+     * @param  string|array $target - Single timeserver, or an array of timeservers.
+     * @param  string       $alias  - OPTIONAL an alias for this timeserver
+     * @throws Zend_TimeSync_Exception
+     */
+    public function addServer($target, $alias = null)
+    {
+        if (is_array($target)) {
+            foreach ($target as $key => $server) {
+                $this->_addServer($server, $key);
+            }
+        } else {
+            $this->_addServer($target, $alias);
+        }
+    }
+
+    /**
+     * Sets the value for the given options
+     *
+     * This will replace any currently defined options.
+     *
+     * @param   array $options - An array of options to be set
+     */
+    public static function setOptions(array $options)
+    {
+        foreach ($options as $key => $value) {
+            Zend_TimeSync::$options[$key] = $value;
+        }
+    }
+
+    /**
+     * Marks a nameserver as current
+     *
+     * @param   string|integer $alias - The alias from the timeserver to set as current
+     * @throws  Zend_TimeSync_Exception
+     */
+    public function setServer($alias)
+    {
+        if (isset($this->_timeservers[$alias]) === true) {
+            $this->_current = $this->_timeservers[$alias];
+        } else {
+            require_once 'Zend/TimeSync/Exception.php';
+            throw new Zend_TimeSync_Exception("'$alias' does not point to valid timeserver");
+        }
+    }
+
+    /**
+     * Returns the value to the option
+     *
+     * @param   string $key - The option's identifier
+     * @return  mixed
+     * @throws  Zend_TimeSync_Exception
+     */
+    public static function getOptions($key = null)
+    {
+        if ($key == null) {
+            return Zend_TimeSync::$options;
+        }
+
+        if (isset(Zend_TimeSync::$options[$key]) === true) {
+            return Zend_TimeSync::$options[$key];
+        } else {
+            require_once 'Zend/TimeSync/Exception.php';
+            throw new Zend_TimeSync_Exception("'$key' does not point to valid option");
+        }
+    }
+
+    /**
+     * Return a specified timeserver by alias
+     * If no alias is given it will return the current timeserver
+     *
+     * @param   string|integer $alias - The alias from the timeserver to return
+     * @return  object
+     * @throws  Zend_TimeSync_Exception
+     */
+    public function getServer($alias = null)
+    {
+        if ($alias === null) {
+            if (isset($this->_current) && $this->_current !== false) {
+                return $this->_current;
+            } else {
+                require_once 'Zend/TimeSync/Exception.php';
+                throw new Zend_TimeSync_Exception('there is no timeserver set');
+            }
+        }
+        if (isset($this->_timeservers[$alias]) === true) {
+            return $this->_timeservers[$alias];
+        } else {
+            require_once 'Zend/TimeSync/Exception.php';
+            throw new Zend_TimeSync_Exception("'$alias' does not point to valid timeserver");
+        }
+    }
+
+    /**
+     * Returns information sent/returned from the current timeserver
+     *
+     * @return  array
+     */
+    public function getInfo()
+    {
+        return $this->getServer()->getInfo();
+    }
+
+    /**
+     * Query the timeserver list using the fallback mechanism
+     *
+     * If there are multiple servers listed, this method will act as a
+     * facade and will try to return the date from the first server that
+     * returns a valid result.
+     *
+     * @param   $locale - OPTIONAL locale
+     * @return  object
+     * @throws  Zend_TimeSync_Exception
+     */
+    public function getDate($locale = null)
+    {
+        require_once 'Zend/TimeSync/Exception.php';
+        foreach ($this->_timeservers as $alias => $server) {
+            $this->_current = $server;
+            try {
+                return $server->getDate($locale);
+            } catch (Zend_TimeSync_Exception $e) {
+                if (!isset($masterException)) {
+                    $masterException = new Zend_TimeSync_Exception('all timeservers are bogus');
+                }
+                $masterException->addException($e);
+            }
+        }
+
+        throw $masterException;
+    }
+
+    /**
+     * Adds a timeserver object to the timeserver list
+     *
+     * @param  string|array $target   - Single timeserver, or an array of timeservers.
+     * @param  string       $alias    - An alias for this timeserver
+     */
+    protected function _addServer($target, $alias)
+    {
+        if ($pos = strpos($target, '://')) {
+            $protocol = substr($target, 0, $pos);
+            $adress = substr($target, $pos + 3);
+        } else {
+            $adress = $target;
+            $protocol = self::DEFAULT_PROTOCOL;
+        }
+
+        if ($pos = strrpos($adress, ':')) {
+            $posbr = strpos($adress, ']');
+            if ($posbr and ($pos > $posbr)) {
+                $port = substr($adress, $pos + 1);
+                $adress = substr($adress, 0, $pos);
+            } else if (!$posbr and $pos) {
+                $port = substr($adress, $pos + 1);
+                $adress = substr($adress, 0, $pos);
+            } else {
+                $port = null;
+            }
+        } else {
+            $port = null;
+        }
+
+        $protocol = ucfirst(strtolower($protocol));
+        if (!in_array($protocol, $this->_allowedSchemes)) {
+            require_once 'Zend/TimeSync/Exception.php';
+            throw new Zend_TimeSync_Exception("'$protocol' is not a supported protocol");
+        }
+
+        $className = 'Zend_TimeSync_' . $protocol;
+        if (!class_exists($className)) {
+            require_once 'Zend/Loader.php';
+            Zend_Loader::loadClass($className);
+        }
+        $timeServerObj = new $className($adress, $port);
+
+        $this->_timeservers[$alias] = $timeServerObj;
+    }
+}
diff --git a/lib/zend/Zend/Translate.php b/lib/zend/Zend/Translate.php
new file mode 100644 (file)
index 0000000..c082f4c
--- /dev/null
@@ -0,0 +1,179 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Translate
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/**
+ * @see Zend_Loader
+ */
+require_once 'Zend/Loader.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Translate
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Translate {
+    /**
+     * Adapter names constants
+     */
+    const AN_ARRAY   = 'Array';
+    const AN_CSV     = 'Csv';
+    const AN_GETTEXT = 'Gettext';
+    const AN_INI     = 'Ini';
+    const AN_QT      = 'Qt';
+    const AN_TBX     = 'Tbx';
+    const AN_TMX     = 'Tmx';
+    const AN_XLIFF   = 'Xliff';
+    const AN_XMLTM   = 'XmlTm';
+
+    const LOCALE_DIRECTORY = 'directory';
+    const LOCALE_FILENAME  = 'filename';
+
+    /**
+     * Adapter
+     *
+     * @var Zend_Translate_Adapter
+     */
+    private $_adapter;
+    private static $_cache = null;
+
+    /**
+     * Generates the standard translation object
+     *
+     * @param  string              $adapter  Adapter to use
+     * @param  array               $data     Translation source data for the adapter
+     *                                       Depends on the Adapter
+     * @param  string|Zend_Locale  $locale   OPTIONAL locale to use
+     * @param  array               $options  OPTIONAL options for the adapter
+     * @throws Zend_Translate_Exception
+     */
+    public function __construct($adapter, $data, $locale = null, array $options = array())
+    {
+        $this->setAdapter($adapter, $data, $locale, $options);
+    }
+
+    /**
+     * Sets a new adapter
+     *
+     * @param  string              $adapter  Adapter to use
+     * @param  string|array        $data     Translation data
+     * @param  string|Zend_Locale  $locale   OPTIONAL locale to use
+     * @param  array               $options  OPTIONAL Options to use
+     * @throws Zend_Translate_Exception
+     */
+    public function setAdapter($adapter, $data, $locale = null, array $options = array())
+    {
+        if (Zend_Loader::isReadable('Zend/Translate/Adapter/' . ucfirst($adapter). '.php')) {
+            $adapter = 'Zend_Translate_Adapter_' . ucfirst($adapter);
+        }
+
+        if (!class_exists($adapter)) {
+            Zend_Loader::loadClass($adapter);
+        }
+
+        if (self::$_cache !== null) {
+            call_user_func(array($adapter, 'setCache'), self::$_cache);
+        }
+        $this->_adapter = new $adapter($data, $locale, $options);
+        if (!$this->_adapter instanceof Zend_Translate_Adapter) {
+            require_once 'Zend/Translate/Exception.php';
+            throw new Zend_Translate_Exception("Adapter " . $adapter . " does not extend Zend_Translate_Adapter");
+        }
+    }
+
+    /**
+     * Returns the adapters name and it's options
+     *
+     * @return Zend_Translate_Adapter
+     */
+    public function getAdapter()
+    {
+        return $this->_adapter;
+    }
+
+    /**
+     * Returns the set cache
+     *
+     * @return Zend_Cache_Core The set cache
+     */
+    public static function getCache()
+    {
+        return self::$_cache;
+    }
+
+    /**
+     * Sets a cache for all instances of Zend_Translate
+     *
+     * @param  Zend_Cache_Core $cache Cache to store to
+     * @return void
+     */
+    public static function setCache(Zend_Cache_Core $cache)
+    {
+        self::$_cache = $cache;
+    }
+
+    /**
+     * Returns true when a cache is set
+     *
+     * @return boolean
+     */
+    public static function hasCache()
+    {
+        if (self::$_cache !== null) {
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Removes any set cache
+     *
+     * @return void
+     */
+    public static function removeCache()
+    {
+        self::$_cache = null;
+    }
+
+    /**
+     * Clears all set cache data
+     *
+     * @return void
+     */
+    public static function clearCache()
+    {
+        self::$_cache->clean();
+    }
+
+    /**
+     * Calls all methods from the adapter
+     */
+    public function __call($method, array $options)
+    {
+        if (method_exists($this->_adapter, $method)) {
+            return call_user_func_array(array($this->_adapter, $method), $options);
+        }
+        require_once 'Zend/Translate/Exception.php';
+        throw new Zend_Translate_Exception("Unknown method '" . $method . "' called!");
+    }
+}
index 92300684e6372947fcf3936cb6c198c1d0f24f61..ede117cabd265e5f3b7cff06ba3f5b650483ee4d 100644 (file)
  *
  * @category  Zend
  * @package   Zend_Uri
- * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
  * @license   http://framework.zend.com/license/new-bsd     New BSD License
  * @version   $Id$
  */
 
-/**
- * @see Zend_Loader
- */
-require_once 'Zend/Loader.php';
-
 /**
  * Abstract class for all Zend_Uri handlers
  *
  * @category  Zend
  * @package   Zend_Uri
- * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
  * @license   http://framework.zend.com/license/new-bsd     New BSD License
  */
 abstract class Zend_Uri
@@ -41,6 +36,15 @@ abstract class Zend_Uri
      */
     protected $_scheme = '';
 
+    /**
+     * Global configuration array
+     *
+     * @var array
+     */
+    static protected $_config = array(
+        'allow_unwise' => false
+    );
+    
     /**
      * Return a string representation of this URI.
      *
@@ -119,7 +123,10 @@ abstract class Zend_Uri
                 break;
         }
 
-        Zend_Loader::loadClass($className);
+        if (!class_exists($className)) {
+            require_once 'Zend/Loader.php';
+            Zend_Loader::loadClass($className);
+        }
         $schemeHandler = new $className($scheme, $schemeSpecific);
 
         return $schemeHandler;
@@ -139,6 +146,18 @@ abstract class Zend_Uri
         }
     }
 
+    /**
+     * Set global configuration options
+     *
+     * @param array $config
+     */
+    static public function setConfig(array $config)
+    {
+        foreach ($config as $k => $v) {
+            self::$_config[$k] = $v;
+        }
+    }
+    
     /**
      * Zend_Uri and its subclasses cannot be instantiated directly.
      * Use Zend_Uri::factory() to return a new Zend_Uri object.
diff --git a/lib/zend/Zend/Validate.php b/lib/zend/Zend/Validate.php
new file mode 100644 (file)
index 0000000..6f56767
--- /dev/null
@@ -0,0 +1,246 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/**
+ * @see Zend_Validate_Interface
+ */
+require_once 'Zend/Validate/Interface.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Validate implements Zend_Validate_Interface
+{
+    /**
+     * Validator chain
+     *
+     * @var array
+     */
+    protected $_validators = array();
+
+    /**
+     * Array of validation failure messages
+     *
+     * @var array
+     */
+    protected $_messages = array();
+
+    /**
+     * Default Namespaces
+     *
+     * @var array
+     */
+    protected static $_defaultNamespaces = array();
+
+    /**
+     * Array of validation failure message codes
+     *
+     * @var array
+     * @deprecated Since 1.5.0
+     */
+    protected $_errors = array();
+
+    /**
+     * Adds a validator to the end of the chain
+     *
+     * If $breakChainOnFailure is true, then if the validator fails, the next validator in the chain,
+     * if one exists, will not be executed.
+     *
+     * @param  Zend_Validate_Interface $validator
+     * @param  boolean                 $breakChainOnFailure
+     * @return Zend_Validate Provides a fluent interface
+     */
+    public function addValidator(Zend_Validate_Interface $validator, $breakChainOnFailure = false)
+    {
+        $this->_validators[] = array(
+            'instance' => $validator,
+            'breakChainOnFailure' => (boolean) $breakChainOnFailure
+            );
+        return $this;
+    }
+
+    /**
+     * Returns true if and only if $value passes all validations in the chain
+     *
+     * Validators are run in the order in which they were added to the chain (FIFO).
+     *
+     * @param  mixed $value
+     * @return boolean
+     */
+    public function isValid($value)
+    {
+        $this->_messages = array();
+        $this->_errors   = array();
+        $result = true;
+        foreach ($this->_validators as $element) {
+            $validator = $element['instance'];
+            if ($validator->isValid($value)) {
+                continue;
+            }
+            $result = false;
+            $messages = $validator->getMessages();
+            $this->_messages = array_merge($this->_messages, $messages);
+            $this->_errors   = array_merge($this->_errors,   array_keys($messages));
+            if ($element['breakChainOnFailure']) {
+                break;
+            }
+        }
+        return $result;
+    }
+
+    /**
+     * Defined by Zend_Validate_Interface
+     *
+     * Returns array of validation failure messages
+     *
+     * @return array
+     */
+    public function getMessages()
+    {
+        return $this->_messages;
+    }
+
+    /**
+     * Defined by Zend_Validate_Interface
+     *
+     * Returns array of validation failure message codes
+     *
+     * @return array
+     * @deprecated Since 1.5.0
+     */
+    public function getErrors()
+    {
+        return $this->_errors;
+    }
+
+    /**
+     * Returns the set default namespaces
+     *
+     * @return array
+     */
+    public static function getDefaultNamespaces()
+    {
+        return self::$_defaultNamespaces;
+    }
+
+    /**
+     * Sets new default namespaces
+     *
+     * @param array|string $namespace
+     * @return null
+     */
+    public static function setDefaultNamespaces($namespace)
+    {
+        if (!is_array($namespace)) {
+            $namespace = array((string) $namespace);
+        }
+
+        self::$_defaultNamespaces = $namespace;
+    }
+
+    /**
+     * Adds a new default namespace
+     *
+     * @param array|string $namespace
+     * @return null
+     */
+    public static function addDefaultNamespaces($namespace)
+    {
+        if (!is_array($namespace)) {
+            $namespace = array((string) $namespace);
+        }
+
+        self::$_defaultNamespaces = array_unique(array_merge(self::$_defaultNamespaces, $namespace));
+    }
+
+    /**
+     * Returns true when defaultNamespaces are set
+     *
+     * @return boolean
+     */
+    public static function hasDefaultNamespaces()
+    {
+        return (!empty(self::$_defaultNamespaces));
+    }
+
+    /**
+     * @param  mixed    $value
+     * @param  string   $classBaseName
+     * @param  array    $args          OPTIONAL
+     * @param  mixed    $namespaces    OPTIONAL
+     * @return boolean
+     * @throws Zend_Validate_Exception
+     */
+    public static function is($value, $classBaseName, array $args = array(), $namespaces = array())
+    {
+        $namespaces = array_merge((array) $namespaces, self::$_defaultNamespaces, array('Zend_Validate'));
+        foreach ($namespaces as $namespace) {
+            $className = $namespace . '_' . ucfirst($classBaseName);
+            try {
+                if (!class_exists($className)) {
+                    require_once 'Zend/Loader.php';
+                    Zend_Loader::loadClass($className);
+                }
+                $class = new ReflectionClass($className);
+                if ($class->implementsInterface('Zend_Validate_Interface')) {
+                    if ($class->hasMethod('__construct')) {
+                        $object = $class->newInstanceArgs($args);
+                    } else {
+                        $object = $class->newInstance();
+                    }
+                    return $object->isValid($value);
+                }
+            } catch (Zend_Validate_Exception $ze) {
+                // if there is an exception while validating throw it
+                throw $ze;
+            } catch (Zend_Exception $ze) {
+                // fallthrough and continue for missing validation classes
+            }
+        }
+        require_once 'Zend/Validate/Exception.php';
+        throw new Zend_Validate_Exception("Validate class not found from basename '$classBaseName'");
+    }
+
+    /**
+     * Returns the maximum allowed message length
+     *
+     * @return integer
+     */
+    public static function getMessageLength()
+    {
+        require_once 'Zend/Validate/Abstract.php';
+        return Zend_Validate_Abstract::getMessageLength();
+    }
+
+    /**
+     * Sets the maximum allowed message length
+     *
+     * @param integer $length
+     */
+    public static function setMessageLength($length = -1)
+    {
+        require_once 'Zend/Validate/Abstract.php';
+        Zend_Validate_Abstract::setMessageLength($length);
+    }
+}
index d84f640790a12913a3dfd894210df3e67a46f934..e55f019eae47a31201e5fdf18125f974ccc77531 100644 (file)
@@ -14,7 +14,7 @@
  *
  * @category   Zend
  * @package    Zend_Version
- * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
  * @version    $Id$
  */
@@ -24,7 +24,7 @@
  *
  * @category   Zend
  * @package    Zend_Version
- * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
  */
 final class Zend_Version
@@ -32,11 +32,11 @@ final class Zend_Version
     /**
      * Zend Framework version identification - see compareVersion()
      */
-    const VERSION = '1.7.3';
+    const VERSION = '1.9.4';
 
     /**
      * Compare the specified Zend Framework version string $version
-     * with the current Zend_Version::VERSION of the Zend Framework.
+     * with the current Zend_Version::VERSION of Zend Framework.
      *
      * @param  string  $version  A version string (e.g. "0.7.1").
      * @return boolean           -1 if the $version is older,
@@ -46,6 +46,8 @@ final class Zend_Version
      */
     public static function compareVersion($version)
     {
-        return version_compare($version, self::VERSION);
+        $version = strtolower($version);
+        $version = preg_replace('/(\d)pr(\d?)/', '$1a$2', $version);
+        return version_compare($version, strtolower(self::VERSION));
     }
 }
diff --git a/lib/zend/Zend/View.php b/lib/zend/Zend/View.php
new file mode 100644 (file)
index 0000000..10d3215
--- /dev/null
@@ -0,0 +1,111 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_View
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+
+/**
+ * Abstract master class for extension.
+ */
+require_once 'Zend/View/Abstract.php';
+
+
+/**
+ * Concrete class for handling view scripts.
+ *
+ * @category   Zend
+ * @package    Zend_View
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_View extends Zend_View_Abstract
+{
+    /**
+     * Whether or not to use streams to mimic short tags
+     * @var bool
+     */
+    private $_useViewStream = false;
+
+    /**
+     * Whether or not to use stream wrapper if short_open_tag is false
+     * @var bool
+     */
+    private $_useStreamWrapper = false;
+
+    /**
+     * Constructor
+     *
+     * Register Zend_View_Stream stream wrapper if short tags are disabled.
+     * 
+     * @param  array $config 
+     * @return void
+     */
+    public function __construct($config = array())
+    {
+        $this->_useViewStream = (bool) ini_get('short_open_tag') ? false : true;
+        if ($this->_useViewStream) {
+            if (!in_array('zend.view', stream_get_wrappers())) {
+                require_once 'Zend/View/Stream.php';
+                stream_wrapper_register('zend.view', 'Zend_View_Stream');
+            }
+        }
+
+        if (array_key_exists('useStreamWrapper', $config)) {
+            $this->setUseStreamWrapper($config['useStreamWrapper']);
+        }
+
+        parent::__construct($config);
+    }
+
+    /**
+     * Set flag indicating if stream wrapper should be used if short_open_tag is off
+     * 
+     * @param  bool $flag 
+     * @return Zend_View
+     */
+    public function setUseStreamWrapper($flag)
+    {
+        $this->_useStreamWrapper = (bool) $flag;
+        return $this;
+    }
+
+    /**
+     * Should the stream wrapper be used if short_open_tag is off?
+     * 
+     * @return bool
+     */
+    public function useStreamWrapper()
+    {
+        return $this->_useStreamWrapper;
+    }
+
+    /**
+     * Includes the view script in a scope with only public $this variables.
+     *
+     * @param string The view script to execute.
+     */
+    protected function _run()
+    {
+        if ($this->_useViewStream && $this->useStreamWrapper()) {
+            include 'zend.view://' . func_get_arg(0);
+        } else {
+            include func_get_arg(0);
+        }
+    }
+}