Spade

Mini Shell

Directory:~$ /home/lmsyaran/public_html/joomla4/
Upload File

[Home] [System Details] [Kill Me]
Current File:~$ /home/lmsyaran/public_html/joomla4/inc.tar

boxpacker/Box.php000064400000001341151156426420007770 0ustar00<?php
/**
 * @package	HikaShop for Joomla!
 * @version	4.4.1
 * @author	hikashop.com
 * @copyright	(C) 2010-2021 HIKARI SOFTWARE. All rights reserved.
 * @license	GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
 */
defined('_JEXEC') or die('Restricted access');
?><?php

namespace DVDoug\BoxPacker;

interface Box
{
    public function getReference();

    public function getOuterWidth();

    public function getOuterLength();

    public function getOuterDepth();

    public function getEmptyWeight();

    public function getInnerWidth();

    public function getInnerLength();

    public function getInnerDepth();

    public function getInnerVolume();

    public function getMaxWeight();
}
boxpacker/BoxList.php000064400000002240151156426420010623 0ustar00<?php
/**
 * @package	HikaShop for Joomla!
 * @version	4.4.1
 * @author	hikashop.com
 * @copyright	(C) 2010-2021 HIKARI SOFTWARE. All rights reserved.
 * @license	GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
 */
defined('_JEXEC') or die('Restricted access');
?><?php

namespace DVDoug\BoxPacker;

class BoxList extends \SplMinHeap
{
    public function compare($boxA, $boxB)
    {
        $boxAVolume = $boxA->getInnerWidth() *
$boxA->getInnerLength() * $boxA->getInnerDepth();
        $boxBVolume = $boxB->getInnerWidth() *
$boxB->getInnerLength() * $boxB->getInnerDepth();

        if ($boxBVolume > $boxAVolume) {
            return 1;
        }
        if ($boxAVolume > $boxBVolume) {
            return -1;
        }

        if ($boxB->getEmptyWeight() > $boxA->getEmptyWeight()) {
            return 1;
        }
        if ($boxA->getEmptyWeight() > $boxB->getEmptyWeight()) {
            return -1;
        }

        if ($boxB->getMaxWeight() > $boxA->getMaxWeight()) {
            return 1;
        }
        if ($boxA->getMaxWeight() > $boxB->getMaxWeight()) {
            return -1;
        }

        return 0;
    }
}
boxpacker/ConstrainedItem.php000064400000000667151156426420012342
0ustar00<?php
/**
 * @package	HikaShop for Joomla!
 * @version	4.4.1
 * @author	hikashop.com
 * @copyright	(C) 2010-2021 HIKARI SOFTWARE. All rights reserved.
 * @license	GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
 */
defined('_JEXEC') or die('Restricted access');
?><?php
namespace DVDoug\BoxPacker;

interface ConstrainedItem extends Item
{
    public function canBePackedInBox(ItemList $alreadyPackedItems, Box
$box);
}
boxpacker/ConstrainedPlacementItem.php000064400000001115151156426420014160
0ustar00<?php
/**
 * @package	HikaShop for Joomla!
 * @version	4.4.1
 * @author	hikashop.com
 * @copyright	(C) 2010-2021 HIKARI SOFTWARE. All rights reserved.
 * @license	GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
 */
defined('_JEXEC') or die('Restricted access');
?><?php
namespace DVDoug\BoxPacker;

interface ConstrainedPlacementItem extends Item
{
    public function canBePacked(
        Box $box,
        PackedItemList $alreadyPackedItems,
        $proposedX,
        $proposedY,
        $proposedZ,
        $width,
        $length,
        $depth
    );
}
boxpacker/index.html000064400000000034151156426420010522
0ustar00<html><body></body></html>
boxpacker/Item.php000064400000001121151156426420010132 0ustar00<?php
/**
 * @package	HikaShop for Joomla!
 * @version	4.4.1
 * @author	hikashop.com
 * @copyright	(C) 2010-2021 HIKARI SOFTWARE. All rights reserved.
 * @license	GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
 */
defined('_JEXEC') or die('Restricted access');
?><?php

namespace DVDoug\BoxPacker;

interface Item
{
    public function getDescription();

    public function getWidth();

    public function getLength();

    public function getDepth();

    public function getWeight();

    public function getVolume();

    public function getKeepFlat();
}
boxpacker/ItemList.php000064400000003521151156426420010774
0ustar00<?php
/**
 * @package	HikaShop for Joomla!
 * @version	4.4.1
 * @author	hikashop.com
 * @copyright	(C) 2010-2021 HIKARI SOFTWARE. All rights reserved.
 * @license	GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
 */
defined('_JEXEC') or die('Restricted access');
?><?php

namespace DVDoug\BoxPacker;

class ItemList extends \SplMaxHeap
{
    public function compare($itemA, $itemB)
    {
        if ($itemA->getVolume() > $itemB->getVolume()) {
            return 1;
        } elseif ($itemA->getVolume() < $itemB->getVolume()) {
            return -1;
        } elseif ($itemA->getWeight() !== $itemB->getWeight()) {
            return $itemA->getWeight() - $itemB->getWeight();
        } elseif ($itemA->getDescription() <
$itemB->getDescription()) {
            return 1;
        } else {
            return -1;
        }
    }

    public function asArray()
    {
        $return = [];
        foreach (clone $this as $item) {
            $return[] = $item;
        }

        return $return;
    }

    public function topN($n)
    {
        $workingList = clone $this;
        $topNList = new self();
        $i = 0;
        while(!$workingList->isEmpty() && $i < $n) {
            $topNList->insert($workingList->extract());
            $i++;
        }

        return $topNList;
    }

    public function remove(Item $item)
    {
        $workingSet = [];
        while (!$this->isEmpty()) {
            $workingSet[] = $this->extract();
        }

        $removed = false; // there can be multiple identical items, ensure
that only 1 is removed
        foreach ($workingSet as $workingSetItem) {
            if (!$removed && $workingSetItem === $item) {
                $removed = true;
            } else {
                $this->insert($workingSetItem);
            }
        }

    }
}
boxpacker/ItemTooLargeException.php000064400000001201151156426420013445
0ustar00<?php
/**
 * @package	HikaShop for Joomla!
 * @version	4.4.1
 * @author	hikashop.com
 * @copyright	(C) 2010-2021 HIKARI SOFTWARE. All rights reserved.
 * @license	GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
 */
defined('_JEXEC') or die('Restricted access');
?><?php


namespace DVDoug\BoxPacker;

use RuntimeException;

class ItemTooLargeException extends RuntimeException
{

    public $item;

    public function __construct($message, Item $item)
    {
        $this->item = $item;
        parent::__construct($message);
    }

    public function getItem()
    {
        return $this->item;
    }
}
boxpacker/LayerStabiliser.php000064400000003154151156426420012342
0ustar00<?php
/**
 * @package	HikaShop for Joomla!
 * @version	4.4.1
 * @author	hikashop.com
 * @copyright	(C) 2010-2021 HIKARI SOFTWARE. All rights reserved.
 * @license	GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
 */
defined('_JEXEC') or die('Restricted access');
?><?php

namespace DVDoug\BoxPacker;

use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerAwareTrait;
use Psr\Log\NullLogger;

class LayerStabiliser implements LoggerAwareInterface
{
    use LoggerAwareTrait;

    public function __construct()
    {
        $this->logger = new NullLogger();
    }

    public function stabilise(array $packedLayers)
    {
        $stabilisedLayers = [];
        usort($packedLayers, [$this, 'compare']);

        $currentZ = 0;
        foreach ($packedLayers as $oldZLayer) {
            $oldZStart = $oldZLayer->getStartDepth();
            $newZLayer = new PackedLayer();
            foreach ($oldZLayer->getItems() as $oldZItem) {
                $newZ = $oldZItem->getZ() - $oldZStart + $currentZ;
                $newZItem = new PackedItem($oldZItem->getItem(),
$oldZItem->getX(), $oldZItem->getY(), $newZ,
$oldZItem->getWidth(), $oldZItem->getLength(),
$oldZItem->getDepth());
                $newZLayer->insert($newZItem);
            }

            $stabilisedLayers[] = $newZLayer;
            $currentZ += $newZLayer->getDepth();
        }

        return $stabilisedLayers;
    }

    private function compare(PackedLayer $layerA, PackedLayer $layerB)
    {
        return ($layerB->getFootprint() - $layerA->getFootprint()) ?:
($layerB->getDepth() - $layerA->getDepth());
    }
}
boxpacker/OrientatedItem.php000064400000004104151156426420012155
0ustar00<?php
/**
 * @package	HikaShop for Joomla!
 * @version	4.4.1
 * @author	hikashop.com
 * @copyright	(C) 2010-2021 HIKARI SOFTWARE. All rights reserved.
 * @license	GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
 */
defined('_JEXEC') or die('Restricted access');
?><?php

namespace DVDoug\BoxPacker;

use JsonSerializable;

class OrientatedItem implements JsonSerializable
{
    protected $item;

    protected $width;

    protected $length;

    protected $depth;

    protected static $tippingPointCache = [];

    public function __construct(Item $item, $width, $length, $depth)
    {
        $this->item = $item;
        $this->width = $width;
        $this->length = $length;
        $this->depth = $depth;
    }

    public function getItem()
    {
        return $this->item;
    }

    public function getWidth()
    {
        return $this->width;
    }

    public function getLength()
    {
        return $this->length;
    }

    public function getDepth()
    {
        return $this->depth;
    }

    public function getSurfaceFootprint()
    {
        return $this->width * $this->length;
    }

    public function getTippingPoint()
    {
        $cacheKey = $this->width . '|' . $this->length .
'|' . $this->depth;

        if (isset(static::$tippingPointCache[$cacheKey])) {
            $tippingPoint = static::$tippingPointCache[$cacheKey];
        } else {
            $tippingPoint = atan(min($this->length, $this->width) /
($this->depth ?: 1));
            static::$tippingPointCache[$cacheKey] = $tippingPoint;
        }

        return $tippingPoint;
    }

