Προς το περιεχόμενο

Προτεινόμενες αναρτήσεις

Δημοσ.

Πριν φτιαχτεί το πρώτο VM όμως, τα έβαλαν κάτω και αποφάσισαν ότι για κάποιο λόγο είναι καλύτερο να φτιάξεις VM παρά AOT compiler για το bytecode του "πρώτου" compiler. Ποιος είναι αυτός ο λόγος/λόγοι είναι αυτό που ρωτάω.

Με το έξτρα πολυπλοκότητα δεν καταλαβαίνω τι ακριβώς εννοείς. Όσο του ότι πρέπει να αναπτύξεις compiler για κάθε πλατφόρμα που θες να υποστηρίξεις, το ίδιο ακριβώς δεν ισχύει και στη περίπτωση της VM; Για κάθε πλατφόρμα που θες να υποστηρίξεις δεν πρέπει να υλοποιήσεις και την VM γι' αυτήν;

 

Σκέψου λίγο τι θα γινόταν αν είχες μόνο AOT. Βασικά, αυτό που γίνεται με π.χ. τη C.

 

Πρώτα απ' όλα θα έπρεπε να διανέμει η (τότε) Sun compiled binaries (ή sources) για όλες τις πλατφόρμες που θέλει να υποστηρίξει. Για κάθε καινούρια πλατφόρμα θα έπρεπε κάποιος να φτιάχνει (με αιματηρό κόστος) καινούριο compiler backend.

 

Μετά θα έπρεπε να υπάρχει "compilation" 2 σταδίων (compile+link) γιατί διαφορετικά πώς θα γίνει να πάρεις ένα εκτελέσιμο που περιλαμβάνει κώδικα και από σένα αλλά και από τη BCL (π.χ. χρησιμοποιεί ένα java.lang.String). Το οποίο σημαίνει πως θα έπρεπε να αναπτυχθεί και ένα ABI για να μπορεί να δουλέψει το έτοιμο compiled τάδε που προέρχεται από κάποιον άλλο με το αποτέλεσμα του δικού σου compiler (ή να σου δίνουν sources και να σου λένε κάντα μόνος σου).

 

Αυτό με τη σειρά του σημαίνει πως τώρα χρειαζόμαστε όχι μόνο διαφορετικό compiler backend για κάθε πλατφόρμα αλλά επίσης σε περίπτωση που αλλάξει το ABI (π.χ. για να υποστηρίξει κάποιο νέο feature) τότε θα πρέπει αυτοί οι δύο compilers να παραμείνουν συγχρονισμένοι για να μπορείς να συνεχίσεις να δουλεύεις. Δηλαδή, αν η Sun θέλει να δώσει ένα νέο feature που χρειάζεται αλλαγή του ΑΒΙ και κάνει καινούριο compile τη BCL, εσύ αυτόματα χάνεις τη δυνατότητα να κάνεις build το πρόγραμμά σου εκτός κι αν μαζί με την "καινούρια Java" πάρεις και "καινούριο compiler", και καινούρια binaries από όλα τα dependencies που έχεις. Το κάθε ένα dependency για να το κάνει αυτό θα πρέπει να έχει πάρει με τη σειρά του binaries από τα δικά του dependencies...

 

I could go on αλλά νομίζω καταλαβαίνεις πως δεν έχει σημασία.

 

Επίσης βλέπεις ότι υπάρχει στην πράξη διαφορά ανάμεσα στο bytecode/JIT και AOT: το bytecode είναι απλά ένα abstraction layer που (εκτός των άλλων) απομονώνει τον "δικό σου" javac και όλα όσα αυτός παράγει από τον javac "του γείτονα" και όσα αυτός παράγει. Παίρνεις ένα bytecode compiled class από είκοσι χρόνια πριν και εφόσον το JVM παραμείνει backwards compatible μπορείς να το χρησιμοποιήσεις μια χαρά εκατό χρόνια στο μέλλον σε πλατφόρμες που σήμερα δεν υπάρχουν, χωρίς να χρειαστεί να κάνεις απολύτως τίποτα ως developer.

  • Απαντ. 37
  • Δημ.
  • Τελ. απάντηση

Συχνή συμμετοχή στο θέμα

Δημοσ.
....

 

