Checkbox removing listing in a random way - php

I have a list of favorite cars which i have added to each favorite car a checkbox for letting the user to remove the favorite car from his favorite car list. The problem is that the checkbox is working in a different way: If I check any car (1st, second.. last or multiple cars) and after hit submit the car that will get removed is the last one added instead of removing the selected one. If I check multiple cars, happens same thing, removes only the last car added.
PHP
public function GetFavoriteCars() {
include("inc/membersite_config.php");
$email = $fgmembersite->UserEmail(); // this is how I take the e-mail of the
global $base_path;
$FavoriteCars = $this->QueryResult("SELECT * FROM favoritecar WHERE email='$email'");
if (count($FavoriteCars)) {
$mystring='http://';
echo '<form action="" class="deletebutton" method="post">';
echo '<input type="submit" name="deletebtn" id="deletebtn" value="Submit">';
echo '<div class="roster_slideri-login">';
foreach ($FavoriteCars as $FavoriteCar) {
$carlink = $FavoriteCar->favoritecarlink;
echo '<div class="car-info-col-login">';
echo '<input type="checkbox" name="checkbox" value="'.$carlink.'" class="checkbox-login">';
$val=strpos($FavoriteCar->favoritecarimg,$mystring);
if ($val !== false) {
if($FavoriteCar->favoritecarimg!='') {
echo '<a href="'.$base_path.'detail-page_'.$FavoriteCar->favoritecarlink.'">';
echo '<img src="'.$FavoriteCar->favoritecarimg.'" alt="'.$FavoriteCar->favoritecartitle.'" width="160" height="120" />';
echo '</a>';
echo '<div class="name">'.substr($FavoriteCar->favoritecartitle,0,20).'</div>';
echo '</div>'; //car-info-col-login
}
} else {
echo '<a href="'.$base_path.'detail-page_'.$FavoriteCar->favoritecarlink.'">';
echo '<img src="'.$base_path.'uploads/no-img.jpg" alt="'.$FavoriteCar->favoritecartitle.'" width="160" height="120" />';
echo '</a>';
echo '<div class="name">'.substr($FavoriteCar->favoritecartitle,0,20).'</div>';
echo '</div>';
}
}
echo '</form>';
if (isset($_POST["checkbox"])) {
$this->QueryResult("DELETE from favoritecar WHERE email='$email' AND favoritecarlink='$carlink'");
echo '<script type="text/javascript">alert("Car had been deleted");</script>';
}
echo '</div>'; // div roster_slideri-login
}
}
Explaning:
$email = $fgmembersite->UserEmail(); - this is how I take the e-mail of the current logged in user. It will echo "email_of_logged_in_user#domain.com"
QueryResult is a custom function that looks like this. I usually use it for SELECTING purposes but it seams that is working for deleting purposes too.
abstract class DBDetails {
protected $link = NULL;
protected function connector() {
global $DBHOSTNAME;
global $DBUSERNAME;
global $DBPASSWORD;
global $DBNAME;
$this->link = mysqli_connect($DBHOSTNAME, $DBUSERNAME, $DBPASSWORD, $DBNAME) or die("Can't connect to MySQL server on localhost");
}
protected function close() {
mysqli_close($this->link);
}
}
abstract class N2 extends DBDetails {
public function QueryResult($strQuery) {
$this->connector();
$query = mysqli_query($this->link, $strQuery);
$arr = array();
if ($query) {
while ($result = mysqli_fetch_object($query)) {
array_push($arr, $result);
}
}
$this->close();
return $arr;
}
}
Expected output
When I check the checkbox of a car, it should delete only that car. If I check the checkboxes of multiple cars, should delete the specific cars that I checked.
Please help, I am quite a noob in checkboxes. I have checked lots of questions from here, but did not find my answer.

In this line :
echo '<input type="checkbox" name="checkbox" value="'.$carlink.'" class="checkbox-login">';
--------------
When using multiple checkboxes with same name , you would need to include [] in the name :
echo '<input type="checkbox" name="checkbox[]" value="'.$carlink.'" class="checkbox-login">';
----------------
Then $_POST["checkbox"] will be an array and you can use foreach on it to get all the checked values .
if( isset( $_POST["checkbox"] ) )
{
foreach( $_POST["checkbox"] as $value )
{
/* $value contains $carlink */
echo $value; // For test purpose
/* Sanitize and use it to identify and delete the corresponding row */
}
}
( Rather than name="checkbox[]" it might be better to choose another name . )

