Jump to content
Sign in to follow this  
jcvenom

PHP Frameworks

Recommended Posts

PHP Framework, it looks pretty good actually. I haven't used it but have been reading the docs on it.

I understand its a framework but what des it actually do and how do i use it? and do major games like TORN use it?

Share this post


Link to post
Share on other sites

I doubt a lot of "major games" use a framework like Laravel, CI, etc. I'm pretty sure these games were around before MVC was the new trend or popular and would take a massive rewrite to change it over

Share this post


Link to post
Share on other sites
I understand its a framework but what des it actually do and how do i use it? and do major games like TORN use it?

Like any framework, make your programming life a hell of a lot easier. Gives you functions etc so you dont have to program them, sets up your MVC system for you so you dont have to program that.

Its more about saving time on general logic that makes the website run and display the way you want allowing you to focus on building your application

Share this post


Link to post
Share on other sites
Like any framework, make your programming life a hell of a lot easier. Gives you functions etc so you dont have to program them, sets up your MVC system for you so you dont have to program that.

Its more about saving time on general logic that makes the website run and display the way you want allowing you to focus on building your application

functions like? and doesnt that mean your limited then function wise

Share this post


Link to post
Share on other sites
functions like? and doesnt that mean your limited then function wise

Most of the MVC apps (can't speak for laravel) come with a lot of useful tools like easy to use ORM/DB wrappers, HTML helpers, etc just to name a few. It lets you load what you need on the fly without auto loading everything, although you can auto load things that you use or need a lot. It also pretty much forces you to separate all your logic which makes it for a cleaner folder structure. And if you feel like you are limited then it's really easy to extend your class with the base class(es) to make what you actually need.

I I mainly use Codeigniter so here is a little snippet to set your whistle based on it:

Some_Model.php

<?php
class Some_model extends Ci_model {
   function __construct() {
       parent::construct();
   }
   function load_table($table) {
       $this->db->get($table);
       if ($this->db-num_rows()) {
           $get = $this-db->results();
           return 
       }
       else return false;
   }
}

My_Controller.php

<?php
class My_Controller extends CI_Controller {
   function __construct() {
       parent::__construct();
       $this-load->model("my_model","myModel");
   }
   public function show_view() {
       $data['name'] = $this->myModel->load_table('users');
       $this->load->view('view',$data);
   }
}

 

View.php

<?php
foreach ($name as $n) { 
   echo $n->name;
}

Share this post


Link to post
Share on other sites
Most of the MVC apps (can't speak for laravel) come with a lot of useful tools like easy to use ORM/DB wrappers, HTML helpers, etc just to name a few. It lets you load what you need on the fly without auto loading everything, although you can auto load things that you use or need a lot. It also pretty much forces you to separate all your logic which makes it for a cleaner folder structure. And if you feel like you are limited then it's really easy to extend your class with the base class(es) to make what you actually need.

I I mainly use Codeigniter so here is a little snippet to set your whistle based on it:

Some_Model.php

<?php
class Some_model extends Ci_model {
   function __construct() {
       parent::construct();
   }
   function load_table($table) {
       $this->db->get($table);
       if ($this->db-num_rows()) {
           $get = $this-db->results();
           return 
       }
       else return false;
   }
}

My_Controller.php

<?php
class My_Controller extends CI_Controller {
   function __construct() {
       parent::__construct();
       $this-load->model("my_model","myModel");
   }
   public function show_view() {
       $data['name'] = $this->myModel->load_table('users');
       $this->load->view('view',$data);
   }
}

 

View.php

<?php
foreach ($name as $n) { 
   echo $n->name;
}

Im so confused, because ive never use a framework or anything you stated

Share this post


Link to post
Share on other sites
Im so confused, because ive never use a framework or anything you stated

A very simple example not exactly a framework but a class EasyPHP, now imagine that but with loads more classes. That's known as a framework. So take the validate(); function in that class, normally you'd have to write all that code, but with a class (or framework) you can use the functions.

Share this post


Link to post
Share on other sites
Im so confused, because ive never use a framework or anything you stated

I think you should spend a week or two getting yourself up to date then. Frameworks and MVC are fast becoming the new standard for PHP/Web Development.

It doesn't limit you function wise because you can just add whatever ones then that you need by, like [MENTION=68711]KyleMassacre[/MENTION] said, extending the base class and adding your own functions to it.

Next up if you don't know what we're talking about when we say extending classes your going to want to do a bit of reading into OOP (Object Oriented Programming).

Share this post


Link to post
Share on other sites
Most of the MVC apps (can't speak for laravel) come with a lot of useful tools like easy to use ORM/DB wrappers, HTML helpers, etc just to name a few. It lets you load what you need on the fly without auto loading everything, although you can auto load things that you use or need a lot. It also pretty much forces you to separate all your logic which makes it for a cleaner folder structure. And if you feel like you are limited then it's really easy to extend your class with the base class(es) to make what you actually need.

Laravel is quite like this, but uses relies on namespaces (which is a good thing in my opinion). Obviously there are difference among the frameworks, I know this as I used to mess around with CodeIgniter!

Here's a controller which I'm currently working on at the moment.

 

<?php
namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Permission;
use Notification;
use Request;
use Validator;

class PermissionsController extends Controller
{

   /**
    * Display a listing of the resource.
    *
    * @return Response
    */
   public function index()
   {
       $permissions = Permission::paginate(10);
       return view('admin.permissions.index', compact('permissions'));
   }

   /**
    * Show the form for creating a new resource.
    *
    * @return Response
    */
   public function create()
   {
       return view('admin.permissions.create');
   }

   /**
    * Store a newly created resource in storage.
    *
    * @return Response
    */
   public function store()
   {
       $input = Request::all();

       $v = Validator::make($input, [
           'display_name' => 'required|unique:permissions|max:255',
           'description' => 'sometimes|required|max:255',
           'slug' => 'required|unique:permissions|min:10|max:255',
       ]);

       if ($v->fails()) {
           return redirect()->back()->withErrors($v->errors())->withInput();
       }

       Permission::create($input);

       Notification::success('You successfully created the ' . $input['display_name'] . ' permission.')
           ->glyphicon('ok-sign');
       return redirect('admin/permissions/create');
   }

}

Share this post


Link to post
Share on other sites

I get it hahahah, so i create functions with php functions inside and then call them noramally and use the like OOP? but then whats the difference with this and normal php function?

 

public static function validate($input, $type) {
       switch($type) {
           case "string":
               return is_string($input) ? $input : FALSE;
               break;
           case "int":
               return is_integer($input) ? $input : FALSE;
               break;
           case "float":
               return is_float($input) ? $input : FALSE;
               break;
           case "email":
               return filter_var($input, FILTER_VALIDATE_EMAIL) ? $input : FALSE;
               break;
           case "IP":
               return filter_var($input, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) ? $input : filter_var($input, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) ? $input : FALSE;
       }
   }

and

 

function validate($type,$input){
switch($type){
case 'string': ".$input."(); break;
and so on

}

 

}

Share this post


Link to post
Share on other sites

[MENTION=69823]jcvenom[/MENTION],

Its pretty easy actually. A model is basically your Database interactions, controllers Re like routes and connects your model with your view

using my example above, you would just navigate to your controller like yoursite.com/some_controller/show_view and it will do all the work for you by fetching your data and passing that data to your view.

Share this post


Link to post
Share on other sites
[MENTION=69823]jcvenom[/MENTION],

Its pretty easy actually. A model is basically your Database interactions, controllers Re like routes and connects your model with your view

using my example above, you would just navigate to your controller like yoursite.com/some_controller/show_view and it will do all the work for you by fetching your data and passing that data to your view.

im starting to understand but when you say fetch you could use the php include function

Share this post


Link to post
Share on other sites

[MENTION=69823]jcvenom[/MENTION] I think you're still thinking in a procedural format.

Consider a landing page for when a user logs in.

I'll show the difference between procedural and MVC very quickly, using what I know of CI lol.

 

Procedural being:


<?php

include "settings.php";
global $settings;
include "userdata.php";
global $user;

echo "
<html>
<head>
  <title>".$settings['game_title']."</title>
</head>
<body>
  Welcome back ".$user['username']."
</body>
</html>";

?>

 

Now MVC is different, assuming twig is also installed.

for that same page you will go through something like this:

controllers/landing.php

<?php
public class Landing extends CI_Controller {

  public function index(){
      $this->load->model("Game/landing");
      $this->twig->render("Game/LandingPage", $this->landing->getLoggedInUser());
  }

}
?>

 

models/Game/landing.php


<?php
public class landing extends CI_Model { // I generally create a new model class that checks the user is logged in and pulls the data from the database

  public function getLoggedInUser(){
      return $this->user; // user = array("id" => value_from_db, "username" => value_from_db);
  }

}
?>

 

views/Game/LandingPage.twig


{% extends Template/template.tpl %}  // this way you can have a consistent layout easily

{% block content %}

<h2>Welcome Back {{ username }} !</h2>

{% endblock %}

 

Now, your looking at that thinking, the hell, thats so much effort for one file.

Yeah kinda true, but it keeps everything clean. All your logic in one place. All your design in the other. The controller stitching the two together.

ie:

Controller

| Controller contacts model.

Model

| Model does logic and may return data

Controller

| Controller chooses which view to render

View

View may accept variables from the controller and use that to display certain information.

 

It may seem like overkill for the example I gave, but its brilliant for things like forums

Share this post


Link to post
Share on other sites

Twig???? Yuck

I create a controller like

class My_Controller extends CI_Controller {

var $template;

   function __construct() {
       parent::__construct();
       $this->template = 'path/to/myheader';
   }

}

 

No for my actual controllers:

class Some_Controller extends MY_Controller {

   function index() {
       $data['result'] = $this->transactions->getWithdrawRequests($status, $grouped);
       foreach ($data['result'] as $res) {
           if ($this->transactions->isInQueue($res->id))
               $this->isQueued[$res->id] = true;
           else
               $this->isQueued[$res->id] = false;
           }
       $data['javascripts'] = array('
           <script src="' . base_url() . 'theme_assets/admin/bower_components/datatables/media/js/jquery.dataTables.min.js"></script>',
           '<script src="' . base_url() . 'theme_assets/admin/bower_components/datatables-plugins/integration/bootstrap/3/dataTables.bootstrap.min.js"></script>',
           '<script src="' . base_url() . 'theme_assets/admin/bower_components/datatables-plugins/tabletools/tabletools.js"></script>',
           '<script src="' . base_url() . 'theme_assets/admin/js/bootbox.min.js"></script>'
       );
       $view_data['dynamic_extras'] = "$('button').attr('name','queue').on('click', function() {
                                       var button = $(this);
                                       var currentClass = $(button).attr('class');
                                       var wID = $(button).val();

                                       $.ajax({
                                           url: $(button).attr('href'),
                                           type: 'POST',
                                           success: function (data) {
                                           switch(currentClass) {
                                               case 'btn btn-danger':
                                                   var newClass = 'btn btn-success';
                                                   var contentName = 'Queue';
                                                   var newHref = '" . base_url('transactions/queue/') . "/'+wID;
                                               break;
                                               case 'btn btn-success':
                                                   var newClass = 'btn btn-danger';
                                                   var contentName = 'Un-Queue';
                                                   var newHref = '" . base_url('transactions/deQueue/') . "/'+wID;
                                               break;
                                           }
                                           $(button).attr({
                                               class: newClass,
                                               href: newHref
                                           });
                                           $(button).html(contentName);
                                           }
                                       });

                                   });
                                   $('button#pay_queue').on('click', function() {
                                       var button = $(this);
                                      $.ajax({
                                           url: $(button).attr('href'),
                                           type: 'POST',
                                           dataType: 'json',
                                           success: function (data) {
                                               var obj = data;
                                               if(obj.status == 'Success') {
                                                   bootbox.dialog({
                                                       message: 'Your payments have been processed.<br/>The total amount was $'+data.total,
                                                       title: 'Amazing Success',
                                                       buttons: {
                                                           success: {
                                                               label: 'Close',
                                                               className: 'btn btn-primary',
                                                               callback: function() {
                                                                   window.location.href = window.location.href
                                                               }
                                                           }
                                                       }
                                                   });
                                               }
                                               else {
                                                   bootbox.dialog({
                                                       message: 'Oh no. Something had to have gone wrong',
                                                       title: 'Son of a *****',
                                                       buttons: {
                                                           success: {
                                                               label: 'Close',
                                                               className: 'btn btn-danger',
                                                               callback: function() {
                                                                   window.location.href = window.location.href
                                                               }
                                                           }
                                                       }
                                                   });
                                               }
                                           }
                                       });
                                   });
                               ";
       $view_data['extra_head'] = "<link href='" . base_url() . "theme_assets/admin/bower_components/datatables-plugins/tabletools/tabletools.css' rel='stylesheet'>";

       $view_data['content'] = $this->load->view('withdraws/withdraws_requests', $data, true);

       $this->load->view($this->template, $view_data);    
   }

}

 

So in my header.php file I have things in there such as $content, $extra_head, $dynamic_extras, and $javascripts.

And yes, I know about the link_tag() lol I just never use it haha. I just recently started "really" using it so I am still learning as I go

Share this post


Link to post
Share on other sites

[MENTION=68711]KyleMassacre[/MENTION] twig was installed on MRPG when I bought it so I had to learn to use it and I kind of like it lol

Share this post


Link to post
Share on other sites
[MENTION=69823]jcvenom[/MENTION] I think you're still thinking in a procedural format.

Consider a landing page for when a user logs in.

I'll show the difference between procedural and MVC very quickly, using what I know of CI lol.

 

Procedural being:


<?php

include "settings.php";
global $settings;
include "userdata.php";
global $user;

echo "
<html>
<head>
  <title>".$settings['game_title']."</title>
</head>
<body>
  Welcome back ".$user['username']."
</body>
</html>";

?>

 

Now MVC is different, assuming twig is also installed.

for that same page you will go through something like this:

controllers/landing.php

<?php
public class Landing extends CI_Controller {

  public function index(){
      $this->load->model("Game/landing");
      $this->twig->render("Game/LandingPage", $this->landing->getLoggedInUser());
  }

}
?>

 

models/Game/landing.php


<?php
public class landing extends CI_Model { // I generally create a new model class that checks the user is logged in and pulls the data from the database

  public function getLoggedInUser(){
      return $this->user; // user = array("id" => value_from_db, "username" => value_from_db);
  }

}
?>

 

views/Game/LandingPage.twig


{% extends Template/template.tpl %}  // this way you can have a consistent layout easily

{% block content %}

<h2>Welcome Back {{ username }} !</h2>

{% endblock %}

 

Now, your looking at that thinking, the hell, thats so much effort for one file.

Yeah kinda true, but it keeps everything clean. All your logic in one place. All your design in the other. The controller stitching the two together.

ie:

Controller

| Controller contacts model.

Model

| Model does logic and may return data

Controller

| Controller chooses which view to render

View

View may accept variables from the controller and use that to display certain information.

 

It may seem like overkill for the example I gave, but its brilliant for things like forums

I actually understand this haha a controller fetechs the model and the model returns the logic stuff etc but does the controller or model have to be CI_Controller/CI_Model are can you change it to something Cws_Controller? once it has the Contoller at the end

Share this post


Link to post
Share on other sites
Twig???? Yuck

I create a controller like

class My_Controller extends CI_Controller {

var $template;

   function __construct() {
       parent::__construct();
       $this->template = 'path/to/myheader';
   }

}

 

No for my actual controllers:

class Some_Controller extends MY_Controller {

   function index() {
       $data['result'] = $this->transactions->getWithdrawRequests($status, $grouped);
       foreach ($data['result'] as $res) {
           if ($this->transactions->isInQueue($res->id))
               $this->isQueued[$res->id] = true;
           else
               $this->isQueued[$res->id] = false;
           }
       $data['javascripts'] = array('
           <script src="' . base_url() . 'theme_assets/admin/bower_components/datatables/media/js/jquery.dataTables.min.js"></script>',
           '<script src="' . base_url() . 'theme_assets/admin/bower_components/datatables-plugins/integration/bootstrap/3/dataTables.bootstrap.min.js"></script>',
           '<script src="' . base_url() . 'theme_assets/admin/bower_components/datatables-plugins/tabletools/tabletools.js"></script>',
           '<script src="' . base_url() . 'theme_assets/admin/js/bootbox.min.js"></script>'
       );
       $view_data['dynamic_extras'] = "$('button').attr('name','queue').on('click', function() {
                                       var button = $(this);
                                       var currentClass = $(button).attr('class');
                                       var wID = $(button).val();

                                       $.ajax({
                                           url: $(button).attr('href'),
                                           type: 'POST',
                                           success: function (data) {
                                           switch(currentClass) {
                                               case 'btn btn-danger':
                                                   var newClass = 'btn btn-success';
                                                   var contentName = 'Queue';
                                                   var newHref = '" . base_url('transactions/queue/') . "/'+wID;
                                               break;
                                               case 'btn btn-success':
                                                   var newClass = 'btn btn-danger';
                                                   var contentName = 'Un-Queue';
                                                   var newHref = '" . base_url('transactions/deQueue/') . "/'+wID;
                                               break;
                                           }
                                           $(button).attr({
                                               class: newClass,
                                               href: newHref
                                           });
                                           $(button).html(contentName);
                                           }
                                       });

                                   });
                                   $('button#pay_queue').on('click', function() {
                                       var button = $(this);
                                      $.ajax({
                                           url: $(button).attr('href'),
                                           type: 'POST',
                                           dataType: 'json',
                                           success: function (data) {
                                               var obj = data;
                                               if(obj.status == 'Success') {
                                                   bootbox.dialog({
                                                       message: 'Your payments have been processed.<br/>The total amount was $'+data.total,
                                                       title: 'Amazing Success',
                                                       buttons: {
                                                           success: {
                                                               label: 'Close',
                                                               className: 'btn btn-primary',
                                                               callback: function() {
                                                                   window.location.href = window.location.href
                                                               }
                                                           }
                                                       }
                                                   });
                                               }
                                               else {
                                                   bootbox.dialog({
                                                       message: 'Oh no. Something had to have gone wrong',
                                                       title: 'Son of a *****',
                                                       buttons: {
                                                           success: {
                                                               label: 'Close',
                                                               className: 'btn btn-danger',
                                                               callback: function() {
                                                                   window.location.href = window.location.href
                                                               }
                                                           }
                                                       }
                                                   });
                                               }
                                           }
                                       });
                                   });
                               ";
       $view_data['extra_head'] = "<link href='" . base_url() . "theme_assets/admin/bower_components/datatables-plugins/tabletools/tabletools.css' rel='stylesheet'>";

       $view_data['content'] = $this->load->view('withdraws/withdraws_requests', $data, true);

       $this->load->view($this->template, $view_data);    
   }

}

 

