how can i create a soap in php for SABRE? - php

I am new to the world of SOAP, I want to know how I can make a request to the saber servers, but I have not succeeded, I need help to make the following request.
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:eb="http://www.ebxml.org/namespaces/messageHeader" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<SOAP-ENV:Header>
<eb:MessageHeader SOAP-ENV:mustUnderstand="1" eb:version="1.0">
<eb:From>
<eb:PartyId>Client</eb:PartyId>
</eb:From>
<eb:To>
<eb:PartyId>SWS</eb:PartyId>
</eb:To>
<eb:CPAId>3DBJ</eb:CPAId>
<eb:ConversationId>MyConversationID</eb:ConversationId>
<eb:Service>Service</eb:Service>
<eb:Action>getReservationRQ</eb:Action>
<eb:MessageData>
<eb:MessageId></eb:MessageId>
<eb:Timestamp></eb:Timestamp>
</eb:MessageData>
</eb:MessageHeader>
<wsse:Security xmlns:wsse="http://schemas.xmlsoap.org/ws/2002/12/secext" xmlns:wsu="http://schemas.xmlsoap.org/ws/2002/12/utility">
<wsse:BinarySecurityToken>Shared/IDL:IceSess\/SessMgr:1\.0.IDL/Common/!ICESMS\/RESE!ICESMSLB\/RES.LB!1</wsse:BinarySecurityToken>
</wsse:Security>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<ns7:GetReservationRQ xmlns:ns7="http://webservices.sabre.com/pnrbuilder/v1_15" Version="1.15.0">
<ns7:Locator>JXJ</ns7:Locator>
<ns7:RequestType>Stateful</ns7:RequestType>
<ns7:ReturnOptions UnmaskCreditCard="true">
<ns7:SubjectAreas>
<ns7:SubjectArea>PRICING_INFORMATION</ns7:SubjectArea>
</ns7:SubjectAreas>
</ns7:ReturnOptions>
</ns7:GetReservationRQ>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
This is my XML that I sent in postman and it generates a result but when I do it in PHP it generates an error.
SOAP-ERROR: Parsing WSDL: Couldn't load from 'https://webservices.havail.sabre.com' : Document is empty
$client = new SoapClient("https://webservices.havail.sabre.com");
$checkVatParameters =array(
'BinarySecurityToken' => 'Shared/IDL:IceSess\/SessMgr:1\.0.IDL/Common/!ICESMS\/RESE!ICESMSLB\/RES.LB!',
'Locator' => 'JXJ',
'RequestType'=>'Stateful',
'SubjectArea'=>'PRICING_INFORMATION'
);//variables
$result=$client->__getFunctions();
$result = $client->GetReservationRQ($checkVatParameters);
echo "REQUEST:\n" . $client->__getLastRequest() . "\n";
}
they only gave me a URL but it asks me WDSL

It looks like the SoapClient is wanting the URL for the WSDL itself, not the service endpoint. For GetReservationRQ, you can find this at http://files.developer.sabre.com/wsdl/sabreXML1.0.00/pnrservices/GetReservation_1.19.0.wsdl.

he solved my problem in this way
$location_URL = "https://sws-crt.cert.havail.sabre.com";
$action_URL = "http://webservices.sabre.com/pnrbuilder/v1_15";
$client = new SoapClient(null, array(
'location' => $location_URL,
'uri' => "",
'trace' => 1,
));
$order_return = $client->__doRequest($xml,$location_URL,$action_URL,1);

I made a modification and works perfectly for PHP SOAP.
function leerreservas($pnr) {
error_reporting(0);
//ini_set('display_errors', true);
//ini_set('display_startup_errors', true);
$oDate = new DateTime();
$timestamp = $oDate->format('Y-m-d\Th:i:sP');
$timetolive = $oDate->add(new DateInterval('PT1H'))->format('Y-m-d\Th:i:sP');
$Locator=$pnr;
$BinarySecurityToken=selectokken(); $endpoint=selecendpoint();
$sabre=sabredatosusuario();
$namespaces="http://webservices.sabre.com/pnrbuilder/v1_15";
$test = '<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:eb="http://www.ebxml.org/namespaces/messageHeader"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<SOAP-ENV:Header>
<eb:MessageHeader SOAP-ENV:mustUnderstand="1" eb:version="1.0">
<eb:From>
<eb:PartyId>Client</eb:PartyId>
</eb:From>
<eb:To>
<eb:PartyId>SWS</eb:PartyId>
</eb:To>
<eb:CPAId>'.$sabre['ipcc'].'</eb:CPAId>
<eb:ConversationId>MyConversationID</eb:ConversationId>
<eb:Service>Service</eb:Service>
<eb:Action>getReservationRQ</eb:Action>
<eb:MessageData>
<eb:MessageId>'.$timestamp.'</eb:MessageId>
<eb:Timestamp>'.$timetolive.'</eb:Timestamp>
</eb:MessageData>
</eb:MessageHeader>
<wsse:Security xmlns:wsse="http://schemas.xmlsoap.org/ws/2002/12/secext"
xmlns:wsu="http://schemas.xmlsoap.org/ws/2002/12/utility">
<wsse:BinarySecurityToken>'.$BinarySecurityToken.'</wsse:BinarySecurityToken>
</wsse:Security>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<ns7:GetReservationRQ xmlns:ns7="'.$namespaces.'" Version="1.15.0">
<ns7:Locator>'.$Locator.'</ns7:Locator>
<ns7:RequestType>Stateful</ns7:RequestType>
<ns7:ReturnOptions UnmaskCreditCard="true">
<ns7:SubjectAreas>
<ns7:SubjectArea>PRICING_INFORMATION</ns7:SubjectArea>
</ns7:SubjectAreas>
</ns7:ReturnOptions>
</ns7:GetReservationRQ>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>';
$location_URL = $endpoint;
$action_URL = $namespaces;
$client = new SoapClient(null, array( 'location' => $location_URL, 'uri' => "",
'trace' => 1, ));
try {
$order_return = $client->__doRequest($test,$location_URL,$action_URL,1);
//Get response from here
if (empty($order_return)) {
echo "vacio";
} else {
$xml2 = reemplazo($order_return);
$xml = simplexml_load_string($xml2, 'SimpleXMLElement', LIBXML_NOCDATA);
$datos = json_decode(json_encode($xml), TRUE);
echo print_r($datos);
}
} catch (SoapFault $exception) {
var_dump(get_class($exception));
var_dump($exception);
}
}

Related

php soap client with nested childs

I am trying to figure how to create this soap envelope using soap client
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<SOAP-ENV:Header>
<m:sendDataExtraccionTraza
xmlns:m="http://www.mop.cl/controlextraccion/xsd/datosExtraccion/SendDataExtraccionRequest">
<m:codigoDeLaObra>OB-0303-204</m:codigoDeLaObra>
<m:timeStampOrigen>2001-12-17T09:30:47Z</m:timeStampOrigen>
</m:sendDataExtraccionTraza>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<m:sendDataExtraccionRequest
xmlns:m="http://www.mop.cl/controlextraccion/xsd/datosExtraccion/SendDataExtraccionRequest">
<m:dataExtraccionSubterranea>
<m:fechaMedicion>17-08-1967</m:fechaMedicion>
<m:horaMedicion>00:01:01</m:horaMedicion>
<m:totalizador>1234567891</m:totalizador>
<m:caudal>12345678.12</m:caudal>
<m:nivelFreaticoDelPozo >12345678.12</m:nivelFreaticoDelPozo >
</m:dataExtraccionSubterranea>
</m:sendDataExtraccionRequest>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Tried making it like this:
$client = new SoapClient($url, array('trace' => 1));
$ns = 'http://www.mop.cl/controlextraccion/xsd/datosExtraccion/SendDataExtraccionRequest';
$headerbody = array('codigoDeLaObra' => POZO_PRUEBA,
'timeStampOrigen' => '2020-01-01T09:30:47Z');
$header = new SOAPHeader($ns, 'sendDataExtraccionTraza', $headerbody);
$client->__setSoapHeaders($header);
$args = array( "fechaMedicion" => "10-10-2020",
"horaMedicion" => "10:01:01",
"totalizador" => "1234567891",
"caudal" => "12345678.12",
"nivelFreaticoDelPozo" => "12345678.12"
);
$res = $client->__soapCall('sendDataExtraccionOp', [
new SoapParam("10-10-2020", "fechaMedicion"),
new SoapParam("10:01:01", "horaMedicion"),
new SoapParam("1234567891", "totalizador"),
new SoapParam("12345678.12", "caudal"),
new SoapParam("1", "nivelFreaticoDelPozo")]);
I am getting an error as result, so i've managed to htmlentities the $client->__getLastRequest() and seeing this outcome
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://www.mop.cl/controlextraccion/xsd/datosExtraccion/SendDataExtraccionRequest">
<SOAP-ENV:Header>
<ns1:sendDataExtraccionTraza>
<ns1:codigoDeLaObra>OB-0202-251</ns1:codigoDeLaObra>
<ns1:timeStampOrigen>2020-01-01T09:30:47Z</ns1:timeStampOrigen>
</ns1:sendDataExtraccionTraza>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<ns1:sendDataExtraccionRequest/>
<horaMedicion>10:01:01</horaMedicion>
<totalizador>1234567891</totalizador>
<caudal>12345678.12</caudal>
<nivelFreaticoDelPozo>1</nivelFreaticoDelPozo>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
I am missing a <m:dataExtraccionSubterranea> parent inside the senddataExtraccionRequest, and i can't figure how to create it.
Any hint?

How to remove the namespace of SOAPHeaderElement using PHP

So basically I want the SOAP header to be like this:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://xfire.super8.com/CrsService" xmlns:ns2="http://www.gzjhotel.com:9999/iPegasus/services/CrsService?wsdl">
<SOAP-ENV:Header>
<AuthenticationToken>
<Username>xxx</Username>
<Password>xxx</Password>
</AuthenticationToken>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<ns1:getHotelList>
<ns1:city>GZ</ns1:city>
</ns1:getHotelList>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
But instead, now I have this:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://xfire.super8.com/CrsService" xmlns:ns2="http://www.gzjhotel.com:9999/iPegasus/services/CrsService?wsdl">
<SOAP-ENV:Header>
<ns2:AuthenticationToken SOAP-ENV:actor="http://schemas.xmlsoap.org/soap/actor/next">
<Username>xxx</Username>
<Password>xxx</Password>
</ns2:AuthenticationToken>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<ns1:getHotelList>
<ns1:city>GZ</ns1:city>
</ns1:getHotelList>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
And this is the php code that I'm currently using:
$headerParam = [
'Username' => $username,
'Password' => $password,
];
$client = new \SoapClient($requestUrl, ['trace' => true]);
$authvalues = new \SoapVar($headerParam, SOAP_ENC_OBJECT);
$header = new \SoapHeader($requestUrl, 'AuthenticationToken', $authvalues,
false, SOAP_ACTOR_NEXT);
$client->__setSoapHeaders($header);
$r = $client->getHotelList(['city' => 'GZ']);
Where have I gone wrong? I seems unable to construct the header properly.
I have solved it, by using XSD_ANYXML
$headerParam = "<AuthenticationToken><Username>$username</Username><Password>$password</Password></AuthenticationToken>";
$client = new \SoapClient($requestUrl, ['trace' => true]);
$authvalues = new \SoapVar($headerParam, XSD_ANYXML);
$header = new \SoapHeader($requestUrl, 'AuthenticationToken', $authvalues, false, SOAP_ACTOR_NEXT);
$client->__setSoapHeaders($header);
Thanks to :enter link description here

Make a soap request via php SoapClient

