Bonjour,
Je veux transférer des fichier pdf via web service. Je les ai transformé en byte[] puis en string base 64 mais ce string est encore tellement enorme que la requête http ne marche pas...
avez vous une solution?
Merci
Bonjour,
Je veux transférer des fichier pdf via web service. Je les ai transformé en byte[] puis en string base 64 mais ce string est encore tellement enorme que la requête http ne marche pas...
avez vous une solution?
Merci
Soit activer MTOM ou bien passer par SWA.
Avec axis2: http://ws.apache.org/axis2/1_5_1/mtom-guide.html#23
ca m'a l'air pas mal MTOM mais comment faire en JAVA?
Et bien le lien plus haut donne des exemples de code java.
Après la manière dépend de comment tu veux faire. As-tu généré du code avec wsdl2Java? quel databinding?
Les exemples de code me paraissent assez clairs pourtant...
un exemple peut-être plus complet: http://www.sayedhashimi.com/CommentV...4e3f5021f.aspx
oups désoléj'avais pas vu. j'ai suivi le tuto avec ce dernier lien que tu m'as donné mais à l'éxécution finale j'ai une erreur que je ne comprend pas :
voici aussi ce que dit TCPMON :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38 Exception in thread "main" org.apache.axis2.AxisFault: Unknow type can not serialize at org.apache.axis2.AxisFault.makeFault(AxisFault.java:430) at org.apache.axis2.transport.http.SOAPMessageFormatter.writeTo(SOAPMessageFormatter.java:83) at org.apache.axis2.transport.http.AxisRequestEntity.writeRequest(AxisRequestEntity.java:84) at org.apache.commons.httpclient.methods.EntityEnclosingMethod.writeRequestBody(EntityEnclosingMethod.java:499) at org.apache.commons.httpclient.HttpMethodBase.writeRequest(HttpMethodBase.java:2114) at org.apache.commons.httpclient.HttpMethodBase.execute(HttpMethodBase.java:1096) at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:398) at org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:171) at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:397) at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:346) at org.apache.axis2.transport.http.AbstractHTTPSender.executeMethod(AbstractHTTPSender.java:542) at org.apache.axis2.transport.http.HTTPSender.sendViaPost(HTTPSender.java:199) at org.apache.axis2.transport.http.HTTPSender.send(HTTPSender.java:76) at org.apache.axis2.transport.http.CommonsHTTPTransportSender.writeMessageWithCommons(CommonsHTTPTransportSender.java:400) at org.apache.axis2.transport.http.CommonsHTTPTransportSender.invoke(CommonsHTTPTransportSender.java:225) at org.apache.axis2.engine.AxisEngine.send(AxisEngine.java:435) at org.apache.axis2.description.OutInAxisOperationClient.send(OutInAxisOperation.java:402) at org.apache.axis2.description.OutInAxisOperationClient.executeImpl(OutInAxisOperation.java:229) at org.apache.axis2.client.OperationClient.execute(OperationClient.java:165) at service.TransfertServiceStub.receiveMTOM(TransfertServiceStub.java:187) at service.TestClient.testMTOM(TestClient.java:104) at service.TestClient.main(TestClient.java:47) Caused by: javax.xml.stream.XMLStreamException: Unknow type can not serialize at org.apache.axis2.databinding.utils.ConverterUtil.serializeAnyType(ConverterUtil.java:1456) at service.TransfertServiceStub$ReceiveMTOM.serialize(TransfertServiceStub.java:1050) at service.TransfertServiceStub$ReceiveMTOM.serialize(TransfertServiceStub.java:972) at service.TransfertServiceStub$ReceiveMTOM$1.serialize(TransfertServiceStub.java:960) at org.apache.axis2.databinding.ADBDataSource.serialize(ADBDataSource.java:93) at org.apache.axiom.om.impl.llom.OMSourcedElementImpl.internalSerializeAndConsume(OMSourcedElementImpl.java:738) at org.apache.axiom.om.impl.llom.OMElementImpl.internalSerialize(OMElementImpl.java:966) at org.apache.axiom.om.impl.llom.OMElementImpl.internalSerializeAndConsume(OMElementImpl.java:995) at org.apache.axiom.soap.impl.llom.SOAPEnvelopeImpl.serializeInternally(SOAPEnvelopeImpl.java:254) at org.apache.axiom.soap.impl.llom.SOAPEnvelopeImpl.internalSerialize(SOAPEnvelopeImpl.java:242) at org.apache.axiom.om.impl.llom.OMElementImpl.internalSerializeAndConsume(OMElementImpl.java:995) at org.apache.axiom.om.impl.llom.OMNodeImpl.serializeAndConsume(OMNodeImpl.java:486) at org.apache.axis2.transport.http.SOAPMessageFormatter.writeTo(SOAPMessageFormatter.java:79) ... 20 more
et
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 POST /axis2/services/TransfertService HTTP/1.1 Content-Type: multipart/related; boundary=MIMEBoundaryurn_uuid_3EC49A4C93B03928CD1264670264141; type="application/xop+xml"; start="<0.urn:uuid:3EC49A4C93B03928CD1264670264142@apache.org>"; start-info="text/xml" SOAPAction: "urn:receiveMTOM" User-Agent: Axis2 Host: 127.0.0.1:9080 Transfer-Encoding: chunked
C'est quoi invalid chunk?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9 HTTP/1.1 500 Erreur Interne de Servlet Server: Apache-Coyote/1.1 Content-Type: text/xml;charset=UTF-8 Transfer-Encoding: chunked Date: Thu, 28 Jan 2010 09:17:44 GMT Connection: close 1c5 <?xml version='1.0' encoding='UTF-8'?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Header xmlns:wsa="http://www.w3.org/2005/08/addressing"><wsa:Action>http://www.w3.org/2005/08/addressing/soap/fault</wsa:Action></soapenv:Header><soapenv:Body><soapenv:Fault><faultcode></faultcode><faultstring>Stream Errorjava.io.IOException: Invalid chunk</faultstring><detail /></soapenv:Fault></soapenv:Body></soapenv:Envelope>
Merci beaucoup!
Alors il me semble (mais je ne peux rien affirmer) que le chunking est le fait de morceler les grosses trames.
Du coup c'est peut-être ton serveur qui n'est pas compatible avec ce mécanisme, car l'erreur semble venir du serveur.
Sinon tu peux peut-être essayer ça dans ton client:
Code : Sélectionner tout - Visualiser dans une fenêtre à part options.setProperty(org.apache.axis2.transport.http.HTTPConstants.CHUNKED, Constants.VALUE_FALSE);
Cette ligne ne change rien. Quand je débug c'est cette ligne de code qui plante :le "localElement" vaut :
Code : Sélectionner tout - Visualiser dans une fenêtre à part org.apache.axis2.databinding.utils.ConverterUtil.serializeAnyType(localElement, xmlWriter);et le xml writer est un "org.apache.commons.httpclient.ChunkedOutputStream" ...
Code : Sélectionner tout - Visualiser dans une fenêtre à part <ns0:receiveMTOM xmlns:ns0="http://service">amF2YS5pby5GaWxlSW5wdXRTdHJlYW1AMjAxNmIw</ns0:receiveMTOM>
je ne sais pas lequel des 2 pose problème mais il n'arrive pas à reconnaitre le type de mon localelement d'où le javax.xml.stream.XMLStreamException: Unknow type can not serialize
Coté client, comment envoies-tu ton attachement? Tu utilises le datahandler?
Coté serveur, pareil, tu devrais pouvoir récupérer un datahandler et en faire ce que bon te semble.
File un peu de code pour voir...
j'ai suivi le tuto http://www.sayedhashimi.com ... ! j'ai juste changé le nom "Test" en "transfert" voici mon client Test
seule différence : ma class n'extends pas TestCase et pour encoder le fichier j'utilise ma méthode ( fonction convertDocToByteArray) et pas readfully car je n'ai pas cette fonction. (le probleme vient de la?)
Je ne pense pas que le problème vienne du serveur car le message n'arrive meme pas à partir... enfin je crois d'après lerreur
Merci beaucoup de ton aide gnienfo
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63 public class TestClient { private static final String EPR = "http://localhost:8080/axis2/services/TransfertService"; private static final String INPUT_FILE = "C:\\gilles.pdf"; public static void main(String[] args) throws Exception { TestClient t = new TestClient(); t.testMTOM(); } public byte[] convertDocToByteArray(String sourcePath) { byte[] byteArray=null; try { InputStream inputStream = new FileInputStream(sourcePath); String inputStreamToString = inputStream.toString(); byteArray = inputStreamToString.getBytes(); inputStream.close(); } catch (FileNotFoundException e) { System.out.println("File Not found"+e); } catch (IOException e) { System.out.println("IO Ex"+e); } return byteArray; } public void testMTOM()throws Exception{ TransfertServiceStub stub = new TransfertServiceStub(EPR); stub._getServiceClient().getOptions().setProperty(Constants.Configuration.ENABLE_MTOM, Constants.VALUE_TRUE); stub._getServiceClient().getOptions().setTimeOutInMilliSeconds(10000); String base64String = Base64.encode(convertDocToByteArray(INPUT_FILE)); ReceiveMTOM rmtom = new ReceiveMTOM(); OMFactory fac = OMAbstractFactory.getOMFactory(); OMText binaryNode =fac.createOMText(base64String,"application/pdf",true); OMNamespace omNs = fac.createOMNamespace("http://service", "ns0"); OMElement method = fac.createOMElement("receiveMTOM", omNs); method.addChild(binaryNode); rmtom.setElement(method); stub.receiveMTOM(rmtom); System.out.println("done calling service..."); } }
Plutôt que de convertir toi même ton pdf en byte[], pourquoi n'utilises-tu pas directement le datahandler:?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9 ... // Creating a javax.activation.FileDataSource from the input file. FileDataSource fileDataSource = new FileDataSource(file); // Create a dataHandler using the fileDataSource. Any implementation of // javax.activation.DataSource interface can fit here. DataHandler dataHandler = new DataHandler(fileDataSource); OMText binaryNode = fac.createOMText(dataHandler, true); ...
Il semble tout de même que tu ai un souci coté serveur puisque ta deuxième trace TCPMON est un réponse du serveur disant que ça ne va pas...
cela donne exactement la même chose.
il n'arrive pas à sérialiser ça. ne connait-il pas le type receiveMTOM? j'ai essayé plein d'autre types mais toujours la même chose.
Code : Sélectionner tout - Visualiser dans une fenêtre à part <ns0:receiveMTOM xmlns:ns0="http://service">amF2YS5pby5GaWxlSW5wdXRTdHJlYW1AMjAxNmIw</ns0:receiveMTOM>
le namespace sans ".fr" ou ".com" au bout le gène?
voici mon wsdl :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104 <?xml version="1.0" encoding="UTF-8"?> <wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:ns1="http://org.apache.axis2/xsd" xmlns:ns="http://service" xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" targetNamespace="http://service"> <wsdl:documentation>TransfertService</wsdl:documentation> <wsdl:types> <xs:schema attributeFormDefault="qualified" elementFormDefault="qualified" targetNamespace="http://service"> <xs:complexType name="Exception"> <xs:sequence> <xs:element minOccurs="0" name="Exception" nillable="true" type="xs:anyType"/> </xs:sequence> </xs:complexType> <xs:element name="Exception"> <xs:complexType> <xs:sequence> <xs:element minOccurs="0" name="Exception" nillable="true" type="ns:Exception"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="receiveMTOM"> <xs:complexType> <xs:sequence> <xs:element minOccurs="0" name="element" nillable="true" type="xs:anyType"/> </xs:sequence> </xs:complexType> </xs:element> </xs:schema> </wsdl:types> <wsdl:message name="receiveMTOMRequest"> <wsdl:part name="parameters" element="ns:receiveMTOM"/> </wsdl:message> <wsdl:message name="receiveMTOMResponse"/> <wsdl:message name="Exception"> <wsdl:part name="parameters" element="ns:Exception"/> </wsdl:message> <wsdl:portType name="TransfertServicePortType"> <wsdl:operation name="receiveMTOM"> <wsdl:input message="ns:receiveMTOMRequest" wsaw:Action="urn:receiveMTOM"/> <wsdl:output message="ns:receiveMTOMResponse" wsaw:Action="urn:receiveMTOMResponse"/> <wsdl:fault message="ns:Exception" name="Exception" wsaw:Action="urn:receiveMTOMException"/> </wsdl:operation> </wsdl:portType> <wsdl:binding name="TransfertServiceSoap11Binding" type="ns:TransfertServicePortType"> <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/> <wsdl:operation name="receiveMTOM"> <soap:operation soapAction="urn:receiveMTOM" style="document"/> <wsdl:input> <soap:body use="literal"/> </wsdl:input> <wsdl:output> <soap:body use="literal"/> </wsdl:output> <wsdl:fault name="Exception"> <soap:fault use="literal" name="Exception"/> </wsdl:fault> </wsdl:operation> </wsdl:binding> <wsdl:binding name="TransfertServiceSoap12Binding" type="ns:TransfertServicePortType"> <soap12:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/> <wsdl:operation name="receiveMTOM"> <soap12:operation soapAction="urn:receiveMTOM" style="document"/> <wsdl:input> <soap12:body use="literal"/> </wsdl:input> <wsdl:output> <soap12:body use="literal"/> </wsdl:output> <wsdl:fault name="Exception"> <soap12:fault use="literal" name="Exception"/> </wsdl:fault> </wsdl:operation> </wsdl:binding> <wsdl:binding name="TransfertServiceHttpBinding" type="ns:TransfertServicePortType"> <http:binding verb="POST"/> <wsdl:operation name="receiveMTOM"> <http:operation location="TransfertService/receiveMTOM"/> <wsdl:input> <mime:content type="text/xml" part="receiveMTOM"/> </wsdl:input> <wsdl:output> <mime:content type="text/xml" part="receiveMTOM"/> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="TransfertService"> <wsdl:port name="TransfertServiceHttpSoap11Endpoint" binding="ns:TransfertServiceSoap11Binding"> <soap:address location="http://localhost:8080/axis2/services/TransfertService.TransfertServiceHttpSoap11Endpoint/"/> </wsdl:port> <wsdl:port name="TransfertServiceHttpSoap12Endpoint" binding="ns:TransfertServiceSoap12Binding"> <soap12:address location="http://localhost:8080/axis2/services/TransfertService.TransfertServiceHttpSoap12Endpoint/"/> </wsdl:port> <wsdl:port name="TransfertServiceHttpEndpoint" binding="ns:TransfertServiceHttpBinding"> <http:address location="http://localhost:8080/axis2/services/TransfertService.TransfertServiceHttpEndpoint/"/> </wsdl:port> </wsdl:service> </wsdl:definitions>
MTOM s'occupe de sortir de l'enveloppe les element base64Binary. Ton element receiveMTOM doit donc être de type base64Binary.
J'ai bien mis un Base64Binary dedans ... idem
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 OMFactory fac = OMAbstractFactory.getOMFactory(); // Creating a javax.activation.FileDataSource from the input file. FileDataSource fileDataSource = new FileDataSource(INPUT_FILE); // Create a dataHandler using the fileDataSource. Any implementation of // javax.activation.DataSource interface can fit here. DataHandler dataHandler = new DataHandler(fileDataSource); Base64Binary b = new Base64Binary(); b.setBase64Binary(dataHandler); OMText binaryNode = fac.createOMText(b, true); //OMText binaryNode =fac.createOMText(base64String,"application/pdf",true); OMNamespace omNs = fac.createOMNamespace("http://service", "ns1"); OMElement method = fac.createOMElement("Base64Binary", omNs); method.addChild(binaryNode); rmtom.setElement(method); stub.receiveMTOM(rmtom);
Oui mais dans ton wsdl, ton element receiveMTOM doit etre de type Base64Binaryun truc comme ça...
Code : Sélectionner tout - Visualiser dans une fenêtre à part <element name="receiveMTOM" type="xsd:base64Binary"/>
On avance... mais comme j'ai modif le wsdl la connexion au service ne fait pas..
voici les messages echangés . apparement le message envoyé est bon et il contient mon fichier cette fois.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 POST /axis2/services/TransfertService HTTP/1.1 Content-Type: multipart/related; boundary=MIMEBoundaryurn_uuid_8F55BCBF9F89E7B5A81264761072729; type="application/xop+xml"; start="<0.urn:uuid:8F55BCBF9F89E7B5A81264761072730@apache.org>"; start-info="application/soap+xml"; action="urn:receiveMTOM" User-Agent: Axis2 Host: 127.0.0.1:9080 Transfer-Encoding: chunked 20f1 --MIMEBoundaryurn_uuid_8F55BCBF9F89E7B5A81264761072729 Content-Type: application/xop+xml; charset=UTF-8; type="application/soap+xml" Content-Transfer-Encoding: binary Content-ID: <0.urn:uuid:8F55BCBF9F89E7B5A81264761072730@apache.org> <?xml version='1.0' encoding='UTF-8'?><soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope"><soapenv:Body><ns1:receiveMTOM xmlns:ns1="http://service">JVBERi0xLjMKJcfsj6IKNSAwIG9iago8PC9MZW5ndGg...</ns1:receiveMTOM></soapenv:Body></soapenv:Envelope> 3a --MIMEBoundaryurn_uuid_8F55BCBF9F89E7B5A81264761072729-- 0
En ce qui concerne le service si j'ai bien compris je ne recois plus un OMElement mais directement un base64 binary...
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 HTTP/1.1 500 Erreur Interne de Servlet Server: Apache-Coyote/1.1 Content-Type: multipart/related; boundary=MIMEBoundaryurn_uuid_958F55C33B8A0B63231264761073065; type="application/xop+xml"; start="<0.urn:uuid:958F55C33B8A0B63231264761073066@apache.org>"; start-info="application/soap+xml"; action="urn:receiveMTOMException" Transfer-Encoding: chunked Date: Fri, 29 Jan 2010 10:31:13 GMT Connection: close 2a1 --MIMEBoundaryurn_uuid_958F55C33B8A0B63231264761073065 Content-Type: application/xop+xml; charset=UTF-8; type="application/soap+xml" Content-Transfer-Encoding: binary Content-ID: <0.urn:uuid:958F55C33B8A0B63231264761073066@apache.org> <?xml version='1.0' encoding='UTF-8'?><soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope"><soapenv:Body><soapenv:Fault><soapenv:Code><soapenv:Value>soapenv:Receiver</soapenv:Value></soapenv:Code><soapenv:Reason><soapenv:Text xml:lang="en-US">Exception occurred while trying to invoke service method receiveMTOM</soapenv:Text></soapenv:Reason><soapenv:Detail /></soapenv:Fault></soapenv:Body></soapenv:Envelope> 38 --MIMEBoundaryurn_uuid_958F55C33B8A0B63231264761073065 2 -- 0
Merci de ton aide gnienfo
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 public void receiveMTOM(OMElement element) throws Exception { System.out.println("received request..."); OMText binaryNode = (OMText) (element.getFirstElement()).getFirstOMChild(); binaryNode.setOptimize(true); DataHandler dh = (DataHandler) binaryNode.getDataHandler(); InputStream is = dh.getInputStream(); byte[] buf = readFully(is); writeOutput(buf); System.out.println("done writing output file."); }
j'ai une :
j'ai un NullpointerException des que je touche au paramètre reçu (element)
Code : Sélectionner tout - Visualiser dans une fenêtre à part Exception occurred while trying to invoke service method receiveMTOM
ça affiche bien "received request" et ça saute!
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 public void receiveMTOM(OMElement element) throws Exception { System.out.println("received request..."); System.out.println("element : "+element.toString());
Celà fonctionne maintenant en remplaçant coté serveurpar :
Code : Sélectionner tout - Visualiser dans une fenêtre à part OMText binaryNode = (OMText) (element.getFirstElement()).getFirstOMChild();
Je ne sais pas si c'est une erreur du tuto ou si c'est mon cas qui implique ce changement mais cela fonctionne.
Code : Sélectionner tout - Visualiser dans une fenêtre à part OMText binaryNode = (OMText) (element.getFirstOMChild());
Bon je t'ai un poil abandonné (vraiment pris...) mais apparemment tu t'en es sorti, cool.
Oui je pense que cela dépend de ta structure du wsdl. Il faut en fait juste que tu récupères le contenu de ton élément binary64, après il est situé différemment dans la structure en fonction des wsdl.
Sinon juste pour compléter le sujet, coté serveur, tu n'es pas obligé de passer par un byte[] car tu pourrais avoir des souci en mémoire pour les gros fichiers.
Perso je fais comme ça:
Il me semble que du coup le datahandler gère le streaming...
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7 OMText binaryNode = (OMText) dataElement.getFirstOMChild(); DataHandler dataHandler = (DataHandler) binaryNode.getDataHandler(); File file = new File("/chemin/clientRequ.truc"); FileOutputStream fileOutputStream = new FileOutputStream(file); dataHandler.writeTo(fileOutputStream); fileOutputStream.flush(); fileOutputStream.close();
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager