<?php

namespace PhpOffice\PhpSpreadsheet\Calculation\Engine;

class Logger
{
    /**
     * Flag to determine whether a debug log should be generated by the calculation engine
     *        If true, then a debug log will be generated
     *        If false, then a debug log will not be generated.
     *
     * @var bool
     */
    private $writeDebugLog = false;

    /**
     * Flag to determine whether a debug log should be echoed by the calculation engine
     *        If true, then a debug log will be echoed
     *        If false, then a debug log will not be echoed
     * A debug log can only be echoed if it is generated.
     *
     * @var bool
     */
    private $echoDebugLog = false;

    /**
     * The debug log generated by the calculation engine.
     *
     * @var string[]
     */
    private $debugLog = [];

    /**
     * The calculation engine cell reference stack.
     *
     * @var CyclicReferenceStack
     */
    private $cellStack;

    /**
     * Instantiate a Calculation engine logger.
     *
     * @param CyclicReferenceStack $stack
     */
    public function __construct(CyclicReferenceStack $stack)
    {
        $this->cellStack = $stack;
    }

    /**
     * Enable/Disable Calculation engine logging.
     *
     * @param bool $pValue
     */
    public function setWriteDebugLog($pValue)
    {
        $this->writeDebugLog = $pValue;
    }

    /**
     * Return whether calculation engine logging is enabled or disabled.
     *
     * @return bool
     */
    public function getWriteDebugLog()
    {
        return $this->writeDebugLog;
    }

    /**
     * Enable/Disable echoing of debug log information.
     *
     * @param bool $pValue
     */
    public function setEchoDebugLog($pValue)
    {
        $this->echoDebugLog = $pValue;
    }

    /**
     * Return whether echoing of debug log information is enabled or disabled.
     *
     * @return bool
     */
    public function getEchoDebugLog()
    {
        return $this->echoDebugLog;
    }

    /**
     * Write an entry to the calculation engine debug log.
     */
    public function writeDebugLog(...$args)
    {
        //    Only write the debug log if logging is enabled
        if ($this->writeDebugLog) {
            $message = implode($args);
            $cellReference = implode(' -> ', $this->cellStack->showStack());
            if ($this->echoDebugLog) {
                echo $cellReference,
                    ($this->cellStack->count() > 0 ? ' => ' : ''),
                    $message,
                    PHP_EOL;
            }
            $this->debugLog[] = $cellReference .
                ($this->cellStack->count() > 0 ? ' => ' : '') .
                $message;
        }
    }

    /**
     * Clear the calculation engine debug log.
     */
    public function clearLog()
    {
        $this->debugLog = [];
    }

    /**
     * Return the calculation engine debug log.
     *
     * @return string[]
     */
    public function getLog()
    {
        return $this->debugLog;
    }
}


<?php

namespace PhpOffice\PhpSpreadsheet\Writer;

use PhpOffice\PhpSpreadsheet\Shared\File;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Exception as WriterException;
use PhpOffice\PhpSpreadsheet\Writer\Ods\Content;
use PhpOffice\PhpSpreadsheet\Writer\Ods\Meta;
use PhpOffice\PhpSpreadsheet\Writer\Ods\MetaInf;
use PhpOffice\PhpSpreadsheet\Writer\Ods\Mimetype;
use PhpOffice\PhpSpreadsheet\Writer\Ods\Settings;
use PhpOffice\PhpSpreadsheet\Writer\Ods\Styles;
use PhpOffice\PhpSpreadsheet\Writer\Ods\Thumbnails;
use ZipArchive;

class Ods extends BaseWriter
{
    /**
     * Private writer parts.
     *
     * @var Ods\WriterPart[]
     */
    private $writerParts = [];

    /**
     * Private PhpSpreadsheet.
     *
     * @var Spreadsheet
     */
    private $spreadSheet;

    /**
     * Create a new Ods.
     *
     * @param Spreadsheet $spreadsheet
     */
    public function __construct(Spreadsheet $spreadsheet)
    {
        $this->setSpreadsheet($spreadsheet);

        $writerPartsArray = [
            'content' => Content::class,
            'meta' => Meta::class,
            'meta_inf' => MetaInf::class,
            'mimetype' => Mimetype::class,
            'settings' => Settings::class,
            'styles' => Styles::class,
            'thumbnails' => Thumbnails::class,
        ];

        foreach ($writerPartsArray as $writer => $class) {
            $this->writerParts[$writer] = new $class($this);
        }
    }

    /**
     * Get writer part.
     *
     * @param string $pPartName Writer part name
     *
     * @return null|Ods\WriterPart
     */
    public function getWriterPart($pPartName)
    {
        if ($pPartName != '' && isset($this->writerParts[strtolower($pPartName)])) {
            return $this->writerParts[strtolower($pPartName)];
        }

        return null;
    }

    /**
     * Save PhpSpreadsheet to file.
     *
     * @param string $pFilename
     *
     * @throws WriterException
     */
    public function save($pFilename)
    {
        if (!$this->spreadSheet) {
            throw new WriterException('PhpSpreadsheet object unassigned.');
        }

        // garbage collect
        $this->spreadSheet->garbageCollect();

        // If $pFilename is php://output or php://stdout, make it a temporary file...
        $originalFilename = $pFilename;
        if (strtolower($pFilename) == 'php://output' || strtolower($pFilename) == 'php://stdout') {
            $pFilename = @tempnam(File::sysGetTempDir(), 'phpxltmp');
            if ($pFilename == '') {
                $pFilename = $originalFilename;
            }
        }

        $zip = $this->createZip($pFilename);

        $zip->addFromString('META-INF/manifest.xml', $this->getWriterPart('meta_inf')->writeManifest());
        $zip->addFromString('Thumbnails/thumbnail.png', $this->getWriterPart('thumbnails')->writeThumbnail());
        $zip->addFromString('content.xml', $this->getWriterPart('content')->write());
        $zip->addFromString('meta.xml', $this->getWriterPart('meta')->write());
        $zip->addFromString('mimetype', $this->getWriterPart('mimetype')->write());
        $zip->addFromString('settings.xml', $this->getWriterPart('settings')->write());
        $zip->addFromString('styles.xml', $this->getWriterPart('styles')->write());

        // Close file
        if ($zip->close() === false) {
            throw new WriterException("Could not close zip file $pFilename.");
        }

        // If a temporary file was used, copy it to the correct file stream
        if ($originalFilename != $pFilename) {
            if (copy($pFilename, $originalFilename) === false) {
                throw new WriterException("Could not copy temporary zip file $pFilename to $originalFilename.");
            }
            @unlink($pFilename);
        }
    }

    /**
     * Create zip object.
     *
     * @param string $pFilename
     *
     * @throws WriterException
     *
     * @return ZipArchive
     */
    private function createZip($pFilename)
    {
        // Create new ZIP file and open it for writing
        $zip = new ZipArchive();

        if (file_exists($pFilename)) {
            unlink($pFilename);
        }
        // Try opening the ZIP file
        if ($zip->open($pFilename, ZipArchive::OVERWRITE) !== true) {
            if ($zip->open($pFilename, ZipArchive::CREATE) !== true) {
                throw new WriterException("Could not open $pFilename for writing.");
            }
        }

        return $zip;
    }

    /**
     * Get Spreadsheet object.
     *
     * @throws WriterException
     *
     * @return Spreadsheet
     */
    public function getSpreadsheet()
    {
        if ($this->spreadSheet !== null) {
            return $this->spreadSheet;
        }

        throw new WriterException('No PhpSpreadsheet assigned.');
    }

    /**
     * Set Spreadsheet object.
     *
     * @param Spreadsheet $spreadsheet PhpSpreadsheet object
     *
     * @return self
     */
    public function setSpreadsheet(Spreadsheet $spreadsheet)
    {
        $this->spreadSheet = $spreadsheet;

        return $this;
    }
}


<?php

namespace XQueue\Maileon\API\Transactions;

use XQueue\Maileon\API\JSON\AbstractJSONWrapper;
use XQueue\Maileon\API\Transactions\ContactReference;
use XQueue\Maileon\API\Transactions\Attachment;
use XQueue\Maileon\API\Contacts\Permission;
use XQueue\Maileon\API\MaileonAPIException;

/**
 * The wrapper class for a Maileon transaction.
 *
 * @author Viktor Balogh | Wanadis Kft. | balogh.viktor@maileon.hu
 * @author Marcus Ständer | Trusted Technologies GmbH | marcus.staender@trusted-technologies.de
 */

class Transaction extends AbstractJSONWrapper {
    /**
     *
     * @var integer
     *      the numeric ID of the transaction type to use
     */
    public $type;

    /**
     *
     * @var com_maileon_api_transactions_ContactReference
     *      an array identifying the contact that contains at least one of the following attributes: id/external_id/email
     */
    public $contact;

    /**
     *
     * @var com_maileon_api_transactions_ContactReference
     *      Used to control import settings. This array also contains the contact. If $contact AND $import exist,
     *      $contact will be ignored and the contact within $import will be used.
     */
    public $import;

    /**
     *
     * @var array
     *      an array that contains the transaction content as defined in the referenced transaction type
     */
    public $content;

    /**
     * @var array
     *      an array that contains the attachments for the transaction e-mail, if any
     */
    public $attachments;

    /**
     * Constructor initializing default values.
     */
    function __construct() {
        $this->content = array();
        $this->attachments = array();
        $this->contact = new ContactReference();
        $this->import = new ContactReference();
        $this->import->permission = Permission::$NONE;
    }

    /**
     * Read a binary file from the file system and adds it as an attachment to this transaction.
     * @param $filename the file system path to read the attachment from
     * @param $mimetype the mime type of the attachment
     * @param null $attachmentFileName the file name to use when sending the attachment as an e-mail. If this is null,
     *        the basename of $filename is used instead.
     */
    function addAttachmentFromFile($filename, $mimetype, $attachmentFileName = null) {
        $handle = fopen($filename, "rb");
        if (FALSE === $filename) {
            throw new MaileonAPIException("Cannot read file " . $filename . ".");
        }
        $contents = '';
        while (!feof($handle)) {
            $contents .= fread($handle, 8192);
        }
        fclose($handle);
        if ($attachmentFileName === null) {
            $attachmentFileName = basename($filename);
        }
        $attachment = new Attachment($attachmentFileName, $mimetype, base64_encode($contents));
        $this->attachments[] = $attachment;
    }

    /**
     * Adds an attachment to this transaction from a string that contains binary data.
     * @param $filename the file name to use when sending the attachment as an e-mail
     * @param $mimetype the mime type of the attachment
     * @param $contents a string containing binary data, e.g. as returned from fread().
     */
    function addAttachmentFromBinaryData($filename, $mimetype, $contents) {
        $attachment = new Attachment($filename, $mimetype, base64_encode($contents));
        $this->attachments[] = $attachment;
    }

    /**
     * Adds an attachment to this transaction from a string that contains base64-encoded data.
     * @param $filename the file name to use when sending the attachment as an e-mail
     * @param $mimetype the mime type of the attachment
     * @param $contents a string containing binary data, e.g. as returned from fread().
     */
    function addAttachmentFromBase64Data($filename, $mimetype, $contents) {
        $attachment = new Attachment($filename, $mimetype, $contents);
        $this->attachments[] = $attachment;
    }

    /**
     * @return \em string
     * 	a human-readable representation listing all the attributes of this transaction and their respective values.
     */
    function toString() {
            return "Transaction [type=" . $this->type .  ", contact=(" . (empty( $this->contact))?"":$this->contact . "), import=(" . (empty( $this->import))?"":$this->import . "), content=(" . json_encode($this->content) . ")]";
    }

    function toArray() {
        $array = parent::toArray();

        if(isset($array['import'])) {
            unset($array['contact']);
            $array['import'] = array( "contact" => $array['import'] );
        }

        return $array;
    }
}


<?php

namespace RodrigoPedra\ClearSaleID\Entity\Request;

use InvalidArgumentException;
use RodrigoPedra\ClearSaleID\Entity\XmlEntityInterface;
use RodrigoPedra\ClearSaleID\Exception\RequiredFieldException;
use XMLWriter;

class Item implements XmlEntityInterface
{
    /** @var  string */
    private $id;

    /** @var  string */
    private $name;

    /** @var  string */
    private $value;

    /** @var  string */
    private $quantity;

    /** @var  string */
    private $notes;

    /** @var  string */
    private $categoryId;

    /** @var  string */
    private $categoryName;

    /**
     * Criar Item com campos obrigatórios preenchidos
     *
     * @param  string  $id       Código do Produto
     * @param  string  $name     Nome do Produto
     * @param  float   $value    Valor Unitário
     * @param  integer $quantity Quantidade
     *
     * @return \RodrigoPedra\ClearSaleID\Entity\Request\Item
     */
    public static function create( $id, $name, $value, $quantity )
    {
        $instance = new self;

        $instance->setId( $id );
        $instance->setName( $name );
        $instance->setValue( $value );
        $instance->setQuantity( $quantity );

        return $instance;
    }

    /**
     * @return string
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * @param  string $id
     *
     * @return $this
     */
    public function setId( $id )
    {
        if (empty( $id )) {
            throw new InvalidArgumentException( 'Id is empty!' );
        }

        $this->id = $id;

        return $this;
    }

    /**
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * @param  string $name
     *
     * @return $this
     */
    public function setName( $name )
    {
        if (empty( $name )) {
            throw new InvalidArgumentException( 'Name is empty!' );
        }

        $this->name = $name;

        return $this;
    }

    /**
     * @return string
     */
    public function getValue()
    {
        return $this->value;
    }

    /**
     * @param  string $value
     *
     * @return $this
     */
    public function setValue( $value )
    {
        if (!is_float( $value )) {
            throw new InvalidArgumentException( sprintf( 'Invalid value', $value ) );
        }

        $this->value = $value;

        return $this;
    }

    /**
     * @return string
     */
    public function getQuantity()
    {
        return $this->quantity;
    }

    /**
     * @param  string $quantity
     *
     * @return $this
     */
    public function setQuantity( $quantity )
    {
        if (!is_int( $quantity )) {
            throw new InvalidArgumentException( sprintf( 'Invalid quantity', $quantity ) );
        }

        $this->quantity = $quantity;

        return $this;
    }

    /**
     * @return string
     */
    public function getNotes()
    {
        return $this->notes;
    }

    /**
     * @param  string $notes
     *
     * @return $this
     */
    public function setNotes( $notes )
    {
        $this->notes = $notes;

        return $this;
    }

    /**
     * @return string
     */
    public function getCategoryId()
    {
        return $this->categoryId;
    }

    /**
     * @param  string $categoryId
     *
     * @return $this
     */
    public function setCategoryId( $categoryId )
    {
        if (!is_int( $categoryId )) {
            throw new InvalidArgumentException( sprintf( 'Invalid categoryId', $categoryId ) );
        }

        $this->categoryId = $categoryId;

        return $this;
    }

    /**
     * @return string
     */
    public function getCategoryName()
    {
        return $this->categoryName;
    }

    /**
     * @param  string $categoryName
     *
     * @return $this
     */
    public function setCategoryName( $categoryName )
    {
        if (empty( $categoryName )) {
            throw new InvalidArgumentException( 'Category name is empty!' );
        }

        $this->categoryName = $categoryName;

        return $this;
    }

    /**
     * @param  \XMLWriter $XMLWriter
     *
     * @throws \RodrigoPedra\ClearSaleID\Exception\RequiredFieldException
     */
    public function toXML( XMLWriter $XMLWriter )
    {
        $XMLWriter->startElement( 'Item' );

        if ($this->id) {
            $XMLWriter->writeElement( 'CodigoItem', $this->id );
        } else {
            throw new RequiredFieldException( 'Field ID of the Item object is required' );
        }

        if ($this->name) {
            $XMLWriter->writeElement( 'NomeItem', $this->name );
        } else {
            throw new RequiredFieldException( 'Field Name of the Item object is required' );
        }

        if ($this->value) {
            $XMLWriter->writeElement( 'ValorItem', $this->value );
        } else {
            throw new RequiredFieldException( 'Field ItemValue of the Item object is required' );
        }

        if ($this->quantity) {
            $XMLWriter->writeElement( 'Quantidade', $this->quantity );
        } else {
            throw new RequiredFieldException( 'Field Quantity of the Item object is required' );
        }

        if ($this->notes) {
            $XMLWriter->writeElement( 'Generico', $this->notes );
        }

        if ($this->categoryId) {
            $XMLWriter->writeElement( 'CodigoCategoria', $this->categoryId );
        }

        if ($this->categoryName) {
            $XMLWriter->writeElement( 'NomeCategoria', $this->categoryName );
        }

        $XMLWriter->endElement();
    }
}


<?php

namespace XQueue\Maileon\API\MarketingAutomation;

use XQueue\Maileon\API\AbstractMaileonService;

/**
 * Facade that wraps the REST service for marketing automation programs.
 *
 * @author Viktor Balogh | Wanadis Kft. | balogh.viktor@maileon.hu
 * @author Marcus Ständer | Trusted Technologies GmbH | marcus.staender@trusted-technologies.de
 */

class MarketingAutomationService extends AbstractMaileonService
{
	/**
	 * Creates a new mailing.
	 * @param int $programId
	 *
	 * @param string $email
	 *
	 * @return \em com_maileon_api_MaileonAPIResult
	 *  the result of the operation
	 */
	public function startMarketingAutomationProgram($programId, $emails) {
		$urlProgramId = urlencode($programId);

		if (!empty($emails)) {
			if (is_array($emails)) {
				$bodyContent['emails'] = $emails;
			} else {
				$bodyContent['emails'] = array($emails);
			}
		}

		return $this->post("marketing-automation/$urlProgramId", json_encode($bodyContent), array(), "application/json");
	}
}


<?php

namespace PhpOffice\PhpSpreadsheet\Writer\Xls;

use PhpOffice\PhpSpreadsheet\Style\Alignment;
use PhpOffice\PhpSpreadsheet\Style\Border;
use PhpOffice\PhpSpreadsheet\Style\Borders;
use PhpOffice\PhpSpreadsheet\Style\Fill;
use PhpOffice\PhpSpreadsheet\Style\Protection;
use PhpOffice\PhpSpreadsheet\Style\Style;

// Original file header of PEAR::Spreadsheet_Excel_Writer_Format (used as the base for this class):
// -----------------------------------------------------------------------------------------
// /*
// *  Module written/ported by Xavier Noguer <xnoguer@rezebra.com>
// *
// *  The majority of this is _NOT_ my code.  I simply ported it from the
// *  PERL Spreadsheet::WriteExcel module.
// *
// *  The author of the Spreadsheet::WriteExcel module is John McNamara
// *  <jmcnamara@cpan.org>
// *
// *  I _DO_ maintain this code, and John McNamara has nothing to do with the
// *  porting of this code to PHP.  Any questions directly related to this
// *  class library should be directed to me.
// *
// *  License Information:
// *
// *    Spreadsheet_Excel_Writer:  A library for generating Excel Spreadsheets
// *    Copyright (c) 2002-2003 Xavier Noguer xnoguer@rezebra.com
// *
// *    This library is free software; you can redistribute it and/or
// *    modify it under the terms of the GNU Lesser General Public
// *    License as published by the Free Software Foundation; either
// *    version 2.1 of the License, or (at your option) any later version.
// *
// *    This library is distributed in the hope that it will be useful,
// *    but WITHOUT ANY WARRANTY; without even the implied warranty of
// *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// *    Lesser General Public License for more details.
// *
// *    You should have received a copy of the GNU Lesser General Public
// *    License along with this library; if not, write to the Free Software
// *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
// */
class Xf
{
    /**
     * Style XF or a cell XF ?
     *
     * @var bool
     */
    private $isStyleXf;

    /**
     * Index to the FONT record. Index 4 does not exist.
     *
     * @var int
     */
    private $fontIndex;

    /**
     * An index (2 bytes) to a FORMAT record (number format).
     *
     * @var int
     */
    private $numberFormatIndex;

    /**
     * 1 bit, apparently not used.
     *
     * @var int
     */
    private $textJustLast;

    /**
     * The cell's foreground color.
     *
     * @var int
     */
    private $foregroundColor;

    /**
     * The cell's background color.
     *
     * @var int
     */
    private $backgroundColor;

    /**
     * Color of the bottom border of the cell.
     *
     * @var int
     */
    private $bottomBorderColor;

    /**
     * Color of the top border of the cell.
     *
     * @var int
     */
    private $topBorderColor;

    /**
     * Color of the left border of the cell.
     *
     * @var int
     */
    private $leftBorderColor;

    /**
     * Color of the right border of the cell.
     *
     * @var int
     */
    private $rightBorderColor;

    /**
     * Constructor.
     *
     * @param Style $style The XF format
     */
    public function __construct(Style $style)
    {
        $this->isStyleXf = false;
        $this->fontIndex = 0;

        $this->numberFormatIndex = 0;

        $this->textJustLast = 0;

        $this->foregroundColor = 0x40;
        $this->backgroundColor = 0x41;

        $this->_diag = 0;

        $this->bottomBorderColor = 0x40;
        $this->topBorderColor = 0x40;
        $this->leftBorderColor = 0x40;
        $this->rightBorderColor = 0x40;
        $this->_diag_color = 0x40;
        $this->_style = $style;
    }

    /**
     * Generate an Excel BIFF XF record (style or cell).
     *
     * @return string The XF record
     */
    public function writeXf()
    {
        // Set the type of the XF record and some of the attributes.
        if ($this->isStyleXf) {
            $style = 0xFFF5;
        } else {
            $style = self::mapLocked($this->_style->getProtection()->getLocked());
            $style |= self::mapHidden($this->_style->getProtection()->getHidden()) << 1;
        }

        // Flags to indicate if attributes have been set.
        $atr_num = ($this->numberFormatIndex != 0) ? 1 : 0;
        $atr_fnt = ($this->fontIndex != 0) ? 1 : 0;
        $atr_alc = ((int) $this->_style->getAlignment()->getWrapText()) ? 1 : 0;
        $atr_bdr = (self::mapBorderStyle($this->_style->getBorders()->getBottom()->getBorderStyle()) ||
                        self::mapBorderStyle($this->_style->getBorders()->getTop()->getBorderStyle()) ||
                        self::mapBorderStyle($this->_style->getBorders()->getLeft()->getBorderStyle()) ||
                        self::mapBorderStyle($this->_style->getBorders()->getRight()->getBorderStyle())) ? 1 : 0;
        $atr_pat = (($this->foregroundColor != 0x40) ||
                        ($this->backgroundColor != 0x41) ||
                        self::mapFillType($this->_style->getFill()->getFillType())) ? 1 : 0;
        $atr_prot = self::mapLocked($this->_style->getProtection()->getLocked())
                        | self::mapHidden($this->_style->getProtection()->getHidden());

        // Zero the default border colour if the border has not been set.
        if (self::mapBorderStyle($this->_style->getBorders()->getBottom()->getBorderStyle()) == 0) {
            $this->bottomBorderColor = 0;
        }
        if (self::mapBorderStyle($this->_style->getBorders()->getTop()->getBorderStyle()) == 0) {
            $this->topBorderColor = 0;
        }
        if (self::mapBorderStyle($this->_style->getBorders()->getRight()->getBorderStyle()) == 0) {
            $this->rightBorderColor = 0;
        }
        if (self::mapBorderStyle($this->_style->getBorders()->getLeft()->getBorderStyle()) == 0) {
            $this->leftBorderColor = 0;
        }
        if (self::mapBorderStyle($this->_style->getBorders()->getDiagonal()->getBorderStyle()) == 0) {
            $this->_diag_color = 0;
        }

        $record = 0x00E0; // Record identifier
        $length = 0x0014; // Number of bytes to follow

        $ifnt = $this->fontIndex; // Index to FONT record
        $ifmt = $this->numberFormatIndex; // Index to FORMAT record

        $align = $this->mapHAlign($this->_style->getAlignment()->getHorizontal()); // Alignment
        $align |= (int) $this->_style->getAlignment()->getWrapText() << 3;
        $align |= self::mapVAlign($this->_style->getAlignment()->getVertical()) << 4;
        $align |= $this->textJustLast << 7;

        $used_attrib = $atr_num << 2;
        $used_attrib |= $atr_fnt << 3;
        $used_attrib |= $atr_alc << 4;
        $used_attrib |= $atr_bdr << 5;
        $used_attrib |= $atr_pat << 6;
        $used_attrib |= $atr_prot << 7;

        $icv = $this->foregroundColor; // fg and bg pattern colors
        $icv |= $this->backgroundColor << 7;

        $border1 = self::mapBorderStyle($this->_style->getBorders()->getLeft()->getBorderStyle()); // Border line style and color
        $border1 |= self::mapBorderStyle($this->_style->getBorders()->getRight()->getBorderStyle()) << 4;
        $border1 |= self::mapBorderStyle($this->_style->getBorders()->getTop()->getBorderStyle()) << 8;
        $border1 |= self::mapBorderStyle($this->_style->getBorders()->getBottom()->getBorderStyle()) << 12;
        $border1 |= $this->leftBorderColor << 16;
        $border1 |= $this->rightBorderColor << 23;

        $diagonalDirection = $this->_style->getBorders()->getDiagonalDirection();
        $diag_tl_to_rb = $diagonalDirection == Borders::DIAGONAL_BOTH
                            || $diagonalDirection == Borders::DIAGONAL_DOWN;
        $diag_tr_to_lb = $diagonalDirection == Borders::DIAGONAL_BOTH
                            || $diagonalDirection == Borders::DIAGONAL_UP;
        $border1 |= $diag_tl_to_rb << 30;
        $border1 |= $diag_tr_to_lb << 31;

        $border2 = $this->topBorderColor; // Border color
        $border2 |= $this->bottomBorderColor << 7;
        $border2 |= $this->_diag_color << 14;
        $border2 |= self::mapBorderStyle($this->_style->getBorders()->getDiagonal()->getBorderStyle()) << 21;
        $border2 |= self::mapFillType($this->_style->getFill()->getFillType()) << 26;

        $header = pack('vv', $record, $length);

        //BIFF8 options: identation, shrinkToFit and  text direction
        $biff8_options = $this->_style->getAlignment()->getIndent();
        $biff8_options |= (int) $this->_style->getAlignment()->getShrinkToFit() << 4;

        $data = pack('vvvC', $ifnt, $ifmt, $style, $align);
        $data .= pack('CCC', self::mapTextRotation($this->_style->getAlignment()->getTextRotation()), $biff8_options, $used_attrib);
        $data .= pack('VVv', $border1, $border2, $icv);

        return $header . $data;
    }