So in my header.php file I have things in there such as $content, $extra_head, $dynamic_extras, and $javascripts.

And yes, I know about the link_tag() lol I just never use it haha. I just recently started "really" using it so I am still learning as I go

Whats the point of this function

 __construct() 

or is it places in your header? which im kinda guessing and as for your example you change the controller name after

extends

which i dont get

Share this post


Link to post
Share on other sites
Whats the point of this function
 __construct() 

or is it places in your header? which im kinda guessing and as for your example you change the controller name after

extends

which i dont get

Like I said Google OOP

Kinda did this for you : http://code.tutsplus.com/tutorials/object-oriented-php-for-beginners--net-12762

Pretty sure [MENTION=70485]G7470[/MENTION] had a good tutorial on OOP on his blog here as well.

Ok so I'll explain a few things.

OOP is centred around objects. Objects are normally instances of classes. So in php to define a class you do:

public class MyClass {

} 

 

You can change the name of MyClass to anything you want.

I learnt OOP while learning Java and its considered good practice to have the name of your file reflect the name of your class, therefore I would save the file as MyClass.php

Ok, let's take it a bit further.

public class MyClass {

  public function __construct(){
     // initialise object code
  }

}

 

Notice the construct function. When you create a new instance of MyClass, this function gets called automatically. To create a new instance of MyClass you would do the following:


$myClass = new MyClass();

 

Notice that MyClass() is the exact same name as the class.

If you've ever worked with mccodes you'll notice this being done with the header file and the globals files.

Ok so again, let's move further with MyClass


public class MyClass {

  var $username;

  public function __construct(){
     $this->username = "jcvenom";
  }

  public function getUsername(){
     return $this->username;
  }

}

 

$myClass = new MyClass();
$username = $myClass->getUsername();

 

Right a few things to notice here, the var $username . This creates a global variable that can be used throughout the MyClass file. You need to use $this to reference it however, otherwise it just creates a new variable called $username.

The getUsername function is pretty self explanatory.

Now moving on to the extends keyword

public class User extends MyClass {

  var $user = array("id"=>0, "username"=>"");
  public function __construct(){
     $this->user['id'] = 1;
     $this->user['username'] = $this->getUsername();
  }

}

 

Wait what? Where is the getUsername function?

The beauty of the extends keyword and OOP.

So because in MyClass, the getUsername() function is public, if I extend MyClass, then any public variables or functions are accessible in the new class.

That's a very basic overview of what's going on in OOP. My terminology for things is probably all wrong but I don't care too much lol, I just want to explain it in a way that you can understand what's going on

Edited by Coly010

Share this post


Link to post
Share on other sites
Like I said Google OOP

Kinda did this for you : http://code.tutsplus.com/tutorials/object-oriented-php-for-beginners--net-12762

Pretty sure [MENTION=70485]G7470[/MENTION] had a good tutorial on OOP on his blog here as well.

Ok so I'll explain a few things.

OOP is centred around objects. Objects are normally classes. So in php to define a class you do:

public class MyClass {

} 

 

You can change the name of MyClass to anything you want.

I learnt OOP while learning Java and its considered good practice to have the name of your file reflect the name of your class, therefore I would save the file as MyClass.php

Ok, let's take it a bit further.

public class MyClass {

  public function __construct(){
     // initialise object code
  }

}

 

Notice the construct function. When you create a new instance of MyClass, this function gets called automatically. To create a new instance of MyClass you would do the following:


$myClass = new MyClass();

 

Notice that MyClass() is the exact same name as the class.

If you've ever worked with mccodes you'll notice this being done with the header file and the globals files.

Ok so again, let's move further with MyClass


public class MyClass {

  var $username;

  public function __construct(){
     $this->username = "jcvenom";
  }

  public function getUsername(){
     return $this->username;
  }

}

 

$myClass = new MyClass();
$username = $myClass->getUsername();

 

Right a few things to notice here, the var $username . This creates a global variable that can be used throughout the MyClass file. You need to use $this to reference it however, otherwise it just creates a new variable called $username.