I have to make a SOAP request but I'm facing some problems because using SoapClient I can't get the same XML that is supposed.
This is the correct xml request
<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
<soap-env:Header>
<wsse:Security
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:Username>10983</wsse:Username>
<wsse:Password>test2019</wsse:Password>
<Context>10000Hoteis</Context>
</wsse:Security>
</soap-env:Header>
<soap-env:Body>
<OTA_ReadRQ xmlns:ns="http://www.opentravel.org/OTA/2003/05/common"
xmlns="http://www.opentravel.org/OTA/2003/05" TimeStamp="2015-07-16T06:38:10.60">
<ReadRequests>
<HotelReadRequest>
<TPA_Extensions>
<RequestType>GetCities</RequestType>
<CountryCode>PT</CountryCode>
</TPA_Extensions>
</HotelReadRequest>
</ReadRequests>
</OTA_ReadRQ>
</soap-env:Body>
</soap-env:Envelope>
And this is my current php code
$xmlheader = <<<XML
<wsse:Security
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:Username>myusername</wsse:Username>
<wsse:Password>mypassword</wsse:Password>
<Context>10000Hoteis</Context>
</wsse:Security>
XML;
$xmlbody = <<<XML
<OTA_ReadRQ xmlns:ns="http://www.opentravel.org/OTA/2003/05/common"
xmlns="http://www.opentravel.org/OTA/2003/05" TimeStamp="2015-07-16T06:38:10.60">
<ReadRequests>
<HotelReadRequest>
<TPA_Extensions>
<RequestType>GetCities</RequestType>
<CountryCode>PT</CountryCode>
</TPA_Extensions>
</HotelReadRequest>
</ReadRequests>
</OTA_ReadRQ>
XML;
$headerXML = new \SoapVar($xmlheader,XSD_ANYXML);
$body = new \SoapVar($xmlbody,XSD_ANYXML);
$client = new \SoapClient(null, ['location' => 'http://10000hoteis.com.pt/NewAvailabilityServlet/staticdata/OTA2014A', 'uri' =>'http://schemas.xmlsoap.org/soap/envelope/' ,'trace' => true]);
$header = new \SoapHeader('http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd', 'Security', $headerXML);
$client->__setSoapHeaders($header);
$result = $client->OTA_ReadRQ($body);
But this don't work because put an extra
<SOAP-ENV:OTA_ReadRQ>
between the body tag and
<OTA_ReadRQ xmlns:ns="http://www.opentravel.org/OTA/2003/05/common"
xmlns="http://www.opentravel.org/OTA/2003/05" TimeStamp="2015-07-16T06:38:10.60">
How can I do this request correctly?

SOAP with literal xml in php

How do i create this specific xml output by SOAP using SoapHeader and __setSoapHeaders? I can't do the same XML like i want. i don't want this ns1 and ns2 in envelope tag, and in header i need this Action SOAP-ENV:mustUnderstand="1" ...
This is my code:
try{
$client = new SoapClient('https://thesite.com.br/wcf/SvcContratos.svc?wsdl', array('trace' => 1,'use' => SOAP_LITERAL));
$usuario='user_1';
$senha='1234';
$tipo='1';
$header = new SoapHeader("http://schemas.microsoft.com/ws/2005/05/addressing/none","Action", "http://tempuri.org/ISvcContratos/GerarToken");
$client->__setSoapHeaders($header);
$params = new SoapVar("<objLogin xmlns:d4p1='http://schemas.datacontract.org/2004/07/EPFWeb.Repository.Default.WCF' xmlns:i='http://www.w3.org/2001/XMLSchema-instance'><d4p1:DsSenha>".$senha."</d4p1:DsSenha><d4p1:DsUsuario>".$usuario."</d4p1:DsUsuario><d4p1:IdTipoConsulta>".$tipo."</d4p1:IdTipoConsulta></objLogin>", XSD_ANYXML);
$data = $client->GerarToken($params);
echo $client->__getLastRequest();
}catch(SoapFault $fault){
echo $client->__getLastRequest()."<br>".$fault->getMessage();
}
With this php code i had this wrong XML:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://tempuri.org/" xmlns:ns2="http://schemas.microsoft.com/ws/2005/05/addressing/none">
<SOAP-ENV:Header>
<ns2:Action>http://tempuri.org/ISvcContratos/GerarToken</ns2:Action>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<GerarToken>
<objLogin xmlns:d4p1='http://schemas.datacontract.org/2004/07/EPFWeb.Repository.Default.WCF' xmlns:i='http://www.w3.org/2001/XMLSchema-instance'>
<d4p1:DsSenha>1234</d4p1:DsSenha>
<d4p1:DsUsuario>user_1</d4p1:DsUsuario>
<d4p1:IdTipoConsulta>1</d4p1:IdTipoConsulta>
</objLogin>
</GerarToken>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
I need to send this XML by soap:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://tempuri.org/ISvcContratos/GerarToken</Action>
</s:Header>
<s:Body>
<GerarToken xmlns="http://tempuri.org/">
<objLogin xmlns:d4p1="http://schemas.datacontract.org/2004/07/EPFWeb.Repository.Default.WCF" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<d4p1:DsSenha>1234</d4p1:DsSenha>
<d4p1:DsUsuario>USER_1</d4p1:DsUsuario>
<d4p1:IdTipoConsulta>1</d4p1:IdTipoConsulta>
</objLogin>
</GerarToken>
</s:Body>
</s:Envelope>
well, finally I got an affirmative answer from the server, which opens the doors for me now to try to consume the wsdl follows below the code that I used to solve the problem:
try{
$client = new SoapClient('https://thesite.com.br/wcf/SvcContratos.svc?wsdl', array('trace' => 1,'use' => SOAP_LITERAL, 'style' => SOAP_DOCUMENT,));
$usuario='user_1';
$senha='1234';
$params = new SoapVar("<GerarToken xmlns='http://tempuri.org/'><objLogin xmlns:d4p1='http://schemas.datacontract.org/2004/07/EPFWeb.Repository.Default.WCF' xmlns:i='http://www.w3.org/2001/XMLSchema-instance'><d4p1:DsUsuario>".$usuario."</d4p1:DsUsuario><d4p1:DsSenha>".$senha."</d4p1:DsSenha><d4p1:IdTipoConsulta>Data</d4p1:IdTipoConsulta></objLogin></GerarToken>", XSD_ANYXML);
$data = $client->GerarToken($params);
$xml = json_decode(json_encode($data),true);
print_r($xml);
echo $client->__getLastRequest();
}catch(SoapFault $fault){
echo $client->__getLastRequest()."<br>".$fault->getMessage();
}

Data at the root level is invalid php SoapClient

I have to create a SOAP header like:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<AuthHeader xmlns="URL">
<Username>string</Username>
<Password>string</Password>
<PublicKey>string</PublicKey>
<NewPassword>string</NewPassword>
<UserType>string</UserType>
</AuthHeader>
</soap:Header>
<soap:Body>
<getClients xmlns="URL" />
</soap:Body>
</soap:Envelope>
Connect with WS With sesion(), it returns nothing, but when the XML contains something, I get that error.
This is my code:
$wsdl= "URL?wsdl';
$options = array(
'uri'=>'http://schemas.xmlsoap.org/soap/envelope/',
'style'=>SOAP_RPC,
'use'=>SOAP_ENCODED,
'soap_version'=>SOAP_1_1,
'cache_wsdl'=>WSDL_CACHE_NONE,
'connection_timeout'=>15,
'trace'=>true,
'encoding'=>'UTF-8',
'exceptions'=>true,
);
try {
$soap = new SoapClient($wsdl, $options);
$valor = $soap->getPublicKey();
}
catch(Exception $e) {
die($e->getMessage());
}
$key=$valor->getPublicKeyResult->any;
$endpoint = 'url';
$user;
$password;
$password64 = mb_convert_encoding($password,'UCS-2LE','auto');
$rsa = new Crypt_RSA();
$rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
$rsa->loadKey($key);
$rsa->setPublicKey($key);
$ciphertext = $rsa->encrypt($password64);
$cipher64 = base64_encode($ciphertext);
$headerbody = array(
'PublicKey'=>$rsa->getPublicKey(),
'Username'=>$user,
'Password'=>$cipher64,
'NewPassword'=>'',
'UserType'=>'U'
);
$header = new SOAPHeader($endpoint, 'AuthHeader', $headerbody);
$soap->__setSoapHeaders($header);
try {
$data = $soap->sesion();
$data = $soap->getClients();
}
catch(Exception $e) {
die($e->getMessage());
}
var_dump($soap->__getTypes());
echo "REQUEST:\n" . htmlentities($soap->__getLastRequest()) . "\n";
echo "RESPONSE:\n" . htmlentities($soap->__getLastResponse()) . "\n";
var_dump($data);
die;
And the header that form:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="URL">
<SOAP-ENV:Header>
<ns1:AuthHeader>
<ns1:Username>$user</ns1:Username>
<ns1:Password>$password</ns1:Password>
<ns1:PublicKey>-----BEGIN PUBLIC KEY-----
 PUBLIC KEY#13; -----END PUBLIC KEY-----</ns1:PublicKey>
<ns1:NewPassword></ns1:NewPassword>
<ns1:UserType>U</ns1:UserType>
</ns1:AuthHeader>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<ns1:getClients/>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
I have tried various solutions proposed and none of them work, I'm not able to include in the envelope the xlms:xsi, xlms:xsd. And I think that is what I need.

Categories