    /**
     * Is this a style XF ?
     *
     * @param bool $value
     */
    public function setIsStyleXf($value)
    {
        $this->isStyleXf = $value;
    }

    /**
     * Sets the cell's bottom border color.
     *
     * @param int $colorIndex Color index
     */
    public function setBottomColor($colorIndex)
    {
        $this->bottomBorderColor = $colorIndex;
    }

    /**
     * Sets the cell's top border color.
     *
     * @param int $colorIndex Color index
     */
    public function setTopColor($colorIndex)
    {
        $this->topBorderColor = $colorIndex;
    }

    /**
     * Sets the cell's left border color.
     *
     * @param int $colorIndex Color index
     */
    public function setLeftColor($colorIndex)
    {
        $this->leftBorderColor = $colorIndex;
    }

    /**
     * Sets the cell's right border color.
     *
     * @param int $colorIndex Color index
     */
    public function setRightColor($colorIndex)
    {
        $this->rightBorderColor = $colorIndex;
    }

    /**
     * Sets the cell's diagonal border color.
     *
     * @param int $colorIndex Color index
     */
    public function setDiagColor($colorIndex)
    {
        $this->_diag_color = $colorIndex;
    }

    /**
     * Sets the cell's foreground color.
     *
     * @param int $colorIndex Color index
     */
    public function setFgColor($colorIndex)
    {
        $this->foregroundColor = $colorIndex;
    }

    /**
     * Sets the cell's background color.
     *
     * @param int $colorIndex Color index
     */
    public function setBgColor($colorIndex)
    {
        $this->backgroundColor = $colorIndex;
    }

    /**
     * Sets the index to the number format record
     * It can be date, time, currency, etc...
     *
     * @param int $numberFormatIndex Index to format record
     */
    public function setNumberFormatIndex($numberFormatIndex)
    {
        $this->numberFormatIndex = $numberFormatIndex;
    }

    /**
     * Set the font index.
     *
     * @param int $value Font index, note that value 4 does not exist
     */
    public function setFontIndex($value)
    {
        $this->fontIndex = $value;
    }

    /**
     * Map of BIFF2-BIFF8 codes for border styles.
     *
     * @var array of int
     */
    private static $mapBorderStyles = [
        Border::BORDER_NONE => 0x00,
        Border::BORDER_THIN => 0x01,
        Border::BORDER_MEDIUM => 0x02,
        Border::BORDER_DASHED => 0x03,
        Border::BORDER_DOTTED => 0x04,
        Border::BORDER_THICK => 0x05,
        Border::BORDER_DOUBLE => 0x06,
        Border::BORDER_HAIR => 0x07,
        Border::BORDER_MEDIUMDASHED => 0x08,
        Border::BORDER_DASHDOT => 0x09,
        Border::BORDER_MEDIUMDASHDOT => 0x0A,
        Border::BORDER_DASHDOTDOT => 0x0B,
        Border::BORDER_MEDIUMDASHDOTDOT => 0x0C,
        Border::BORDER_SLANTDASHDOT => 0x0D,
    ];

    /**
     * Map border style.
     *
     * @param string $borderStyle
     *
     * @return int
     */
    private static function mapBorderStyle($borderStyle)
    {
        if (isset(self::$mapBorderStyles[$borderStyle])) {
            return self::$mapBorderStyles[$borderStyle];
        }

        return 0x00;
    }

    /**
     * Map of BIFF2-BIFF8 codes for fill types.
     *
     * @var array of int
     */
    private static $mapFillTypes = [
        Fill::FILL_NONE => 0x00,
        Fill::FILL_SOLID => 0x01,
        Fill::FILL_PATTERN_MEDIUMGRAY => 0x02,
        Fill::FILL_PATTERN_DARKGRAY => 0x03,
        Fill::FILL_PATTERN_LIGHTGRAY => 0x04,
        Fill::FILL_PATTERN_DARKHORIZONTAL => 0x05,
        Fill::FILL_PATTERN_DARKVERTICAL => 0x06,
        Fill::FILL_PATTERN_DARKDOWN => 0x07,
        Fill::FILL_PATTERN_DARKUP => 0x08,
        Fill::FILL_PATTERN_DARKGRID => 0x09,
        Fill::FILL_PATTERN_DARKTRELLIS => 0x0A,
        Fill::FILL_PATTERN_LIGHTHORIZONTAL => 0x0B,
        Fill::FILL_PATTERN_LIGHTVERTICAL => 0x0C,
        Fill::FILL_PATTERN_LIGHTDOWN => 0x0D,
        Fill::FILL_PATTERN_LIGHTUP => 0x0E,
        Fill::FILL_PATTERN_LIGHTGRID => 0x0F,
        Fill::FILL_PATTERN_LIGHTTRELLIS => 0x10,
        Fill::FILL_PATTERN_GRAY125 => 0x11,
        Fill::FILL_PATTERN_GRAY0625 => 0x12,
        Fill::FILL_GRADIENT_LINEAR => 0x00, // does not exist in BIFF8
        Fill::FILL_GRADIENT_PATH => 0x00, // does not exist in BIFF8
    ];

    /**
     * Map fill type.
     *
     * @param string $fillType
     *
     * @return int
     */
    private static function mapFillType($fillType)
    {
        if (isset(self::$mapFillTypes[$fillType])) {
            return self::$mapFillTypes[$fillType];
        }

        return 0x00;
    }

    /**
     * Map of BIFF2-BIFF8 codes for horizontal alignment.
     *
     * @var array of int
     */
    private static $mapHAlignments = [
        Alignment::HORIZONTAL_GENERAL => 0,
        Alignment::HORIZONTAL_LEFT => 1,
        Alignment::HORIZONTAL_CENTER => 2,
        Alignment::HORIZONTAL_RIGHT => 3,
        Alignment::HORIZONTAL_FILL => 4,
        Alignment::HORIZONTAL_JUSTIFY => 5,
        Alignment::HORIZONTAL_CENTER_CONTINUOUS => 6,
    ];

