 |
Das deutsche QBasic- und FreeBASIC-Forum Für euch erreichbar unter qb-forum.de, fb-forum.de und freebasic-forum.de!
|
Vorheriges Thema anzeigen :: Nächstes Thema anzeigen |
Autor |
Nachricht |
braesident
Anmeldungsdatum: 15.04.2008 Beiträge: 189 Wohnort: Berlin
|
Verfasst am: 09.03.2013, 12:29 Titel: verknüpfungs frage |
|
|
Hallo mal wieder
mit 3d ohne libs und eurer hilfe hab ich es endlich geschaft einen sich drehenden Kreis mit Text zu erstellen. Kann das ganze auch in einen anderen Code einbinden. Ausser in ein Program in dem ich die TSNE Play benutze - zumindest nicht so oder an der stelle wie ich das gern hätte.
und zwar folgendes bzw so ähnlich
Code: | DO
sleep 40
Screenlock: DrawCube(@Ans[0]): Screenunlock
axis_z=(axis_z-st) Mod 360 : ax=3 : ro=-st
Rotate(@Ans[0],ax,ro)
IF MULTIKEY(FB.SC_n) THEN
neuer_kreis ("- Text -")
Ans[0].Vie(0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 1.0, Mnx, Mny, Six, Vpd, Fpd, Bpd)
Ans[0].Scr(x1, y2, x2, y1)
NormM4(Ans[0].MC_WC()): Ans[0].LocalInit(): Ans[0].updateMats()
axis_x=(axis_x+11) Mod 360 : ax=1 : ro=11
Rotate(@Ans[0],ax,ro)
End If
h = Inkey
Loop Until h = CHR(27)
|
hätte ich gern in diesem Teil
Code: | ...
FOR iVerbindung = 1 TO 10
IF LEN(TxtArray(iVerbindung)) > 0 THEN
ServerAdresse = TxtArray(iVerbindung)
? "Verbinde mit " & ServerAdresse
RV = TSNEPlay_ConnectToServer(ServerAdresse, 1234, "Client", "geheimesPasswort", _
@TSNEPlay_ConnectionState, @TSNEPlay_Player_Connected, @TSNEPlay_Player_Disconnected, _
@TSNEPlay_Message, @TSNEPlay_Move, @TSNEPlay_Data) ' Port ist UShort
If RV = TSNEPlay_NoError Then
Dim XTot as Double = Timer() + 6
Do Until InKey() = Chr(27)
Locate 1, 40: ? "Bereit in " & XTot - TIMER()
Select Case TSNEPlay_Connection_GetState()
Case TSNEPlay_State_Disconnected: Exit Do
Case TSNEPlay_State_Ready: TConnected = 1
End Select
Sleep 1, 1
If XTot < Timer() Then Exit Do
Loop
If TSNEPlay_Connection_GetState() = TSNEPlay_State_Ready Then TConnected = 1:EXIT FOR
End If
END IF 'LEN(TxtArray(iVerbindung) > 0
NEXT iVerbindung
... |
und zwar dieses "verbinde mit ...." soll auf diesen Kreis getan werden und dieser soll sich natürlich auch weiterhin drehen während TSNE auf antwort wartet. Kann man diese Schleife als Thread setzen der im hintergrund weiter läuft? Wenn ja wie?
Ich muss dazu sagen das ich schon versucht hab den oberen Code also die DO LOOP Schleife in eine Sub zu ändern. Ging aber nicht da ein Array nicht deklariert war - habs dann mit SHARED versucht aber wieder nur fehlermeldung - ich glaube Konstante erwartet oder so. |
|
Nach oben |
|
 |
braesident
Anmeldungsdatum: 15.04.2008 Beiträge: 189 Wohnort: Berlin
|
Verfasst am: 10.03.2013, 17:26 Titel: |
|
|
nochmal dazu die Hauptschleife in eine Sub zu packen. Und nicht verwirren lassen wegen kreis und cube - habs nur noch nicht geändert.
Code: | ...
SUB drehe_kreis()
Screenlock
DrawCube(@Ans[0])
Screenunlock
axis_z=(axis_z-st) Mod 360 : ax=3 : ro=-st
Rotate(@Ans[0],ax,ro)
END SUB
DO
sleep 40
drehe_kreis
h = Inkey
Loop Until h = CHR(27)
Delete[] Ans |
ergibt variable Ans nicht definiert
hab dann folgendes
Code: | Dim As ansicht PTR Ans = New ansicht[3]
|
geändert in
Code: | Dim SHARED As ansicht PTR Ans = New ansicht[3]
|
was aber dann zu diesem führt
Expected constant in 'Dim Shared As ansicht PTR Ans = New ansicht
kann ein pointer generell nicht Shared sein oder muss etwas im Type geändert werden.
Code: | Type ansicht
PUBLIC:
Declare Sub Clr()
Declare Sub Scr(Byval As Single, Byval As Single, Byval As Single, Byval As Single)
Declare Sub MCtoDC(Byref V As v3, Byref X As Single, Byref Y As Single)
Declare Sub Vie(Byval As Single, Byval As Single, Byval As Single, _
Byval As Single, Byval As Single, Byval As Single, _
Byval As Single, Byval As Single, Byval As Single, _
Byval As Single, Byval As Single, Byval As Single, _
Byval As Single, Byval As Single, Byval As Single)
Declare Sub LocalInit()
Declare Sub updateMats()
As Single MC_WC(3, 3), MC_DC(3, 3)
PRIVATE:
Declare Sub Init()
Declare Sub SetV()
Declare Sub SetS(Byval Lu As v2, Byval Ro As v2)
Declare Sub CalcVRC_NPC()
Declare Sub CalcWC_VRC()
As Uinteger maxint
As Integer frame, MaChe
As Single lux, luy, rox, roy
As Single YsubO, YsubU, SpanMemSize
As Single VPD, FPD, BPD
As Single xMin, yMin, xMax, yMax, xSize, ySize
As Single xwinsize, ywinsize, xwinoffs, ywinoffs
As v3 VRP, NRP, VUP
As v3 eyePoint
As Single WC_NPC(3, 3), MC_NPC(3, 3)
As Single WC_MC(3, 3), WC_DC(3, 3), NPC_MC(3, 3), NPC_DC(3, 3)
As Single WC_VRC(3, 3), VRC_NPC(3, 3), NPC_WC(3, 3)
End Type
|
|
|
Nach oben |
|
 |
Eternal_pain

Anmeldungsdatum: 08.08.2006 Beiträge: 1783 Wohnort: BW/KA
|
Verfasst am: 10.03.2013, 17:33 Titel: |
|
|
Doch das geht...
Code: |
Dim SHARED As ansicht PTR Ans
Ans = New ansicht[3]
|
warum man es nicht direkt dahinter zuweisen kann ist mir selbst nicht ganz klar, aber sollte nicht das Problem sein das in zwei Zeilen zu machen... _________________
 |
|
Nach oben |
|
 |
braesident
Anmeldungsdatum: 15.04.2008 Beiträge: 189 Wohnort: Berlin
|
Verfasst am: 10.03.2013, 18:16 Titel: |
|
|
ok das geht - prog stürzt aber sofort ab. Nach start über Konsole folgende Meldung: Out of bounds Array Access - at Line 381 - DRAWCUBE()
zeile 381
Code: | line (x(i), y(i)) - (x(i+360), y(i+360))
|
ist in der Sub DrawCube(Byval A As ansicht Ptr) |
|
Nach oben |
|
 |
nemored

Anmeldungsdatum: 22.02.2007 Beiträge: 4702 Wohnort: ~/
|
Verfasst am: 10.03.2013, 18:25 Titel: |
|
|
Zitat: | warum man es nicht direkt dahinter zuweisen kann ist mir selbst nicht ganz klar, aber sollte nicht das Problem sein das in zwei Zeilen zu machen... |
SHARED-Variablen werden anders reserviert als normale Variablen. Sie werden zur Compile-Zeit umgesetzt und können daher als Direktzuweisung nur Konstanten erhalten. Siehe Referenzeintrag zu SHARED.
Zitat: | Nach start über Konsole folgende Meldung: Out of bounds Array Access - at Line 381 - DRAWCUBE() |
Das heißt dann wohl, dass du außerhalb der Arraygrenzen zugreifst ...
Nachprüfen, wie groß i ist und wie groß die Felder x() und y() dimensioniert wurden! (Hinweis: Fehlermeldungen sind deine Freunde ) _________________ Deine Chance beträgt 1:1000. Also musst du folgendes tun: Vergiss die 1000 und konzentriere dich auf die 1. |
|
Nach oben |
|
 |
braesident
Anmeldungsdatum: 15.04.2008 Beiträge: 189 Wohnort: Berlin
|
Verfasst am: 10.03.2013, 19:28 Titel: |
|
|
dimensioniert ist es bis 2500
gefüllt wird es mit 2x 360 koordinaten und ein paar mit den pixelkoordinaten für ein schriftzug. Gesamt sind es ca 1100.
aufgerufen wird diese zeile nach
for i = 1 to 360
i+360 kann hier also höchstens 720 sein. und in einer for next unmittelbar davor mit 1 to 720 gibt es ja scheinbar keine probleme.
und der selbe code in dem drawcube in der hauptschleife aufgerufen wird und nicht in eine SUB verpackt ist funzt ja problem los. |
|
Nach oben |
|
 |
braesident
Anmeldungsdatum: 15.04.2008 Beiträge: 189 Wohnort: Berlin
|
Verfasst am: 10.03.2013, 20:51 Titel: |
|
|
was mir gerade beim konsolenaufruf noch aufgefallen ist:
...at Line 381 of C:\.....\3d-fb.bas::DRAWCUBE()
obwohl ich die datei mit exe und nicht mit bas aufgerufen habe |
|
Nach oben |
|
 |
Eternal_pain

Anmeldungsdatum: 08.08.2006 Beiträge: 1783 Wohnort: BW/KA
|
Verfasst am: 10.03.2013, 20:59 Titel: |
|
|
noch die option -exx beim compilieren drin?
Dir bleibt nichts anderen übrig als deine Array zugriffsvariablen zu kontrollieren, evtl einmal ohne aufs array zuzugreifen per print ausgeben lassen... eine prüfung einbauen wenn die zugrifsvariable grösser ist als der maximal zulässige Wert eine warnung ausgeben oder ähnliches.... _________________
 |
|
Nach oben |
|
 |
braesident
Anmeldungsdatum: 15.04.2008 Beiträge: 189 Wohnort: Berlin
|
Verfasst am: 10.03.2013, 21:26 Titel: |
|
|
ja hab noch -exx drin
ich hatte folgendes versucht um zu sehen bis wohin wir kommen
for i = 1 to 360
locate 1,1: print i: sleep 500
line (x(i)....
bin nichtmal bis zum print gekommen - ich versuch mal heraus zu finden bis wo der code funktioniert
EDIT/ oje hab mein Fehler gefunden. hab ja nicht nur das anzeigen in eine SUB gepackt sondern das erstellen des Kreises bzw des Rings mit neuem Text darauf auch. diese müsste man natürlich erstmal aufrufen.
Was mich somit wieder zu meiner ursprünglichen Frage bringt.
Kann ich diese Grafische Sache als Thread starten so das sich der Kreis dreht während das program andere dinge macht wie zB auf eine Verbindung zum Server zu warten.
Zuletzt bearbeitet von braesident am 10.03.2013, 21:43, insgesamt einmal bearbeitet |
|
Nach oben |
|
 |
Eternal_pain

Anmeldungsdatum: 08.08.2006 Beiträge: 1783 Wohnort: BW/KA
|
Verfasst am: 10.03.2013, 21:41 Titel: |
|
|
bei der fehlersuche das -exx mal wieder raus nehmen, weil wenn mit -exx ein fehler 'erkannt' wird, wie der zugriff auf pointer oder arrays über dessen grenzen hinaus, wird das programm beendet _________________
 |
|
Nach oben |
|
 |
braesident
Anmeldungsdatum: 15.04.2008 Beiträge: 189 Wohnort: Berlin
|
Verfasst am: 10.03.2013, 21:44 Titel: |
|
|
jetzt warste doch noch schneller. hab oben nochmal editiert. sorry und danke |
|
Nach oben |
|
 |
Eternal_pain

Anmeldungsdatum: 08.08.2006 Beiträge: 1783 Wohnort: BW/KA
|
Verfasst am: 10.03.2013, 21:53 Titel: |
|
|
Möglich? Vermutlich!
Aber ich glaube weder ratsam noch wirklich einfach, daher verweise ich mal auf die Tutorials:
Threading
Threading-Optimierung
Threading-Optimierung - Teil2
Mutexe
Hab mich nie so mit TSNE beschäftigt, aber dachte das dieser bereits per Thread arbeitet, so dass das eigentliche Programm weiter läuft während das Daten auswerten in einem extra Thread statt findet? _________________
 |
|
Nach oben |
|
 |
nemored

Anmeldungsdatum: 22.02.2007 Beiträge: 4702 Wohnort: ~/
|
Verfasst am: 11.03.2013, 00:22 Titel: |
|
|
Eternal_pain hat Folgendes geschrieben: | bei der fehlersuche das -exx mal wieder raus nehmen, weil wenn mit -exx ein fehler 'erkannt' wird, wie der zugriff auf pointer oder arrays über dessen grenzen hinaus, wird das programm beendet |
Deshalb lasse ich gerade für die Fehlersuche das -exx drin. Wenn das Programm mit einem Fehler beendet, weiß ich, dass ich die richtige Stelle noch nicht gefunden habe. _________________ Deine Chance beträgt 1:1000. Also musst du folgendes tun: Vergiss die 1000 und konzentriere dich auf die 1. |
|
Nach oben |
|
 |
braesident
Anmeldungsdatum: 15.04.2008 Beiträge: 189 Wohnort: Berlin
|
Verfasst am: 12.03.2013, 22:46 Titel: |
|
|
Hab jetzt mal nen Test gestartet. Der Thread soll den Ring drehen und anzeigen und die Hauptschleife soll einfach nur TIMER ausgeben.
Das ganze startet und dreht auch, schmiert aber nach ein paar sekunden ab.
mit -exx compiliert und über konsole gestartet - wieder nach wenigen sekunden abgestürzt ohne Fehlermeldung.
Code: | #INCLUDE "fbgfx.bi"
Dim As Any Ptr kreisthread
Dim Shared As Integer terminate
Dim Shared As Any Ptr mutex
screenres 1024, 600, 32,, &h10
#Include "c:\programmieren\freebasic\projekte\3d_mit_fb.bi"
neuer_kreis ("- Text -")
axis_x=(axis_x+11) Mod 360 : ax=1 : ro=11
Rotate(@Ans[0],ax,ro)
Sub MyThread (ByVal Parameter as Any Ptr)
DO
sleep 40
Screenlock: DrawCube(@Ans[0]): Screenunlock
axis_z=(axis_z-st) Mod 360 : ax=3 : ro=-st
Rotate(@Ans[0],ax,ro)
MutexLock(mutex)
If terminate = 1 Then 'abbrechen wenn 1
MutexUnLock(mutex)
Exit Do
End if
MutexUnLock(mutex)
Loop
END SUB
kreisthread = ThreadCreate(@MyThread)
DO
sleep 25
locate 1,1: ? TIMER
h = Inkey
LOOP Until h = CHR(27)
MutexLock(mutex): terminate = 1: MutexUnLock(mutex) 'MyThread abbrechen
ThreadWait(kreisthread) 'warten bis MyThread endet
? "THREAD BEENDET"
sleep
Delete[] Ans
END
|
|
|
Nach oben |
|
 |
Eternal_pain

Anmeldungsdatum: 08.08.2006 Beiträge: 1783 Wohnort: BW/KA
|
Verfasst am: 13.03.2013, 00:22 Titel: |
|
|
Ähnliche Probleme hatte ich damals mit DashIt auch...
http://forum.qbasic.at/viewtopic.php?t=7664
Eternal_pain hat Folgendes geschrieben: | ...Screenlock/Screenunlock aufrufe, kann es sein das es zeitweise ganz gut funktioniert wie erwartet... aber ich hab das nun eine weile getestet und es ist eigentlich nur eine frage der Zeit bis da irgendwas kollidiert und alles einfriert... |
ThePuppetMaster hat Folgendes geschrieben: | hi. das problem kenne ich sehr gut. es liegt am maus / tasta in kombination mit gfx.
sperre einfach mous /tasta mit dem selben mutex das du für gfx nutzt. sprich, diese funktionen dürfen nicht gleichzeitig aufgerufen werden. hier gibts leider probleme mit dem multithreading.
dann sollts eigetnlich funzen. |
@Nemored Nemored hat Folgendes geschrieben: | Deshalb lasse ich gerade für die Fehlersuche das -exx drin. Wenn das Programm mit einem Fehler beendet, weiß ich, dass ich die richtige Stelle noch nicht gefunden habe. |
Wenn ich mir aber Variablenwerte zum auswerten des Fehlers 'ansehen/anzeigen' lassen möchte kann ich das nicht mit -exx machen da das Programm ja sofort wieder schliesst... _________________
 |
|
Nach oben |
|
 |
ThePuppetMaster

Anmeldungsdatum: 18.02.2007 Beiträge: 1839 Wohnort: [JN58JR]
|
Verfasst am: 13.03.2013, 01:01 Titel: |
|
|
Muss noch hinzufügen, das es unter umständen nicht ausreicht, Maus und Tasta zu sperren.
Auch Sleep mus mit in das Mutex einfliesen.
Das Problem, welches sich dadurch allerdigns ergibst ist, das die Threaded Programmausführung dadurch zunichte gemacht wird.
Ob dies jedoch auch für Windows gilt, kann ich nciht sagen.
Unter Linux jedoch, dank X gibt es hier Probleme.
Am besten ist es, wenn Tastatur, Maus, Sleep, GFX Befehle alle im selben Thread bzw. Hauptthread (Hauptprogramm) laufen. Das veruhrsacht keine Probleme.
Das Betrifft im Übrigen auch die LINE, PSET, usw. kommandos auf ImagCreate Strukturen.
Eine Abhilfe hierfür wäre es z.B. wenn zeichenoberationen zeitaufwendig sind, und in einem anderen Thread ausgeführt werden sollen, eigene GFX Routinen mit eigenen Speicherbereichen zu schreiben, in denen threadsafe gearbeitet werden kann.
Im Hauptthread, in welchem auch die ganzen anderen zu schützenden Operationen ausgeführt werden, kann dann der Eigene GFX Speicher auf einen BF-Internen geblittet und dieser auf dem screen ausgegeben werden.
Das hat bei mir recht gut funktioniert, und keine Probleme mehr verursacht.
EDIT: so mache ich das in etwa. http://ops.ath.cx/code?id=277
MfG
TPM _________________ [ WebFBC ][ OPS ][ ToOFlo ][ Wiemann.TV ] |
|
Nach oben |
|
 |
nemored

Anmeldungsdatum: 22.02.2007 Beiträge: 4702 Wohnort: ~/
|
Verfasst am: 13.03.2013, 14:46 Titel: |
|
|
Eternal_pain hat Folgendes geschrieben: | Wenn ich mir aber Variablenwerte zum auswerten des Fehlers 'ansehen/anzeigen' lassen möchte kann ich das nicht mit -exx machen da das Programm ja sofort wieder schliesst... |
Dafür gibt es ja auch GETKEY (oder SLEEP als Variante). Damit kann ich sicherstellen, dass das Programm bis hierher ordentlich gelaufen ist und der Fehler erst später auftritt. Ohne eine solche Pausierung bringt dir -exx natürlcih nicht viel (auch wenn du die Werteausgaben in die Konsole oder in eine Datei schreiben lässt; dann schadet -exx zwar nicht, bringt aber auch nicht sehr viel mehr).
Ansonsten halt gleich einen Debugger und Schritt-Für-Schritt-Verfolgung. _________________ Deine Chance beträgt 1:1000. Also musst du folgendes tun: Vergiss die 1000 und konzentriere dich auf die 1. |
|
Nach oben |
|
 |
braesident
Anmeldungsdatum: 15.04.2008 Beiträge: 189 Wohnort: Berlin
|
Verfasst am: 13.03.2013, 18:43 Titel: |
|
|
ich bekomms nicht hin. ich glaub ich hab jetzt alles gespeert was geht.
Code: | Sub MyThread (ByVal Parameter as Any Ptr)
DO
MutexLock(mutex)
Screenlock: DrawCube(@Ans[0]): Screenunlock
axis_z=(axis_z-st) Mod 360 : ax=3 : ro=-st
Rotate(@Ans[0],ax,ro)
If terminate = 1 Then 'abbrechen wenn 1
MutexUnLock(mutex)
Exit Do
End if
MutexUnLock(mutex)
Loop
END SUB
kreisthread = ThreadCreate(@MyThread)
DO
sleep 25
MutexLock(mutex)
locate 1,1: ? TIMER
h = Inkey
MutexUnLock(mutex)
LOOP Until h = CHR(27)
MutexLock(mutex): terminate = 1: MutexUnLock(mutex) 'MyThread abbrechen
|
sleep hab ich im thread entfernt und das sleep im hauptteil hatte ich auch schon hinterm mutex
kann es sein das es probleme gibt da Drawcube auf weitere oder andere speicher oder pointer zugreift ?
EDIT/
da ihr sagtet es ist besser wenn die grafischen sachen in der hauptschleife laufen, hab ich mal den Inhalt des Threads mit dem des Hauptteils gewechselt - trotzdem absturz, sogar noch schlimmer
Code: | Sub MyThread (ByVal Parameter as Any Ptr)
DO
MutexLock(mutex)
locate 1,1: ? TIMER
If terminate = 1 Then 'abbrechen wenn 1
MutexUnLock(mutex)
Exit Do
End if
MutexUnLock(mutex)
Loop
END SUB
kreisthread = ThreadCreate(@MyThread)
DO
sleep 25
MutexLock(mutex)
Screenlock: DrawCube(@Ans[0]): Screenunlock
axis_z=(axis_z-st) Mod 360 : ax=3 : ro=-st
Rotate(@Ans[0],ax,ro)
h = Inkey
MutexUnLock(mutex)
LOOP Until h = CHR(27)
MutexLock(mutex): terminate = 1: MutexUnLock(mutex) 'MyThread abbrechen
|
|
|
Nach oben |
|
 |
Eternal_pain

Anmeldungsdatum: 08.08.2006 Beiträge: 1783 Wohnort: BW/KA
|
Verfasst am: 13.03.2013, 19:53 Titel: |
|
|
Eigentlich sehe ich keinen Fehler, SOLLTE mMn so funktionieren...
wobei locate und print auch grafik/fenster operationen sind...
nachdem ich das geändert habe, läuft es in dem von mir zum testen abgeändertem Beispiel durch...
Code: |
Dim hthread as any ptr
Dim mutex as any ptr
Dim Shared terminate as integer
Dim h as string
Dim shared T as double
Sub MyThread (ByVal mutex as Any Ptr)
DO
MutexLock(mutex)
'locate 1,1: ? TIMER
T=Timer
If terminate = 1 Then 'abbrechen wenn 1
MutexUnLock(mutex)
Exit Do
End if
MutexUnLock(mutex)
Loop
END SUB
screenres 640,480,32
hthread = ThreadCall MyThread(mutex)
DO
MutexLock(mutex)
sleep 25
Screenlock
line(rnd*640,rnd*480)-(rnd*640,rnd*480),rnd*&hFFFFFF
locate 1,1:?T
Screenunlock
h = Inkey
MutexUnLock(mutex)
LOOP Until h = CHR(27)
MutexLock(mutex): terminate = 1: MutexUnLock(mutex) 'MyThread abbrechen
Threadwait(hthread)
mutexdestroy(mutex)
end
|
Warum das so aber läuft und mit dem locate/print im thread trotz mutex hab ich leider keine Erklärung...
Edit: sobald IRGENEINE Grafikoperation stattfindet.. egal ob mit/ohne Screenlock/unlock, print, line oder sonsetwas dergleichen hängt es sich auf.... _________________
 |
|
Nach oben |
|
 |
ThePuppetMaster

Anmeldungsdatum: 18.02.2007 Beiträge: 1839 Wohnort: [JN58JR]
|
Verfasst am: 13.03.2013, 20:42 Titel: |
|
|
Du machst das schon richtig @braesident
wenn du jetzt noch das Sleep mi in das mutex packst, dann sollte es auch problemlos laufen.
MfG
TPM _________________ [ WebFBC ][ OPS ][ ToOFlo ][ Wiemann.TV ] |
|
Nach oben |
|
 |
|
|
Du kannst keine Beiträge in dieses Forum schreiben. Du kannst auf Beiträge in diesem Forum nicht antworten. Du kannst deine Beiträge in diesem Forum nicht bearbeiten. Du kannst deine Beiträge in diesem Forum nicht löschen. Du kannst an Umfragen in diesem Forum nicht mitmachen.
|
|