The getUsername function is pretty self explanatory.

Now moving on to the extends keyword

public class User extends MyClass {

  var $user = array("id"=>0, "username"=>"");
  public function __construct(){
     $this->user['id'] = 1;
     $this->user['username'] = $this->getUsername();
  }

}

 

Wait what? Where is the getUsername function?

The beauty of the extends keyword and OOP.

So because in MyClass, the getUsername() function is public, if I extend MyClass, then any public variables or functions are accessible in the new class.

That's a very basic overview of what's going on in OOP. My terminology for things is probably all wrong but I don't care too much lol, I just want to explain it in a way that you can understand what's going on

I was reading my way through the link anyways i wanted to learn OOP in my early stages a few years back but i never really bothered until now lol so i know php,css,html,jquery,ajax,mysql and javascript but not OOP lmaoo, anyways thanks for your tutorial i rather like it and very easy to pick up :)

Share this post


Link to post
Share on other sites
I was reading my way through the link anyways i wanted to learn OOP in my early stages a few years back but i never really bothered until now lol so i know php,css,html,jquery,ajax,mysql and javascript but not OOP lmaoo, anyways thanks for your tutorial i rather like it and very easy to pick up :)

Yeah no problem. Not all languages have it but c++ and Java basically revolve around it, Java especially

Share this post


Link to post
Share on other sites

I believe huge text based game websites like torn won't be using 3rd party php frameworks due to some security risk, unless they created their own.

and in addition, if you're planning to create your own php framework, you definitely need to learn OOP. the advantage ofcourse is that you'll be recycling these codes for your new projects and will give you a good kickstart.

Edited by flixbeat

Share this post


Link to post
Share on other sites
I believe huge text based game websites like torn won't be using 3rd party php frameworks due to some security risk, unless they created their own.

and in addition, if you're planning to create your own php framework, you definitely need to learn OOP. the advantage ofcourse is that you'll be recycling these codes for your new projects and will give you a good kickstart.

I don't think they aren't using it for security risks. I see that as a load of codwallop. The reason I don't they would be using it is that they've been around that long that their code was developed before or while some of the major frameworks were still being developed to the point they are today. Coding styles were different back then.

Share this post


Link to post
Share on other sites

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.   Paste as plain text instead

  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.

Sign in to follow this  

×
×
  • Create New...