    /**
     * Map to BIFF2-BIFF8 codes for horizontal alignment.
     *
     * @param string $hAlign
     *
     * @return int
     */
    private function mapHAlign($hAlign)
    {
        if (isset(self::$mapHAlignments[$hAlign])) {
            return self::$mapHAlignments[$hAlign];
        }

        return 0;
    }

    /**
     * Map of BIFF2-BIFF8 codes for vertical alignment.
     *
     * @var array of int
     */
    private static $mapVAlignments = [
        Alignment::VERTICAL_TOP => 0,
        Alignment::VERTICAL_CENTER => 1,
        Alignment::VERTICAL_BOTTOM => 2,
        Alignment::VERTICAL_JUSTIFY => 3,
    ];

    /**
     * Map to BIFF2-BIFF8 codes for vertical alignment.
     *
     * @param string $vAlign
     *
     * @return int
     */
    private static function mapVAlign($vAlign)
    {
        if (isset(self::$mapVAlignments[$vAlign])) {
            return self::$mapVAlignments[$vAlign];
        }

        return 2;
    }

    /**
     * Map to BIFF8 codes for text rotation angle.
     *
     * @param int $textRotation
     *
     * @return int
     */
    private static function mapTextRotation($textRotation)
    {
        if ($textRotation >= 0) {
            return $textRotation;
        } elseif ($textRotation == -165) {
            return 255;
        } elseif ($textRotation < 0) {
            return 90 - $textRotation;
        }
    }

    /**
     * Map locked.
     *
     * @param string $locked
     *
     * @return int
     */
    private static function mapLocked($locked)
    {
        switch ($locked) {
            case Protection::PROTECTION_INHERIT:
                return 1;
            case Protection::PROTECTION_PROTECTED:
                return 1;
            case Protection::PROTECTION_UNPROTECTED:
                return 0;
            default:
                return 1;
        }
    }

    /**
     * Map hidden.
     *
     * @param string $hidden
     *
     * @return int
     */
    private static function mapHidden($hidden)
    {
        switch ($hidden) {
            case Protection::PROTECTION_INHERIT:
                return 0;
            case Protection::PROTECTION_PROTECTED:
                return 1;
            case Protection::PROTECTION_UNPROTECTED:
                return 0;
            default:
                return 0;
        }
    }
}


<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
 * PHP support for the Libravatar.org service.
 *
 * PHP version 5
 *
 * The MIT License
 *
 * Copyright (c) 2011 Services_Libravatar committers.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * @category  Services
 * @package   Services_Libravatar
 * @author    Melissa Draper <melissa@meldraweb.com>
 * @copyright 2011 Services_Libravatar committers.
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Services_Libravatar
 * @since     File available since Release 0.1.0
 */

/**
 * PHP support for the Libravatar.org service.
 *
 * Using this class is easy. After including or requiring
 * Services/Libravatar.php simply do:
 *
 * $libravatar = new Services_Libravatar();
 * $url = $libravatar->getUrl('melissa@meldraweb.com');
 *
 *
 * This would populate $url with the string:
 *
 * http://cdn.libravatar.org/avatar/4db84629c121f2d443d33bdb9fd149bc
 *
 *
 * A complicated lookup using all the options is:
 *
 * $libravatar = new Services_Libravatar();
 * $libravatar->setSize(40);
 * $libravatar->setAlgorithm('sha256');
 * $libravatar->setHttps(true);
 * $libravatar->setDefault(
 *     'http://upload.wikimedia.org/wikipedia/commons/a/af/Tux.png'
 * );
 * $url = $libravatar->getUrl('melissa@meldraweb.com');
 *
 *
 * @category  Services
 * @package   Services_Libravatar
 * @author    Melissa Draper <melissa@meldraweb.com>
 * @copyright 2011 Services_Libravatar committers.
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @version   Release: @package_version@
 * @link      http://pear.php.net/package/Services_Libravatar
 * @since     Class available since Release 0.1.0
 */
class Services_Libravatar
{
    /**
     * Hashing algorithm to use
     *
     * @var string
     * @see processAlgorithm()
     * @see setAlgorithm()
     */
    protected $algorithm = 'md5';

    /**
     * Default image URL to use
     *
     * @var string
     * @see processDefault()
     * @see setDefault()
     */
    protected $default;

    /**
     * If HTTPS URLs should be used
     *
     * @var boolean
     * @see detectHttps()
     * @see setHttps()
     */
    protected $https;

    /**
     * Image size in pixels
     *
     * @var integer
     * @see processSize()
     * @see setSize()
     */
    protected $size;

    /**
     * Composes a URL for the identifier and options passed in
     *
     * Compose a full URL as specified by the Libravatar API, based on the
     * email address or openid URL passed in, and the options specified.
     *
     * @param string $identifier a string of either an email address
     *                           or an openid url
     * @param array  $options    an array of (bool) https, (string) algorithm
     *                           (string) size, (string) default.
     *                           See the set* methods.
     *
     * @return string A string of a full URL for an avatar image
     *
     * @since Method available since Release 0.2.0
     * @deprecated Use getUrl() instead
     */
    public function url($identifier, $options = array())
    {
        return $this->getUrl($identifier, $options);
    }

    /**
     * Composes a URL for the identifier and options passed in
     *
     * Compose a full URL as specified by the Libravatar API, based on the
     * email address or openid URL passed in, and the options specified.
     *
     * @param string $identifier a string of either an email address
     *                           or an openid url
     * @param array  $options    an array of (bool) https, (string) algorithm
     *                           (string) size, (string) default.
     *                           See the set* methods.
     *
     * @return string A string of a full URL for an avatar image
     *
     * @since  Method available since Release 0.2.0
     * @throws InvalidArgumentException When an invalid option is passed
     */
    public function getUrl($identifier, $options = array())
    {
        // If no identifier has been passed, set it to a null.
        // This way, there'll always be something returned.
        if (!$identifier) {
            $identifier = null;
        } else {
            $identifier = $this->normalizeIdentifier($identifier);
        }

        // Load all options
        $options = $this->checkOptionsArray($options);
        $https = $this->https;
        if (isset($options['https'])) {
            $https = (bool)$options['https'];
        }

        $algorithm = $this->algorithm;
        if (isset($options['algorithm'])) {
            $algorithm = $this->processAlgorithm($options['algorithm']);
        }

        $default = $this->default;
        if (isset($options['default'])) {
            $default = $this->processDefault($options['default']);
        }
        $size = $this->size;
        if (isset($options['size'])) {
            $size = $this->processSize($options['size']);
        }

        $identifierHash = $this->identifierHash($identifier, $algorithm);

        // Get the domain so we can determine the SRV stuff for federation
        $domain = $this->domainGet($identifier);

        // If https has been specified in $options, make sure we make the
        // correct SRV lookup
        $service  = $this->srvGet($domain, $https);
        $protocol = $https ? 'https' : 'http';

        $params = array();
        if ($size !== null) {
            $params['size'] = $size;
        }
        if ($default !== null) {
            $params['default'] = $default;
        }
        $paramString = '';
        if (count($params) > 0) {
            $paramString = '?' . http_build_query($params);
        }

        // Compose the URL from the pieces we generated
        $url = $protocol . '://' . $service . '/avatar/' . $identifierHash
            . $paramString;

        // Return the URL string
        return $url;
    }

