diff options
Diffstat (limited to '')
-rw-r--r-- | library/vendor/Zend/Filter/Encrypt.php | 134 | ||||
-rw-r--r-- | library/vendor/Zend/Filter/Encrypt/Interface.php | 47 | ||||
-rw-r--r-- | library/vendor/Zend/Filter/Encrypt/Mcrypt.php | 352 | ||||
-rw-r--r-- | library/vendor/Zend/Filter/Encrypt/Openssl.php | 480 |
4 files changed, 1013 insertions, 0 deletions
diff --git a/library/vendor/Zend/Filter/Encrypt.php b/library/vendor/Zend/Filter/Encrypt.php new file mode 100644 index 0000000..0dca4c1 --- /dev/null +++ b/library/vendor/Zend/Filter/Encrypt.php @@ -0,0 +1,134 @@ +<?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-2015 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 + */ + +/** + * @see Zend_Loader + */ + +/** + * Encrypts a given string + * + * @category Zend + * @package Zend_Filter + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Filter_Encrypt implements Zend_Filter_Interface +{ + /** + * Encryption adapter + */ + protected $_adapter; + + /** + * Class constructor + * + * @param string|array $options (Optional) Options to set, if null mcrypt is used + */ + public function __construct($options = null) + { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } + + $this->setAdapter($options); + } + + /** + * Returns the name of the set adapter + * + * @return string + */ + public function getAdapter() + { + return $this->_adapter->toString(); + } + + /** + * Sets new encryption options + * + * @param string|array $options (Optional) Encryption options + * @return Zend_Filter_Encrypt + */ + public function setAdapter($options = null) + { + if (is_string($options)) { + $adapter = $options; + } else if (isset($options['adapter'])) { + $adapter = $options['adapter']; + unset($options['adapter']); + } else { + $adapter = 'Mcrypt'; + } + + if (!is_array($options)) { + $options = array(); + } + + if (Zend_Loader::isReadable('Zend/Filter/Encrypt/' . ucfirst($adapter). '.php')) { + $adapter = 'Zend_Filter_Encrypt_' . ucfirst($adapter); + } + + if (!class_exists($adapter)) { + Zend_Loader::loadClass($adapter); + } + + $this->_adapter = new $adapter($options); + if (!$this->_adapter instanceof Zend_Filter_Encrypt_Interface) { + throw new Zend_Filter_Exception("Encoding adapter '" . $adapter . "' does not implement Zend_Filter_Encrypt_Interface"); + } + + return $this; + } + + /** + * Calls adapter methods + * + * @param string $method Method to call + * @param string|array $options Options for this method + */ + public function __call($method, $options) + { + $part = substr($method, 0, 3); + if ((($part != 'get') and ($part != 'set')) or !method_exists($this->_adapter, $method)) { + throw new Zend_Filter_Exception("Unknown method '{$method}'"); + } + + return call_user_func_array(array($this->_adapter, $method), $options); + } + + /** + * Defined by Zend_Filter_Interface + * + * Encrypts the content $value with the defined settings + * + * @param string $value Content to encrypt + * @return string The encrypted content + */ + public function filter($value) + { + return $this->_adapter->encrypt($value); + } +} diff --git a/library/vendor/Zend/Filter/Encrypt/Interface.php b/library/vendor/Zend/Filter/Encrypt/Interface.php new file mode 100644 index 0000000..1510e7f --- /dev/null +++ b/library/vendor/Zend/Filter/Encrypt/Interface.php @@ -0,0 +1,47 @@ +<?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-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ + +/** + * Encryption interface + * + * @category Zend + * @package Zend_Filter + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +interface Zend_Filter_Encrypt_Interface +{ + /** + * Encrypts $value with the defined settings + * + * @param string $value Data to encrypt + * @return string The encrypted data + */ + public function encrypt($value); + + /** + * Decrypts $value with the defined settings + * + * @param string $value Data to decrypt + * @return string The decrypted data + */ + public function decrypt($value); +} diff --git a/library/vendor/Zend/Filter/Encrypt/Mcrypt.php b/library/vendor/Zend/Filter/Encrypt/Mcrypt.php new file mode 100644 index 0000000..ee7a45b --- /dev/null +++ b/library/vendor/Zend/Filter/Encrypt/Mcrypt.php @@ -0,0 +1,352 @@ +<?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-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ + +/** + * @see Zend_Filter_Encrypt_Interface + */ + +/** @see Zend_Crypt_Math */ + +/** + * Encryption adapter for mcrypt + * + * @category Zend + * @package Zend_Filter + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Filter_Encrypt_Mcrypt implements Zend_Filter_Encrypt_Interface +{ + /** + * Definitions for encryption + * array( + * 'key' => encryption key string + * 'algorithm' => algorithm to use + * 'algorithm_directory' => directory where to find the algorithm + * 'mode' => encryption mode to use + * 'modedirectory' => directory where to find the mode + * ) + */ + protected $_encryption = array( + 'key' => 'ZendFramework', + 'algorithm' => 'blowfish', + 'algorithm_directory' => '', + 'mode' => 'cbc', + 'mode_directory' => '', + 'vector' => null, + 'salt' => false + ); + + /** + * Internal compression + * + * @var array + */ + protected $_compression; + + protected static $_srandCalled = false; + + /** + * Class constructor + * + * @param string|array|Zend_Config $options Cryption Options + */ + public function __construct($options) + { + if (!extension_loaded('mcrypt')) { + throw new Zend_Filter_Exception('This filter needs the mcrypt extension'); + } + + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } elseif (is_string($options)) { + $options = array('key' => $options); + } elseif (!is_array($options)) { + throw new Zend_Filter_Exception('Invalid options argument provided to filter'); + } + + if (array_key_exists('compression', $options)) { + $this->setCompression($options['compression']); + unset($options['compress']); + } + + $this->setEncryption($options); + } + + /** + * Returns the set encryption options + * + * @return array + */ + public function getEncryption() + { + return $this->_encryption; + } + + /** + * Sets new encryption options + * + * @param string|array $options Encryption options + * @return Zend_Filter_File_Encryption + */ + public function setEncryption($options) + { + if (is_string($options)) { + $options = array('key' => $options); + } + + if (!is_array($options)) { + throw new Zend_Filter_Exception('Invalid options argument provided to filter'); + } + + $options = $options + $this->getEncryption(); + $algorithms = mcrypt_list_algorithms($options['algorithm_directory']); + if (!in_array($options['algorithm'], $algorithms)) { + throw new Zend_Filter_Exception("The algorithm '{$options['algorithm']}' is not supported"); + } + + $modes = mcrypt_list_modes($options['mode_directory']); + if (!in_array($options['mode'], $modes)) { + throw new Zend_Filter_Exception("The mode '{$options['mode']}' is not supported"); + } + + if (!mcrypt_module_self_test($options['algorithm'], $options['algorithm_directory'])) { + throw new Zend_Filter_Exception('The given algorithm can not be used due an internal mcrypt problem'); + } + + if (!isset($options['vector'])) { + $options['vector'] = null; + } + + $this->_encryption = $options; + $this->setVector($options['vector']); + + return $this; + } + + /** + * Returns the set vector + * + * @return string + */ + public function getVector() + { + return $this->_encryption['vector']; + } + + /** + * Sets the initialization vector + * + * @param string $vector (Optional) Vector to set + * @return Zend_Filter_Encrypt_Mcrypt + */ + public function setVector($vector = null) + { + $cipher = $this->_openCipher(); + $size = mcrypt_enc_get_iv_size($cipher); + if (empty($vector)) { + $this->_srand(); + if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN' && version_compare(PHP_VERSION, '5.3.0', '<')) { + $method = MCRYPT_RAND; + } else { + if (file_exists('/dev/urandom') || (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN')) { + $method = MCRYPT_DEV_URANDOM; + } elseif (file_exists('/dev/random')) { + $method = MCRYPT_DEV_RANDOM; + } else { + $method = MCRYPT_RAND; + } + } + $vector = mcrypt_create_iv($size, $method); + } else if (strlen($vector) != $size) { + throw new Zend_Filter_Exception('The given vector has a wrong size for the set algorithm'); + } + + $this->_encryption['vector'] = $vector; + $this->_closeCipher($cipher); + + return $this; + } + + /** + * Returns the compression + * + * @return array + */ + public function getCompression() + { + return $this->_compression; + } + + /** + * Sets a internal compression for values to encrypt + * + * @param string|array $compression + * @return Zend_Filter_Encrypt_Mcrypt + */ + public function setCompression($compression) + { + if (is_string($this->_compression)) { + $compression = array('adapter' => $compression); + } + + $this->_compression = $compression; + return $this; + } + + /** + * Defined by Zend_Filter_Interface + * + * Encrypts $value with the defined settings + * + * @param string $value The content to encrypt + * @return string The encrypted content + */ + public function encrypt($value) + { + // compress prior to encryption + if (!empty($this->_compression)) { + $compress = new Zend_Filter_Compress($this->_compression); + $value = $compress->filter($value); + } + + $cipher = $this->_openCipher(); + $this->_initCipher($cipher); + $encrypted = mcrypt_generic($cipher, $value); + mcrypt_generic_deinit($cipher); + $this->_closeCipher($cipher); + + return $encrypted; + } + + /** + * Defined by Zend_Filter_Interface + * + * Decrypts $value with the defined settings + * + * @param string $value Content to decrypt + * @return string The decrypted content + */ + public function decrypt($value) + { + $cipher = $this->_openCipher(); + $this->_initCipher($cipher); + $decrypted = mdecrypt_generic($cipher, $value); + mcrypt_generic_deinit($cipher); + $this->_closeCipher($cipher); + + // decompress after decryption + if (!empty($this->_compression)) { + $decompress = new Zend_Filter_Decompress($this->_compression); + $decrypted = $decompress->filter($decrypted); + } + + return $decrypted; + } + + /** + * Returns the adapter name + * + * @return string + */ + public function toString() + { + return 'Mcrypt'; + } + + /** + * Open a cipher + * + * @throws Zend_Filter_Exception When the cipher can not be opened + * @return resource Returns the opened cipher + */ + protected function _openCipher() + { + $cipher = mcrypt_module_open( + $this->_encryption['algorithm'], + $this->_encryption['algorithm_directory'], + $this->_encryption['mode'], + $this->_encryption['mode_directory']); + + if ($cipher === false) { + throw new Zend_Filter_Exception('Mcrypt can not be opened with your settings'); + } + + return $cipher; + } + + /** + * Close a cipher + * + * @param resource $cipher Cipher to close + * @return Zend_Filter_Encrypt_Mcrypt + */ + protected function _closeCipher($cipher) + { + mcrypt_module_close($cipher); + + return $this; + } + + /** + * Initialises the cipher with the set key + * + * @param resource $cipher + * @throws + * @return resource + */ + protected function _initCipher($cipher) + { + $key = $this->_encryption['key']; + + $keysizes = mcrypt_enc_get_supported_key_sizes($cipher); + if (empty($keysizes) || ($this->_encryption['salt'] == true)) { + $this->_srand(); + $keysize = mcrypt_enc_get_key_size($cipher); + $key = substr(md5($key), 0, $keysize); + } else if (!in_array(strlen($key), $keysizes)) { + throw new Zend_Filter_Exception('The given key has a wrong size for the set algorithm'); + } + + $result = mcrypt_generic_init($cipher, $key, $this->_encryption['vector']); + if ($result < 0) { + throw new Zend_Filter_Exception('Mcrypt could not be initialize with the given setting'); + } + + return $this; + } + + /** + * _srand() interception + * + * @see ZF-8742 + */ + protected function _srand() + { + if (version_compare(PHP_VERSION, '5.3.0', '>=')) { + return; + } + if (!self::$_srandCalled) { + srand(Zend_Crypt_Math::randInteger(0, PHP_INT_MAX)); + self::$_srandCalled = true; + } + } +} diff --git a/library/vendor/Zend/Filter/Encrypt/Openssl.php b/library/vendor/Zend/Filter/Encrypt/Openssl.php new file mode 100644 index 0000000..7a46b8e --- /dev/null +++ b/library/vendor/Zend/Filter/Encrypt/Openssl.php @@ -0,0 +1,480 @@ +<?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-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ + +/** + * @see Zend_Filter_Encrypt_Interface + */ + +/** + * Encryption adapter for openssl + * + * @category Zend + * @package Zend_Filter + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Filter_Encrypt_Openssl implements Zend_Filter_Encrypt_Interface +{ + /** + * Definitions for encryption + * array( + * 'public' => public keys + * 'private' => private keys + * 'envelope' => resulting envelope keys + * ) + */ + protected $_keys = array( + 'public' => array(), + 'private' => array(), + 'envelope' => array() + ); + + /** + * Internal passphrase + * + * @var string + */ + protected $_passphrase; + + /** + * Internal compression + * + * @var array + */ + protected $_compression; + + /** + * Internal create package + * + * @var boolean + */ + protected $_package = false; + + /** + * Class constructor + * Available options + * 'public' => public key + * 'private' => private key + * 'envelope' => envelope key + * 'passphrase' => passphrase + * 'compression' => compress value with this compression adapter + * 'package' => pack envelope keys into encrypted string, simplifies decryption + * + * @param string|array $options Options for this adapter + */ + public function __construct($options = array()) + { + if (!extension_loaded('openssl')) { + throw new Zend_Filter_Exception('This filter needs the openssl extension'); + } + + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } + + if (!is_array($options)) { + $options = array('public' => $options); + } + + if (array_key_exists('passphrase', $options)) { + $this->setPassphrase($options['passphrase']); + unset($options['passphrase']); + } + + if (array_key_exists('compression', $options)) { + $this->setCompression($options['compression']); + unset($options['compress']); + } + + if (array_key_exists('package', $options)) { + $this->setPackage($options['package']); + unset($options['package']); + } + + $this->_setKeys($options); + } + + /** + * Sets the encryption keys + * + * @param string|array $keys Key with type association + * @return Zend_Filter_Encrypt_Openssl + */ + protected function _setKeys($keys) + { + if (!is_array($keys)) { + throw new Zend_Filter_Exception('Invalid options argument provided to filter'); + } + + foreach ($keys as $type => $key) { + if (ctype_print($key) && is_file(realpath($key)) && is_readable($key)) { + $file = fopen($key, 'r'); + $cert = fread($file, 8192); + fclose($file); + } else { + $cert = $key; + $key = count($this->_keys[$type]); + } + + switch ($type) { + case 'public': + $test = openssl_pkey_get_public($cert); + if ($test === false) { + throw new Zend_Filter_Exception("Public key '{$cert}' not valid"); + } + + openssl_free_key($test); + $this->_keys['public'][$key] = $cert; + break; + case 'private': + $test = openssl_pkey_get_private($cert, $this->_passphrase); + if ($test === false) { + throw new Zend_Filter_Exception("Private key '{$cert}' not valid"); + } + + openssl_free_key($test); + $this->_keys['private'][$key] = $cert; + break; + case 'envelope': + $this->_keys['envelope'][$key] = $cert; + break; + default: + break; + } + } + + return $this; + } + + /** + * Returns all public keys + * + * @return array + */ + public function getPublicKey() + { + $key = $this->_keys['public']; + return $key; + } + + /** + * Sets public keys + * + * @param string|array $key Public keys + * @return Zend_Filter_Encrypt_Openssl + */ + public function setPublicKey($key) + { + if (is_array($key)) { + foreach($key as $type => $option) { + if ($type !== 'public') { + $key['public'] = $option; + unset($key[$type]); + } + } + } else { + $key = array('public' => $key); + } + + return $this->_setKeys($key); + } + + /** + * Returns all private keys + * + * @return array + */ + public function getPrivateKey() + { + $key = $this->_keys['private']; + return $key; + } + + /** + * Sets private keys + * + * @param string $key Private key + * @param string $passphrase + * @return Zend_Filter_Encrypt_Openssl + */ + public function setPrivateKey($key, $passphrase = null) + { + if (is_array($key)) { + foreach($key as $type => $option) { + if ($type !== 'private') { + $key['private'] = $option; + unset($key[$type]); + } + } + } else { + $key = array('private' => $key); + } + + if ($passphrase !== null) { + $this->setPassphrase($passphrase); + } + + return $this->_setKeys($key); + } + + /** + * Returns all envelope keys + * + * @return array + */ + public function getEnvelopeKey() + { + $key = $this->_keys['envelope']; + return $key; + } + + /** + * Sets envelope keys + * + * @param string|array $options Envelope keys + * @return Zend_Filter_Encrypt_Openssl + */ + public function setEnvelopeKey($key) + { + if (is_array($key)) { + foreach($key as $type => $option) { + if ($type !== 'envelope') { + $key['envelope'] = $option; + unset($key[$type]); + } + } + } else { + $key = array('envelope' => $key); + } + + return $this->_setKeys($key); + } + + /** + * Returns the passphrase + * + * @return string + */ + public function getPassphrase() + { + return $this->_passphrase; + } + + /** + * Sets a new passphrase + * + * @param string $passphrase + * @return Zend_Filter_Encrypt_Openssl + */ + public function setPassphrase($passphrase) + { + $this->_passphrase = $passphrase; + return $this; + } + + /** + * Returns the compression + * + * @return array + */ + public function getCompression() + { + return $this->_compression; + } + + /** + * Sets a internal compression for values to encrypt + * + * @param string|array $compression + * @return Zend_Filter_Encrypt_Openssl + */ + public function setCompression($compression) + { + if (is_string($this->_compression)) { + $compression = array('adapter' => $compression); + } + + $this->_compression = $compression; + return $this; + } + + /** + * Returns if header should be packaged + * + * @return boolean + */ + public function getPackage() + { + return $this->_package; + } + + /** + * Sets if the envelope keys should be included in the encrypted value + * + * @param boolean $package + * @return Zend_Filter_Encrypt_Openssl + */ + public function setPackage($package) + { + $this->_package = (boolean) $package; + return $this; + } + + /** + * Encrypts $value with the defined settings + * Note that you also need the "encrypted" keys to be able to decrypt + * + * @param string $value Content to encrypt + * @return string The encrypted content + * @throws Zend_Filter_Exception + */ + public function encrypt($value) + { + $encrypted = array(); + $encryptedkeys = array(); + + if (count($this->_keys['public']) == 0) { + throw new Zend_Filter_Exception('Openssl can not encrypt without public keys'); + } + + $keys = array(); + $fingerprints = array(); + $count = -1; + foreach($this->_keys['public'] as $key => $cert) { + $keys[$key] = openssl_pkey_get_public($cert); + if ($this->_package) { + $details = openssl_pkey_get_details($keys[$key]); + if ($details === false) { + $details = array('key' => 'ZendFramework'); + } + + ++$count; + $fingerprints[$count] = md5($details['key']); + } + } + + // compress prior to encryption + if (!empty($this->_compression)) { + $compress = new Zend_Filter_Compress($this->_compression); + $value = $compress->filter($value); + } + + $crypt = openssl_seal($value, $encrypted, $encryptedkeys, $keys); + foreach ($keys as $key) { + openssl_free_key($key); + } + + if ($crypt === false) { + throw new Zend_Filter_Exception('Openssl was not able to encrypt your content with the given options'); + } + + $this->_keys['envelope'] = $encryptedkeys; + + // Pack data and envelope keys into single string + if ($this->_package) { + $header = pack('n', count($this->_keys['envelope'])); + foreach($this->_keys['envelope'] as $key => $envKey) { + $header .= pack('H32n', $fingerprints[$key], strlen($envKey)) . $envKey; + } + + $encrypted = $header . $encrypted; + } + + return $encrypted; + } + + /** + * Defined by Zend_Filter_Interface + * + * Decrypts $value with the defined settings + * + * @param string $value Content to decrypt + * @return string The decrypted content + * @throws Zend_Filter_Exception + */ + public function decrypt($value) + { + $decrypted = ""; + $envelope = current($this->getEnvelopeKey()); + + if (count($this->_keys['private']) !== 1) { + throw new Zend_Filter_Exception('Please give a private key for decryption with Openssl'); + } + + if (!$this->_package && empty($envelope)) { + throw new Zend_Filter_Exception('Please give a envelope key for decryption with Openssl'); + } + + foreach($this->_keys['private'] as $key => $cert) { + $keys = openssl_pkey_get_private($cert, $this->getPassphrase()); + } + + if ($this->_package) { + $details = openssl_pkey_get_details($keys); + if ($details !== false) { + $fingerprint = md5($details['key']); + } else { + $fingerprint = md5("ZendFramework"); + } + + $count = unpack('ncount', $value); + $count = $count['count']; + $length = 2; + for($i = $count; $i > 0; --$i) { + $header = unpack('H32print/nsize', substr($value, $length, 18)); + $length += 18; + if ($header['print'] == $fingerprint) { + $envelope = substr($value, $length, $header['size']); + } + + $length += $header['size']; + } + + // remainder of string is the value to decrypt + $value = substr($value, $length); + } + + $crypt = openssl_open($value, $decrypted, $envelope, $keys); + openssl_free_key($keys); + + if ($crypt === false) { + throw new Zend_Filter_Exception('Openssl was not able to decrypt you content with the given options'); + } + + // decompress after decryption + if (!empty($this->_compression)) { + $decompress = new Zend_Filter_Decompress($this->_compression); + $decrypted = $decompress->filter($decrypted); + } + + return $decrypted; + } + + /** + * Returns the adapter name + * + * @return string + */ + public function toString() + { + return 'Openssl'; + } +} |