Related

Unable to use an array as an array?

I am in the process of building a software download site for my company.
However, I have come across a problem that I am unsure how to get past.
I am retrieving all the information from a table about a particular software release and placing them in a multidimensional array. I am then trying to run a foreach (I have even tried a for loop) against that array and I get an error shown below:
When I run var dump against the original array, I get this:
So I am really confused as I don't know what I'm missing or where I am going wrong. The reason why I want to run this is so that I can filter the array into a one dimensional array.
Below is the code for the main web page
<?php
//Displays list of companies in 2 columns
$versionAccess = VersionAccess::findAccess($relId);//This gets set earlier in the webpage
$count = count($versionAccess);
var_dump($versionAccess);
foreach ($versionAccess as $va)
{
if ($va->company_access != '0')
{
$versionAcc[] = $va->comapny_id;
}
}
foreach ($company as $compAccess)
{
$compAccessId = $compAccess->company_id;
if (in_array($compAccessId, $versionAcc))
{
$access = 'checked disabled';
}
else { $access = 'disabled'; }
$accessName = 'access'.$compAccessId;
if ($ctr % 2 == 0)
{
echo '<td>'.$compAccess->company_name.':</td>';
echo '<td><label class="switch"><input type="checkbox" name="'.$accessName.'" value="1" '.$access.'><span class="slider round"></span></label></td>';
echo '</tr>';
}
else
{
if ($ctr < $compCount)
{
echo '<tr>';
echo '<td>'.$compAccess->company_name.':</td>';
echo '<td><label class="switch"><input type="checkbox" name="'.$accessName.'" value="1" '.$access.'><span class="slider round"></span></label></td>';
}
else
{
echo '<tr>';
echo '<td>'.$compAccess->company_name.':</td>';
echo '<td><label class="switch"><input type="checkbox" name="'.$accessName.'" value="1" '.$access.'><span class="slider round"></span></label></td>';
echo '</tr>';
}
}
$ctr++;
}
?>
The function that brings the data from the database is:
public static function findAccess($accessId)
//find the version access in database
{
return self::findQuery("SELECT * FROM version_access WHERE version_id = '$accessId'");
}
The findQuery method:
public static function findQuery($sql)
{
global $database;
$resultSet = $database->query($sql);
$objectArray = array();
while ($row = mysqli_fetch_array($resultSet))
{
$objectArray[] = self::instant($row);
}
return $objectArray;
}
I am still relatively new and any help is greatly appreciated.

how to validate and limit dynamic radio button inside a while loop