    /**
     * Checks the options array and verify that only allowed options are in it.
     *
     * @param array $options Array of options for getUrl()
     *
     * @return void
     * @throws Exception When an invalid option is used
     */
    protected function checkOptionsArray($options)
    {
        //this short options are deprecated!
        if (isset($options['s'])) {
            $options['size'] = $options['s'];
            unset($options['s']);
        }
        if (isset($options['d'])) {
            $options['default'] = $options['d'];
            unset($options['d']);
        }

        $allowedOptions = array(
            'algorithm' => true,
            'default'   => true,
            'https'     => true,
            'size'      => true,
        );
        foreach ($options as $key => $value) {
            if (!isset($allowedOptions[$key])) {
                throw new InvalidArgumentException(
                    'Invalid option in array: ' . $key
                );
            }
        }

        return $options;
    }

    /**
     * Normalizes the identifier (E-mail address or OpenID)
     *
     * @param string $identifier E-Mail address or OpenID
     *
     * @return string Normalized identifier
     */
    protected function normalizeIdentifier($identifier)
    {
        if (filter_var($identifier, FILTER_VALIDATE_EMAIL)) {
            return strtolower($identifier);
        } else {
            return self::normalizeOpenId($identifier);
        }
    }

    /**
     * Create a hash of the identifier.
     *
     * Create a hash of the email address or openid passed in. Algorithm
     * used for email address ONLY can be varied. Either md5 or sha256
     * are supported by the Libravatar API. Will be ignored for openid.
     *
     * @param string $identifier A string of the email address or openid URL
     * @param string $hash       A string of the hash algorithm type to make
     *                           Uses the php implementation of hash()
     *                           MD5 preferred for Gravatar fallback
     *
     * @return string A string hash of the identifier.
     *
     * @since Method available since Release 0.1.0
     */
    protected function identifierHash($identifier, $hash = 'md5')
    {
        if (filter_var($identifier, FILTER_VALIDATE_EMAIL) || $identifier === null) {
            // If email, we can select our algorithm. Default to md5 for
            // gravatar fallback.
            return hash($hash, $identifier);
        }

        //no email, so the identifier has to be an OpenID
        return hash('sha256', $identifier);
    }

    /**
     * Normalizes an identifier (URI or XRI)
     *
     * @param mixed $identifier URI or XRI to be normalized
     *
     * @return string Normalized Identifier.
     *                Empty string when the OpenID is invalid.
     *
     * @internal Adapted from OpenID::normalizeIdentifier()
     */
    public static function normalizeOpenId($identifier)
    {
        // XRI
        if (preg_match('@^xri://@i', $identifier)) {
            return preg_replace('@^xri://@i', '', $identifier);
        }

        if (in_array($identifier[0], array('=', '@', '+', '$', '!'))) {
            return $identifier;
        }

        // URL
        if (!preg_match('@^http[s]?://@i', $identifier)) {
            $identifier = 'http://' . $identifier;
        }
        if (strpos($identifier, '/', 8) === false) {
            $identifier .= '/';
        }
        if (!filter_var($identifier, FILTER_VALIDATE_URL)) {
            return '';
        }

        $parts = parse_url($identifier);
        $parts['scheme'] = strtolower($parts['scheme']);
        $parts['host']   = strtolower($parts['host']);

        //http://openid.net/specs/openid-authentication-2_0.html#normalization
        return $parts['scheme'] . '://'
            . (isset($parts['user']) ? $parts['user'] : '')
            . (isset($parts['pass']) ? ':' . $parts['pass'] : '')
            . (isset($parts['user']) || isset($parts['pass']) ? '@' : '')
            . $parts['host']
            . (
                (isset($parts['port'])
                && $parts['scheme'] === 'http' && $parts['port'] != 80)
                || (isset($parts['port'])
                && $parts['scheme'] === 'https' && $parts['port'] != 443)
                ? ':' . $parts['port'] : ''
            )
            . $parts['path']
            . (isset($parts['query']) ? '?' . $parts['query'] : '');
            //leave out fragment as requested by the spec
    }

    /**
     * Grab the domain from the identifier.
     *
     * Extract the domain from the Email or OpenID.
     *
     * @param string $identifier A string of the email address or openid URL
     *
     * @return string A string of the domain to use
     *
     * @since Method available since Release 0.1.0
     */
    protected function domainGet($identifier)
    {
        if ($identifier === null) {
            return null;
        }

        // What are we, email or openid? Split ourself up and get the
        // important bit out.
        if (filter_var($identifier, FILTER_VALIDATE_EMAIL)) {
            $email = explode('@', $identifier);
            return $email[1];
        }

        //OpenID
        $url = parse_url($identifier);
        if (!isset($url['host'])) {
            //invalid URL
            return null;
        }

        $domain = $url['host'];
        if (isset($url['port']) && $url['scheme'] === 'http'
            && $url['port'] != 80
            || isset($url['port']) && $url['scheme'] === 'https'
            && $url['port'] != 443
        ) {
            $domain .= ':' . $url['port'];
        }

        return $domain;
    }