Διαφωνώ με τη φιλοσοφία που το πιάνεις το θέμα. AOT compilation φυσικά και μπορεί να γίνει. Όταν μου δίνεις το λογισμικό σου να το τρέξω, μου έχεις δώσει όλα τα απαραίτητα .class files, σε ότι package format θες. Από αυτά, binary code μπορώ να δώσω είτε κατά το runtime με JIT ή από πριν με AOT. Δεν υπάρχει κάποια πληροφορία που δεν έχω και θα την αποκτήσω κατά το runtime. To android από την έκδοση 5.0 και μετά, έχει AOT compiler ο οποίος τρέχει κατά την εγκατάσταση.

 

Η δική σου προσέγγιση είναι του να κάνω distribute τις βιβλιοθήκες σε native binaries, το οποίο πράγματι δε μπορεί να λειτουργήσει. Αλλά δεν υπάρχει τέτοιος λόγος.

 

Επίσης η Oracle στην έκδοση 9.0 της Java SE θα δώσει πειραματικά έναν AOT compiler.

 

Ωστόσο για την ερώτηση JIT vs AOT, ένας AOT compiler δεν παράγει binary που εκτελείται γρηγορότερα. O JIT κατά το runtime, έχει πολύ περισσότερη πληροφορία για το τι και πως να κάνει optimize, άρα και δυνατότητα ώστε να παράξει γρηγορότερα binaries, από την άλλη με τον AOT δεν υπάρχει warm up time.

Δημοσ.

Διαφωνώ με τη φιλοσοφία που το πιάνεις το θέμα. AOT compilation φυσικά και μπορεί να γίνει. Όταν μου δίνεις το λογισμικό σου να το τρέξω, μου έχεις δώσει όλα τα απαραίτητα .class files, σε ότι package format θες. Από αυτά, binary code μπορώ να δώσω είτε κατά το runtime με JIT ή από πριν με AOT. Δεν υπάρχει κάποια πληροφορία που δεν έχω και θα την αποκτήσω κατά το runtime. To android από την έκδοση 5.0 και μετά, έχει AOT compiler ο οποίος τρέχει κατά την εγκατάσταση.

Είτε διαφωνείς είτε όχι, δεν μπορώ να πιάσω το θέμα από αλλού καθώς η ερώτηση ήταν "ποιο είναι το πρόβλημα με το AOT" :)

 

Φυσικά και γίνεται να δουλέψεις μόνο AOT κλπ κλπ, έχουμε τη C και το ξέρουμε. Αλλά υπάρχουν επίσης λόγοι να μην κάνεις AOT, και προσπάθησα να το παραλληλίσω με την απόφαση "θέλουμε να βάλουμε ένα abstraction layer εδώ ή όχι". Χωρίς να λάβουμε υπόψη τους συγκεκριμένους στόχους που θέλουμε να πετύχουμε με το project δε μπορεί να απαντηθεί αυτή η ερώτηση. Η Sun με τη Java αποφάσισε να βάλει, εγώ απλά αναφέρω λόγους που μπορεί να σε οδηγήσουν σ' αυτή την απόφαση.

 

Επίσης, λες "να δώσω τα απαραίτητα σε class files". Τα class files είναι bytecode. Άρα ήδη παίρνεις σα δεδομένο πως έχεις VM. Άρα τα πράγματα γίνονται ακόμα πιο σφιχτά για την απόφαση: έχεις ήδη τη δυνατότητα να εκτελέσεις bytecode χωρίς compilation σε native. Αν κάνεις έναν μόνο compiler, προφανώς αυτός θα είναι JIT. Άρα η ερώτηση γίνεται "αξίζει εκτός από όλα αυτά να κάνουμε και AOT"; Και νομίζω πως είναι προφανές εκ του αποτελέσματος, όχι μόνο από Java αλλά και πολλές άλλες γλώσσες, πως δεν είναι καθόλου αυτόματη η απάντηση "ναι".

 

Η δική σου προσέγγιση είναι του να κάνω distribute τις βιβλιοθήκες σε native binaries, το οποίο πράγματι δε μπορεί να λειτουργήσει. Αλλά δεν υπάρχει τέτοιος λόγος.

 

Επίσης η Oracle στην έκδοση 9.0 της Java SE θα δώσει πειραματικά έναν AOT compiler.

 