I tried to generate radio buttons dynamically from my database, but I am stuck where I need to limit (check if the user selected at least 5 groups(5 different games) of the generated button before submission into the database.
<?php while($row = mysql_fetch_array($query)) : ?>
<?php
$home_team = $row\['home_team'\];
$away_team = $row\['away_team'\];
$game_id = $row\['game_id'\];
$team_joined = $home_team.' VS '.$away_team;
$teams = $home_team.'vs'.$away_team;
$match_day = #$row\['match_day'\];
$match_time = #$row\['match_time'\];
date_default_timezone_set('Africa/Lagos');
$time = date('l, jS F h:iA');
?>
<?php
if (isset($_POST\['submit'\])) {
$amount = mysql_real_escape_string($_POST\['amount'\]);
$games = #$_POST\[''.$game_id.''\];
$countGames = count($games);
echo $countGames;
/* if ($countGames < 3) {
$errorfill = "please selecet 3 games";
} else { */
if ($amount) {
foreach ($games as $game) {
$gameValue = $game;
if ($amount < $bank_verify) {
$money_left = $bank_verify - $amount;
$deduct_query = mysql_query("UPDATE bank SET money_unit='$money_left' WHERE username='$username' ");
$query_start_game = mysql_query("INSERT INTO bet10_players VALUES('', '$username', '$amount',
'$gameValue', '$team_joined', '$game_id','$time', '$pin', '$match_day', '$match_time')") or die(mysql_error());
header("Location: print.php?pin=$pin&time=$time");
} else {
$errorbank = "SORRY!!! You do not have enough units to stake this bet";
}
}
} else {
$errorfill = "You have not entered any amount";
}
//}
}
?>
<form role="form" action="#" method="post">
<h5><?php echo $team_joined; ?></h5>
<h5><?php echo '<span style="color:#f0ad4e;">' . $match_day . ', ' . $match_time . '</span>'; ?></h5>
<label><input type="radio" name="<?php echo '' . $game_id . '\[' . $game_id . '\]'; ?>" value="<?php echo $home_team; ?>">Home</label>
<label><input type="radio" name="<?php echo '' . $game_id . '\[' . $game_id . '\]'; ?>" value="Draw ">Draw</label>
<label><input type="radio" name="<?php echo '' . $game_id . '\[' . $game_id . '\]'; ?>" value="<?php echo $away_team; ?>">Away</label>
<hr>
<?php endwhile; ?>
<div class="form-group">
<input type="text" name="amount" class="form-control" placeholder="Enter your amount here">
<input type="submit" name="submit" value="submit" class="btn btn-danger" style="margin-bottom: 10px;">
This is the link to the image of what I intend to achieve with these code https://i.stack.imgur.com/Xif8M.png
Because there are a lot of issues just with what you have, I can not actually "fix" what you have in good conscience. The mysql_* library is deprecated (removed in >= PHP7) and you are escaping a bunch of things you don't need to, as I noted. Also, as noted, using # to silence warnings is not a good idea, you will want to just fix them. If I were to do this, I would have a series of classes that I would create. I would also do an .htaccess or web.config (Windows) to force everything through the index page, but I suspect from your script you have individual pages, so I will go on that notion:
First off, I would probably create a base app that had some simple, helpful features.
/vendors/App.php
<?php
class App
{
# Easily return post values even if they don't exist without drawing errors
public function getPost($key=false)
{
if(!empty($key))
return (isset($_POST[$key]))? $_POST[$key] : false;
return $_POST;
}
# Easily return session values even if they don't exist without drawing errors
public function getSession($key=false)
{
if(!empty($key))
return (isset($_SESSION[$key]))? $_SESSION[$key] : false;
return $_SESSION;
}
# Used to render pages
public function render($file)
{
ob_start();
include($file);
$data = ob_get_contents();
ob_end_clean();
return $data;
}
}
/vendors/Game.php
If you create a base Game class, you will better be able to control Game-related base features
<?php
class Game extends App
{
protected $games = array();
protected $errors = array();
protected $con;
# Inject the database
public function __construct(\PDO $con)
{
$this->con = $con;
}
# Fetch a list (or just one) game
public function gameList($game_id = false)
{
$where = (!empty($game_id))? " WHERE game_id = '{$game_id}'" : "";
$this->games = array();
$query = $this->con->query("SELECT * FROM games{$where}");
while($result = $query->fetch(PDO::FETCH_ASSOC)) {
$this->games[] = $result;
}
return $this;
}
# Send back the games if stored
public function getGames($first = false)
{
# If you you only need one row returned
if($first)
return (isset($this->games[0]))? $this->games[0] : false;
# Return entire list
return $this->games;
}
# Count how many are currently stored
public function getCount()
{
return count($this->games);
}
}
/vendors/Game/Observer.php
If you create a base Game Observer class, you will better be able to control listeners and processing of requests.
<?php
namespace Game;
class Observer extends \Game
{
protected $time;
# This is a general listener method, listens for the post
# It needs work, I don't know where you are getting some of these
# variables from...I am injecting for example-sake
public function listen($bank_verify,$pin,$min=5)
{
# Listen for the submission
if(empty($this->getPost('submit')))
return $this;
elseif(empty($this->getSession('username')))
return $this;
# Fetch the post values, fitler empty
$REQUEST = array_filter($this->getPost('game'));
# See if there are at least 5 submitted
if(count($REQUEST) < $min) {
$this->errors[] = 'You must have at least '.$min.' selected';
return $this;
}
foreach($REQUEST as $id => $value) {
$this->games[$id] = $value;
}
$username = $this->getSession('username');
$amount = $this->getPost('amount');
if($amount < $bank_verify) {
$money_left = $bank_verify - $amount;
$this->updateAccount($money_left,$username);
foreach($this->games as $id => $value) {
$query_start_game = $this->con->prepare("INSERT INTO bet10_players VALUES('',?,?,?,?,?,?,?,?,?)");
$query_start_game->execute(array(
$username,
$amount,
$gameValue,
$team_joined,
$game_id,
$time,
$pin,
$match_day,
$match_time
));
}
}
else {
$this->errors[] = 'Not enough money.';
return $this;
}
header("Location: print.php?pin=$pin&time=$time");
exit;
}
# This sets the timezone (just once)
public function setTime($tz = 'Africa/Lagos')
{
date_default_timezone_set($tz);
$this->time = date('l, jS F h:iA');
return $this;
}
# This will update the account safely
public function updateAccount($money_left,$username)
{
$sql = "UPDATE bank SET money_unit = ? WHERE username = ?";
$query = $this->con->prepare($sql);
$query->execute(array($money_left,$username));
return $query;
}
# This probably needs work, but you should insert using this method
public function addBets($array,$table='bet10_players')
{
$fill = "'', ".implode(', ',array_fill(0,count($array),'?'));
$sql = "INSERT INTO `{$table}` VALUES({$fill})";
$query = $this->con->prepare($sql);
$query->execute($array);
return $query;
}
# Returns the time if need be...
public function getTime()
{
return $this->time;
}
}
/config.php
I would create this page to be included on all pages at the top. It can be expanded and is good to keep everything consistent like your root path and such.
<?php
# start the session
session_start();
# Create some useful defines
define('DS',DIRECTORY_SEPARATOR);
define('ROOT_DIR',__DIR__);
define('CLASSES',ROOT_DIR.DS.'vendors');
define('DB_HOST','localhost');
define('DB_NAME','databasename');
define('DB_USER','root');
define('DB_PASS','');
# Create a class autoloader which turns a \Namespace\Class into a directory
# like /var/html/domain/mydomain/vendor/Namespace/Class.php
spl_autoload_register(function($class) {
$path = str_replace(DS.DS,DS,CLASSES.DS.str_replace('\\',DS,$class).'.php');
if(is_file($path))
include_once($path);
});
/index.php
<?php
# Check if we are inside the class, if not, do so
if(!isset($this)) {
# Include the config file
require_once(__DIR__.DIRECTORY_SEPARATOR.'config.php');
# Create your connection (you should expand on this...)
$con = new PDO("mysql:host=".DB_HOST.";dbname=".DB_NAME,DB_USER,DB_PASS);
# Create a Game object
echo (new \Game\Observer($con))->render(__FILE__);
# Stop further execution
exit;
}
# Now we are inside the \Game\Observer class, so you can now use $this
# Set the time and add a listener for post
$this->setTime();
# Since there is no indication of where some of these variables come from,
# this listen method will need attention...actually all the elements from the
# \Game and \Game\Observer need review, but they should be close enough to figure out
$this->listen($bank_verify,$pin);
?>
<form role="form" action="" method="post">
<?php
# $this->gameList()->getGames() should just return an array from your database
foreach($this->gameList()->getGames() as $row) {
$team_joined = $row['home_team'].' VS '.$row['away_team'];
$teams = $row['home_team'].'vs'.$row['away_team'];
?>
<h5><?php echo $team_joined; ?></h5>
<h5><span style="color:#f0ad4e;"><?php echo $row['match_day'].', '.$row['match_time'] ?></span></h5>
<input type="hidden" name="game[<?php echo $row['game_id'] ?>]" value="" />
<label><input type="radio" name="game[<?php echo $row['game_id'] ?>]" value="<?php echo $row['home_team']; ?>" />Home</label>
<label><input type="radio" name="game[<?php echo $row['game_id'] ?>]" value="draw" />Draw</label>
<label><input type="radio" name="game[<?php echo $row['game_id'] ?>]" value="<?php echo $row['away_team']; ?>" />Away</label>
<hr>
<?php
}
?>
<div class="form-group">
<input type="text" name="amount" class="form-control" placeholder="Enter your amount here" />
<input type="submit" name="submit" value="submit" class="btn btn-danger" style="margin-bottom: 10px;" />
</div>
</form>
When you process the post, you will retrieve data from the database based on the game id, so you should get all the variables you need except for ones that have no indication of origin in your script. Anyway, this is what I would do if I were you. One final note, I have not tested any of this, some of the methods are based off a framework I use, but I think it's a safer version of your script where sql injection is concerned, though you will have to research what some of this is doing...

Instead of submit get data on entering page php

I use this snippet to get vehicle data from a external database:
<form method="post" action="<?php echo $_SERVER['REQUEST_URI'] ?>" class="vwe-kenteken-widget">
<p><input type="text" name="open_data_rdw_kenteken" value="<?php echo $_POST['open_data_rdw_kenteken'] ?>" maxlength="8"></p>
<p><input name="submit" type="submit" id="submit" value="<?php _e('Kenteken opzoeken', 'open_data_rdw') ?>"></p>
</form>
<?php if($data): ?>
<h3><?php _e('Voertuiggegevens', 'open_data_rdw') ?></h3>
<table>
<?php
$categories = array();
foreach ($data as $d) {
if( !is_array($fields) || in_array($d['name'], $fields) ) {
if( !in_array($d['category'], $categories) ) {
$categories[] = $d['category'];
echo '<tr class="open-rdw-header">';
echo '<td colspan="2" style="font-weight: bold;">';
echo ''.$d['category'].'';
echo '</td>';
echo '</tr>';
}
echo '<tr style="display:none">';
echo '<td>'.$d['label'].'</td>';
echo '<td>'.$d['value'].'</td>';
echo '</tr>';
}
}
?>
</table>
<?php endif; ?>
What i want to accomplish is that the data is loaded without the user have to enter a value and hit the submit button. The input value will get loaded based on the product page the user is viewing.
EDIT:
The data is loaded based on:
public function get_json() {
if ( isset( $_POST['kenteken'] ) ) {
$data = $this->rdw->get_formatted($_POST['kenteken']);
foreach ($data as $row) {
$json['result'][$row['name']] = $row['value'];
}
if ($_POST['kenteken']) {
if ($data[0]['value'] == '') {
$json['errors'] = __( 'No license plates found', 'open_data_rdw' );
}
else {
$json['errors'] = false;
}
}
else {
$json['errors'] = __( 'No license plate entered', 'open_data_rdw' );
}
header('Content-type: application/json');
echo json_encode($json);
die();
}
}
So instead of a $_POST action just get the data based on a pre-declared value that is different on each page.
Hard to answer - but I'll try to use my crystal ball.
$data comes from a database query, right?
I assume further, that the query takes the value from the open_data_rdw_kenteken form field to gather $data.
To have the table rendered, you have to fill $data with the right data. That implies that you must have a kind of default value for open_data_rdw_kenteken to get the data out of the DB. The default can be "all" which should reflect on your SQL Query or as your wrote "defined by product page".
Pseudo Code
$data = getData('BT-VP-41');
function getData($open_data_rdw_kenteken="")
{
$where = "";
if(!empty($open_data_rdw_kenteken)) {
$where = 'WHERE rdw_kenteken = "'.mysqli_real_escape_string($open_data_rdw_kenteken)';
}
$data = myslqi->query("SELECT * FROM dbTbl ".$where)
return $data;
}
As I wrote - this is pseudo code and will not run out of the box. You'll have to adapt that to your environment.
TL;DR: The line
<?php if($data): ?>
keeps you from rendering the table. To render you need $data filled with the right data.
Hope that will get you in the right direction.

Loop through form values from a dynamic php form

I building on top of an existing PHP based application to ability to update menu items name and prices.
I have generated a dynamic form which is populated with the results form the database. The idea is that the user can update the item name or price to update the information in the database.
The form works fine, but I am having dome trouble getting the info out of the form. each Item has a separate ID so I need to essentially do a foreach through the form and call the update function each time with the respective item id.
I can handle the DB side of things fine, but the application I am building on has a 'getInput' function to check input exists and to get the input form the form and I would like to use this.
This is the getInput function:
public static function exists($type = 'post') {
switch($type) {
case 'post':
return (!empty($_POST)) ? true : false;
break;
case 'get';
return (!empty($_GET)) ? true : false;
break;
default:
return false;
break;
}
}
public static function get($item) {
if(isset($_POST[$item])) {
return $_POST[$item];
} else if(isset($_GET[$item])) {
return $_GET[$item];
}
return '';
}
}
The problem I have is when calling this function it only returns the last item form the form. Is there a way i can iterate though the form and get each item?
This is the dynamic form and the getInput code so far:
$menuItems = DB::getInstance()->get('menu_items', array('cat_id', '=', $cat_id ));
if($menuItems->count()) {
echo '<form class="updateMenu" action="" method="post">';
echo '<table class="gridtable gridtableMenu">';
echo '<tr><th>Item Name</th><th>Item Price</th></tr>';
foreach($menuItems->results() as $item) {
echo '<tr>';
echo '<td class="menu-name"><input type="text" name="itemName" value="' . $item->item_name . '" required></td>';
echo '<td class="menu-price"><input type="number" step="any" name="itemPrice" value="' . $item->item_price . '" required></td>';
echo '<input type="hidden" name="id" value="' . $item->id . '">';
echo '</tr>';
}
echo '</table>';
echo '<input type="submit" name="updateMneu" value="Update Menu">';
echo '</form>';
} else {
echo '<div class="error">No items have been added to this menu</div>';
}
} // close categories foreach
} // close if category set
if(isset($_POST['updateMneu'])) {
echo Input::get('id'), '</br>';
echo Input::get('itemName'), '</br>';
echo Input::get('itemPrice'), '</br>';
} //close if isset updateMenu If
So I would like a foreach I think around this section:
if(isset($_POST['updateMneu'])) {
echo Input::get('id'), '</br>';
echo Input::get('itemName'), '</br>';
echo Input::get('itemPrice'), '</br>';
//update ite in the database, and move to gthe next item.
} //close if isset updateMenu If
I will handle data validation and what not later on.
As posted by 'noobHere' the answer was to set the input types name as arrays. e.g. name="itemName[]" instead of name="itemName"