    /**
     * Get the target to use.
     *
     * Get the SRV record, filtered by priority and weight. If our domain
     * has no SRV records, fall back to Libravatar.org
     *
     * @param string  $domain A string of the domain we extracted from the
     *                        provided identifier with domainGet()
     * @param boolean $https  Whether or not to look for https records
     *
     * @return string The target URL.
     *
     * @since Method available since Release 0.1.0
     */
    protected function srvGet($domain, $https = false)
    {
        // Are we going secure? Set up a fallback too.
        if (isset($https) && $https === true) {
            $subdomain = '_avatars-sec._tcp.';
            $fallback  = 'seccdn.';
            $port      = 443;
        } else {
            $subdomain = '_avatars._tcp.';
            $fallback  = 'cdn.';
            $port      = 80;
        }

        if ($domain === null) {
            // No domain means invalid email address/openid
            return $fallback . 'libravatar.org';
        }

        // Lets try get us some records based on the choice of subdomain
        // and the domain we had passed in.
        $srv = dns_get_record($subdomain . $domain, DNS_SRV);

        // Did we get anything? No?
        if (count($srv) == 0) {
            // Then let's try Libravatar.org.
            return $fallback . 'libravatar.org';
        }

        // Sort by the priority. We must get the lowest.
        usort($srv, array($this, 'comparePriority'));

        $top = $srv[0];
        $sum = 0;

        // Try to adhere to RFC2782's weighting algorithm, page 3
        // "arrange all SRV RRs (that have not been ordered yet) in any order,
        // except that all those with weight 0 are placed at the beginning of
        // the list."
        shuffle($srv);
        $srvs = array();
        foreach ($srv as $s) {
            if ($s['weight'] == 0) {
                array_unshift($srvs, $s);
            } else {
                array_push($srvs, $s);
            }
        }

        foreach ($srvs as $s) {
            if ($s['pri'] == $top['pri']) {
                // "Compute the sum of the weights of those RRs"
                $sum += (int) $s['weight'];
                // "and with each RR associate the running sum in the selected
                // order."
                $pri[$sum] = $s;
            }
        }

        // "Then choose a uniform random number between 0 and the sum computed
        // (inclusive)"
        $random = rand(0, $sum);

        // "and select the RR whose running sum value is the first in the selected
        // order which is greater than or equal to the random number selected"
        foreach ($pri as $k => $v) {
            if ($k >= $random) {
                $target = $v['target'];
                if ($v['port'] !== $port) {
                    $target.= ':'. $v['port'];
                }
                return $target;
            }
        }
    }

    /**
     * Sorting function for record priorities.
     *
     * @param mixed $a A mixed value passed by usort()
     * @param mixed $b A mixed value passed by usort()
     *
     * @return mixed The result of the comparison
     *
     * @since Method available since Release 0.1.0
     */
    protected function comparePriority($a, $b)
    {
        return $a['pri'] - $b['pri'];
    }

    /**
     * Automatically set the https option depending on the current connection
     * value.
     *
     * If the current connection is HTTPS, the https options is activated.
     * If it is not HTTPS, the https option is deactivated.
     *
     * @return self
     */
    public function detectHttps()
    {
        $this->setHttps(
            isset($_SERVER['HTTPS']) && $_SERVER['HTTPS']
        );

        return $this;
    }

    /**
     * Verify and cast the email address hashing algorithm to use.
     *
     * @param string $algorithm Algorithm to use, "sha256" or "md5".
     *
     * @return string Algorithm
     *
     * @throws InvalidArgumentException When an unsupported algorithm is given
     */
    protected function processAlgorithm($algorithm)
    {
        $algorithm = (string)$algorithm;
        if ($algorithm !== 'md5' && $algorithm !== 'sha256') {
            throw new InvalidArgumentException(
                'Only md5 and sha256 hashing supported'
            );
        }

        return $algorithm;
    }

    /**
     * Verify and cast the default URL to use when no avatar image can be found.
     * If none is set, the libravatar logo is returned.
     *
     * @param string $url Full URL to use OR one of the following:
     *                    - "404" - give a "404 File not found" instead of an image
     *                    - "mm"
     *                    - "identicon"
     *                    - "monsterid"
     *                    - "wavatar"
     *                    - "retro"
     *
     * @return string Default URL
     *
     * @throws InvalidArgumentException When an invalid URL is given
     */
    protected function processDefault($url)
    {
        if ($url === null) {
            return $url;
        }

        $url = (string)$url;

        switch ($url) {
        case '404':
        case 'mm':
        case 'identicon':
        case 'monsterid':
        case 'wavatar':
        case 'retro':
            break;
        default:
            $valid = filter_var($url, FILTER_VALIDATE_URL);
            if (!$valid) {
                throw new InvalidArgumentException('Invalid default avatar URL');
            }
            break;
        }

        return $url;
    }

    /**
     * Verify and cast the required size of the images.
     *
     * @param integer $size Size (width and height in pixels) of the image.
     *                      NULL for the default width.
     *
     * @return integer Size
     *
     * @throws InvalidArgumentException When a size <= 0 is given
     */
    protected function processSize($size)
    {
        if ($size === null) {
            return $size;
        }

        $size = (int)$size;
        if ($size <= 0) {
            throw new InvalidArgumentException('Size has to be larger than 0');
        }

        return (int)$size;
    }

    /**
     * Set the email address hashing algorithm to use.
     * To keep gravatar compatibility, use "md5".
     *
     * @param string $algorithm Algorithm to use, "sha256" or "md5".
     *
     * @return self
     * @throws InvalidArgumentException When an unsupported algorithm is given
     */
    public function setAlgorithm($algorithm)
    {
        $this->algorithm = $this->processAlgorithm($algorithm);

        return $this;
    }

    /**
     * Set the default URL to use when no avatar image can be found.
     * If none is set, the gravatar logo is returned.
     *
     * @param string $url Full URL to use OR one of the following:
     *                    - "404" - give a "404 File not found" instead of an image
     *                    - "mm"
     *                    - "identicon"
     *                    - "monsterid"
     *                    - "wavatar"
     *                    - "retro"
     *
     * @return self
     * @throws InvalidArgumentException When an invalid URL is given
     */
    public function setDefault($url)
    {
        $this->default = $this->processDefault($url);

        return $this;
    }

    /**
     * Set if HTTPS URLs shall be returned.
     *
     * @param boolean $useHttps If HTTPS url shall be returned
     *
     * @return self
     *
     * @see detectHttps()
     */
    public function setHttps($useHttps)
    {
        $this->https = (bool)$useHttps;

        return $this;
    }

    /**
     * Set the required size of the images.
     * Every avatar image is square sized, which means you need to set only number.
     *
     * @param integer $size Size (width and height) of the image
     *
     * @return self
     * @throws InvalidArgumentException When a size <= 0 is given
     */
    public function setSize($size)
    {
        $this->size = $this->processSize($size);

        return $this;
    }

}

/*
 * Local variables:
 * tab-width: 4
 * c-basic-offset: 4
 * c-hanging-comment-ender-p: nil
 * End:
 */

?>