    public function isStable()
    {
        return $this->getTippingPoint() > 0.261;
    }

    public function jsonSerialize()
    {
        return [
            'item' => $this->item,
            'width' => $this->width,
            'length' => $this->length,
            'depth' => $this->depth,
        ];
    }

    public function __toString()
    {
        return $this->width . '|' . $this->length .
'|' . $this->depth;
    }
}
boxpacker/OrientatedItemFactory.php000064400000024366151156426420013521
0ustar00<?php
/**
 * @package	HikaShop for Joomla!
 * @version	4.4.1
 * @author	hikashop.com
 * @copyright	(C) 2010-2021 HIKARI SOFTWARE. All rights reserved.
 * @license	GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
 */
defined('_JEXEC') or die('Restricted access');
?><?php
namespace DVDoug\BoxPacker;

use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerAwareTrait;

class OrientatedItemFactory implements LoggerAwareInterface
{
    use LoggerAwareTrait;


    protected $box;

    protected static $emptyBoxCache = [];

    public function __construct(Box $box)
    {
        $this->box = $box;
    }

    public function getBestOrientation(
        Item $item,
        OrientatedItem $prevItem = null,
        ItemList $nextItems,
        $isLastItem,
        $widthLeft,
        $lengthLeft,
        $depthLeft,
        $rowLength,
        $x,
        $y,
        $z,
        PackedItemList $prevPackedItemList
    ) {
        $possibleOrientations = $this->getPossibleOrientations($item,
$prevItem, $widthLeft, $lengthLeft, $depthLeft, $x, $y, $z,
$prevPackedItemList);
        $usableOrientations = $this->getUsableOrientations($item,
$possibleOrientations, $isLastItem);

        if (empty($usableOrientations)) {
            return null;
        }

        usort($usableOrientations, function (OrientatedItem $a,
OrientatedItem $b) use ($widthLeft, $lengthLeft, $depthLeft, $nextItems,
$rowLength, $x, $y, $z, $prevPackedItemList) {
            $orientationAWidthLeft = $widthLeft - $a->getWidth();
            $orientationALengthLeft = $lengthLeft - $a->getLength();
            $orientationADepthLeft = $depthLeft - $a->getDepth();
            $orientationBWidthLeft = $widthLeft - $b->getWidth();
            $orientationBLengthLeft = $lengthLeft - $b->getLength();
            $orientationBDepthLeft = $depthLeft - $b->getDepth();

            $orientationAMinGap = min($orientationAWidthLeft,
$orientationALengthLeft);
            $orientationBMinGap = min($orientationBWidthLeft,
$orientationBLengthLeft);

            if ($orientationAMinGap === 0 && ($orientationBMinGap
!== 0 || PHP_MAJOR_VERSION > 5)) { // prefer A if it leaves no gap
                return -1;
            }
            if ($orientationBMinGap === 0) { // prefer B if it leaves no
gap
                return 1;
            }

            if ($nextItems->count()) {
                $nextItemFitA =
count($this->getPossibleOrientations($nextItems->top(), $a,
$orientationAWidthLeft, $lengthLeft, $depthLeft, $x, $y, $z,
$prevPackedItemList));
                $nextItemFitB =
count($this->getPossibleOrientations($nextItems->top(), $b,
$orientationBWidthLeft, $lengthLeft, $depthLeft, $x, $y, $z,
$prevPackedItemList));
                if ($nextItemFitA && !$nextItemFitB) {
                    return -1;
                }
                if ($nextItemFitB && !$nextItemFitA) {
                    return 1;
                }

                $additionalPackedA =
$this->calculateAdditionalItemsPackedWithThisOrientation($a, $nextItems,
$widthLeft, $lengthLeft, $depthLeft, $rowLength);
                $additionalPackedB =
$this->calculateAdditionalItemsPackedWithThisOrientation($b, $nextItems,
$widthLeft, $lengthLeft, $depthLeft, $rowLength);
                if ($additionalPackedA > $additionalPackedB) {
                    return -1;
                }
                if ($additionalPackedA < $additionalPackedB) {
                    return 1;
                }
                if ($additionalPackedA === 0) {
                    return PHP_MAJOR_VERSION > 5 ? -1 : 1;
                }
            }
            return ($orientationADepthLeft - $orientationBDepthLeft) ?:
($orientationAMinGap - $orientationBMinGap) ?:
($a->getSurfaceFootprint() - $b->getSurfaceFootprint());
        });

        $bestFit = reset($usableOrientations);
        $this->logger->debug('Selected best fit
orientation', ['orientation' => $bestFit]);

        return $bestFit;
    }

    public function getPossibleOrientations(
        Item $item,
        OrientatedItem $prevItem = null,
        $widthLeft,
        $lengthLeft,
        $depthLeft,
        $x,
        $y,
        $z,
        PackedItemList $prevPackedItemList
    ) {
        $orientations = [];

        if ($prevItem &&
$this->isSameDimensions($prevItem->getItem(), $item)) {
            $orientations[] = new OrientatedItem($item,
$prevItem->getWidth(), $prevItem->getLength(),
$prevItem->getDepth());
        } else {
            $orientations[] = new OrientatedItem($item,
$item->getWidth(), $item->getLength(), $item->getDepth());
            $orientations[] = new OrientatedItem($item,
$item->getLength(), $item->getWidth(), $item->getDepth());

            if (!$item->getKeepFlat()) {
                $orientations[] = new OrientatedItem($item,
$item->getWidth(), $item->getDepth(), $item->getLength());
                $orientations[] = new OrientatedItem($item,
$item->getLength(), $item->getDepth(), $item->getWidth());
                $orientations[] = new OrientatedItem($item,
$item->getDepth(), $item->getWidth(), $item->getLength());
                $orientations[] = new OrientatedItem($item,
$item->getDepth(), $item->getLength(), $item->getWidth());
            }
        }

        $orientations = array_unique($orientations);

        $orientations = array_filter($orientations, function
(OrientatedItem $i) use ($widthLeft, $lengthLeft, $depthLeft) {
            return $i->getWidth() <= $widthLeft &&
$i->getLength() <= $lengthLeft && $i->getDepth() <=
$depthLeft;
        });

        if ($item instanceof ConstrainedPlacementItem) {
            $box = $this->box;
            $orientations = array_filter($orientations, function
(OrientatedItem $i) use ($box, $x, $y, $z, $prevPackedItemList) {

                $constrainedItem = $i->getItem();

                return $constrainedItem->canBePacked($box,
$prevPackedItemList, $x, $y, $z, $i->getWidth(), $i->getLength(),
$i->getDepth());
            });
        }

        return $orientations;
    }

    public function getPossibleOrientationsInEmptyBox(Item $item)
    {
        $cacheKey = $item->getWidth() .
            '|' .
            $item->getLength() .
            '|' .
            $item->getDepth() .
            '|' .
            ($item->getKeepFlat() ? '2D' : '3D') .
            '|' .
            $this->box->getInnerWidth() .
            '|' .
            $this->box->getInnerLength() .
            '|' .
            $this->box->getInnerDepth();

        if (isset(static::$emptyBoxCache[$cacheKey])) {
            $orientations = static::$emptyBoxCache[$cacheKey];
        } else {
            $orientations = $this->getPossibleOrientations(
                $item,
                null,
                $this->box->getInnerWidth(),
                $this->box->getInnerLength(),
                $this->box->getInnerDepth(),
                0,
                0,
                0,
                new PackedItemList()
            );
            static::$emptyBoxCache[$cacheKey] = $orientations;
        }

        return $orientations;
    }

    protected function getUsableOrientations(
        Item $item,
        $possibleOrientations,
        $isLastItem
    ) {
        $orientationsToUse = $stableOrientations = $unstableOrientations =
[];

        foreach ($possibleOrientations as $orientation) {
            if ($orientation->isStable()) {
                $stableOrientations[] = $orientation;
            } else {
                $unstableOrientations[] = $orientation;
            }
        }

        if (count($stableOrientations) > 0) {
            $orientationsToUse = $stableOrientations;
        } elseif (count($unstableOrientations) > 0) {
            $stableOrientationsInEmptyBox =
$this->getStableOrientationsInEmptyBox($item);

            if ($isLastItem || count($stableOrientationsInEmptyBox) === 0)
{
                $orientationsToUse = $unstableOrientations;
            }
        }

        return $orientationsToUse;
    }

    protected function getStableOrientationsInEmptyBox(Item $item)
    {
        $orientationsInEmptyBox =
$this->getPossibleOrientationsInEmptyBox($item);

        return array_filter(
            $orientationsInEmptyBox,
            function (OrientatedItem $orientation) {
                return $orientation->isStable();
            }
        );
    }

    protected function isSameDimensions(Item $itemA, Item $itemB)
    {
        $itemADimensions = [$itemA->getWidth(), $itemA->getLength(),
$itemA->getDepth()];
        $itemBDimensions = [$itemB->getWidth(), $itemB->getLength(),
$itemB->getDepth()];
        sort($itemADimensions);
        sort($itemBDimensions);

        return $itemADimensions === $itemBDimensions;
    }

    protected function calculateAdditionalItemsPackedWithThisOrientation(
        OrientatedItem $prevItem,
        ItemList $nextItems,
        $originalWidthLeft,
        $originalLengthLeft,
        $depthLeft,
        $currentRowLengthBeforePacking
    ) {
        $packedCount = 0;

        $currentRowLength = max($prevItem->getLength(),
$currentRowLengthBeforePacking);

        $itemsToPack = $nextItems->topN(8); // cap lookahead as this
gets recursive and slow

        $tempBox = new WorkingVolume($originalWidthLeft -
$prevItem->getWidth(), $currentRowLength, $depthLeft, PHP_INT_MAX);
        $tempPacker = new VolumePacker($tempBox, clone $itemsToPack);
        $tempPacker->setLookAheadMode(true);
        $remainingRowPacked = $tempPacker->pack();

        foreach ($remainingRowPacked->getItems() as $packedItem) {
            $itemsToPack->remove($packedItem);
        }

        $tempBox = new WorkingVolume($originalWidthLeft,
$originalLengthLeft - $currentRowLength, $depthLeft, PHP_INT_MAX);
        $tempPacker = new VolumePacker($tempBox, clone $itemsToPack);
        $tempPacker->setLookAheadMode(true);
        $nextRowsPacked = $tempPacker->pack();

        foreach ($nextRowsPacked->getItems() as $packedItem) {
            $itemsToPack->remove($packedItem);
        }

        $this->logger->debug('Lookahead with orientation',
['packedCount' => $packedCount, 'orientatedItem'
=> $prevItem]);

        return $nextItems->count() - $itemsToPack->count();
    }
}
boxpacker/PackedBox.php000064400000011272151156426420011104
0ustar00<?php
/**
 * @package	HikaShop for Joomla!
 * @version	4.4.1
 * @author	hikashop.com
 * @copyright	(C) 2010-2021 HIKARI SOFTWARE. All rights reserved.
 * @license	GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
 */
defined('_JEXEC') or die('Restricted access');
?><?php

namespace DVDoug\BoxPacker;

use RuntimeException;

class PackedBox
{
    protected $box;