Ωστόσο για την ερώτηση JIT vs AOT, ένας AOT compiler δεν παράγει binary που εκτελείται γρηγορότερα. O JIT κατά το runtime, έχει πολύ περισσότερη πληροφορία για το τι και πως να κάνει optimize, άρα και δυνατότητα ώστε να παράξει γρηγορότερα binaries, από την άλλη με τον AOT δεν υπάρχει warm up time.

 

Εδώ θέλω να υπογραμμίσω το εξής...

 

"Δεν υπάρχει τέτοιος λόγος"

 

Σε ποιό σενάριο όμως;

 

Είναι σα να συζητάμε θέματα security, που δεν έχει κανένα νόημα αν δε συμφωνήσουμε πρώτα στο threat model. Έτσι κι εδώ πρέπει να συμφωνήσουμε στο usage model. Αν μη τι άλλο στην απάντησή μου δεν εξέταζα την περίπτωση "VM δεδομένο, τώρα JIT or AOT?" αλλά την περίπτωση "VM (ενδεχομένως με JIT) ή ΑΟΤ χωρίς VM?". Κι αυτό γιατί αν πάρεις το VM δεδομένο όπως είπα παραπάνω υπάρχουν ακόμα λιγότερα επιχειρήματα για AOT.

 

Τώρα, για το χαβαλέ της υπόθεσης, ανέφερες Android. Το Android μέχρι την έκδοση 2.2 δεν είχε καν JIT compiler, παρά μόνο VM (το λεγόμενο Dalvik). Οι λόγοι προφανείς: ship it σήμερα και αύριο έχει ο θεός. Τα performance θέματα δεν είναι σημαντικά όταν έχεις μηδέν πελατειακή βάση.

 

Όσον αφορά την Oracle, κι αυτό είναι καλό παράδειγμα για συζήτηση. Καταρχήν εδώ μιλάμε για Java SE, έχεις υπόψη ότι η Java Micro Edition (πρώην J2ME, νυν Java ME) υποστηρίζει και υποστήριζε (από πάντα?) AOT compilation; Είναι προφανές το γιατί: όταν τρέχεις σε smart θερμόμετρο πάντα υπάρχει κίνητρο να πας native για να μειώσεις όσο το δυνατόν περισσότερο το overhead του runtime. Αντίθετα όταν τρέχεις σε "κανονικό υπολογιστή" απλά δεν υπάρχει το κίνητρο -- αυτό είναι που προσπαθώ να πω.

 

Επίσης υπάρχει limited ΑΟΤ υποστήριξη σε .NET -- και πάντα ήταν πολίτης δεύτερης κατηγορίας. Για τον ίδιο λόγο: what for? Στο 99% των περιπτώσεων δεν υπάρχει πειστική απάντηση, οπότε απλά δεν το κάνεις.

 

Κλείνω με quote από το link σου:

 

 

Still, AOT "will give an opportunity for experts to find possible use cases and see where it could provide measurable benefits in practice," Klang noted. Dmitry Leskov, director of marketing at Java technology vendor Excelsior, is more positive about the long-term potential of AOT. "Now that AOT is kosher, more developers will become interested in it and if there will be enough interest from Oracle customers, more positives may come in the future," he said.

 

 

to emphasize my point πως με τις σημερινές συνθήκες, στην πλειοψηφία των περιπτόσεων, είναι μάλλον μια λύση που ψάχνει πρόβλημα και όχι το αντίθετο.

Δημοσ.

Είτε διαφωνείς είτε όχι, δεν μπορώ να πιάσω το θέμα από αλλού καθώς η ερώτηση ήταν "ποιο είναι το πρόβλημα με το AOT" :)

 

Αυτό από το προηγούμενο ποστ σου διαφέρουν αρκετά. Εδώ το πιάνεις από το γεγονός ότι το AOT στο σύμπαν της Java είναι στο 99% των περιπτώσεων άχρηστο, με το οποίο συμφωνώ, ενώ στο προηγούμενο αναφερόσουν στο ότι είναι τεχνικά δύσκολο να σχεδιάσεις γλώσσα που να στηρίζεται σε AOT και να υπακούει στο WORA, με το οποίο διαφωνώ.

 

 