multiple forms handled by one script php

I try to create an order page on php. I have created a form which stores data into the database. The form number is based on the user and it is created dynamic.
<?php
if(isset($_POST['submit_num']))
{
$number=$_POST['sky'];
for($i=0;$i<$number;$i++)
{
$item = $_SESSION['item'];
echo $item;
$rec_query = "SELECT * FROM ylika";
$rec_result= mysql_query($rec_query) or die("my eroors");
echo '<form action="user_order_form.php" method="POST">';
echo '<html>';
while($row_rec = mysql_fetch_array($rec_result))
{
echo '<input type="checkbox" name="yliko[]" value='.$row_rec['onoma'].'> '.$row_rec['onoma'].'';
echo '<br>';
}
echo '<br>';
echo '<input type="submit" name="submit" value="ORDER">';
echo '</form>';
}
}
?>
So I have many forms and 1 script to handle them. If I submit 1 form then it applies the data to the database but the other forms dissapear. This is the second php 'handler'.
<?php
if (isset($_POST['submit']))
{
$max_id = "SELECT MAX(id_order) FROM id_of_orders";
$x=mysql_query($max_id) or die("my eroors");
$id= mysql_fetch_array($x);
$xyz = $id['MAX(id_order)'];
$item = $_SESSION['item'];
$temp = $_POST['yliko'];
$temp2 = implode(",", $temp);
$inserts = ("INSERT INTO orders (order_id,product,ulika) VALUES ('$xyz' , '$item','$temp2')");
$inc_prod=("UPDATE proion SET Counter = Counter + 1 WHERE proion.onomasia='$item'");
mysql_query($inserts) or die(mysql_error());
mysql_query($inc_prod) or die(mysql_error());
}
?>
I want to submit all the forms. Should I try to create one submit button for all of the forms or is there a way to handle all of them separately ?
You can have many submit forms, but simply define one big <form> with all of them, then you will not lose any information.
<?php
if(isset($_POST['submit_num']))
{
$number=$_POST['sky'];
echo '<form action="user_order_form.php" method="POST">';
for($i=0;$i<$number;$i++)
{
$item = $_SESSION['item'];
echo $item;
$rec_query = "SELECT * FROM ylika";
$rec_result= mysql_query($rec_query) or die("my eroors");
echo '<html>';
while($row_rec = mysql_fetch_array($rec_result))
{
echo '<input type="checkbox" name="yliko[]" value='.$row_rec['onoma'].'> '.$row_rec['onoma'].'';
echo '<br>';
}
echo '<br>';
echo '<input type="submit" name="submit" value="ORDER">';
}
echo '</form>';
}
?>
now you can also add the ~$i~ identifier to input names, so you can easily distinguish which is which.

Categories