    protected $items;

    protected $weight;

    protected $itemWeight;

    protected $remainingWidth;

    protected $remainingLength;

    protected $remainingDepth;

    protected $remainingWeight;

    protected $usedWidth;

    protected $usedLength;

    protected $usedDepth;

    protected $packedItemList;

    public function getBox()
    {
        return $this->box;
    }

    public function getItems()
    {
        return $this->items;
    }

    public function getWeight()
    {
        return $this->box->getEmptyWeight() +
$this->getItemWeight();
    }

    public function getItemWeight()
    {
        if (!is_null($this->itemWeight)) {
            return $this->itemWeight;
        }
        $this->itemWeight = 0;

        foreach (clone $this->items as $item) {
            $this->itemWeight += $item->getWeight();
        }

        return $this->itemWeight;
    }

    public function getRemainingWidth()
    {
        return $this->remainingWidth;
    }

    public function getRemainingLength()
    {
        return $this->remainingLength;
    }

    public function getRemainingDepth()
    {
        return $this->remainingDepth;
    }

    public function getUsedWidth()
    {
        return $this->usedWidth;
    }

    public function getUsedLength()
    {
        return $this->usedLength;
    }

    public function getUsedDepth()
    {
        return $this->usedDepth;
    }

    public function getRemainingWeight()
    {
        return $this->remainingWeight;
    }

    public function getInnerVolume()
    {
        return $this->box->getInnerWidth() *
$this->box->getInnerLength() * $this->box->getInnerDepth();
    }

    public function getUsedVolume()
    {
        $volume = 0;

        foreach (clone $this->items as $item) {
            $volume += $item->getVolume();
        }

        return $volume;
    }

    public function getUnusedVolume()
    {
        return $this->getInnerVolume() - $this->getUsedVolume();
    }

    public function getVolumeUtilisation()
    {
        $itemVolume = 0;


        foreach (clone $this->items as $item) {
            $itemVolume += $item->getVolume();
        }

        return round($itemVolume / $this->box->getInnerVolume() *
100, 1);
    }

    public function getPackedItems()
    {
        if (!$this->packedItemList instanceof PackedItemList) {
            throw new RuntimeException('No PackedItemList was set. Are
you using the old constructor?');
        }
        return $this->packedItemList;
    }

    public function setPackedItems(PackedItemList $packedItemList)
    {
        $this->packedItemList = $packedItemList;
    }

    public function __construct(
        Box $box,
        ItemList $itemList,
        $remainingWidth,
        $remainingLength,
        $remainingDepth,
        $remainingWeight,
        $usedWidth,
        $usedLength,
        $usedDepth
    ) {
        $this->box = $box;
        $this->items = $itemList;
        $this->remainingWidth = $remainingWidth;
        $this->remainingLength = $remainingLength;
        $this->remainingDepth = $remainingDepth;
        $this->remainingWeight = $remainingWeight;
        $this->usedWidth = $usedWidth;
        $this->usedLength = $usedLength;
        $this->usedDepth = $usedDepth;
    }

    public static function fromPackedItemList(Box $box, PackedItemList
$packedItems)
    {
        $maxWidth = $maxLength = $maxDepth = $weight = 0;

        foreach (clone $packedItems as $item) {
            $maxWidth = max($maxWidth, $item->getX() +
$item->getWidth());
            $maxLength = max($maxLength, $item->getY() +
$item->getLength());
            $maxDepth = max($maxDepth, $item->getZ() +
$item->getDepth());
            $weight += $item->getItem()->getWeight();
        }

        $packedBox = new self(
            $box,
            $packedItems->asItemList(),
            $box->getInnerWidth() - $maxWidth,
            $box->getInnerLength() - $maxLength,
            $box->getInnerDepth() - $maxDepth,
            $box->getMaxWeight() - $box->getEmptyWeight() - $weight,
            $maxWidth,
            $maxLength,
            $maxDepth
        );
        $packedBox->setPackedItems($packedItems);

        return $packedBox;
    }
}
boxpacker/PackedBoxList.php000064400000004670151156426420011744
0ustar00<?php
/**
 * @package	HikaShop for Joomla!
 * @version	4.4.1
 * @author	hikashop.com
 * @copyright	(C) 2010-2021 HIKARI SOFTWARE. All rights reserved.
 * @license	GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
 */
defined('_JEXEC') or die('Restricted access');
?><?php

namespace DVDoug\BoxPacker;

class PackedBoxList extends \SplMinHeap
{
    protected $meanWeight;

    public function compare($boxA, $boxB)
    {
        $choice = $boxA->getItems()->count() -
$boxB->getItems()->count();
        if ($choice == 0) {
            $choice = $boxA->getVolumeUtilisation() -
$boxB->getVolumeUtilisation();
        }
        if ($choice == 0) {
            $choice = $boxA->getUsedVolume() -
$boxB->getUsedVolume();
        }
        if ($choice == 0) {
            $choice = $boxA->getWeight() - $boxB->getWeight();
        }

        return $choice;
    }

    public function reverseCompare($boxA, $boxB)
    {
        $choice = $boxB->getItems()->count() -
$boxA->getItems()->count();
        if ($choice === 0) {
            $choice = $boxA->getBox()->getInnerVolume() -
$boxB->getBox()->getInnerVolume();
        }
        if ($choice === 0) {
            $choice = $boxB->getWeight() - $boxA->getWeight();
        }

        return $choice;
    }

    public function getMeanWeight()
    {
        if (!is_null($this->meanWeight)) {
            return $this->meanWeight;
        }

        foreach (clone $this as $box) {
            $this->meanWeight += $box->getWeight();
        }

        return $this->meanWeight /= $this->count();
    }

    public function getWeightVariance()
    {
        $mean = $this->getMeanWeight();

        $weightVariance = 0;
        foreach (clone $this as $box) {
            $weightVariance += pow($box->getWeight() - $mean, 2);
        }

        return round($weightVariance / $this->count(), 1);
    }

    public function getVolumeUtilisation()
    {
        $itemVolume = 0;
        $boxVolume = 0;


        foreach (clone $this as $box) {
            $boxVolume += $box->getBox()->getInnerVolume();


            foreach (clone $box->getItems() as $item) {
                $itemVolume += $item->getVolume();
            }
        }

        return round($itemVolume / $boxVolume * 100, 1);
    }

    public function insertFromArray(array $boxes)
    {
        foreach ($boxes as $box) {
            $this->insert($box);
        }
    }
}
boxpacker/PackedItem.php000064400000003630151156426420011251
0ustar00<?php
/**
 * @package	HikaShop for Joomla!
 * @version	4.4.1
 * @author	hikashop.com
 * @copyright	(C) 2010-2021 HIKARI SOFTWARE. All rights reserved.
 * @license	GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
 */
defined('_JEXEC') or die('Restricted access');
?><?php

namespace DVDoug\BoxPacker;

class PackedItem
{
    protected $x;

    protected $y;

    protected $z;

    protected $item;

    protected $width;

    protected $length;

    protected $depth;

    public function __construct(Item $item, $x, $y, $z, $width, $length,
$depth)
    {
        $this->item = $item;
        $this->x = $x;
        $this->y = $y;
        $this->z = $z;
        $this->width = $width;
        $this->length = $length;
        $this->depth = $depth;
    }

    public function getX()
    {
        return $this->x;
    }

    public function getY()
    {
        return $this->y;
    }

    public function getZ()
    {
        return $this->z;
    }

    public function getItem()
    {
        return $this->item;
    }

    public function getWidth()
    {
        return $this->width;
    }

    public function getLength()
    {
        return $this->length;
    }

    public function getDepth()
    {
        return $this->depth;
    }

    public function getVolume()
    {
        return $this->width * $this->length * $this->depth;
    }

    public static function fromOrientatedItem(OrientatedItem
$orientatedItem, $x, $y, $z)
    {
        return new static(
            $orientatedItem->getItem(),
            $x,
            $y,
            $z,
            $orientatedItem->getWidth(),
            $orientatedItem->getLength(),
            $orientatedItem->getDepth()
        );
    }

    public function toOrientatedItem()
    {
        return new OrientatedItem($this->item, $this->width,
$this->length, $this->depth);
    }
}
boxpacker/PackedItemList.php000064400000002512151156426420012103
0ustar00<?php
/**
 * @package	HikaShop for Joomla!
 * @version	4.4.1
 * @author	hikashop.com
 * @copyright	(C) 2010-2021 HIKARI SOFTWARE. All rights reserved.
 * @license	GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
 */
defined('_JEXEC') or die('Restricted access');
?><?php

namespace DVDoug\BoxPacker;

class PackedItemList extends \SplMaxHeap
{
    public function compare($itemA, $itemB)
    {
        if ($itemA->getItem()->getVolume() >
$itemB->getItem()->getVolume()) {
            return 1;
        } elseif ($itemA->getItem()->getVolume() <
$itemB->getItem()->getVolume()) {
            return -1;
        } else {
            return $itemA->getItem()->getWeight() -
$itemB->getItem()->getWeight();
        }
    }

    public function asArray()
    {
        $return = [];
        foreach (clone $this as $item) {
            $return[] = $item;
        }

        return $return;
    }

    public function asItemArray()
    {
        $return = [];
        foreach (clone $this as $item) {
            $return[] = $item->getItem();
        }

        return $return;
    }

    public function asItemList()
    {
        $return = new ItemList();
        foreach (clone $this as $packedItem) {
            $return->insert($packedItem->getItem());
        }

        return $return;
    }
}
boxpacker/PackedLayer.php000064400000002620151156426420011425
0ustar00<?php
/**
 * @package	HikaShop for Joomla!
 * @version	4.4.1
 * @author	hikashop.com
 * @copyright	(C) 2010-2021 HIKARI SOFTWARE. All rights reserved.
 * @license	GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
 */
defined('_JEXEC') or die('Restricted access');
?><?php
namespace DVDoug\BoxPacker;

class PackedLayer
{
    protected $items = [];

    public function insert(PackedItem $packedItem)
    {
        $this->items[] = $packedItem;
    }

    public function getItems()
    {
        return $this->items;
    }

    public function getFootprint()
    {
        $layerWidth = 0;
        $layerLength = 0;

        foreach ($this->items as $item) {
            $layerWidth = max($layerWidth, $item->getX() +
$item->getWidth());
            $layerLength = max($layerLength, $item->getY() +
$item->getLength());
        }

        return $layerWidth * $layerLength;
    }

    public function getStartDepth()
    {
        $startDepth = PHP_INT_MAX;

        foreach ($this->items as $item) {
            $startDepth = min($startDepth, $item->getZ());
        }

        return $startDepth;
    }

    public function getDepth()
    {
        $layerDepth = 0;

        foreach ($this->items as $item) {
            $layerDepth = max($layerDepth, $item->getZ() +
$item->getDepth());
        }

        return $layerDepth - $this->getStartDepth();
    }
}
boxpacker/Packer.php000064400000010345151156426420010451 0ustar00<?php
/**
 * @package	HikaShop for Joomla!
 * @version	4.4.1
 * @author	hikashop.com
 * @copyright	(C) 2010-2021 HIKARI SOFTWARE. All rights reserved.
 * @license	GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
 */
defined('_JEXEC') or die('Restricted access');
?><?php
namespace DVDoug\BoxPacker;

use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerAwareTrait;
use Psr\Log\LogLevel;
use Psr\Log\NullLogger;

class Packer implements LoggerAwareInterface
{
    use LoggerAwareTrait;

    protected $maxBoxesToBalanceWeight = 12;

    protected $items;

    protected $boxes;

    public function __construct()
    {
        $this->items = new ItemList();
        $this->boxes = new BoxList();

        $this->logger = new NullLogger();
    }

    public function addItem(Item $item, $qty = 1)
    {
        for ($i = 0; $i < $qty; ++$i) {
            $this->items->insert($item);
        }
        $this->logger->log(LogLevel::INFO, "added {$qty} x
{$item->getDescription()}", ['item' => $item]);
    }

    public function setItems($items)
    {
        if ($items instanceof ItemList) {
            $this->items = clone $items;
        } else {
            $this->items = new ItemList();
            foreach ($items as $item) {
                $this->items->insert($item);
            }
        }
    }

    public function addBox(Box $box)
    {
        $this->boxes->insert($box);
        $this->logger->log(LogLevel::INFO, "added box
{$box->getReference()}", ['box' => $box]);
    }

    public function setBoxes(BoxList $boxList)
    {
        $this->boxes = clone $boxList;
    }

    public function getMaxBoxesToBalanceWeight()
    {
        return $this->maxBoxesToBalanceWeight;
    }

    public function setMaxBoxesToBalanceWeight($maxBoxesToBalanceWeight)
    {
        $this->maxBoxesToBalanceWeight = $maxBoxesToBalanceWeight;
    }

    public function pack()
    {
        $packedBoxes = $this->doVolumePacking();

        if ($packedBoxes->count() > 1 &&
$packedBoxes->count() <= $this->maxBoxesToBalanceWeight) {
            $redistributor = new WeightRedistributor($this->boxes);
            $redistributor->setLogger($this->logger);
            $packedBoxes =
$redistributor->redistributeWeight($packedBoxes);
        }

        $this->logger->log(LogLevel::INFO, "[PACKING COMPLETED],
{$packedBoxes->count()} boxes");

        return $packedBoxes;
    }

    public function doVolumePacking()
    {
        $packedBoxes = new PackedBoxList();

        while ($this->items->count()) {
            $boxesToEvaluate = clone $this->boxes;
            $packedBoxesIteration = new PackedBoxList();

            while (!$boxesToEvaluate->isEmpty()) {
                $box = $boxesToEvaluate->extract();

                $volumePacker = new VolumePacker($box, clone
$this->items);
                $volumePacker->setLogger($this->logger);
                $packedBox = $volumePacker->pack();
                if ($packedBox->getItems()->count()) {
                    $packedBoxesIteration->insert($packedBox);

                    if ($packedBox->getItems()->count() ===
$this->items->count()) {
                        break;
                    }
                }
            }

            if ($packedBoxesIteration->isEmpty()) {
                throw new ItemTooLargeException('Item
'.$this->items->top()->getDescription().' is too large
to fit into any box', $this->items->top());
            }


            $bestBox = $packedBoxesIteration->top();
            $unPackedItems = $this->items->asArray();
            foreach (clone $bestBox->getItems() as $packedItem) {
                foreach ($unPackedItems as $unpackedKey =>
$unpackedItem) {
                    if ($packedItem === $unpackedItem) {
                        unset($unPackedItems[$unpackedKey]);
                        break;
                    }
                }
            }
            $unpackedItemList = new ItemList();
            foreach ($unPackedItems as $unpackedItem) {
                $unpackedItemList->insert($unpackedItem);
            }
            $this->items = $unpackedItemList;
            $packedBoxes->insert($bestBox);
        }

        return $packedBoxes;
    }
}
boxpacker/VolumePacker.php000064400000024076151156426420011647
0ustar00<?php
/**
 * @package	HikaShop for Joomla!
 * @version	4.4.1
 * @author	hikashop.com
 * @copyright	(C) 2010-2021 HIKARI SOFTWARE. All rights reserved.
 * @license	GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
 */
defined('_JEXEC') or die('Restricted access');
?><?php
namespace DVDoug\BoxPacker;

use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerAwareTrait;
use Psr\Log\NullLogger;

class VolumePacker implements LoggerAwareInterface
{
    use LoggerAwareTrait;

    protected $box;

    protected $boxWidth;

    protected $boxLength;

    protected $items;

    protected $skippedItems;

    protected $remainingWeight;

    protected $boxRotated = false;

    protected $layers = [];

    protected $lookAheadMode = false;

    public function __construct(Box $box, ItemList $items)
    {
        $this->box = $box;
        $this->items = $items;

        $this->boxWidth = max($this->box->getInnerWidth(),
$this->box->getInnerLength());
        $this->boxLength = min($this->box->getInnerWidth(),
$this->box->getInnerLength());
        $this->remainingWeight = $this->box->getMaxWeight() -
$this->box->getEmptyWeight();
        $this->skippedItems = new ItemList();
        $this->logger = new NullLogger();

        if ($this->box->getInnerWidth() !== $this->boxWidth ||
$this->box->getInnerLength() !== $this->boxLength) {
            $this->boxRotated = true;
        }
    }

    public function setLookAheadMode($lookAhead)
    {
        $this->lookAheadMode = $lookAhead;
    }

    public function pack()
    {
        $this->logger->debug("[EVALUATING BOX]
{$this->box->getReference()}", ['box' =>
$this->box]);

        while (count($this->items) > 0) {
            $layerStartDepth = $this->getCurrentPackedDepth();
            $this->packLayer($layerStartDepth, $this->boxWidth,
$this->boxLength, $this->box->getInnerDepth() -
$layerStartDepth);
        }

        if ($this->boxRotated) {
            $this->rotateLayersNinetyDegrees();
        }

        if (!$this->lookAheadMode) {
            $this->stabiliseLayers();
        }

        $this->logger->debug('done with this box');

        return PackedBox::fromPackedItemList($this->box,
$this->getPackedItemList());
    }

    protected function packLayer($startDepth, $widthLeft, $lengthLeft,
$depthLeft)
    {
        $this->layers[] = $layer = new PackedLayer();
        $prevItem = null;
        $x = $y = $rowWidth = $rowLength = $layerDepth = 0;

        while (count($this->items) > 0) {
            $itemToPack = $this->items->extract();

            if (!$this->checkConstraints($itemToPack)) {
                $this->rebuildItemList();
                continue;
            }

            $orientatedItem = $this->getOrientationForItem($itemToPack,
$prevItem, $this->items, $this->hasItemsLeftToPack(), $widthLeft,
$lengthLeft, $depthLeft, $rowLength, $x, $y, $startDepth);

            if ($orientatedItem instanceof OrientatedItem) {
                $packedItem =
PackedItem::fromOrientatedItem($orientatedItem, $x, $y, $startDepth);
                $layer->insert($packedItem);
                $this->remainingWeight -=
$orientatedItem->getItem()->getWeight();
                $widthLeft -= $orientatedItem->getWidth();

                $rowWidth += $orientatedItem->getWidth();
                $rowLength = max($rowLength,
$orientatedItem->getLength());
                $layerDepth = max($layerDepth,
$orientatedItem->getDepth());

                $stackableDepth = $layerDepth -
$orientatedItem->getDepth();
                $this->tryAndStackItemsIntoSpace($layer, $prevItem,
$this->items, $orientatedItem->getWidth(),
$orientatedItem->getLength(), $stackableDepth, $x, $y, $startDepth +
$orientatedItem->getDepth(), $rowLength);
                $x += $orientatedItem->getWidth();

                $prevItem = $packedItem;
                $this->rebuildItemList();
            } elseif (count($layer->getItems()) === 0) { // zero items
on layer
                $this->logger->debug("doesn't fit on layer
even when empty, skipping for good");
                continue;
            } elseif ($widthLeft > 0 && count($this->items)
> 0) { // skip for now, move on to the next item
                $this->logger->debug("doesn't fit, skipping
for now");
                $this->skippedItems->insert($itemToPack);
            } elseif ($x > 0 && $lengthLeft >=
min($itemToPack->getWidth(), $itemToPack->getLength(),
$itemToPack->getDepth())) {
                $this->logger->debug('No more fit in width wise,
resetting for new row');
                $widthLeft += $rowWidth;
                $lengthLeft -= $rowLength;
                $y += $rowLength;
                $x = $rowWidth = $rowLength = 0;
                $this->rebuildItemList($itemToPack);
                $prevItem = null;
                continue;
            } else {
                $this->logger->debug('no items fit, so starting
next vertical layer');
                $this->rebuildItemList($itemToPack);

                return;
            }
        }
    }

    public function stabiliseLayers()
    {
        $stabiliser = new LayerStabiliser();
        $this->layers = $stabiliser->stabilise($this->layers);
    }

    protected function getOrientationForItem(
        Item $itemToPack,
        PackedItem $prevItem = null,
        ItemList $nextItems,
        $isLastItem,
        $maxWidth,
        $maxLength,
        $maxDepth,
        $rowLength,
        $x,
        $y,
        $z
    ) {
        $this->logger->debug(
            "evaluating item {$itemToPack->getDescription()} for
fit",
            [
                'item' => $itemToPack,
                'space' => [
                    'maxWidth' => $maxWidth,
                    'maxLength' => $maxLength,
                    'maxDepth' => $maxDepth,
                ],
            ]
        );

        $prevOrientatedItem = $prevItem ? $prevItem->toOrientatedItem()
: null;
        $prevPackedItemList = $itemToPack instanceof
ConstrainedPlacementItem ? $this->getPackedItemList() : new
PackedItemList(); // don't calculate it if not going to be used

        $orientatedItemFactory = new OrientatedItemFactory($this->box);
        $orientatedItemFactory->setLogger($this->logger);
        $orientatedItemDecision =
$orientatedItemFactory->getBestOrientation($itemToPack,
$prevOrientatedItem, $nextItems, $isLastItem, $maxWidth, $maxLength,
$maxDepth, $rowLength, $x, $y, $z, $prevPackedItemList);

        return $orientatedItemDecision;
    }

    protected function tryAndStackItemsIntoSpace(
        PackedLayer $layer,
        PackedItem $prevItem = null,
        ItemList $nextItems,
        $maxWidth,
        $maxLength,
        $maxDepth,
        $x,
        $y,
        $z,
        $rowLength
    ) {
        while (count($this->items) > 0 &&
$this->checkNonDimensionalConstraints($this->items->top())) {
            $stackedItem = $this->getOrientationForItem(
                $this->items->top(),
                $prevItem,
                $nextItems,
                $this->items->count() === 1,
                $maxWidth,
                $maxLength,
                $maxDepth,
                $rowLength,
                $x,
                $y,
                $z
            );
            if ($stackedItem) {
                $this->remainingWeight -=
$this->items->top()->getWeight();
               
$layer->insert(PackedItem::fromOrientatedItem($stackedItem, $x, $y,
$z));
                $this->items->extract();
                $maxDepth -= $stackedItem->getDepth();
                $z += $stackedItem->getDepth();
            } else {
                break;
            }
        }
    }

    protected function checkConstraints(
        Item $itemToPack
    ) {
        return $this->checkNonDimensionalConstraints($itemToPack)
&&
               $this->checkDimensionalConstraints($itemToPack);
    }

    protected function checkNonDimensionalConstraints(Item $itemToPack)
    {
        $weightOK = $itemToPack->getWeight() <=
$this->remainingWeight;

        if ($itemToPack instanceof ConstrainedItem) {
            return $weightOK &&
$itemToPack->canBePackedInBox($this->getPackedItemList()->asItemList(),
$this->box);
        }

        return $weightOK;
    }

    protected function checkDimensionalConstraints(Item $itemToPack)
    {
        $orientatedItemFactory = new OrientatedItemFactory($this->box);
        $orientatedItemFactory->setLogger($this->logger);

        return (bool)
$orientatedItemFactory->getPossibleOrientationsInEmptyBox($itemToPack);
    }

    protected function rebuildItemList(Item $currentItem = null)
    {
        if (count($this->items) === 0) {
            $this->items = $this->skippedItems;
            $this->skippedItems = new ItemList();
        }

        if ($currentItem instanceof Item) {
            $this->items->insert($currentItem);
        }
    }

    protected function rotateLayersNinetyDegrees()
    {
        foreach ($this->layers as $i => $originalLayer) {
            $newLayer = new PackedLayer();
            foreach ($originalLayer->getItems() as $item) {
                $packedItem = new PackedItem($item->getItem(),
$item->getY(), $item->getX(), $item->getZ(),
$item->getLength(), $item->getWidth(), $item->getDepth());
                $newLayer->insert($packedItem);
            }
            $this->layers[$i] = $newLayer;
        }
    }

    protected function hasItemsLeftToPack()
    {
        return count($this->skippedItems) + count($this->items) ===
0;
    }

    protected function getPackedItemList()
    {
        $packedItemList = new PackedItemList();
        foreach ($this->layers as $layer) {
            foreach ($layer->getItems() as $packedItem) {
                $packedItemList->insert($packedItem);
            }
        }

        return $packedItemList;
    }

    protected function getCurrentPackedDepth()
    {
        $depth = 0;
        foreach ($this->layers as $layer) {
            $depth += $layer->getDepth();
        }

        return $depth;
    }
}
boxpacker/WeightRedistributor.php000064400000011312151156426420013250
0ustar00<?php
/**
 * @package	HikaShop for Joomla!
 * @version	4.4.1
 * @author	hikashop.com
 * @copyright	(C) 2010-2021 HIKARI SOFTWARE. All rights reserved.
 * @license	GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
 */
defined('_JEXEC') or die('Restricted access');
?><?php
namespace DVDoug\BoxPacker;

use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerAwareTrait;
use Psr\Log\LogLevel;
use Psr\Log\NullLogger;

class WeightRedistributor implements LoggerAwareInterface
{
    use LoggerAwareTrait;

    private $boxes;

    public function __construct(BoxList $boxList)
    {
        $this->boxes = clone $boxList;
        $this->logger = new NullLogger();
    }

    public function redistributeWeight(PackedBoxList $originalBoxes)
    {
        $targetWeight = $originalBoxes->getMeanWeight();
        $this->logger->log(LogLevel::DEBUG, "repacking for
weight distribution, weight variance
{$originalBoxes->getWeightVariance()}, target weight
{$targetWeight}");


        $boxes = iterator_to_array($originalBoxes);

        usort($boxes, function (PackedBox $boxA, PackedBox $boxB) {
            return $boxB->getWeight() - $boxA->getWeight();
        });

        do {
            $iterationSuccessful = false;

            foreach ($boxes as $a => &$boxA) {
                foreach ($boxes as $b => &$boxB) {
                    if ($b <= $a || $boxA->getWeight() ===
$boxB->getWeight()) {
                        continue; //no need to evaluate
                    }

                    $iterationSuccessful = $this->equaliseWeight($boxA,
$boxB, $targetWeight);
                    if ($iterationSuccessful) {
                        $boxes = array_filter($boxes, function ($box) {
//remove any now-empty boxes from the list
                            return $box instanceof PackedBox;
                        });
                        break 2;
                    }
                }
            }
        } while ($iterationSuccessful);

        $packedBoxes = new PackedBoxList();
        $packedBoxes->insertFromArray($boxes);

        return $packedBoxes;
    }

    private function equaliseWeight(PackedBox &$boxA, PackedBox
&$boxB, $targetWeight)
    {
        $anyIterationSuccessful = false;

        if ($boxA->getWeight() > $boxB->getWeight()) {
            $overWeightBox = $boxA;
            $underWeightBox = $boxB;
        } else {
            $overWeightBox = $boxB;
            $underWeightBox = $boxA;
        }

        $overWeightBoxItems = $overWeightBox->getItems()->asArray();
        $underWeightBoxItems =
$underWeightBox->getItems()->asArray();

        foreach ($overWeightBoxItems as $key => $overWeightItem) {
            if ($overWeightItem->getWeight() + $boxB->getWeight()
> $targetWeight) {
                continue; // moving this item would harm more than help
            }

            $newLighterBoxes =
$this->doVolumeRepack(array_merge($underWeightBoxItems,
[$overWeightItem]));
            if (count($newLighterBoxes) !== 1) {
                continue; //only want to move this item if it still fits in
a single box
            }

            $underWeightBoxItems[] = $overWeightItem;

            if (count($overWeightBoxItems) === 1) { //sometimes a repack
can be efficient enough to eliminate a box
                $boxB = $newLighterBoxes->top();
                $boxA = null;

                return true;
            } else {
                unset($overWeightBoxItems[$key]);
                $newHeavierBoxes =
$this->doVolumeRepack($overWeightBoxItems);
                if (count($newHeavierBoxes) !== 1) {
                    continue;
                }

                if ($this->didRepackActuallyHelp($boxA, $boxB,
$newHeavierBoxes->top(), $newLighterBoxes->top())) {
                    $boxB = $newLighterBoxes->top();
                    $boxA = $newHeavierBoxes->top();
                    $anyIterationSuccessful = true;
                }
            }
        }

        return $anyIterationSuccessful;
    }

    private function doVolumeRepack($items)
    {
        $packer = new Packer();
        $packer->setBoxes($this->boxes); // use the full set of boxes
to allow smaller/larger for full efficiency
        $packer->setItems($items);

        return $packer->doVolumePacking();
    }

    private function didRepackActuallyHelp(PackedBox $oldBoxA, PackedBox
$oldBoxB, PackedBox $newBoxA, PackedBox $newBoxB)
    {
        $oldList = new PackedBoxList();
        $oldList->insertFromArray([$oldBoxA, $oldBoxB]);

        $newList = new PackedBoxList();
        $newList->insertFromArray([$newBoxA, $newBoxB]);

        return $newList->getWeightVariance() <
$oldList->getWeightVariance();
    }
}
boxpacker/WorkingVolume.php000064400000003572151156426420012060
0ustar00<?php
/**
 * @package	HikaShop for Joomla!
 * @version	4.4.1
 * @author	hikashop.com
 * @copyright	(C) 2010-2021 HIKARI SOFTWARE. All rights reserved.
 * @license	GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
 */
defined('_JEXEC') or die('Restricted access');
?><?php
namespace DVDoug\BoxPacker;

use JsonSerializable;

class WorkingVolume implements Box, JsonSerializable
{
    private $width;

    private $length;

    private $depth;

    private $maxWeight;

    public function __construct(
        $width,
        $length,
        $depth,
        $maxWeight
    ) {
        $this->width = $width;
        $this->length = $length;
        $this->depth = $depth;
        $this->maxWeight = $maxWeight;
    }

    public function getReference()
    {
        return 'Working Volume';
    }

    public function getOuterWidth()
    {
        return $this->width;
    }

    public function getOuterLength()
    {
        return $this->length;
    }

    public function getOuterDepth()
    {
        return $this->depth;
    }

    public function getEmptyWeight()
    {
        return 0;
    }

    public function getInnerWidth()
    {
        return $this->width;
    }

    public function getInnerLength()
    {
        return $this->length;
    }

    public function getInnerDepth()
    {
        return $this->depth;
    }

    public function getMaxWeight()
    {
        return $this->maxWeight;
    }

    public function getInnerVolume()
    {
        return $this->width * $this->length * $this->depth;
    }

    public function jsonSerialize()
    {
        return [
            'reference' => $this->getReference(),
            'width' => $this->width,
            'length' => $this->length,
            'depth' => $this->depth,
            'maxWeight' => $this->maxWeight,
        ];
    }
}
boxpacker.php000064400000000500151156426420007234 0ustar00<?php
/**
 * @package	HikaShop for Joomla!
 * @version	4.4.1
 * @author	hikashop.com
 * @copyright	(C) 2010-2021 HIKARI SOFTWARE. All rights reserved.
 * @license	GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
 */
defined('_JEXEC') or die('Restricted access');
?><?php

class hikashopBoxpackerInc {

}
compat.php000064400000002163151156426420006550 0ustar00<?php
/**
 * @package	HikaShop for Joomla!
 * @version	4.4.1
 * @author	hikashop.com
 * @copyright	(C) 2010-2021 HIKARI SOFTWARE. All rights reserved.
 * @license	GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
 */
defined('_JEXEC') or die('Restricted access');
?><?php

function bccomp($num1, $num2, $scale = 0) {
	if(!preg_match("/^\+?(\d+)(\.\d+)?$/", $num1, $tmp1) ||
!preg_match("/^\+?(\d+)(\.\d+)?$/", $num2, $tmp2))
		return 0;
	$num1 = ltrim($tmp1[1], '0');
	$num2 = ltrim($tmp2[1], '0');
	if(strlen($num1) > strlen($num2))
		return 1;
	if(strlen($num1) < strlen($num2))
		return -1;
	$dec1 = isset($tmp1[2]) ? rtrim(substr($tmp1[2], 1), '0') :
'';
	$dec2 = isset($tmp2[2]) ? rtrim(substr($tmp2[2], 1), '0') :
'';
	if($scale != null) {
		$dec1 = substr($dec1, 0, $scale);
		$dec2 = substr($dec2, 0, $scale);
	}
	$DLen = max(strlen($dec1), strlen($dec2));
	$num1 .= str_pad($dec1, $DLen, '0');
	$num2 .= str_pad($dec2, $DLen, '0');
	for($i = 0; $i < strlen($num1); $i++) {
		if((int)$num1[$i] > (int)$num2[$i])
			return 1;
		if((int)$num1[$i] < (int)$num2[$i])
			return -1;
	}
	return 0;
}
expression.php000064400000052041151156426420007464 0ustar00<?php
/**
 * @package	HikaShop for Joomla!
 * @version	4.4.1
 * @author	hikashop.com
 * @copyright	(C) 2010-2021 HIKARI SOFTWARE. All rights reserved.
 * @license	GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
 */
defined('_JEXEC') or die('Restricted access');
?><?php


class HikashopExpressionInc {

    var $suppress_errors = false;
    var $last_error = null;

    var $v = array('e'=>2.71,'pi'=>3.14); //
variables (and constants)
    var $f = array(); // user-defined functions
    var $vb = array('e', 'pi'); // constants
    var $fb = array(  // built-in functions
       
'sin','sinh','arcsin','asin','arcsinh','asinh',
       
'cos','cosh','arccos','acos','arccosh','acosh',
       
'tan','tanh','arctan','atan','arctanh','atanh',
        'sqrt','abs','ln','log',
'ceil', 'intval', 'floor', 'round',
'exp');

    var $functions = array(); // function defined outside of Expression as
closures

    function __construct() {
        $this->v['pi'] = pi();
        $this->v['e'] = exp(1);
    }

    function e($expr) {
        return $this->evaluate($expr);
    }

    function evaluate($expr) {
        $this->last_error = null;
        $expr = trim($expr);
        if (substr($expr, -1, 1) == ';') $expr = substr($expr, 0,
strlen($expr)-1); // strip semicolons at the end
        if (preg_match('/^\s*([a-z]\w*)\s*=(?!~|=)\s*(.+)$/',
$expr, $matches)) {
            if (in_array($matches[1], $this->vb)) { // make sure
we're not assigning to a constant
                return $this->trigger("cannot assign to constant
'$matches[1]'");
            }
            $tmp = $this->pfx($this->nfx($matches[2]));
            $this->v[$matches[1]] = $tmp; // if so, stick it in the
variable array
            return $this->v[$matches[1]]; // and return the resulting
value
        } elseif
(preg_match('/^\s*([a-z]\w*)\s*\((?:\s*([a-z]\w*(?:\s*,\s*[a-z]\w*)*)\s*)?\)\s*=(?!~|=)\s*(.+)$/',
$expr, $matches)) {
            $fnn = $matches[1]; // get the function name
            if (in_array($matches[1], $this->fb)) { // make sure it
isn't built in
                return $this->trigger("cannot redefine built-in
function '$matches[1]()'");
            }

            if ($matches[2] != "") {
                $args = explode(",",
preg_replace("/\s+/", "", $matches[2])); // get the
arguments
            } else {
                $args = array();
            }
            if (($stack = $this->nfx($matches[3])) === false) return
false; // see if it can be converted to postfix
            for ($i = 0; $i<count($stack); $i++) { // freeze the state
of the non-argument variables
                $token = $stack[$i];
                if (preg_match('/^[a-z]\w*$/', $token) and
!in_array($token, $args)) {
                    if (array_key_exists($token, $this->v)) {
                        $stack[$i] = $this->v[$token];
                    } else {
                        return $this->trigger("undefined variable
'$token' in function definition");
                    }
                }
            }
            $this->f[$fnn] = array('args'=>$args,
'func'=>$stack);
            return true;
        } else {
            return $this->pfx($this->nfx($expr)); // straight up
evaluation, woo
        }
    }

    function vars() {
        $output = $this->v;
        unset($output['pi']);
        unset($output['e']);
        return $output;
    }

    function funcs() {
        $output = array();
        foreach ($this->f as $fnn=>$dat)
            $output[] = $fnn . '(' . implode(',',
$dat['args']) . ')';
        return $output;
    }


    function nfx($expr) {
        $index = 0;
        $stack = new HikashopExpressionStack;
        $output = array(); // postfix form of expression, to be passed to
pfx()
        $expr = trim($expr);

        $ops   = array('+', '-', '*',
'/', '^', '_', '%',
'>', '<', '>=', '<=',
'==', '!=', '=~', '&&',
'||', '!');
        $ops_r =
array('+'=>0,'-'=>0,'*'=>0,'/'=>0,'%'=>0,'^'=>1,'>'=>0,
                      
'<'=>0,'>='=>0,'<='=>0,'=='=>0,'!='=>0,'=~'=>0,
                      
'&&'=>0,'||'=>0,'!'=>0); //
right-associative operator?
        $ops_p =
array('+'=>3,'-'=>3,'*'=>4,'/'=>4,'_'=>4,'%'=>4,'^'=>5,'>'=>2,'<'=>2,
                      
'>='=>2,'<='=>2,'=='=>2,'!='=>2,'=~'=>2,'&&'=>1,'||'=>1,'!'=>5);
// operator precedence

        $expecting_op = false; // we use this in syntax-checking the
expression

        $first_argument = false;
        $i = 0;
        $matcher = false;
        while(1) { // 1 Infinite Loop ;)
            $op = substr(substr($expr, $index), 0, 2); // get the first two
characters at the current index
            if
(preg_match("/^[+\-*\/^_\"<>=%(){\[!~,](?!=|~)/", $op)
|| preg_match("/\w/", $op)) {
                $op = substr($expr, $index, 1);
            }
            $single_str =
'(?<!\\\\)"(?:(?:(?<!\\\\)(?:\\\\{2})*\\\\)"|[^"])*(?<![^\\\\]\\\\)"';
            $double_str =
"(?<!\\\\)'(?:(?:(?<!\\\\)(?:\\\\{2})*\\\\)'|[^'])*(?<![^\\\\]\\\\)'";
            $regex =
"(?<!\\\\)\/(?:[^\/]|\\\\\/)+\/[imsxUXJ]*";
            $json =
'[\[{](?>"(?:[^"]|\\\\")*"|[^[{\]}]|(?1))*[\]}]';
            $number = '[\d.]+e\d+|\d+(?:\.\d*)?|\.\d+';
            $name = '[a-z]\w*\(?|\\$\w+';
            $parenthesis = '\\(';
            $ex =
preg_match("%^($single_str|$double_str|$json|$name|$regex|$number|$parenthesis)%",
substr($expr, $index), $match);
            if ($op == '[' && $expecting_op &&
$ex) {
                if (!preg_match("/^\[(.*)\]$/", $match[1],
$matches)) {
                    return $this->trigger("invalid array
access");
                }
                $stack->push('[');
                $stack->push($matches[1]);
                $index += strlen($match[1]);
            } elseif ($op == '-' and !$expecting_op) { // is it a
negation instead of a minus?
                $stack->push('_'); // put a negation on the
stack
                $index++;
            } elseif ($op == '_') { // we have to explicitly deny
this, because it's legal on the stack
                return $this->trigger("illegal character
'_'"); // but not in the input expression
            } elseif ($ex && $matcher &&
preg_match("%^" . $regex . "$%", $match[1])) {
                $stack->push('"' . $match[1] .
'"');
                $index += strlen($match[1]);
                $op = null;
                $expecting_op = false;
                $matcher = false;
                break;
            } elseif (((in_array($op, $ops) or $ex) and $expecting_op) or
in_array($op, $ops) and !$expecting_op or
                      (!$matcher && $ex &&
preg_match("%^" . $regex . "$%", $match[1]))) {
                while($stack->count > 0 and ($o2 = $stack->last())
and in_array($o2, $ops) and ($ops_r[$op] ? $ops_p[$op] < $ops_p[$o2] :
$ops_p[$op] <= $ops_p[$o2])) {
                    $output[] = $stack->pop(); // pop stuff off the
stack into the output

                }
                $stack->push($op); // finally put OUR operator onto the
stack
                $index += strlen($op);
                $expecting_op = false;
                $matcher = $op == '=~';
            } elseif ($op == ')' and $expecting_op || !$ex) { //
ready to close a parenthesis?
                while (($o2 = $stack->pop()) != '(') { // pop
off the stack back to the last (
                    if (is_null($o2)) return
$this->trigger("unexpected ')'");
                    else $output[] = $o2;
                }
                if (preg_match("/^([a-z]\w*)\($/",
$stack->last(2), $matches)) { // did we just close a function?
                    $fnn = $matches[1]; // get the function name
                    $arg_count = $stack->pop(); // see how many
arguments there were (cleverly stored on the stack, thank you)
                    $output[] = $stack->pop(); // pop the function and
push onto the output
                    if (in_array($fnn, $this->fb)) { // check the
argument count
                        if($arg_count > 1)
                            return $this->trigger("too many
arguments ($arg_count given, 1 expected)");
                    } elseif (array_key_exists($fnn, $this->f)) {
                        if ($arg_count !=
count($this->f[$fnn]['args']))
                            return $this->trigger("wrong number of
arguments ($arg_count given, " .
count($this->f[$fnn]['args']) . " expected) " .
json_encode($this->f[$fnn]['args']));
                    } elseif (array_key_exists($fnn, $this->functions))
{
                        $func_reflection = new
ReflectionFunction($this->functions[$fnn]);
                        $count =
$func_reflection->getNumberOfParameters();
                        if ($arg_count != $count)
                            return $this->trigger("wrong number of
arguments ($arg_count given, " . $count . " expected)");
                    } else { // did we somehow push a non-function on the
stack? this should never happen
                        return $this->trigger("internal
error");
                    }
                }
                $index++;
            } elseif ($op == ',' and $expecting_op) { // did we
just finish a function argument?

                while (($o2 = $stack->pop()) != '(') {
                    if (is_null($o2)) return
$this->trigger("unexpected ','"); // oops, never had
a (
                    else $output[] = $o2; // pop the argument expression
stuff and push onto the output
                }
                if (!preg_match("/^([a-z]\w*)\($/",
$stack->last(2), $matches))
                    return $this->trigger("unexpected
','");
                if ($first_argument) {
                    $first_argument = false;
                } else {
                    $stack->push($stack->pop()+1); // increment the
argument count
                }
                $stack->push('('); // put the ( back on,
we'll need to pop back to it again
                $index++;
                $expecting_op = false;
            } elseif ($op == '(' and !$expecting_op) {
                $stack->push('('); // that was easy
                $index++;
                $allow_neg = true;
            } elseif ($ex and !$expecting_op) { // do we now have a
function/variable/number?
                $expecting_op = true;
                $val = $match[1];
                if ($op == '[' || $op == "{" ||
preg_match("/null|true|false/", $match[1])) {
                    $output[] = $val;
                } elseif (preg_match("/^([a-z]\w*)\($/", $val,
$matches)) { // may be func, or variable w/ implicit multiplication against
parentheses...
                    if (in_array($matches[1], $this->fb) or
                        array_key_exists($matches[1], $this->f) or
                        array_key_exists($matches[1], $this->functions))
{ // it's a func
                        $stack->push($val);
                        $stack->push(0);
                        $stack->push('(');
                        $expecting_op = false;
                    } else { // it's a var w/ implicit multiplication
                        $val = $matches[1];
                        $output[] = $val;
                    }
                } else { // it's a plain old var or num
                    $output[] = $val;
                    if (preg_match("/^([a-z]\w*)\($/",
$stack->last(3))) {
                        $first_argument = true;
                        while (($o2 = $stack->pop()) != '(')
{
                            if (is_null($o2)) return
$this->trigger("unexpected error"); // oops, never had a (
                            else $output[] = $o2; // pop the argument
expression stuff and push onto the output
                        }
                        if (!preg_match("/^([a-z]\w*)\($/",
$stack->last(2), $matches))
                            return $this->trigger("unexpected
error");

                        $stack->push($stack->pop()+1); // increment
the argument count
                        $stack->push('('); // put the ( back
on, we'll need to pop back to it again
                    }
                }
                $index += strlen($val);
            } elseif ($op == ')') { // miscellaneous error
checking
                return $this->trigger("unexpected
')'");
            } elseif (in_array($op, $ops) and !$expecting_op) {
                return $this->trigger("unexpected operator
'$op'");
            } else { // I don't even want to know what you did to get
here
                return $this->trigger("an unexpected error occured
" . json_encode($op) . " " . json_encode($match) . "
". ($ex?'true':'false') . " " . $expr);
            }
            if ($index == strlen($expr)) {
                if (in_array($op, $ops)) { // did we end with an operator?
bad.
                    return $this->trigger("operator '$op'
lacks operand");
                } else {
                    break;
                }
            }
            while (substr($expr, $index, 1) == ' ') { // step the
index past whitespace (pretty much turns whitespace
                $index++;                             // into implicit
multiplication if no operator is there)
            }

        }
        while (!is_null($op = $stack->pop())) { // pop everything off
the stack and push onto output
            if ($op == '(') return
$this->trigger("expecting ')'"); // if there are (s
on the stack, ()s were unbalanced
            $output[] = $op;
        }
        return $output;
    }

    function pfx($tokens, $vars = array()) {

        if ($tokens == false) return false;
        $stack = new HikashopExpressionStack();
        foreach ($tokens as $token) { // nice and easy
            if (in_array($token, array('+', '-',
'*', '/', '^', '<',
'>', '<=', '>=', '==',
'&&', '||', '!=', '=~',
'%'))) {
                $op2 = $stack->pop();
                $op1 = $stack->pop();
                switch ($token) {
                    case '+':
                        if (is_string($op1) || is_string($op2)) {
                            $stack->push((string)$op1 . (string)$op2);
                        } else {
                            $stack->push($op1 + $op2);
                        }
                        break;
                    case '-':
                        $stack->push($op1 - $op2); break;
                    case '*':
                        $stack->push($op1 * $op2); break;
                    case '/':
                        if ($op2 == 0) return
$this->trigger("division by zero");
                        $stack->push($op1 / $op2); break;
                    case '%':
                        $stack->push($op1 % $op2); break;
                    case '^':
                        $stack->push(pow($op1, $op2)); break;
                    case '>':
                        $stack->push($op1 > $op2); break;
                    case '<':
                        $stack->push($op1 < $op2); break;
                    case '>=':
                        $stack->push($op1 >= $op2); break;
                    case '<=':
                        $stack->push($op1 <= $op2); break;
                    case '==':
                        if (is_array($op1) && is_array($op2)) {
                            $stack->push(json_encode($op1) ==
json_encode($op2));
                        } else {
                            $stack->push($op1 == $op2);
                        }
                        break;
                    case '!=':
                        if (is_array($op1) && is_array($op2)) {
                            $stack->push(json_encode($op1) !=
json_encode($op2));
                        } else {
                            $stack->push($op1 != $op2);
                        }
                        break;
                    case '=~':
                        $value = @preg_match($op2, $op1, $match);

                        if (!is_int($value)) {
                            return $this->trigger("Invalid regex
" . json_encode($op2));
                        }
                        $stack->push($value);
                        for ($i = 0; $i < count($match); $i++) {
                            $this->v['$' . $i] = $match[$i];
                        }
                        break;
                    case '&&':
                        $stack->push($op1 ? $op2 : $op1); break;
                    case '||':
                        $stack->push($op1 ? $op1 : $op2); break;
                }
            } elseif ($token == '!') {
                $stack->push(!$stack->pop());
            } elseif ($token == '[') {
                $selector = $stack->pop();
                $object = $stack->pop();
                if (is_object($object)) {
                    $stack->push($object->$selector);
                } elseif (is_array($object)) {
                    $stack->push($object[$selector]);
                } else {
                    return $this->trigger("invalid object for
selector");
                }
            } elseif ($token == "_") {
                $stack->push(-1*$stack->pop());
            } elseif (preg_match("/^([a-z]\w*)\($/", $token,
$matches)) { // it's a function!
                $fnn = $matches[1];
                if (in_array($fnn, $this->fb)) { // built-in function:
                    if (is_null($op1 = $stack->pop())) return
$this->trigger("internal error");
                    $fnn = preg_replace("/^arc/", "a",
$fnn); // for the 'arc' trig synonyms
                    if ($fnn == 'ln') $fnn = 'log';
                    $stack->push($fnn($op1)); // perfectly safe variable
function call
                } elseif (array_key_exists($fnn, $this->f)) { // user
function
                    $args = array();
                    for ($i = count($this->f[$fnn]['args'])-1;
$i >= 0; $i--) {
                        if ($stack->empty()) {
                            return $this->trigger("internal error
" . $fnn . " " .
json_encode($this->f[$fnn]['args']));
                        }
                        $args[$this->f[$fnn]['args'][$i]] =
$stack->pop();
                    }
                   
$stack->push($this->pfx($this->f[$fnn]['func'], $args));
// yay... recursion!!!!
                } else if (array_key_exists($fnn, $this->functions)) {
                    $reflection = new
ReflectionFunction($this->functions[$fnn]);
                    $count = $reflection->getNumberOfParameters();
                    for ($i = $count-1; $i >= 0; $i--) {
                        if ($stack->empty()) {
                            return $this->trigger("internal
error");
                        }
                        $args[] = $stack->pop();
                    }
                    $stack->push($reflection->invokeArgs($args));
                }
            } else {
                if
(preg_match('/^([\[{](?>"(?:[^"]|\\")*"|[^[{\]}]|(?1))*[\]}])$/',
$token) ||
                    preg_match("/^(null|true|false)$/", $token))
{ // json
                    if ($token == 'null') {
                        $value = null;
                    } elseif ($token == 'true') {
                        $value = true;
                    } elseif ($token == 'false') {
                        $value = false;
                    } else {
                        $value = json_decode($token);
                        if ($value == null) {
                            return $this->trigger("invalid json
" . $token);
                        }
                    }
                    $stack->push($value);
                } elseif (is_numeric($token)) {
                    $stack->push(0+$token);
                } else if
(preg_match("/^['\\\"](.*)['\\\"]$/",
$token)) {
                   
$stack->push(json_decode(preg_replace_callback("/^['\\\"](.*)['\\\"]$/",
function($matches) {
                        $m = array("/\\\\'/",
'/(?<!\\\\)"/');
                        $r = array("'",
'\\"');
                        return '"' . preg_replace($m, $r,
$matches[1]) . '"';
                    }, $token)));
                } elseif (array_key_exists($token, $this->v)) {
                    $stack->push($this->v[$token]);
                } elseif (array_key_exists($token, $vars)) {
                    $stack->push($vars[$token]);
                } else {
                    return $this->trigger("undefined variable
'$token'");
                }
            }
        }
        if ($stack->count != 1) return $this->trigger("internal
error");
        return $stack->pop();
    }

    function trigger($msg) {
        $this->last_error = $msg;
        if (!$this->suppress_errors) trigger_error($msg,
E_USER_WARNING);
        return false;
    }
}

class HikashopExpressionStack {

    var $stack = array();
    var $count = 0;

    function push($val) {
        $this->stack[$this->count] = $val;
        $this->count++;
    }

    function pop() {
        if ($this->count > 0) {
            $this->count--;
            return $this->stack[$this->count];
        }
        return null;
    }

    function empty() {
        return empty($this->stack);
    }

    function last($n=1) {
        if (isset($this->stack[$this->count-$n])) {
          return $this->stack[$this->count-$n];
        }
        return;
    }
}
geolocation.php000064400000005251151156426430007572 0ustar00<?php
/**
 * @package	HikaShop for Joomla!
 * @version	2.2.3
 * @author	hikashop.com
 * @copyright	(C) 2010-2013 HIKARI SOFTWARE. All rights reserved.
 * @license	GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
 */
defined('_JEXEC') or die('Restricted access');
?><?php

class hikashopGeolocationInc{
	var $errors = array();
	var $service = 'api.ipinfodb.com';
	var $version = 'v3';
	var $apiKey = '';
	var $timeout = 10;

	function setKey($key){
		if(!empty($key)) $this->apiKey = $key;
	}
	function setTimeout($key){
		if(!empty($key)) $this->timeout = $key;
	}

	function getError(){
		return implode("\n", $this->errors);
	}

	function getCountry($host){
		return $this->getResult($host, 'ip-country');
	}

	function getCity($host){
		return $this->getResult($host, 'ip-city');
	}

	function getResult($host, $name){
		$ip = @gethostbyname($host);

		if(preg_match('/^(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:[.](?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}$/',
$ip)){
			return $this->curlRequest($ip);
		}

		$this->errors[] = '"' . $host . '" is not a
valid IP address or hostname.';
		return;
	}
	function curlRequest($ip) {
		$qs = 'http://' . $this->service . '/' .
$this->version . '/ip-country/' . '?ip=' . $ip .
'&format=json&key=' . $this->apiKey;
		$app =& JFactory::getApplication();
		if(!function_exists('curl_init')){
			$app->enqueueMessage('The HikaShop Geolocation plugin needs the
CURL library installed but it seems that it is not available on your
server. Please contact your web hosting to set it
up.','error');
			return false;
		}
		if(!function_exists('json_decode')){
			$app->enqueueMessage('The HikaShop Geolocation plugin can only
work with PHP 5.2 at least. Please ask your web hosting to update your PHP
version','error');
			return false;
		}
		if (!isset($this->curl)) {
			$this->curl = curl_init();
			curl_setopt ($this->curl, CURLOPT_FAILONERROR, TRUE);
			if (@ini_get('open_basedir') == '' &&
@ini_get('safe_mode' == 'Off')) {
				curl_setopt ($this->curl, CURLOPT_FOLLOWLOCATION, TRUE);
			}
			curl_setopt ($this->curl, CURLOPT_RETURNTRANSFER, TRUE);
			curl_setopt ($this->curl, CURLOPT_CONNECTTIMEOUT,
$this->timeout);
			curl_setopt ($this->curl, CURLOPT_TIMEOUT, $this->timeout);
		}

		curl_setopt ($this->curl, CURLOPT_URL, $qs);

		$json = curl_exec($this->curl);

		if(curl_errno($this->curl) || $json === FALSE) {
			$err = curl_error($this->curl);
			$app->enqueueMessage('cURL failed. Error: ' . $err);
		}

		$response = json_decode($json);

		if ($response->statusCode != 'OK') {
			$app->enqueueMessage('API returned error: ' .
$response->statusMessage);
		}

		return $response;
	}
}
geoplugin.php000064400000006360151156426430007262 0ustar00<?php
/**
 * @package	HikaShop for Joomla!
 * @version	4.4.1
 * @author	hikashop.com
 * @copyright	(C) 2010-2021 HIKARI SOFTWARE. All rights reserved.
 * @license	GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
 */
defined('_JEXEC') or die('Restricted access');
?><?php

class HikashopGeopluginInc {

	var $host =
'http://www.geoplugin.net/php.gp?ip={IP}&base_currency={CURRENCY}';

	var $currency = 'USD';

	var $ip = null;
	var $city = null;
	var $regionName = null;
	var $areaCode = null;
	var $dmaCode = null;
	var $countryCode = null;
	var $countryName = null;
	var $continentCode = null;
	var $latitude = null;
	var $longitude = null;
	var $currencyCode = null;
	var $currencySymbol = null;
	var $currencyConverter = null;

	var $timeout= 10;

	function geoPlugin() {

	}

	function locate($ip = null) {

		global $_SERVER;

		if ( is_null( $ip ) ) {
			$ip = $_SERVER['REMOTE_ADDR'];
		}

		$host = str_replace( '{IP}', $ip, $this->host );
		$host = str_replace( '{CURRENCY}', $this->currency, $host
);

		$data = array();

		$response = $this->fetch($host);

		if(preg_match('#O:[0-9]+:#',$response)){
			return false;
		}

		$data = hikashop_unserialize($response);

		$this->ip = $ip;
		$this->city = $data['geoplugin_city'];
		$this->regionName = $data['geoplugin_region'];
		$this->areaCode = $data['geoplugin_areaCode'];
		$this->dmaCode = $data['geoplugin_dmaCode'];
		$this->countryCode = $data['geoplugin_countryCode'];
		$this->countryName = $data['geoplugin_countryName'];
		$this->continentCode = $data['geoplugin_continentCode'];
		$this->latitude = $data['geoplugin_latitude'];
		$this->longitude = $data['geoplugin_longitude'];
		$this->currencyCode = $data['geoplugin_currencyCode'];
		$this->currencySymbol = $data['geoplugin_currencySymbol'];
		$this->currencyConverter =
$data['geoplugin_currencyConverter'];

	}

	function fetch($host) {

		if ( function_exists('curl_init') ) {

			$ch = curl_init();
			curl_setopt($ch, CURLOPT_URL, $host);
			curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
			curl_setopt($ch, CURLOPT_USERAGENT, 'geoPlugin PHP Class
v1.0');
			curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, $this->timeout);
			curl_setopt ($ch, CURLOPT_TIMEOUT, $this->timeout);
			$response = curl_exec($ch);
			curl_close ($ch);

		} else if ( ini_get('allow_url_fopen') ) {

			$response = file_get_contents($host, 'r');

		} else {

			trigger_error ('geoPlugin class Error: Cannot retrieve data. Either
compile PHP with cURL support or enable allow_url_fopen in php.ini ',
E_USER_ERROR);
			return;

		}

		return $response;
	}

	function convert($amount, $float=2, $symbol=true) {

		if ( !is_numeric($this->currencyConverter) ||
$this->currencyConverter == 0 ) {
			trigger_error('geoPlugin class Notice: currencyConverter has no
value.', E_USER_NOTICE);
			return $amount;
		}
		if ( !is_numeric($amount) ) {
			trigger_error ('geoPlugin class Warning: The amount passed to
geoPlugin::convert is not numeric.', E_USER_WARNING);
			return $amount;
		}
		if ( $symbol === true ) {
			return $this->currencySymbol . round( ($amount *
$this->currencyConverter), $float );
		} else {
			return round( ($amount * $this->currencyConverter), $float );
		}
	}


}

index.html000064400000000032151156426430006543
0ustar00<html><body></body></html>