2015-01-21 20:37:25 +01:00
|
|
|
<?php
|
2017-03-26 19:44:55 +02:00
|
|
|
|
2015-01-21 20:37:25 +01:00
|
|
|
namespace ManiaControl\ManiaExchange;
|
|
|
|
|
2017-03-29 19:54:50 +02:00
|
|
|
use ManiaControl\Files\AsyncHttpRequest;
|
2017-03-26 19:44:55 +02:00
|
|
|
use ManiaControl\General\UsageInformationAble;
|
|
|
|
use ManiaControl\General\UsageInformationTrait;
|
2015-01-21 20:37:25 +01:00
|
|
|
use ManiaControl\ManiaControl;
|
|
|
|
use Maniaplanet\DedicatedServer\Xmlrpc\GameModeException;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Mania Exchange Map Searching Class
|
|
|
|
*
|
|
|
|
* @author ManiaControl Team <mail@maniacontrol.com>
|
2017-02-04 11:49:23 +01:00
|
|
|
* @copyright 2014-2017 ManiaControl Team
|
2015-01-21 20:37:25 +01:00
|
|
|
* @license http://www.gnu.org/licenses/ GNU General Public License, Version 3
|
|
|
|
*/
|
2017-03-26 19:44:55 +02:00
|
|
|
class ManiaExchangeMapSearch implements UsageInformationAble {
|
|
|
|
use UsageInformationTrait;
|
2017-03-29 19:54:50 +02:00
|
|
|
|
2015-11-16 22:07:06 +01:00
|
|
|
//Search orders (prior parameter) https://api.mania-exchange.com/documents/enums#orderings
|
2015-01-21 20:37:25 +01:00
|
|
|
const SEARCH_ORDER_NONE = -1;
|
|
|
|
const SEARCH_ORDER_TRACK_NAME = 0;
|
|
|
|
const SEARCH_ORDER_AUTHOR = 1;
|
|
|
|
const SEARCH_ORDER_UPLOADED_NEWEST = 2;
|
|
|
|
const SEARCH_ORDER_UPLOADED_OLDEST = 3;
|
|
|
|
const SEARCH_ORDER_UPDATED_NEWEST = 4;
|
|
|
|
const SEARCH_ORDER_UPDATED_OLDEST = 5;
|
|
|
|
const SEARCH_ORDER_ACTIVITY_LATEST = 6;
|
|
|
|
const SEARCH_ORDER_ACTIVITY_OLDEST = 7;
|
|
|
|
const SEARCH_ORDER_AWARDS_MOST = 8;
|
|
|
|
const SEARCH_ORDER_AWARDS_LEAST = 9;
|
|
|
|
const SEARCH_ORDER_COMMENTS_MOST = 10;
|
|
|
|
const SEARCH_ORDER_COMMENTS_LEAST = 11;
|
|
|
|
const SEARCH_ORDER_DIFFICULTY_EASIEST = 12;
|
|
|
|
const SEARCH_ORDER_DIFFICULTY_HARDEST = 13;
|
|
|
|
const SEARCH_ORDER_LENGTH_SHORTEST = 14;
|
|
|
|
const SEARCH_ORDER_LENGTH_LONGEST = 15;
|
|
|
|
const SEARCH_ORDER_TRACK_VALUE_LTH = 24;
|
|
|
|
const SEARCH_ORDER_TRACK_VALUE_HTL = 25;
|
|
|
|
const SEARCH_ORDER_ONLINE_RATING_LTH = 26;
|
|
|
|
const SEARCH_ORDER_ONLINE_RATING_HTL = 27;
|
|
|
|
|
2015-11-16 22:07:06 +01:00
|
|
|
//Special Search Orders (mode parameter): https://api.mania-exchange.com/documents/enums#modes
|
2015-01-21 20:37:25 +01:00
|
|
|
const SEARCH_ORDER_SPECIAL_DEFAULT = 0;
|
|
|
|
const SEARCH_ORDER_SPECIAL_USER_TRACKS = 1;
|
|
|
|
const SEARCH_ORDER_SPECIAL_LATEST_TRACKS = 2;
|
|
|
|
const SEARCH_ORDER_SPECIAL_RECENTLY_AWARDED = 3;
|
|
|
|
const SEARCH_ORDER_SPECIAL_BEST_OF_WEEK_AWARDS = 4;
|
|
|
|
const SEARCH_ORDER_SPECIAL_BEST_OF_MONTH_AWARDS = 5;
|
|
|
|
const SEARCH_ORDER_SPECIAL_MX_SUPPORTER_TRACKS = 10;
|
|
|
|
const SEARCH_ORDER_SPECIAL_DUO_ACCOUNT_TRACKS = 11;
|
|
|
|
const SEARCH_ORDER_SPECIAL_MOST_COMPETITIVE_WEEK = 19;
|
|
|
|
const SEARCH_ORDER_SPECIAL_MOST_COMPETITIVE_MONTH = 20;
|
|
|
|
const SEARCH_ORDER_SPECIAL_BEST_ONLINE_RATING_WEEK = 21;
|
|
|
|
const SEARCH_ORDER_SPECIAL_BEST_ONLINE_RATING_MONTH = 22;
|
|
|
|
|
|
|
|
//Private Properties
|
2015-01-21 20:59:24 +01:00
|
|
|
private $url = "";
|
|
|
|
private $titlePrefix = "";
|
2015-01-21 20:37:25 +01:00
|
|
|
|
|
|
|
private $mode = null;
|
2015-01-21 21:26:48 +01:00
|
|
|
private $mapName = null;
|
2015-01-21 20:37:25 +01:00
|
|
|
private $authorName = null;
|
|
|
|
private $mod = null;
|
|
|
|
private $authorId = null;
|
|
|
|
private $maniaScriptType = null;
|
|
|
|
private $titlePack = null;
|
|
|
|
private $replayType = null;
|
|
|
|
private $style = null;
|
|
|
|
private $length = null;
|
|
|
|
private $lengthOperator = null;
|
|
|
|
private $priorityOrder = null;
|
|
|
|
private $secondaryOrder = null;
|
|
|
|
private $environments = null;
|
|
|
|
private $vehicles = null;
|
|
|
|
private $page = null;
|
2015-01-21 21:26:48 +01:00
|
|
|
private $mapLimit = null;
|
2015-01-21 20:37:25 +01:00
|
|
|
private $unreleased = null;
|
|
|
|
private $mapGroup = null;
|
|
|
|
private $commentsMinLength = null;
|
|
|
|
private $customScreenshot = null;
|
|
|
|
private $minExeBuild = null;
|
|
|
|
private $envMix = null;
|
|
|
|
private $ghostBlocks = null;
|
|
|
|
private $embeddedObjects = null;
|
2017-03-29 19:54:50 +02:00
|
|
|
private $key = null;
|
2015-01-21 20:37:25 +01:00
|
|
|
|
|
|
|
/** @var ManiaControl $maniaControl */
|
|
|
|
private $maniaControl = null;
|
|
|
|
|
2015-01-21 21:26:48 +01:00
|
|
|
//TODO use class by mxlist
|
2015-01-21 20:59:24 +01:00
|
|
|
|
2015-01-21 20:37:25 +01:00
|
|
|
/**
|
|
|
|
* Construct map manager
|
|
|
|
*
|
|
|
|
* @param \ManiaControl\ManiaControl $maniaControl
|
|
|
|
*/
|
|
|
|
public function __construct(ManiaControl $maniaControl) {
|
|
|
|
$this->maniaControl = $maniaControl;
|
|
|
|
|
|
|
|
|
2015-01-21 20:59:24 +01:00
|
|
|
$titleId = $this->maniaControl->getServer()->titleId;
|
|
|
|
$this->titlePrefix = $this->maniaControl->getMapManager()->getCurrentMap()->getGame();
|
2015-01-21 20:37:25 +01:00
|
|
|
|
2015-11-06 16:23:53 +01:00
|
|
|
$this->url = 'https://' . $this->titlePrefix . '.mania-exchange.com/tracksearch2/search?api=on';
|
2015-01-21 20:37:25 +01:00
|
|
|
|
2017-03-29 19:54:50 +02:00
|
|
|
if ($key = $this->maniaControl->getSettingManager()->getSettingValue($this->maniaControl->getMapManager()->getMXManager(), ManiaExchangeManager::SETTING_MX_KEY)) {
|
2017-03-06 19:03:09 +01:00
|
|
|
$this->url .= "&key=" . $key;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-01-21 20:37:25 +01:00
|
|
|
//Set some defaults:
|
2015-07-23 13:09:16 +02:00
|
|
|
$this->mapLimit = 100;
|
2015-01-21 20:59:24 +01:00
|
|
|
$this->priorityOrder = self::SEARCH_ORDER_UPDATED_NEWEST;
|
|
|
|
|
2015-01-21 20:37:25 +01:00
|
|
|
//Set Min Exe Build Default for games which are not Trackmania
|
2015-01-21 20:59:24 +01:00
|
|
|
if ($this->titlePrefix !== "tm") {
|
2015-01-21 20:37:25 +01:00
|
|
|
$this->minExeBuild = ManiaExchangeManager::MIN_EXE_BUILD;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Set MapTypes
|
|
|
|
try {
|
|
|
|
$scriptInfos = $this->maniaControl->getClient()->getModeScriptInfo();
|
|
|
|
$mapTypes = $scriptInfos->compatibleMapTypes;
|
|
|
|
$this->maniaScriptType = $mapTypes;
|
|
|
|
} catch (GameModeException $e) {
|
|
|
|
}
|
|
|
|
|
|
|
|
//Set Environments on Trackmania
|
|
|
|
$game = explode('@', $titleId);
|
|
|
|
$envNumber = $this->getEnvironment($game[0]); //TODO enviroment as constant
|
|
|
|
if ($envNumber > -1) {
|
|
|
|
$this->environments = $envNumber;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Fetch a MapList Asynchronously
|
|
|
|
*
|
|
|
|
* @param callable $function
|
|
|
|
*/
|
|
|
|
public function fetchMapsAsync(callable $function) {
|
|
|
|
// compile search URL
|
|
|
|
$parameters = "";
|
|
|
|
|
2015-01-21 20:59:24 +01:00
|
|
|
if ($this->mode) {
|
|
|
|
$parameters .= "&mode=" . $this->mode;
|
|
|
|
}
|
2015-01-21 21:26:48 +01:00
|
|
|
if ($this->mapName) {
|
|
|
|
$parameters .= "&trackname=" . urlencode($this->mapName);
|
2015-01-21 20:59:24 +01:00
|
|
|
}
|
|
|
|
if ($this->authorName) {
|
2015-01-21 21:26:48 +01:00
|
|
|
$parameters .= "&author=" . urlencode($this->authorName);
|
2015-01-21 20:59:24 +01:00
|
|
|
}
|
|
|
|
if ($this->mod) {
|
2015-01-21 21:26:48 +01:00
|
|
|
$parameters .= "&mod=" . urlencode($this->mod);
|
2015-01-21 20:59:24 +01:00
|
|
|
}
|
|
|
|
if ($this->authorId) {
|
|
|
|
$parameters .= "&authorid= " . $this->authorId;
|
|
|
|
}
|
|
|
|
if ($this->maniaScriptType) {
|
2015-01-21 21:26:48 +01:00
|
|
|
$parameters .= "&mtype=" . urlencode($this->maniaScriptType);
|
2015-01-21 20:59:24 +01:00
|
|
|
}
|
|
|
|
if ($this->titlePack) {
|
2015-01-21 21:26:48 +01:00
|
|
|
$parameters .= "&tpack=" . urlencode($this->titlePack);
|
2015-01-21 20:59:24 +01:00
|
|
|
}
|
|
|
|
if ($this->replayType) {
|
|
|
|
$parameters .= "&rytpe=" . $this->replayType;
|
|
|
|
}
|
|
|
|
if ($this->style) {
|
|
|
|
$parameters .= "&style=" . $this->style;
|
|
|
|
}
|
|
|
|
if ($this->length) {
|
|
|
|
$parameters .= "&length=" . $this->length;
|
|
|
|
}
|
|
|
|
if ($this->lengthOperator) {
|
|
|
|
$parameters .= "&lengthop=" . $this->lengthOperator;
|
|
|
|
}
|
|
|
|
if ($this->priorityOrder) {
|
|
|
|
$parameters .= "&priord=" . $this->priorityOrder;
|
|
|
|
}
|
|
|
|
if ($this->secondaryOrder) {
|
|
|
|
$parameters .= "&secord=" . $this->secondaryOrder;
|
|
|
|
}
|
|
|
|
if ($this->environments) {
|
|
|
|
$parameters .= "&environemtns=" . $this->environments;
|
|
|
|
}
|
|
|
|
if ($this->vehicles) {
|
|
|
|
$parameters .= "&vehicles=" . $this->vehicles;
|
|
|
|
}
|
|
|
|
if ($this->page) {
|
|
|
|
$parameters .= "&page=" . $this->page;
|
|
|
|
}
|
2015-01-21 21:26:48 +01:00
|
|
|
if ($this->mapLimit) {
|
|
|
|
$parameters .= "&limit=" . $this->mapLimit;
|
2015-01-21 20:59:24 +01:00
|
|
|
}
|
|
|
|
if (isset($this->unreleased)) {
|
2015-01-21 21:26:48 +01:00
|
|
|
$parameters .= "&unreleased=" . (int) $this->unreleased;
|
2015-01-21 20:59:24 +01:00
|
|
|
}
|
|
|
|
if ($this->mapGroup) {
|
|
|
|
$parameters .= "&mapgroup=" . $this->mapGroup;
|
|
|
|
}
|
|
|
|
if ($this->commentsMinLength) {
|
|
|
|
$parameters .= "&commentsminlength=" . $this->commentsMinLength;
|
|
|
|
}
|
|
|
|
if (isset($this->customScreenshot)) {
|
|
|
|
$parameters .= "&customscreenshot=" . $this->customScreenshot;
|
|
|
|
}
|
|
|
|
if ($this->minExeBuild) {
|
2015-01-21 21:26:48 +01:00
|
|
|
$parameters .= "&minexebuild=" . urlencode($this->minExeBuild);
|
2015-01-21 20:59:24 +01:00
|
|
|
}
|
|
|
|
if (isset($this->envMix)) {
|
|
|
|
$parameters .= "&envmix=" . (int) $this->envMix;
|
|
|
|
}
|
|
|
|
if (isset($this->ghostBlocks)) {
|
|
|
|
$parameters .= "&ghostblocks=" . (int) $this->ghostBlocks;
|
|
|
|
}
|
|
|
|
if (isset($this->embeddedObjects)) {
|
2015-01-21 21:02:48 +01:00
|
|
|
$parameters .= "&embeddedobjects=" . (int) $this->embeddedObjects;
|
2015-01-21 20:59:24 +01:00
|
|
|
}
|
2017-03-29 19:54:50 +02:00
|
|
|
if (isset($this->key)) {
|
|
|
|
$parameters .= "&key=" . $this->key;
|
|
|
|
}
|
2015-01-21 20:37:25 +01:00
|
|
|
|
2017-03-29 19:54:50 +02:00
|
|
|
$asyncHttpRequest = new AsyncHttpRequest($this->maniaControl, $this->url . $parameters);
|
|
|
|
$asyncHttpRequest->setContentType(AsyncHttpRequest::CONTENT_TYPE_JSON);
|
|
|
|
$asyncHttpRequest->setCallable(function ($mapInfo, $error) use (&$function) {
|
2015-01-21 20:37:25 +01:00
|
|
|
if ($error) {
|
|
|
|
trigger_error($error);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
$mxMapList = json_decode($mapInfo);
|
|
|
|
|
|
|
|
if (!isset($mxMapList->results)) {
|
|
|
|
trigger_error('Cannot decode searched JSON data');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
$mxMapList = $mxMapList->results;
|
2017-03-26 19:44:55 +02:00
|
|
|
|
2015-01-21 20:37:25 +01:00
|
|
|
if ($mxMapList === null) {
|
|
|
|
trigger_error('Cannot decode searched JSON data');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
$maps = array();
|
|
|
|
foreach ($mxMapList as $map) {
|
|
|
|
if (!empty($map)) {
|
2015-01-21 20:59:24 +01:00
|
|
|
array_push($maps, new MXMapInfo($this->titlePrefix, $map));
|
2015-01-21 20:37:25 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
call_user_func($function, $maps);
|
2017-03-29 19:54:50 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
$asyncHttpRequest->getData();
|
2015-01-21 20:37:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the Current Environment by String
|
|
|
|
*
|
|
|
|
* @param string $env
|
|
|
|
* @return int
|
|
|
|
*/
|
|
|
|
private function getEnvironment($env) {
|
|
|
|
switch ($env) {
|
|
|
|
case 'TMCanyon':
|
|
|
|
return 1;
|
|
|
|
case 'TMStadium':
|
|
|
|
return 2;
|
|
|
|
case 'TMValley':
|
|
|
|
return 3;
|
|
|
|
default:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param int $mode
|
|
|
|
*/
|
|
|
|
public function setMode($mode) {
|
|
|
|
$this->mode = $mode;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2015-01-21 21:26:48 +01:00
|
|
|
* @param string $mapName
|
2015-01-21 20:37:25 +01:00
|
|
|
*/
|
2015-01-21 21:26:48 +01:00
|
|
|
public function setMapName($mapName) {
|
|
|
|
$this->mapName = $mapName;
|
2015-01-21 20:37:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param string $authorName
|
|
|
|
*/
|
|
|
|
public function setAuthorName($authorName) {
|
|
|
|
$this->authorName = $authorName;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param int $authorId
|
|
|
|
*/
|
|
|
|
public function setAuthorId($authorId) {
|
|
|
|
$this->authorId = $authorId;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param string $maniaScriptType
|
|
|
|
*/
|
|
|
|
public function setManiaScriptType($maniaScriptType) {
|
|
|
|
$this->maniaScriptType = $maniaScriptType;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param string $mod
|
|
|
|
*/
|
|
|
|
public function setMod($mod) {
|
|
|
|
$this->mod = $mod;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param string $titlePack
|
|
|
|
*/
|
|
|
|
public function setTitlePack($titlePack) {
|
|
|
|
$this->titlePack = $titlePack;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param int $replayType
|
|
|
|
*/
|
|
|
|
public function setReplayType($replayType) {
|
|
|
|
$this->replayType = $replayType;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param int $length
|
|
|
|
*/
|
|
|
|
public function setLength($length) {
|
|
|
|
$this->length = $length;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param int $style
|
|
|
|
*/
|
|
|
|
public function setStyle($style) {
|
|
|
|
$this->style = $style;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param int $lengthOperator
|
|
|
|
*/
|
|
|
|
public function setLengthOperator($lengthOperator) {
|
|
|
|
$this->lengthOperator = $lengthOperator;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param int $secondaryOrder
|
|
|
|
*/
|
2015-01-21 21:26:48 +01:00
|
|
|
public function setSecondarySortOrder($secondaryOrder) {
|
2015-01-21 20:37:25 +01:00
|
|
|
$this->secondaryOrder = $secondaryOrder;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param int $priorityOrder
|
|
|
|
*/
|
2015-01-21 21:26:48 +01:00
|
|
|
public function setPrioritySortOrder($priorityOrder) {
|
2015-01-21 20:37:25 +01:00
|
|
|
$this->priorityOrder = $priorityOrder;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param string $environments
|
|
|
|
*/
|
|
|
|
public function setEnvironments($environments) {
|
|
|
|
$this->environments = $environments;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param int $page
|
|
|
|
*/
|
|
|
|
public function setPage($page) {
|
|
|
|
$this->page = $page;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param string $vehicles
|
|
|
|
*/
|
|
|
|
public function setVehicles($vehicles) {
|
|
|
|
$this->vehicles = $vehicles;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param bool $unreleased
|
|
|
|
*/
|
|
|
|
public function setUnreleased($unreleased) {
|
|
|
|
$this->unreleased = $unreleased;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param int $mapGroup
|
|
|
|
*/
|
|
|
|
public function setMapGroup($mapGroup) {
|
|
|
|
$this->mapGroup = $mapGroup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param int $commentsMinLength
|
|
|
|
*/
|
|
|
|
public function setCommentsMinLength($commentsMinLength) {
|
|
|
|
$this->commentsMinLength = $commentsMinLength;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param bool $customScreenshot
|
|
|
|
*/
|
|
|
|
public function setCustomScreenshot($customScreenshot) {
|
|
|
|
$this->customScreenshot = $customScreenshot;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param bool $envMix
|
|
|
|
*/
|
|
|
|
public function setEnvMix($envMix) {
|
|
|
|
$this->envMix = $envMix;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param string $minExeBuild
|
|
|
|
*/
|
|
|
|
public function setMinExeBuild($minExeBuild) {
|
|
|
|
$this->minExeBuild = $minExeBuild;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param bool $ghostBlocks
|
|
|
|
*/
|
|
|
|
public function setGhostBlocks($ghostBlocks) {
|
|
|
|
$this->ghostBlocks = $ghostBlocks;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param bool $embeddedObjects
|
|
|
|
*/
|
|
|
|
public function setEmbeddedObjects($embeddedObjects) {
|
|
|
|
$this->embeddedObjects = $embeddedObjects;
|
|
|
|
}
|
2015-01-21 21:26:48 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @param null $mapLimit
|
|
|
|
*/
|
|
|
|
public function setMapLimit($mapLimit) {
|
|
|
|
$this->mapLimit = $mapLimit;
|
|
|
|
}
|
2017-03-29 19:54:50 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @param null $key
|
|
|
|
*/
|
|
|
|
public function setKey($key) {
|
|
|
|
$this->key = $key;
|
|
|
|
}
|
2015-01-21 20:37:25 +01:00
|
|
|
}
|