Φυσικά και γίνεται να δουλέψεις μόνο AOT κλπ κλπ, έχουμε τη C και το ξέρουμε. Αλλά υπάρχουν επίσης λόγοι να μην κάνεις AOT, και προσπάθησα να το παραλληλίσω με την απόφαση "θέλουμε να βάλουμε ένα abstraction layer εδώ ή όχι". Χωρίς να λάβουμε υπόψη τους συγκεκριμένους στόχους που θέλουμε να πετύχουμε με το project δε μπορεί να απαντηθεί αυτή η ερώτηση. Η Sun με τη Java αποφάσισε να βάλει, εγώ απλά αναφέρω λόγους που μπορεί να σε οδηγήσουν σ' αυτή την απόφαση.

 

Επίσης, λες "να δώσω τα απαραίτητα σε class files". Τα class files είναι bytecode. Άρα ήδη παίρνεις σα δεδομένο πως έχεις VM. Άρα τα πράγματα γίνονται ακόμα πιο σφιχτά για την απόφαση: έχεις ήδη τη δυνατότητα να εκτελέσεις bytecode χωρίς compilation σε native. Αν κάνεις έναν μόνο compiler, προφανώς αυτός θα είναι JIT. Άρα η ερώτηση γίνεται "αξίζει εκτός από όλα αυτά να κάνουμε και AOT"; Και νομίζω πως είναι προφανές εκ του αποτελέσματος, όχι μόνο από Java αλλά και πολλές άλλες γλώσσες, πως δεν είναι καθόλου αυτόματη η απάντηση "ναι".

 

Το bytecode θα μπορούσε να είναι οποιοδήποτε ενδιάμεσο abstraction layer σε οποιαδήποτε μορφή. Επίσης στην τελική και το ίδιο το bytecode το κάνω ότι θέλω, παρόλο που σε ένα λογικό σύμπαν όταν χρησιμοποιώ κάποιο instruction set, το αναμενόμενο είναι να το δώσω σε κάποια φυσική ή εικονική μηχανή.

 

Παρ' όλα αυτά απαντούσα στην αρχική ερώτηση, που ήταν για ποιο λόγο πιθανόν, γιατί όλους τους πραγματικούς λόγους μόνο οι ίδιοι τους ξέρουν, οι μηχανικοί της Java αποφάσισαν να έχουν VM (και κατ' επέκταση bytecode) και όχι κάποιον AOT compiler και κάποιο άλλιο ενδιάμεσο layer, που θα βρίσκεται στα μηχανήματα των τελικών χρηστών. Επίσης ο JIT compiler δεν υπήρχε εξ' αρχής, αλλά μπήκε νομίζω στην Java 1.1.

 

Οπότε αν πρέπει να απαντήσω γιατί εξ' αρχής υπήρξε VM θα μπορούσα εύκολα να πω τα εξής:

  • Το κυριότερο και βασικότερο ότι η Java από την πρώτη της έκδοση υποστήριζε χαρακτηριστικά όπως τα applets. Γι' αυτά και όχι μόνο, είχε ανάγκη για instant deployment, instant run. Αυτό αν το compile πρέπει να γίνεται στο μηχάνημα του τελικού χρήστη δε γίνεται.
  • Πρόβλημα με τη συνύπαρξη τόσο του deployment package όσο και των binaries μετά τον AOT έχουν τα σημερινά android τηλέφωνα με αρκετό αποθηκευτικό χώρο, όχι τα μηχανήματα του 1995.
  • Σε μεγάλα λογισμικά ήταν πολύ δυσκολότερο εκείνη την εποχή να γίνει compile και σε εύλογο χρονικό διάστημα από τα μηχανήματα των χρηστών, λόγω περιορισμένων πόρων.

Αν η ερώτηση είναι και γιατί μετέπειτα αναπτύχθηκε JIT και όχι AOT compiler, θεωρώντας πως κάποιος που κάνει αυτή την ερώτηση έχει στο μυαλό του ότι "όλα compile = ταχύτητα":

  • Ένας καλός JIT compiler έχει τη δυνατότητα να κάνει πολύ καλύτερο optimization σε κρίσιμο κώδικα, καθώς έχει πολύ περισσότερα δεδομένα για αυτόν αφού έχει τρέξει μερικές χιλιάδες φορές, παρά ένας AOT.
  • Ένας JIT compiler στη Java, θα είχε επίδραση σε οποιοδήποτε λογισμικό ήταν γραμμένο σε αυτή μέχρι τότε.

 

