Jump to content

OOP PHP: Where to put a "variable assigning" function


mtorbin

Recommended Posts

Quick question: why am I getting "syntax error, unexpected T_CLASS, expecting T_FUNCTION" errors from this:

 

<?php
abstract class TranslateXML {

}

class StatScheduleXML extends TranslateXML {
private $myXML;
public function __construct($type,$url) {
	switch($type) {
		case 'mlb':
			$myXML = new mblXML($url);
            	break;
		case 'nba':
			$myXML = new nbaXML($url);
            	break;
		case 'nfl':
			$myXML = new nflXML($url);
            	break;
		case 'nhl':
			$myXML = new nhlXML($url);
            	break;
}
}

class mlbXML extends StatScheduleXML {
public function __contstruct() {

}
}
?>

Link to comment
Share on other sites

Got it:

 

<?php
abstract class TranslateXML {

}

class StatScheduleXML extends TranslateXML {
private $myXML;
public function __construct($type,$url) {
	switch($type) {
		case 'mlb':
			$myXML = new mlbXML($url);
            	break;
		case 'nba':
			$myXML = new nbaXML($url);
            	break;
		case 'nfl':
			$myXML = new nflXML($url);
            	break;
		case 'nhl':
			$myXML = new nhlXML($url);
            	break;
	}
}
}

class mlbXML extends StatScheduleXML {
public function __contstruct() {

}
}
?>

 

Missing a curly.  Lunch always helps the brain. ;)  Back to writing this thing.

 

- MT

Link to comment
Share on other sites

Thanks again for all of you helping me through this learning curve.  Below is what I perceive to be a good start towards a much better (and to Nightslyr's point, a better "smelling") class file.  Please give me your thoughts and criticisms:

 

<?php
abstract class TranslateXML {
function setEventVars($myOBJ,$myCount) {
	$tempOBJ					= new Object();
	$tempOBJ->myGameID			= $myOBJ[$myCount]->getGameID();
	$tempOBJ->myHomeTeamName 	= $myOBJ[$myCount]->getTeamName('home');
	$tempOBJ->myHomeTeamCity	= $myOBJ[$myCount]->getTeamCity('home');
	$tempOBJ->myVisitTeamName	= $myOBJ[$myCount]->getTeamName('visit');
	$tempOBJ->myVisitTeamCity	= $myOBJ[$myCount]->getTeamCity('visit');
	$tempOBJ->myGameDate		= $myOBJ[$myCount]->getGameDate();
	$tempOBJ->myGameTime		= $myOBJ[$myCount]->getGameTime();
	$tempOBJ->myVenueID			= $myOBJ[$myCount]->getVenueID();
	$tempOBJ->myPerfID			= $myOBJ[$myCount]->getPerfID();
	$tempOBJ->myGenre			= $myOBJ[$myCount]->getPcomGenre();
	return $tempOBJ;
}

function buildNode($myOBJ) {
	$tempData .= "\t<event>\n";
	$tempData = "\t\t<event_id>STATS" . $myOBJ->myGameID . "</event_id>\n";
	$tempData .= "\t\t<event_title>" . $myOBJ->myVisitTeamCity . ' ' . $myOBJ->myVisitTeamName . ' (away) vs. ' . $myOBJ->myHomeTeamCity . ' ' . $myOBJ->myHomeTeamName . " (home)</event_title>\n";
	$tempData .= "\t\t<perf_id>" . $myOBJ->myPerfID . "</perf_id>\n";
	$tempData .= "\t\t<addl_perfs></addl_perfs>\n";
	$tempData .= "\t\t<venue_id>" . $myOBJ->myVenueID . "</venue_id>\n";
	$tempData .= "\t\t<event_desc>" . $myOBJ->myVisitTeamCity . ' ' . $myOBJ->myVisitTeamName . ' (away) vs. ' . $myOBJ->myHomeTeamCity . ' ' . $myOBJ->myHomeTeamName . " (home) [" . $myOBJ->myGameDate . ' @' . $myOBJ->myGameTime .  "]</event_desc>\n";
	$tempData .= "\t\t<genres>\n";
	$tempData .= "\t\t\t<genre>" . $myOBJ->myGenre . "</genre>\n";
	$tempData .= "\t\t</genres>\n";
	$tempData .= "\t\t<showtimes></showtimes>\n";
	$tempData .= "\t\t<schedule>\n";
	$tempData .= "\t\t\t<performance date=\"" . $myOBJ->myGameDate . "\">" . $myOBJ->myGameTime . "</performance>\n";
	$tempData .= "\t\t</schedule>\n";
	$tempData .= "\t</event>\n";
	return $tempData;
}

function compareDates($myGameDate) {
	$currentYear = date('y');
	$currentMonth = date('m');
	$currentDay = date('d');
	$today = strtotime($currentMonth . "/" . $currentDay . "/20" . $currentYear);
	$myGameDate = strtotime($myGameDate);
	if($today <= $myGameDate) {return 'future';}
	else {return 'past';}
}
}

class StatScheduleXML extends TranslateXML {
private $myXML;
public function __construct($type,$url) {
	switch($type) {
		case 'mlb':
			include 'class/class.MlbSchedule.php';
			$this->myXML = new mlbXML($url);
            	break;
		case 'nba':
			include 'class/class.NbaSchedule.php';
			$this->myXML = new nbaXML($url);
            	break;
		case 'nfl':
			include 'class/class.NflSchedule.php';
			$this->myXML = new nflXML($url);
            	break;
		case 'nhl':
			include 'class/class.NhlSchedule.php';
			$this->myXML = new nhlXML($url);
            	break;
	}
}
}

class mlbXML extends StatScheduleXML {
public function __construct($url) {
	$data			= simplexml_load_file($url);
	$counter		= 0;
	$mlbEvents		= Array();
	$scheduleXML	= "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<events>\n";

	foreach($data->{'sports-schedule'}->{'baseball-mlb-schedule'}->{'game-schedule'} as $schedule) {
		$scheduleOBJ 			= new MlbSchedule($schedule,$data);
		$mlbEvents[$counter]	= $scheduleOBJ;

		if(($this->compareDates($sportSchedules[$counter]->getGameDate()) == 'future')&&(($sportSchedules[$counter]->getTeamName('home') == "Phillies")||($sportSchedules[$counter]->getTeamName('visit') == "Phillies"))) {
			$currentOBJ = setEventVars($mlbEvents,$counter);
			$this->scheduleXML	.= $this->buildNode($currentOBJ);
		}
		$counter++;
	}
	$scheduleXML .= "</events>\n";
}
}
?>

 

- MT

Link to comment
Share on other sites

PLEASE IGNORE THE ABOVE POST:

 

Here is the new code that I was able to get to work properly:

 

<?php
abstract class TranslateXML {
function setEventVars($myOBJ,$myCount) {
	$tempOBJ;
	$tempOBJ->myGameID			= $myOBJ[$myCount]->getGameID();
	$tempOBJ->myHomeTeamName 	= $myOBJ[$myCount]->getTeamName('home');
	$tempOBJ->myHomeTeamCity	= $myOBJ[$myCount]->getTeamCity('home');
	$tempOBJ->myVisitTeamName	= $myOBJ[$myCount]->getTeamName('visit');
	$tempOBJ->myVisitTeamCity	= $myOBJ[$myCount]->getTeamCity('visit');
	$tempOBJ->myGameDate		= $myOBJ[$myCount]->getGameDate();
	$tempOBJ->myGameTime		= $myOBJ[$myCount]->getGameTime();
	$tempOBJ->myVenueID			= $myOBJ[$myCount]->getVenueID();
	$tempOBJ->myPerfID			= $myOBJ[$myCount]->getPerfID();
	$tempOBJ->myGenre			= $myOBJ[$myCount]->getPcomGenre();
	return $tempOBJ;
}

function buildNode($myOBJ) {
	$tempData .= "\t<event>\n";
	$tempData = "\t\t<event_id>STATS" . $myOBJ->myGameID . "</event_id>\n";
	$tempData .= "\t\t<event_title>" . $myOBJ->myVisitTeamCity . ' ' . $myOBJ->myVisitTeamName . ' (away) vs. ' . $myOBJ->myHomeTeamCity . ' ' . $myOBJ->myHomeTeamName . " (home)</event_title>\n";
	$tempData .= "\t\t<perf_id>" . $myOBJ->myPerfID . "</perf_id>\n";
	$tempData .= "\t\t<addl_perfs></addl_perfs>\n";
	$tempData .= "\t\t<venue_id>" . $myOBJ->myVenueID . "</venue_id>\n";
	$tempData .= "\t\t<event_desc>" . $myOBJ->myVisitTeamCity . ' ' . $myOBJ->myVisitTeamName . ' (away) vs. ' . $myOBJ->myHomeTeamCity . ' ' . $myOBJ->myHomeTeamName . " (home) [" . $myOBJ->myGameDate . ' @' . $myOBJ->myGameTime .  "]</event_desc>\n";
	$tempData .= "\t\t<genres>\n";
	$tempData .= "\t\t\t<genre>" . $myOBJ->myGenre . "</genre>\n";
	$tempData .= "\t\t</genres>\n";
	$tempData .= "\t\t<showtimes></showtimes>\n";
	$tempData .= "\t\t<schedule>\n";
	$tempData .= "\t\t\t<performance date=\"" . $myOBJ->myGameDate . "\">" . $myOBJ->myGameTime . "</performance>\n";
	$tempData .= "\t\t</schedule>\n";
	$tempData .= "\t</event>\n";
	return $tempData;
}

function compareDates($myGameDate) {
	$currentYear = date('y');
	$currentMonth = date('m');
	$currentDay = date('d');
	$today = strtotime($currentMonth . "/" . $currentDay . "/20" . $currentYear);
	$myGameDate = strtotime($myGameDate);
	if($today <= $myGameDate) {return 'future';}
	else {return 'past';}
}
}

class StatScheduleXML extends TranslateXML {
private $myXML;
public function __construct($type,$url) {
	switch($type) {
		case 'mlb':
			include 'class/class.MlbSchedule.php';
			$this->myXML = new mlbXML($url);
            	break;
		case 'nba':
			include 'class/class.NbaSchedule.php';
			$this->myXML = new nbaXML($url);
            	break;
		case 'nfl':
			include 'class/class.NflSchedule.php';
			$this->myXML = new nflXML($url);
            	break;
		case 'nhl':
			include 'class/class.NhlSchedule.php';
			$this->myXML = new nhlXML($url);
            	break;
	}
}
function getNewXml() {return $this->myXML->getScheduleXml();}
}

class mlbXML extends StatScheduleXML {
public function __construct($url) {
	$data				= simplexml_load_file($url);
	$counter			= 0;
	$mlbEvents			= Array();
	$this->scheduleXML	= "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<events>\n";

	foreach($data->{'sports-schedule'}->{'baseball-mlb-schedule'}->{'game-schedule'} as $schedule) {
		$scheduleOBJ 			= new MlbSchedule($schedule,$data);
		$mlbEvents[$counter]	= $scheduleOBJ;
		if(($this->compareDates($mlbEvents[$counter]->getGameDate()) == 'future')&&(($mlbEvents[$counter]->getTeamName('home') == "Phillies")||($mlbEvents[$counter]->getTeamName('visit') == "Phillies"))) {
			$currentOBJ = $this->setEventVars($mlbEvents,$counter);
			$this->scheduleXML	.= $this->buildNode($currentOBJ);
		}
		$counter++;
	}
	$this->scheduleXML .= "</events>\n";
}

function getScheduleXml() {
	return $this->scheduleXML;
}
}
?>

Link to comment
Share on other sites

That first function inside of TranslateXML (setEventVars) gives me the following errors:

 

Fatal error: Class 'object' not found

 

Googling this just returns a bunch of error pages.  Any suggestions?

 

The following line:

$tempOBJ = new Object();

 

Isn't doing what you think it is.  PHP isn't like JavaScript - you can't create a generic object, then populate it.  PHP interprets this line as you attempting to create a new object of type Object.  It's throwing an error because no such data type exists, as there is no class named 'Object' in your system.

 

Also, your system is becoming a bit circular with the way you have it now.  You don't need to create a temporary object that's only going to be discarded after the function ends.  It's simpler to stuff these results in an array.

 

Finally, with abstract classes, you can have data members.  So, you can have something like:

abstract class TranslateXML
{
   protected $eventResults;

   public function setEventVars($obj, $count)
   {
      $this->eventResults['myGameID'] = $obj[$count]->getGameID();
      $this->eventResults['myHomeTeamName'] = $obj[$count]->getTeamName('home');
      $this->eventResults['myHomeTeamCity'] = $obj[$count]->getTeamCity('home');
      $this->eventResults['myVisitTeamName'] = $obj[$count]->getTeamName('visit');
      $this->eventResults['myVisitTeamCity'] = $obj[$count]->getTeamCity('visit');
      $this->eventResults['myGameDate'] = $obj[$count]->getGameDate();
      $this->eventResults['myGameTime'] = $obj[$count]->getGameTime();
      $this->eventResults['myVenueID'] = $obj[$count]->getVenueID();
      $this->eventResults['myPerfID'] = $obj[$count]->getPerfID();
      $this->eventResults['myGenre'] = $obj[$count]->getPcomGenre();

      return $this->eventResults;
   }
}

 

You should be able to access the data just as easly.

 

This brings me to encapsulation.  I've noticed that you like to keep data members public.  This is actually a bad idea, as this means they can be overwritten/modified/deleted at any time.  This, in turn, pretty much negates the entire point of doing OOP, as objects are supposed to be used like black boxes...their internals shouldn't be exposed for them to be able to work.  The general rule of thumb is to give data members only as much access to the public world that they need to function, and nothing more.  This generally means that data members declared in the parent classes are protected, and everything else is private.  Public get/set functions are then used to modify those protected/private values.

 

It's a bit of a pain in the butt, but a necessary one, especially if you write code that could be used by other sources within your project.  It's better to be safe than wonder why values are mysteriously changing.

Link to comment
Share on other sites

This brings me to encapsulation.  I've noticed that you like to keep data members public.  This is actually a bad idea, as this means they can be overwritten/modified/deleted at any time.  This, in turn, pretty much negates the entire point of doing OOP, as objects are supposed to be used like black boxes...their internals shouldn't be exposed for them to be able to work.  The general rule of thumb is to give data members only as much access to the public world that they need to function, and nothing more.  This generally means that data members declared in the parent classes are protected, and everything else is private.  Public get/set functions are then used to modify those protected/private values.

 

It's a bit of a pain in the butt, but a necessary one, especially if you write code that could be used by other sources within your project.  It's better to be safe than wonder why values are mysteriously changing.

 

OK, so I'm going through and making the suggested changes.  In reference to your protected/private/public comment, we're talking about variables, right?  In other words, all of my variables that are not in the abstract class should be declared private, yes?

 

- MT

Link to comment
Share on other sites

This brings me to encapsulation.  I've noticed that you like to keep data members public.  This is actually a bad idea, as this means they can be overwritten/modified/deleted at any time.  This, in turn, pretty much negates the entire point of doing OOP, as objects are supposed to be used like black boxes...their internals shouldn't be exposed for them to be able to work.  The general rule of thumb is to give data members only as much access to the public world that they need to function, and nothing more.  This generally means that data members declared in the parent classes are protected, and everything else is private.  Public get/set functions are then used to modify those protected/private values.

 

It's a bit of a pain in the butt, but a necessary one, especially if you write code that could be used by other sources within your project.  It's better to be safe than wonder why values are mysteriously changing.

 

OK, so I'm going through and making the suggested changes.  In reference to your protected/private/public comment, we're talking about variables, right?  In other words, all of my variables that are not in the abstract class should be declared private, yes?

 

- MT

 

Pretty much.  Like I said before, those that are in parent class(es...whether or not they're abstract) should be protected.  This will ensure that inheritance works and they're passed down to their children.  The rest should be private.  In all cases, public accessor functions (get/set functions) should be used to modify or retrieve their values.

Link to comment
Share on other sites

Ok, so I think I'm good now.  I've addressed the object vs. array issue, I believe I've addressed the public/private/protected issue.  The circular logic issue is one that I didn't quite understand.  Could you explain?  I've tested the code below and it definitely works.

 

<?php
abstract class TranslateXML {
protected $eventData,$eventXML,$currentYear,$currentMonth,$currentDay,$today;
function setEventVars($myOBJ,$myCount) {
	$this->eventData['myGameID']		= $myOBJ[$myCount]->getGameID();
	$this->eventData['myHomeTeamName'] 	= $myOBJ[$myCount]->getTeamName('home');
	$this->eventData['myHomeTeamCity']	= $myOBJ[$myCount]->getTeamCity('home');
	$this->eventData['myVisitTeamName']	= $myOBJ[$myCount]->getTeamName('visit');
	$this->eventData['myVisitTeamCity']	= $myOBJ[$myCount]->getTeamCity('visit');
	$this->eventData['myGameDate']		= $myOBJ[$myCount]->getGameDate();
	$this->eventData['myGameTime']		= $myOBJ[$myCount]->getGameTime();
	$this->eventData['myVenueID']		= $myOBJ[$myCount]->getVenueID();
	$this->eventData['myPerfID']		= $myOBJ[$myCount]->getPerfID();
	$this->eventData['myGenre']			= $myOBJ[$myCount]->getPcomGenre();
	return $this->eventData;
}

function buildNode($myEvent) {
	$eventXML .= "\t<event>\n";
	$eventXML = "\t\t<event_id>STATS" . $myEvent['myGameID'] . "</event_id>\n";
	$eventXML .= "\t\t<event_title>" . $myEvent['myVisitTeamCity'] . ' ' . $myEvent['myVisitTeamName'] . ' (away) vs. ' . $myEvent['myHomeTeamCity'] . ' ' . $myEvent['myHomeTeamName'] . " (home)</event_title>\n";
	$eventXML .= "\t\t<perf_id>" . $myEvent['myPerfID'] . "</perf_id>\n";
	$eventXML .= "\t\t<addl_perfs></addl_perfs>\n";
	$eventXML .= "\t\t<venue_id>" . $myEvent['myVenueID'] . "</venue_id>\n";
	$eventXML .= "\t\t<event_desc>" . $myEvent['myVisitTeamCity'] . ' ' . $myEvent['myVisitTeamName'] . ' (away) vs. ' . $myEvent['myHomeTeamCity'] . ' ' . $myEvent['myHomeTeamName'] . " (home) [" . $myEvent['myGameDate'] . ' @' . $myEvent['myGameTime'] .  "]</event_desc>\n";
	$eventXML .= "\t\t<genres>\n";
	$eventXML .= "\t\t\t<genre>" . $myEvent['myGenre'] . "</genre>\n";
	$eventXML .= "\t\t</genres>\n";
	$eventXML .= "\t\t<showtimes></showtimes>\n";
	$eventXML .= "\t\t<schedule>\n";
	$eventXML .= "\t\t\t<performance date=\"" . $myEvent['myGameDate'] . "\">" . $myEvent['myGameTime'] . "</performance>\n";
	$eventXML .= "\t\t</schedule>\n";
	$eventXML .= "\t</event>\n";
	return $eventXML;
}

function compareDates($myGameDate) {
	$currentYear = date('y');
	$currentMonth = date('m');
	$currentDay = date('d');
	$today = strtotime($currentMonth . "/" . $currentDay . "/20" . $currentYear);
	$myGameDate = strtotime($myGameDate);
	if($today <= $myGameDate) {return 'future';}
	else {return 'past';}
}
}

class StatScheduleXML extends TranslateXML {
private $myXML;
public function __construct($type,$url) {
	switch($type) {
		case 'mlb':
			include 'class/class.MlbSchedule.php';
			$this->myXML = new mlbXML($url);
            	break;
		case 'nba':
			include 'class/class.NbaSchedule.php';
			$this->myXML = new nbaXML($url);
            	break;
		case 'nfl':
			include 'class/class.NflSchedule.php';
			$this->myXML = new nflXML($url);
            	break;
		case 'nhl':
			include 'class/class.NhlSchedule.php';
			$this->myXML = new nhlXML($url);
            	break;
	}
}
function getNewXml() {return $this->myXML->getScheduleXml();}
}

class mlbXML extends StatScheduleXML {
public function __construct($url) {
	$data				= simplexml_load_file($url);
	$counter			= 0;
	$mlbEvents			= Array();
	$this->scheduleXML	= "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<events>\n";

	foreach($data->{'sports-schedule'}->{'baseball-mlb-schedule'}->{'game-schedule'} as $schedule) {
		$scheduleOBJ 			= new MlbSchedule($schedule,$data);
		$mlbEvents[$counter]	= $scheduleOBJ;
		if(($this->compareDates($mlbEvents[$counter]->getGameDate()) == 'future')&&(($mlbEvents[$counter]->getTeamName('home') == "Phillies")||($mlbEvents[$counter]->getTeamName('visit') == "Phillies"))) {
			$currentOBJ = $this->setEventVars($mlbEvents,$counter);
			$this->scheduleXML	.= $this->buildNode($currentOBJ);
		}
		$counter++;
	}
	$this->scheduleXML .= "</events>\n";
}

function getScheduleXml() {
	return $this->scheduleXML;
}
}

class nbaXML extends StatScheduleXML {
public function __construct($url) {
	$data				= simplexml_load_file($url);
	$counter			= 0;
	$nbaEvents			= Array();
	$this->scheduleXML	= "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<events>\n";

	foreach($data->{'sports-schedule'}->{'nba-schedule'}->{'game-schedule'} as $schedule) {
		$scheduleOBJ 			= new nbaSchedule($schedule,$data);
		$nbaEvents[$counter]	= $scheduleOBJ;
		if(($this->compareDates($nbaEvents[$counter]->getGameDate()) == 'future')&&(($nbaEvents[$counter]->getTeamName('home') == "76ers")||($nbaEvents[$counter]->getTeamName('visit') == "76ers"))) {
			$currentOBJ = $this->setEventVars($nbaEvents,$counter);
			$this->scheduleXML	.= $this->buildNode($currentOBJ);
		}
		$counter++;
	}
	$this->scheduleXML .= "</events>\n";
}

function getScheduleXml() {
	return $this->scheduleXML;
}
}

class nflXML extends StatScheduleXML {
public function __construct($url) {
	$data				= simplexml_load_file($url);
	$counter			= 0;
	$nflEvents			= Array();
	$this->scheduleXML	= "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<events>\n";

	foreach($data->{'sports-schedule'}->{'football-nfl-schedule'}->{'game-schedule'} as $schedule) {
		$scheduleOBJ 			= new nflSchedule($schedule,$data);
		$nflEvents[$counter]	= $scheduleOBJ;
		if(($this->compareDates($nflEvents[$counter]->getGameDate()) == 'future')&&(($nflEvents[$counter]->getTeamName('home') == "Eagles")||($nflEvents[$counter]->getTeamName('visit') == "Eagles"))) {
			$currentOBJ = $this->setEventVars($nflEvents,$counter);
			$this->scheduleXML	.= $this->buildNode($currentOBJ);
		}
		$counter++;
	}
	$this->scheduleXML .= "</events>\n";
}

function getScheduleXml() {
	return $this->scheduleXML;
}
}

class nhlXML extends StatScheduleXML {
public function __construct($url) {
	$data				= simplexml_load_file($url);
	$counter			= 0;
	$nhlEvents			= Array();
	$this->scheduleXML	= "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<events>\n";

	foreach($data->{'sports-schedule'}->{'hockey-nhl-schedule'}->{'game-schedule'} as $schedule) {
		$scheduleOBJ 			= new nhlSchedule($schedule,$data);
		$nhlEvents[$counter]	= $scheduleOBJ;
		if(($this->compareDates($nhlEvents[$counter]->getGameDate()) == 'future')&&(($nhlEvents[$counter]->getTeamName('home') == "Flyers")||($nhlEvents[$counter]->getTeamName('visit') == "Flyers"))) {
			$currentOBJ = $this->setEventVars($nhlEvents,$counter);
			$this->scheduleXML	.= $this->buildNode($currentOBJ);
		}
		$counter++;
	}
	$this->scheduleXML .= "</events>\n";
}

function getScheduleXml() {
	return $this->scheduleXML;
}
}
?>

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.