Άρα ναι, ο JIT ήταν no brainer για τις χρήσεις τις Java. Ο ΑΟΤ compiler έχει νόημα όταν ενδιαφέρεσαι για consistent performance. Στις περισσότερες εφαρμογές της Java SE ή του .ΝΕΤ ακόμη και σήμερα, αυτό δεν είναι το τυπικό σενάριο, γι' αυτό και κανείς δεν ασχολήθηκε ιδιαίτερα. Όχι πάντως γιατί είναι δύσκολο να αναπτυχθεί...

  • Like 1
Δημοσ.

Πολύ κατατοπιστική η απάντηση του jimex. Thanks!

Μια ακόμα ερώτηση. Ο AOT που αναφέρθηκε πριν για .NET (ή και για Java αν υπάρχει) κάνει source to native ή CIL to native; Ή υπάρχουν και τα δύο;

Δημοσ.

Αυτό από το προηγούμενο ποστ σου διαφέρουν αρκετά. Εδώ το πιάνεις από το γεγονός ότι το AOT στο σύμπαν της Java είναι στο 99% των περιπτώσεων άχρηστο, με το οποίο συμφωνώ, ενώ στο προηγούμενο αναφερόσουν στο ότι είναι τεχνικά δύσκολο να σχεδιάσεις γλώσσα που να στηρίζεται σε AOT και να υπακούει στο WORA, με το οποίο διαφωνώ.

 

Δε νομίζω πως είπα οποτεδήποτε ότι είναι τεχνικά δύσκολο. Είπα πως είναι πρακτικά δύσκολο.

 

 

Το bytecode θα μπορούσε να είναι οποιοδήποτε ενδιάμεσο abstraction layer σε οποιαδήποτε μορφή. Επίσης στην τελική και το ίδιο το bytecode το κάνω ότι θέλω, παρόλο που σε ένα λογικό σύμπαν όταν χρησιμοποιώ κάποιο instruction set, το αναμενόμενο είναι να το δώσω σε κάποια φυσική ή εικονική μηχανή.

Δεν καταλαβαίνω τι θες να πεις εδώ. Φιλοσοφικά ναι, "θα μπορούσε" να είναι οτιδήποτε, όπως και "θα μπορούσες" να σκάψεις με οποιοδήποτε εργαλείο. Στην πράξη όμως κάποια πράγματα λειτουργούν τόσο καλύτερα από άλλα γι' αυτή τη δουλειά που σαφώς και δεν θα μπορούσε οτιδήποτε. Υπάρχει κάποιος λόγος που π.χ. τα επιβατικά μέσα μεταφοράς έχουν σε κάθε κατηγορία το ίδιο βασικά σχήμα και λειτουργικότητα.

 

 

Παρ' όλα αυτά απαντούσα στην αρχική ερώτηση, που ήταν για ποιο λόγο πιθανόν, γιατί όλους τους πραγματικούς λόγους μόνο οι ίδιοι τους ξέρουν, οι μηχανικοί της Java αποφάσισαν να έχουν VM (και κατ' επέκταση bytecode) και όχι κάποιον AOT compiler και κάποιο άλλιο ενδιάμεσο layer, που θα βρίσκεται στα μηχανήματα των τελικών χρηστών. Επίσης ο JIT compiler δεν υπήρχε εξ' αρχής, αλλά μπήκε νομίζω στην Java 1.1.

 

Οπότε αν πρέπει να απαντήσω γιατί εξ' αρχής υπήρξε VM θα μπορούσα εύκολα να πω τα εξής:

  • Το κυριότερο και βασικότερο ότι η Java από την πρώτη της έκδοση υποστήριζε χαρακτηριστικά όπως τα applets. Γι' αυτά και όχι μόνο, είχε ανάγκη για instant deployment, instant run. Αυτό αν το compile πρέπει να γίνεται στο μηχάνημα του τελικού χρήστη δε γίνεται.
  • Πρόβλημα με τη συνύπαρξη τόσο του deployment package όσο και των binaries μετά τον AOT έχουν τα σημερινά android τηλέφωνα με αρκετό αποθηκευτικό χώρο, όχι τα μηχανήματα του 1995.
  • Σε μεγάλα λογισμικά ήταν πολύ δυσκολότερο εκείνη την εποχή να γίνει compile και σε εύλογο χρονικό διάστημα από τα μηχανήματα των χρηστών, λόγω περιορισμένων πόρων.
Αν η ερώτηση είναι και γιατί μετέπειτα αναπτύχθηκε JIT και όχι AOT compiler, θεωρώντας πως κάποιος που κάνει αυτή την ερώτηση έχει στο μυαλό του ότι "όλα compile = ταχύτητα":
  • Ένας καλός JIT compiler έχει τη δυνατότητα να κάνει πολύ καλύτερο optimization σε κρίσιμο κώδικα, καθώς έχει πολύ περισσότερα δεδομένα για αυτόν αφού έχει τρέξει μερικές χιλιάδες φορές, παρά ένας AOT.
  • Ένας JIT compiler στη Java, θα είχε επίδραση σε οποιοδήποτε λογισμικό ήταν γραμμένο σε αυτή μέχρι τότε.
Άρα ναι, ο JIT ήταν no brainer για τις χρήσεις τις Java. Ο ΑΟΤ compiler έχει νόημα όταν ενδιαφέρεσαι για consistent performance. Στις περισσότερες εφαρμογές της Java SE ή του .ΝΕΤ ακόμη και σήμερα, αυτό δεν είναι το τυπικό σενάριο, γι' αυτό και κανείς δεν ασχολήθηκε ιδιαίτερα. Όχι πάντως γιατί είναι δύσκολο να αναπτυχθεί...

 

Αυτά που λες σαφώς ισχύουν, προσωπικά όμως δε νομίζω πως βρίσκουν το στόχο. Τελείως ενδεικτικά λες για instant deployment, instant run και ότι αυτό δε γίνεται στο μηχάνημα του χρήστη. Δεκτό. Από που κι ως πού όμως το compile στο μηχάνημα του χρήστη πάει χέρι χέρι με το AOT? Όλα τα AOT compiled προγράμματα που χρησιμοποιείς καθημερινά, συμπεριλαμβανομένου του browser αυτή τη στιγμή, εσύ τα έκανες compile?

 

Με άλλα λόγια, τα facts καλά τα λες αλλά δε συμφωνώ με τα συμπεράσματα στα οποία καταλήγεις.

Μια ακόμα ερώτηση. Ο AOT που αναφέρθηκε πριν για .NET (ή και για Java αν υπάρχει) κάνει source to native ή CIL to native; Ή υπάρχουν και τα δύο;

CIL to native, από τη στιγμή που ήδη έχεις compiler source to CIL τι νόημα έχει να κάνεις ξανά την ίδια δουλειά, να πρέπει να κάνεις maintain παράλληλα δύο ίδια πράγματα κλπ κλπ;

Δημοσ.

Αυτά που λες σαφώς ισχύουν, προσωπικά όμως δε νομίζω πως βρίσκουν το στόχο. Τελείως ενδεικτικά λες για instant deployment, instant run και ότι αυτό δε γίνεται στο μηχάνημα του χρήστη. Δεκτό. Από που κι ως πού όμως το compile στο μηχάνημα του χρήστη πάει χέρι χέρι με το AOT? Όλα τα AOT compiled προγράμματα που χρησιμοποιείς καθημερινά, συμπεριλαμβανομένου του browser αυτή τη στιγμή, εσύ τα έκανες compile?

 

Γιατί το νόημα είναι να μπορώ να σου κάνω deploy το ίδιο package, δίχως να με ενδιαφέρει σε τι το τρέχεις. Αυτό γίνεται μονάχα αν σου περιγράψω πλήρως το λογισμικό μου με κάποιο κοινά αποδεκτό ενδιάμεσο layer, και το τελικό binary το φτιάξεις στο μηχάνημά σου με εργαλεία που ξέρουν πως να διαβάσουν αυτό το ενδιάμεσο layer και να δώσουν binary για το μηχάνημά σου. Αν είναι να κάνω εγώ το compile και να σου δώσω έτοιμο binary για το μηχάνημά σου, τι να το κάνω; Που κολλάει αυτό με τη λογική της Java;

Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε

Πρέπει να είστε μέλος για να αφήσετε σχόλιο

Δημιουργία λογαριασμού

Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!

Δημιουργία νέου λογαριασμού

Σύνδεση

Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.

Συνδεθείτε τώρα

  • Δημιουργία νέου...