Pages

Κυριακή 20 Σεπτεμβρίου 2020

DeepSeaRobotix - coYaght

Το σχολικό έτος 2019-2020 είχα την τιμή να βρίσκομαι σε τρία πολύ καλά σχολειά. Γυμνάσια και τα τρία, αλλά πολύ ενεργά σε εξωσχολικές δραστηριότητες. Ένα από αυτά ήταν και το 1ο Γυμνάσιο Γέρακα που ανήκει στη Δ.Δ.Ε Ανατολικής Αττικής. Στο συγκεκριμμένο σχολείο υπήρξε παλαιότερα ένα project που με τη βοήθεια του Ευγενιδίου Ιδρύματος είχαν φτιάξει ένα Hydrobot. Κάποια στιγμή ένας συνάδελφος, μαζί με το Διευθυντή του σχολείου, με ρώτησαν αν ήθελα να τους βοηθήσω να το εξελίξουν. Φυσικά η απάντηση ήταν θετική.

Το σχολείο ξεκίνησε τη συμμετοχή του στο διαγωνισμό European Junior Achievement 2019-2020, όπου κάθε σχολείο που συμμετέχει δημιουργεί μια εικονική επιχείριση και προωθεί το προϊόν της. Η διαδικασία περιέχει όλα τα καλά, όπως τη δημιουργία ενός Επιχειρισιακού Πλάνου, τη Διοίκηση της Επιχείρισης, κλπ. Ο διαγωνισμός, τελικά, έγινε μέσω διαδικτύου λόγω της πανδημίας του COVID-19.

Το όνομα της επιχείρησής μας; DeepSeaRobotix Α.Β.Ε.Ε. και το προϊόν μας είχε την ονομασία coYaght, μιας κι επρόκειτο για ένα Drone Θαλάσσης που θα ήταν η εξέλιξη του Hydrobot. Στο διαγωνισμό η επιχείρισή μας βαθμολογήθηκε με 91/100 καταλαμβάνοντας τη 12η θέση, ενώ κέρδισε το Ειδικό Βραβείο Αξιοποίησης Νέων Τεχνολογιών. Στο άρθρο αυτό, θα δούμε τον τρόπο κατασκευής και λειτουργίας του coYaght, αλλά πρώτα από όλα θα ήθελα να ευχαριστήσουμε το Ευγενίδιο Ίδρυμα για την προσφορά του που μας διέθεσε δωρεάν το κιτ του Hydrobot αλλά και του συστήματος HydroSensors V2 που περιείχε ένα Arduino Uno, ένα shield με δυνατότητα χρήσης κάρτας SD για εγγραφή δεδομένων, Real Time Clock για να κρατάει την ώρα με τη βοήθεια μπαταρίας και τρεις αισθητήρες, ένα θερμοκρασίας, έναν πίεσης κι ένα φωτισμού.

Τι θα δούμε σε αυτό το άρθρο

  • Τι είναι το coYaght
    • Μονάδα τροφοδοσίας
    • Οδηγοί κινητήρων
    • Arduino Uno και Υποκυκλώματά του
    • Raspberry Pi - Ο "Εγκέφαλος" του συστήματος
  • Έλεγχος του coYaght
    • Εγκατάσταση Λειτουργικού
    • Πρώτες παραμετροποιήσεις Hardware
    • Προετοιμασία δικτύωσης
    • Σύνδεση σε δικό μας τοπικό δίκτυο
    • Εγκατάσταση Arduino Software
    • Arduino Firmware
    • Προετοιμασία βάσης δεδομένων MySQL
    • Προετοιμασία Python
    • coYaght Server
    • Αυτόματη εκκίνηση του server με την εκκίνηση του Raspberry Pi
  • Χρήση του coYaght
  • Συμπεράσματα

Τι είναι το coYaght

Το coYaght είναι ένα drone θαλάσσης. Έχει τη δυνατότητα να μπαίνει μέσα στο νερό και με τη βοήθεια τριών μοτέρ να μπορεί να κατευθυνθεί όπου ο χρήστης επιθυμεί. Το κέλυφός του είναι ελαφρύ και κατασκευασμένο από πλαστικούς σωλήνες, εκτός από το τμήμα που περιέχει τα ηλεκτρονικά συστήματα που είναι κατασκευασμένο από plexiglass. Τα τοιχώματα από plexiglass είναι κολλημένα με εποξική κόλλα έτσι ώστε να είναι στεγανά και να μη μπαίνει νερό μέσα τους.

Τα ηλεκτρονικά συστήματα που προστατεύει το κουτί από plexiglass είναι:

  • Ένα Raspberry Pi 3B+
  • Ένα Arduino Uno
  • Ένα SD Card + Real Time Clock Shield για το Arduino
  • Έναν αισθητήρα θερμοκρασίας
  • Έναν αισθητήρα πίεσης
  • Έναν αισθητήρα φωτεινότητας περιβάλλοντος
  • Μία κάμερα συνδεδεμένη στο Raspberry Pi
  • Δύο προβολείς λευκού φωτός για την κάμερα
  • Ένα κόκκινο κι ένα πράσινο φως που συμφωνούν με τα πρώτυπα της ναυσιπλοΐας (το κόκκινο αριστερά και το πράσινο δεξιά)
  • Τρεις οδηγούς για τα μοτέρ
  • Μια διάταξη τροφοδοσίας για τα ηλεκτρονικά χαμηλής τάσης (Raspberry και Arduino + Shield)

Ας γνωρίσουμε ένα-ένα τα κομμάτια του συστήματος και τη λειτουργία τους

Μονάδα τροφοδοσίας

Το coYaght τροφοδοτείται μέσω του καλωδίου δικτύου που περιέχει (Power Over Ethernet - PoE). Η τάση που δίδεται είναι μεγάλη, για να μπορέσει να κινήσει τα μοτερ της πλοήγησης και τους προβολείς. Αυτό σημαίνει πως δε μπορεί να συνδεθεί απευθείας στις ηλεκτρονικές πλακέτες του Raspberry Pi και του Arduino Uno. Επίσης, άλλο ένα πρόβλημα που υπάρχει είναι πως η τελική τάση που φτάνει στα κυκλώματα του coYaght δεν είναι καθόλου σταθερή· Εξαρτάται από την εξωτερική τροφοδοσία, τη ζήτηση σε ρεύμα την κάθε χρονική στιγμή κλπ. Η ζήτηση ρεύματος διαφέρει, διότι εξαρτάται πολύ από τον αριθμό των μοτέρ που είναι ενεργοποιημένα, αλλά και την επεξεργασία που κάνει το ίδιο το Raspberry Pi.

Για να μπορέσουμε να ξεπεράσουμε τα προβλήματα αυτά, είναι επιτακτική η ανάγκη χρήσης μιας τροφοδοτικής διάταξης που θα κατεβάζει την τάση που φτάνει στο coYaght μέσω του καλωδίου, στην τάση που μπορούν να δεχθούν τα ηλεκτρονικά κυκλώματα. Η μονάδα αυτή θα πρέπει επίσης να έχει αντοχή μεγάλη σε ριπές ρεύματος, λόγω του Raspberry Pi. Παρότι οι ασύρματες συνδέσεις BLE και WiFi δεν είναι ενεργοποιημένες, μιας και δεν είναι χρήσιμες, όπως και το γραφικό περιβάλλον χρήστη, το Raspberry Pi ζητάει ακανόνιστες ριπές ρεύματος, ανάλογα με τις λειτουργίες που εκτελεί κάθε στιγμή. Είναι, λοιπόν, ανάγκη η τροφοδοτική διάταξη να έχει αντοχές σε τέτοιες ριπές ρεύματος.

Κάτι επίσης σημαντικό, είναι πως η τροφοδοτική διάταξη θα πρέπει να έχει μεγάλη απόδοση για να θερμένεται όσο το δυνατόν λιγότερο και να μη δαπανάται ενέργεια επάνω στη λειτουργία της άσκοπα.

Η μονάδα τροφοδοσίας που χρησιμοποιήθηκε βασίστηκε στον ολοκληρωμένο σταθεροποιητή τάσης LM2596S-5.0. Είναι ένας σταθεροποιητής τύπου παλμοτροφοδοτικού για να επιτύχει μεγάλη απόδοση και μικρή αύξηση θερμοκρασίας. Το σχηματικό διάγραμμα του κυκλώματος φαίνεται στην ακόλουθη εικόνα:

Το κύκλωμα έχει δημιουργηθεί επάνω σε ένα κομμάτι διάτρητης πλακέτας, ενώ χρησιμοποιείται κι ένα κομμάτι φύλλου χαλκού για να λειτουργήσει ως ψύκτρα του σταθεροποιητή.

Οδηγοί κινητήρων

Το CoYaght διαθέτει τρεις κινητήρες (μοτέρ) για την πλοήγησή του μέσα στη θάλασσα, ένα για την κατακόρυφη κίνηση (βύθιση ή ανάδυση), ένα για την κίνηση του δεξιού του μέρους κι ένα για την κίνηση του αριστερού. Η κίνηση των δύο τελευταίων μπορεί να είναι και προς τις δύο κατευθύνσεις (πρόσω και όπισθεν). Οι κινητήρες λειτουργούν με τάση 12V ενώ οδηγούνται από τη μονάδα Arduino Uno. Συνεπώς, πρέπει να μπορούν να κινηθούν είτε δεξιόστροφα, είτε αριστερόστροφα με τάση οδήγησης αρκετά μεγαλύτερη από αυτή του κυκλώματος που δίνει τις εντολές.

Για να μπορέσει το Arduino να οδηγήσει τους κινητήρες θα πρέπει να παρεμβληθεί ένα κύκλωμα που να έχει τη δυνατότητα να οδηγεί τους κινητήρες με μεγάλη τάση (σε σύγκριση με αυτή του Arduino) ενώ ταυτόχρονα για πρέπει να μπορεί να επιλεχθεί και η πολικότητά της. Το κύκλωμα βασίζεται στην αρχή λειτουργείας της γέφυρας με MOSFET. Η γέφυρα οδηγείται από ειδικό ολοκληρωμένο κύκλωμα για να αποφευχθούν συμπεριφορές βραχυκυκλώματος της τροφοδοσίας και κατά συνέπεια την καταστροφή των κυκλωμάτων. Τα MOSFET λειτουργούν ως διακόπτες που συνδέουν το κάθε άκρο του μοτέρ που οδηγούν, είτε στα +12V, είτε στο 0. Το ποιο άκρο θα συνδεθεί πού, εξαρτάται από την εντολή που δίνει το Arduino.

Το σχηματικό διάγραμμα του κυκλώματος οδήγησης ενός κινητήρα φαίνεται στην ακόλουθη εικόνα:

Arduino Uno και Υποκυκλώματά του

Το όλο σύστημα του coYaght περιέχει ένα μικρό προγραμματιζόμενο υπολογιστή, μικρών δυνατοτήτων, το Arduino Uno. Αυτό δομείται από ένα μικροελεγκτή τύπου AVR atmega328P της Atmel (πλέον κομμάτι της Microchip, Inc.). Το κύκλωμα είναι open source. Έχει ένα απλό περιβάλλον προγραμματισμού που μπορούμε να γράψουμε κώδικα και να προγραμματίσουμε το Arduino με γλώσσα που μοιάζει αρκετά με τη C. Επιπλέον, περιέχει πολλές έτοιμες βιβλιοθήκες που μας γλυτώνουν από τον κόπο του προγραμματισμού χαμηλού επιπέδου και κάνουν τη ζωή μας πιο εύκολη. Με αυτό τον τρόπο, ο χρόνος που χρειαζόμαστε για να φτιάξουμε μια πλήρη εφαρμογή είναι αρκετά μικρότερος σε σύγκριση με περιπτώσεις χρήσης μικροελεγκτών άλλων εταιριών. Καθίσταται ιδανικό, λοιπόν, για ένα σχολικό περιβάλλον και μαθητές με όρεξη να γευτούν τον κόσμο των ψηφιακών ηλεκτρονικών και του προγραμματισμού.

Οι δυνατότητες που παρέχει το Arduino είναι η οδήγηση ή το διάβασμα ψηφιακών σημάτων, το διάβασμα αναλογικών σημάτων (ο μικροελεγκτής περιέχει μετατροπέα αναλογικού σήματος σε ψηφιακό), η επικοινωνία μέσω σειριακής θύρας, η οποία δρομολογείται σε υπολογιστή μέσω συνδέσμου USB. Υπάρχουν, επίσης, στο εμπόριο αρκετά κυκλώματα που εφαρμόζουν στους συνδέσμους του, δίνοντάς του επιπλέον δυνατότητες. Αυτά τα ονομάζουμε shields.

Στην περίπτωση του coYaght, το Arduino είναι το σύστημα που παίρνει μετρήσεις από τους αισθητήρες που είναι συνδεδεμένοι σε αυτό. Τις μετρήσεις τις δίνει στη σειριακή του έξοδο, η οποία οδηγείται στο σύνδεσμο USB. Αυτό σημαίνει πως ένας υπολογιστής συνδεδεμένος στο USB του, μπορεί να διαβάσει τις μετρήσεις που δίνει κάθε δευτερόλεπτο, το Arduino.

Κάτι ακόμα που κάνει το Arduino για το coYaght, είναι το να οδηγεί τους τρεις κινητήρες πλοήγησης. Ο τρόπος που θα πλοηγηθεί το coYaght μέσα στη θάλασσα περιγράφεται από εντολές που δίνει ο χρήστης, πού αλλού; στη σειριακή του πόρτα.

Τέλος, χρησιμοποιείται ένα shield που περιέχει ένα ολοκληρωμένο Real Time Clock (RTC) και μια θέση κάρτας SD. Η δουλειά του RTC είναι να μετράει το χρόνο, κρατώντας την ημερομηνία και την τρέχουσα ώρα. Τροφοδοτείται από μια μπαταρία, έτσι ώστε ακόμα κι αν το σύστημα δεν τροφοδοτείται, το RTC να συνεχίζει να μετράει το χρόνο χωρίς να χάνει ούτε δευτερόλεπτο. Το τμήμα της κάρτας SD δε χρησιμοποιείται στο coYaght.

Το μπλοκ διάγραμμα του υποσυστήματος φαίνεται στο ακόλουθο σχήμα:

Στο διάγραμμα, τα τμήματα που φαίνονται ως κινητήρες, εννοείται πως είναι μαζί και τα αντίστοιχα κυκλώματα οδήγησης.

Raspberry Pi - Ο "Εγκέφαλος" του συστήματος

Στο σύστημα του coYaght πρέπει να υπάρχει κι ένα υπολογιστικό σύστημα ικανό να μπορεί να συνδέεται με μια κάμερα και να δίνει το βίντεό της διαμέσου δικτύου σε real time streaming. Μια καλή λύση είναι ο υπολογιστής μιας πλακέτας Raspberry Pi και συγκεκριμμένα η έκδοση 3B+. Ο υπολογιστής αυτός διαθέτει όλα τα χαρακτηριστικά που χρειάζονται: Δικτύωση ethernet, σύνδεση για κάμερα, σύνδεση USB για να συνδεθεί το Arduino κλπ.

Το Raspberry τρέχει λειτουργικό Linux. Αυτό λύνει τα χέρια, τόσο στα θέματα της δικτύωσης και το χειρισμό περιφερειακών συσκευών, όπως η κάμερα και το Arduino, όσο και στην ανάπτυξη του κώδικα που χρειάζεται για να μπορέσει να λειτουργήσει σαν εξυπηρετητής web και να παρέχει ένα αρκετα φιλικό περιβάλλον χρήστη για το χειρισμό του συστήματος coYaght. Εύκολα δίνεται η δυνατότητα σύνδεσης σε κάποιο φορητό υπολογιστή, ο προγραμματισμός σε γλώσσα προγραμματισμού Python, ακόμα και η αναβάθμιση του firmware του Arduino. Η σύνδεση για τις ανάγκες προγραμματισμού γίνεται μέσω SSH ενώ μπορούν να τρέχουν ταυτόχρονα κι άλλοι servers για τις ανάγκες της δικτύωσης, όπως DHCP. Στη συνέχεια θα δούμε το στήσιμό του για να μπορέσει το coYaght να αποτελέσει ένα ολοκληρωμένο σύστημα υποβρύχιου drone.

Έλεγχος του coYaght

Όλος ο έλεγχος του coYaght γίνεται διαμέσου του Raspbery Pi. Ας δούμε, αρχικά, τον τρόπο με τον οποίο επιθυμούμε να λειτουργεί και με βάση αυτή τη λογική θα στήσουμε σιγά-σιγά το Raspberry για την επίτευξη του τελικού μας στόχου.

Κατ' αρχήν, η χρήση του συστήματος θα πρέπει να γίνεται από ένα απλό φυλλομετρητή (browser) σε ένα υπολογιστή ανεξαρτήτου λειτουργικού συστήματος. Αυτό σημαίνει πως θα πρέπει να υπάρχει μια σύνδεση δικτύου μεταξύ ενός υπολογιστή και του coYaght. Η σύνδεση με την οποία λειτουργεί το coYaght είναι μέσω καλωδίου ethernet το οποίο μεταφέρει και την ισχύ τροφοδοσίας του (Power over Ethernet - PoE).

Όταν το coYaght συνδεθεί, με τη βοήθεια καλωδίου, στον υπολογιστή, θα πρέπει ο χρήστης να μπορεί να ανοίξει όποιο φυλλομετρητή επιθυμεί και να μπει στην ιστοσελίδα του coYaght. Εκεί θα πρέπει να υπάρχουν όλα τα διαθέσιμα χειριστήρια αλλά και ενδείξεις που να δείχνουν την κατάσταση των αισθητήρων και το βίντεο της κάμερας. Τα χειριστήρια θα πρέπει να δίνουν τη δυνατότητα πλοήγησής του με ευκολία.

Όλα αυτά, παρότι φαίνονται εύκολα σαν ιδέα, κρύβουν πολλές λεπτομέρειες που θα πρέπει να υλοποιηθούν για να μπορέσουμε να έχουμε το επιθυμητό αποτέλεσμα. Ας δούμε, λοιπόν, το στήσιμο κομμάτι-κομμάτι.

Εγκατάσταση Λειτουργικού

Το Raspberry Pi είναι, όπως λέμε, υπολογιστής μιας πλακέτας (Single Board Computer - SBC). Για να γίνει χρήσιμο πρέπει να του φορτώσουμε ένα λειτουργικό σύστημα, όπως και στους υπολογιστές μας. Η εγκατάσταση γίνεται σε μια κάρτα μνήμης microSD. Η εγκατάσταση του λειτουργικού συστήματος γίνεται όπως περιγράφεται στο site του Raspberry.org. Στη σελίδα περιγράφεται η εγκατάσταση διαφόρων λειτουργικών. Εμείς χρησιμοποιήσαμε το προκαθορισμένο Raspberry Pi OS που είναι βασισμένο στο Ubuntu.

Μετά την εγκατάσταση του λειτουργικού στη διαθέσιμη microSD κάρτα, τποθετούμε την κάρτα στο Raspberry Pi, του συνδέουμε ένα πληκτρολόγιο, ένα ποντίκι μια οθόνη και δίκτυο. Λίγα δευτερόλεπτα μετά την ενεργοποίησή του βλέπουμε την αρχική οθόνη του γραφικού περιβάλλοντος Ubuntu.

Πρώτες παραμετροποιήσεις Hardware

Η παραμετροποίηση του Raspberry γίνεται από το εργαλείο raspi-config. Μιας και μιλάμε για παραμετροποίηση συστήματος, φυσικά, το raspi-config πρέπει να τρέξει κάτω από τον χρήστη root. Για να το τρέξουμε, ανοίγουμε μια κονσόλα και γράφουμε:

pi@coyaght:~ $ sudo raspi-config

Το ακόλουθο παράθυρο ανοίγει:

Με το πληκτρολόγιο μπορούμε να πλοηγηθούμε μέσα στα μενού και τις επιλογές του παραθύρου. Κάνουμε τις ακόλουθες επιλογές:

  • Network Options -> Hostname -> OK -> coyaght: Ρυθμίζουμε την ονομασία του coYaght. Πρέπει να χρησιμοποιήσουμε πεζούς χαρακτήρες σε όλα τα γράμματα
  • Boot Options -> Desktop / CLI -> Console: Απενεργοποιούμε το γραφικό περιβάλλον για να μη χρησιμοποιεί πόρους του συστήματος, αφού δεν πρόκειται να το συνδέσουμε σε μια οθόνη
  • Localization Options -> Change Time Zone -> Europe -> Athens: Ρυθμίζουμε τη ζώνη ώρας του συστήματος, να είναι σύμφωνη με τα πρότυπα της Ελλάδας
  • Interfacing Options -> Camera -> Yes: Ενεργοποιούμε το δίαυλο επικοινωνίας του επεξεργαστή με την κάμερα
  • Interfacing Options -> SSH -> Yes: Ενεργοποιούμε την πρόσβαση μέσω SSH

Προετοιμασία δικτύωσης

Συνέχεια έχει η προετοιμασία του δικτύου. Όταν το coYaght συνδέεται σε ένα laptop, στο χώρο στον οποίο θα χρησιμοποιηθεί, πρέπει να μην υπάρχει η ανάγκη ενός router ή άλλης δικτυακής συσκευής. Αυτό σημαίνει πως το σύστημα θα πρέπει να έχει μια στατική διεύθυνση δικτύου IP και να μπορεί να στείλει χαρακτηριστικά δικτύωσης και στο εν λόγω laptop. Χρειάζεται, δηλαδή, να τρέχει ένας DHCP server στο Raspberry Pi για να μπορέσει να γίνει η επικοινωνία σωστά. Άλλο ένα σημαντικό πράγμα που θα πρέπει να προσέξουμε, είναι πως αν το laptop έχει και ασύρματη σύνδεση, επειδή υπάρχουν πιθανότητες να είναι και αυτή συνδεδεμένη σε κάποιο ασύρματο δίκτυο, τα δύο υποδίκτυα να μην είναι κοινά. Με βάση όλες αυτές τις παραμέτρους, θα ορίσουμε τη διεύθυνση του Raspberry να είναι η 192.168.111.10/24. Ας δούμε πως γίνεται αυτή η διαδικασία.

Για να ρυθμίσουμε τη στατική IP θα πρέπει να ανοίξουμε το αρχείο /etc/dhcpcd.conf. Εκεί μέσα βάζουμε τις κατάλληλες ρυθμίσεις για το interface eth0. Φυσικά αν υπάρχουν προηγούμενες ρυθμίσεις θα πρέπει να τις σβήσουμε. Με τον επιθυμητό editor ανοίγουμε το αρχείο πάντα ως root και το τροποποιούμε:

pi@coyaght:~ $ sudo vi /etc/dhcpcd.conf

interface eth0
  static ip_address=192.168.111.10/24
  static routers=192.168.111.1
  static domain_name_servers=8.8.8.8

Το επόμενο βήμα είναι να κάνουμε το Raspberry Pi να λειτουργεί και ως DHCP server. Το πρωτο πράγμα που πρέπει να κάνουμε είναι να εγκαταστήσουμε το κατάλληλο πακέτο:

pi@coyaght:~ $ sudo apt-get install isc-dhcp-server

Στη συνέχεια πρέπει να παραμετροποιήσουμε τον εξυπηρετητή. Το πρώτο πράγμα που πρέπει να κάνουμε είναι να του πούμε ποιον δικτυακό σύνδεσμο θα χρησιμοποιεί:

pi@coyaght:~ $ sudo vi /etc/default/isc-dhcp-server

Προς το τέλος του αρχείου θα βρούμε κάπου τη γραμμή INTERFACESv4. Θα πρέπει να σιγουρευτούμε πως περιέχει μέσα το σύνδεσμο eth0. Με αυτό τον τρόπο λέμε στο server πως θα εξυπηρετεί το σύνδεσμο eth0 στον οποίο θα συνδέεται ο υπολογιστής:

INTERFACESv4="eth0"
INTERFACESv6=""

Τώρα πρέπει να του πούμε τι παραμέτρους θα στέλνει στους clients. Αυτές βρίσκονται στο αρχείο /etc/dhcp/dhcpd.conf:

pi@coyaght:~ $ sudo vi /etc/dhcp/dhcpd.conf

Στην αρχή του αρχείου βρίσκουμε τις γραμμές για options του domain-name και του domain-name-servers. Δίνουμε τις ακόλουθες τιμές:

# option definitions common to all supported networks...
option domain-name "coyaght_home";
option domain-name-servers 192.168.111.1;

Ο server αυτός είναι ο κυρίαρχος server του δικτύου, μιας και θα είναι ο μοναδικός μεταξύ του coYaght και του laptop που θα το χειρίζεται. Πρέπει να ενεργοποιήσουμε το authoritative. Ψάχνουμε μέσα στο αρχείο και το ενεργοποιούμε:

# If this DHCP server is the official DHCP server for the local
# network, the authoritative directive should be uncommented.
authoritative;

Τέλος προσθέτουμε γραμμές για τη δημιουργία του υποδικτύου που χρειάζεται να εξυπηρετεί αυτός ο DHCP:

subnet 192.168.111.0 netmask 255.255.255.0 {
  range 192.168.111.11 192.168.111.249;     #//Available address range to clients
  option domain-name-servers 192.168.111.1; #//DNS requests are sent to router (Though there won't be any :)
  option domain-name "coyaght_home";        #//The domain name. Here we set the same as earlier
  option routers 192.168.111.1;             #//The router is the gateway to other networks
  option broadcast-address 192.168.111.255; #//Broadcast address for this subnet
  default-lease-time 600;
  max-lease-time 7200;
}

Τώρα μένει να ενεργοποιήσουμε την υπηρεσία, ώστε να τρέχει αυτόματα στην εκκίνηση του συστήματος:

pi@coyaght:~ $ sudo update-rc.d isc-dhcp-server start
pi@coyaght:~ $ sudo service isc-dhcp-server start

Η τελευταία εντολή τρέχει την υπηρεσία αυτή τη στιγμή. Τώρα αν συνδέσουμε το καλώδιο δικτύου του coYaght σε έναν υπολογιστή, αυτός πρέπει να πάρει αυτόματα μια διεύθυνση IP στο υποδίκτυο 192.168.111.x

Τέλος, (για την ώρα), μιας και μέχρι να τελειώσουμε με την όλη εγκατάσταση ώστε να έχουμε ένα λειτουργικό coYaght, η σύνδεσή του θα γίνεται στο δικό μας τοπικό δίκτυο, καλό είναι να φτιάξουμε ένα μικρό script που να προσθέτει ρυθμίσεις ώστε να λειτουργεί σωστά ΚΑΙ στο δικό μας δίκτυο. Φτιάχνουμε ένα αρχείο που το ονομάζουμε bin/initnet.sh:

pi@coyaght:~ $ vi bin/initnet.sh

Στο αρχείο βάζουμε τις ακόλουθες γραμμές:

#!/bin/bash
# Must be run using sudo!
service isc-dhcp-server stop
ip address add 192.168.1.16/24 dev eth0
ip route del default
route add default gw 192.168.1.1 dev eth0
echo "The network is ready."

Το script αυτό κάνει τις εξής εργασίες:

  • Απενεργοποιεί προσωρινά τον DHCP server. Το δίκτυό μας σίγουρα έχει το δικό του από το router μας και δεν είναι καλό αυτά τα δύο να λειτουργούν ταυτόχρονα. Κάποια δικτυακή συσκευή θα μπορούσε να πάρει τις ρυθμίσεις που στέλνει το coYaght και να μην έχει πρόσβαση στο διαδίκτυο.
  • Προσθέτει μια IP διεύθυνση στον σύνδεσμο ethernet. Τώρα το coYaght ακούει και στις δύο διευθύνσεις (192.168.111.10 και 192.168.1.16).
  • Σβήνει το default route μιας και δεν υπάρχει σύνδεση internet σε αυτή
  • Προσθέτει ως default route το router του δικτύου μας, ώστε να έχει το coYaght πρόσβαση στο διαδίκτυο για updates και εγκαταστάσεις άλλων προγραμμάτων

Τώρα πρέπει να δηλωθεί ως εκτελέσιμο:

pi@coyaght:~ $ chmmod +x bin/initnet.sh

Τώρα, όταν συνδέουμε το coYaght στο δικό μας δίκτυο μπορούμε να μπαίνουμε με ssh και να τρέχουμε το script που μόλις φτιάξαμε με:

pi@coyaght:~ $ sudo bin/initnet.sh

Είναι, πλέον ώρα, να αρχίσουμε να λειτουργούμε το Raspberry Pi μέσω δικτύου. Το απενεργοποιούμε και μπορουμε να το συνδέσουμε στ δίκτυό μας με ένα καλώδιο:

pi@coyaght:~ $ sudo shutdown -h now

Σύνδεση σε δικό μας τοπικό δίκτυο

Στην κατάσταση που βρίσκεται αυτή τη στιγμή το Raspberry Pi δεν έχει πρόβλημα να συνδεθεί στο δικό μας τοπικό δίκτυο, όσο το προετοιμάζουμε για το coYaght. Αν θέλετε, πλέον μπορείτε να του αποσυνδέσετε το πληκτρολόγιο, το ποντίκι και την οθόνη. Είναι ρυθμισμένο για να μπορούμε να το χρησιμοποιούμε μέσω δικτύου.

Αυτό που θα πρέπει να προσέξουμε είναι πως όταν το συνδέσουμε στο δίκτυό μας, το Raspberry Pi ήδη τρέχει ένα DHCP server. Αν τον αφήσουμε έτσι, τότε αν προσπαθήσει να συνδεθεί κάποια άλλη συσκευή, δύο DHCP servers, ένας από το router του δικτύου μας κι ένας από το Raspberry Pi, θα στείλουν ρυθμίσεις. Η συσκευή έχει πιθανότητες να πάρει τις ρυθμίσεις του τελευταίου και να μη μπορεί να επικοινωνήσει σωστά ούτε με τις συσκευές του δικτύου, ούτε με το internet. Έτσι, θα πρέπει με το που ενεργοποιηθεί να συνδεθούμε και να τρέξουμε το script που φτιάξαμε τελευταίο.

Για να μπορέσουμε να συνδεθούμε θα πρέπει οι ρυθμίσεις της κάρτας δικτύου μας να είναι για το ίδιο υποδίκτυο που θεωρεί το Raspberry, δηλάδη το 192.168.111.0/24. Ανάλογα, λοιπόν, με το λειτουργικό που τρέχει ο υπολογιστής μας θα πρέπει να κάνουμε τις κατάλληλες ρυθμίσεις στην κάρτα δικτύου. Στην περίπτωση που και ο υπολογιστής μας τρέχει κάποια διανομή Linux μπορούμε να δώσουμε τις ακόλουθες εντολές σε μια κονσόλα:

eliaschr@pluto:~> su
Password: 
pluto:/home/eliaschr # ip address add 192.168.111.11/24 dev eth0
pluto:/home/eliaschr # exit

Σε διανομές βασισμένες σε Ubuntu, αρκεί να δώσουμε, αντί για τις παραπάνω, μόνο την ακόλουθη:

eliaschr@pluto:~> sudo ip address add 192.168.111.11/24 dev eth0

Θα έχει το ίδιο αποτέλεσμα. Τώρα, μπορούμε πολύ εύκολα να μπούμε στο Raspberry Pi και να εκτελέσουμε το Script bin/initnet.sh

eliaschr@pluto:~> ssh pi@192.168.111.10
pi@192.168.111.10's password: 
Linux coyaght 5.4.72-v7+ #1356 SMP Thu Oct 22 13:56:54 BST 2020 armv7l

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Mon Nov  9 18:35:46 2020 from 192.168.111.11

SSH is enabled and the default password for the 'pi' user has not been changed.
This is a security risk - please login as the 'pi' user and type 'passwd' to set a new password.

pi@coyaght:~ $ sudo bin/initnet.sh
The network is ready.
pi@coyaght:~ $ 

Πλέον το σύστημα είναι εναρμονισμένο με το δικό μας δίκτυο και μπορούμε να κάνουμε όλους τους υπόλοιπους χειρισμούς για να το ολοκληρώσουμε.

Εγκατάσταση Arduino Software

Είναι ώρα να εγκαταστήσουμε προγράμματα. Μιας και το Raspberry Pi θα συνδεθεί με ένα Arduino μέσω USB θύρας, καλό είναι να έχουμε μέσα τα προγράμματα που μας χρειάζονται για να μπορούμε να κάνουμε και τον προγραμματισμό του τελευταίου. Αυτό θα μας βοηθήσει να μπορούμε να πειράζουμε το Firmware του ακόμα κι όταν τα ηλεκτρονικά κυκλώματα είναι αεροστεγώς κλεισμένα μέσα στο κουτί από plexiglass. Το βασικό πρόγραμμα που χρειαζόμαστε είναι το arduino-cli, αλλά για λόγους πληρότητας θα εγκαταστήσουμε και το περιβάλλον του Arduino IDE. Από τις ακόλουθες εντολές, οι δύο πρώτες είναι για να αναβαθμιστούν τα ήδη εγκαταστημένα πακέτα. Είναι μια διαδικασία που μας βοηθάει να έχουμε τις πιο πρόσφατες ενημερώσεις του λογισμικού μας:

pi@coyaght:~ $ sudo apt-get update
  .
  .
  .
pi@coyaght:~ $ sudo apt-get upgrade
  .
  .
  .
pi@coyaght:~ $ sudo apt-get install arduino
  .
  .
  .
pi@coyaght:~ $ sudo apt-get install avrdude
  .
  .
  .
pi@coyaght:~ $ sudo apt-get install avrdude-doc
  .
  .
  .
pi@coyaght:~ $ mkdir Downloads
pi@coyaght:~ $ cd Downloads/
pi@coyaght:~ $ curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | sh
  .
  .
  .
pi@coyaght:~ $ mv bin/ ..
pi@coyaght:~ $ cd ..
 

Τώρα θα πρέπει να ρυθμίσουμε το arduino-cli για να μπορεί να δει το Arduino μας:

pi@coyaght:~ $ arduino-cli config init
  .
  .
pi@coyaght:~ $ arduino-cli core update-index
  .
  .
pi@coyaght:~ $ arduino-cli core install arduino:avr

Μετά από αυτές τις εντολές, το arduino-cli θα μπορεί να δει κανονικά το Arduino μας και να το προγραμματίσει. Πώς, όμως, μπορεί να γίνει αυτό; Η δύναμη του arduino-cli είναι πως μπορεί να φορτώσει στο Arduino οποιδήποτε .hex αρχείο θελήσουμε. Για να δημιουργήσουμε το αρχείο .hex της εφαρμογής μας, μπορούμε να το κάνουμε στον υπολογιστή, στον οποίο κάνουμε και την ανάπτυξή του. Έχοντας την εφαρμογή του Arduino ανοιχτή στο Arduino IDE, πατάμε το πλήκτρο Verify. Στο κάτω τμήμα του παραθύρου βλέπουμε τα μηνύματα της μεταγλώτισσης. Στο τέλος, μπορούμε να δούμε σε ποιο κατάλογο καταχωρεί το τελικό εκτελέσιμο αρχείο που δημιουργήθηκε. Στη δικιά μας περίπτωση το αρχείο λέγεται /tmp/arduino_build_361228/hydrosensor_shield.ino.elf. Κάθε φορά που τρέχουμε το περιβάλλον ανάπτυξης, αυτός ο κατάλογος αλλάζει, γι' αυτό και πρέπει να το κοιτάζουμε κάθε φορά. Στον ίδιο κατάλογο βρίσκεται και το αρχείο που θα πούμε στο arduino-cli να στείλει στο arduino του coYaght.

Αρχικά θε πρέπει να αντιγράψουμε το .hex αρχείο στο Raspberry Pi για να προγραμματίσουμε το Arduino. Η εντολή που μας χρειάζεται είναι:

eliaschr@pluto:~> scp /tmp/arduino_build_361228/hydrosensor_shield.ino.hex pi@192.168.111.10:/home/pi/Dow
nloads/
pi@192.168.111.10's password: 
hydrosensor_shield.ino.hex                                                100%   29KB  29.0KB/s   00:00    

Αν συνδέσουμε το Arduino στο Raspberry Pi, τότε στο τελευταίο δημιουργείται μια σειριακή πόρτα με την ονομασία /dev/ttyACM0. Μέσω αυτής είναι που γίνεται η επικοινωνία μεταξύ των δύο. Για να γίνει ο προγραμματισμός, πρέπει να μπούμε στον κατάλογο που γράψαμε το .hex αρχείο και να χρησιμοποιήσουμε το arduino-cli:

pi@coyaght:~ $ cd Downloads/
pi@coyaght:~/Downloads $ arduino-cli upload -b arduino:avr:uno -p /dev/ttyACM0 -t -v -i hydrosensor_shiel
d.ino.hex
  .
  .

Μόλις τελειώσει η διαδικασία, το arduino θα τρέχει τον κώδικα που του στείλαμε.

Arduino Firmware

Τον τελικό κώδικα του firmware μπορεί κανείς να τον κατεβάσει από το GitHub. Θα πρέπει να κατεβάσετε τα τέσσερα αρχεία .ino και να τα τοποθετήσετε μέσα σε ένα κατάλογο με το όνομα hydrosensor_shield. Από εκεί μπορείτε να ανοίξετε το hydrosensor_shield.ino με το περιβάλλον προγραμματισμού Arduino IDE, να το παραλάξετε και να το λειτουργήσετε όπως επιθυμείτε. Μπορείτε να το κάνετε compile με το πλήκτρο Verify και να το στείλετε στο Arduino σας.

Ο κώδικας του firmware είναι βασισμένος στον κώδικα που δίνει το Ευγενίδιο Ίδρυμα στο αντίστοιχο project Hydrobot. Φυσικά έχουν γίνει αρκετές τροποποιήσεις για να μπορέσει να έρθει στα "μέτρα" του coYaght. Έχει απενεργοποιηθεί το τμήμα που ασχολείται με την SD κάρτα μνήμης, έχουν προστεθεί εντολές και παραμετροποιήσεις κι έχει παραλλαχθεί το μήνυμα των μετρήσεων που δίνει στη σειριακή θύρα, έτσι ώστε να ταιριάζει καλύτερα στο δικό μας σύστημα.

Στη σελιδα του GitHub υπάρχουν διαθέσιμες πληροφορίες για τον κώδικα του firmware. Τα ίδια τα αρχεία περιέχουν αρκετές πληροφορίες μέσα. Έτσι, μπορείτε να δείτε με λεπτομέρειες τον τρόπο με τον οποίο λειτουργεί όλο το firmware.

Προετοιμασία βάσης δεδομένων MySQL

Το σύστημά μας χρησιμοποιεί μια βάση δεδομένων για να καταχωρεί τις μετρήσεις έτσι ώστε όταν χρειαστεί να μπορέσουμε να τις ξαναδούμε. Η επιλεγμένη βάση δεδομένων είναι η MySQL (ή σε νεότερες εκδόσεις, mariaDB). Για να την εγκαταστήσουμε αρκεί η εντολή:

pi@coyaght:~ $ sudo apt-get install mariadb-server

Αρχικά η MySQL είναι ρυθμισμένη με ανοικτό το χρήστη root, τη σύνδεση νέσω δικτύου κλπ. Καλό είναι να γίνουν οι απαραίτητες ρυθμίσεις για τη θωράκιση του συστήματος:

pi@coyaght:~ $ sudo mysql_secure_installation

Με αυτή την εντολή μπορούμε να ρυθμίσουμε ένα password της αρεσκείας μας για το χρήστη root, να σβήσουμε τους ανώνυμους χρήστες, να απαγορέψουμε την πρόσβαση στη βάση δεδομένων από τον χρήστη root απομακρυσμένα και να σβήσουε την πρoτοποθετημένη βάση δεδομένων test. Φυσικά δεν ξεχνάμε να πούμε να επαναφορτωθούν τα δικαιώματα των χρηστών του εξυπηρετητή.

Το σύστημα του coYaght χρειάζεται ένα δικό του χρήστη και μια δικιά του βάση με τους δικούς της πίνακες. Ας δούμε πως θα γίνουν όλες αυτές οι ρυθμίσεις. Πρώτα θα δημιουργήσουμε τη βάση δεδομένων και τον χρήστη της:

pi@coyaght:~ $ mysql -u root -p
Enter password:
  .
  .

Στο σημείο αυτό έχουμε μπει στον server της MySQL. Ας δημιουργήσουμε τη βάση δεδομένων και τον χρήστη της:

MariaDB [(none)]> CREATE DATABASE coYaght;
CREATE USER 'coyaght'@localhost IDENTIFIED BY 'coYaght_Gerakas';
GRANT ALL PRIVILEGES ON coYaght.* TO 'coyaght'@localhost;
FLUSH PRIVILEGES;
EXIT;

Σειρά έχει το να φτιάξουμε τον πίνακα που θε κρατάει τις μετρήσεις από τους αισθητήρες. Ο πίνακας θα πρέπει να έχει επτά στήλες. Ο τρόπος δημιουργίας του φαίνεται ακολούθως:

pi@coyaght:~ $ mysql -u coyaght -p
Enter password:
  .
  .
MariaDB [(none)]> USE coYaght;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
MariaDB [coYaght]> CREATE TABLBE `measurements` (
    -> `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
    -> `DateStamp` DATETIME NOT NULL,
    -> `Temp` DECIMAL(5,2) NOT NULL,
    -> `Press` DECIMAL(8,2) NOT NULL,
    -> `Depth` DECIMAL(7,3) NOT NULL,
    -> `Lux` DECIMAL(7,2) NOT NULL,
    -> `Batt` DECIMAL(4,2) NOT NULL,
    -> PRIMARY KEY (`id`),
    -> UNIQUE KEY `DateStamp` (`DateStamp`)
    -> ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Τώρα η βάση δεδομένων του coYaght είναι έτοιμη να δεχθεί δεδομένα.

Προετοιμασία Python

Για να λειτουργήσει το σύστημα, ο server που δημιουργούμε έχει γραφτεί σε python 3. Αυτό σημαίνει πως χρειάζονται τα κατάλληλα modules για να μπορέσει να γίνει χρήση της βάσης δεδομένων, της κάμερας και της σειριακής πόρτας. Το σύστημα πρέπει να έχει τη δυνατότητα να χρησιμοποιεί νήματα για να μπορεί να στέλνει δεδομένα από την κάμερα, να ελέγχει τα δεδομένα από τη σειριακή πόρτα και να στέλνει σε αυτήν εντολές. Όλα αυτά είναι ασύγχρονα κι έτσι δε θα μπορούσε ποτέ να γίνει με άλλο τρόπο.

Για να εγκαταστήσουμε τη βιβλιοθήκη που μας δίνει πρόσβαση στην κάμερα, εκτελούμε την εντολή:

pi@coyaght:~ $ sudo apt-get install python3-picamera ffmpeg python3-ws4py

Η βιβλιοθήκη χρήσης της κάμερας από την python είναι η picamera. Η βιβλιοθήκη ffmpeg είναι για επεξεργασία της εικόνας της κάμερας. Κανονικά δεν είναι απαραίτητη, αλλά μπορεί να μας φανεί χρήσιμη σε κάποιες περιπτώσεις test. Τέλος η βιβλιοθήκη ws4py δίνει τη δυνατότητα στην python να χρησιμοποιεί web sockets. Είναι χρήσιμη για το video streaming που θέλουμε να πετύχουμε. Οι δύο τελευταίες βιβλιοθήκες μας χρειάστηκαν κατά τη διάρκεια ανάπτυξης του κώδικα του συστήματος για διάφορα test. Δεν είναι απαραίτητες για την τελική λειτουργία του coYaght.

Για να εγκαταστήσουμε την κατάλληλη βιβλιοθήκη χρήσης της σειριακής πόρτας θα πρέπει πρώτα να εγαταστήσουμε το pip3:

pi@coyaght:~ $ sudo apt-get install python3-pip

Τώρα είμαστε σε θέση να εγκαταστήσουμε τη βιβλιοθήκη χρήσης της σειριακής θύρας, pyserial:

pi@coyaght:~ $ sudo pip3 install pyserial

Αν δε χρησιμοποιηθεί η εντολή sudo πριν την pip3, τότε η βιβλιοθήκη θα εγκατασταθεί, αλλά τοπικά στο χρήστη και όχι καθολικά στο σύστημα. Παρόλα αυτά θα συνεχίσει να είναι λειτουργική, αλλά πριν τη χρησιμοποιήσουμε ως root θα πρέπει να προσθέσουμε τον κατάλογο /home/pi/.local/lib/python3.7/site-packages στη μεταβλητή συστήματος PYTHONPATH.

Τέλος, θα πρέπει να εγκαταστήσουμε τη βιβλιοθήκη που δίνει τη συνατότητα στην python να έχει πρόσβαση στη MySQL:

pi@coyaght:~ $ sudo apt-get install python3-pymysql

Πλέον είναι έτοιμη η python να επικοινωνήσει με όλα τα τμήματα που μας ενδιαφέρουν. Είναι ώρα να στήσουμε τον server μας.

coYaght Server

Στο σύστημα coYaght θα πρέπει να υπάρχει πρόσβαση μέσω ενός web browser ώστε να μην υπάρχει η ανάγκη για εγκατάσταση κάποιας στοχευμένης εφαρμογής. Η ιστοσελίδα που θα εμφανίζεται πρέπει να περιέχει όλα τα απαραίτητα στοιχεία για να μπορούμε να:

  • παρακολουθούμε την κάμερά του
  • μπορούμε να κάνουμε παύση στο βίντεο που μας δείχνει και να το ξαναεκκινούμε
  • παρακολουθούμε τις μετρήσεις των αισθητήρων ως γραφικές παραστάσεις
  • να σταματάμε και ξαναεκκινούμε τις μετρήσεις των αισθητήρων
  • πλοηγούμε το coYaght μέσα στη θάλασσα

Ο κώδικας του server έχει γραφτεί, όπως προείπαμε, σε python 3. Σαν εναρκτήριος κώδικας υπήρξε αυτός που βρίσκεται στη σελίδα 4. Advanced Recipes - Picamera 1.13 documentation. Πάνω σε αυτό τον κώδικα βασίστηκε η ομάδα μας για τη δημιουργία του server.

Φυσικά, το τμήμα της ιστοσελίδας πλοήγησης του coYaght κάνει χρήση τεχνολογιών διαδικυου, HTML, CSS και JavaScript. Το κομμάτι εμφάνισης γραφικών παραστάσεων προέρχεται από τη Google - Google Charts.

Τον πλήρη κώδικα μπορείτε να τον δείτε και να τον κατεβάσετε από το GitHub. Εκεί θα βρείτε και αρκετή τεκμηρίωση για τον τρόπο που λειτουργεί ο κώδικας. Επίσης, μέσα στα αρχεία υπάρχει επιπλέον τεκμηρίωση, ώστε κάποιος να μπορέσει να έχει μια καλύτερη καταννόηση της λειτουργίας του κάθε τμήματος κώδικα. Ας δούμε κι εδώ λίγα βασικά πράγματα.

Ο βασικός κώδικας του server (python) αποτελείται από τρία αρχεία:

  • database.py: Δημιουργεί την κλάση με την οποία μπορούμε πολύ εύκολα να έχουμε πρόσβαση στη βάση δεδομένων coYaght της MySQL
  • serial_arduino.py: Δημιουργεί την κλάση με την οποία μπορούμε να έχουμε πρόσβαση στη σειραική θύρα του arduino. Κάνει χρήση νημάτων για να μπορεί να διαχειριστεί τόσο την αποστολή εντολών προς αυτό, όσο και τη λήψη των μηνυμάτων που στέλνει το arduino. Κάθε γραμμή εισόδου ελέγχεται, τόσο για να πιστοποιηθεί η κατάσταση του συστήματος του arduino, όσο και για να φιλτραριστούν οι πληροφορίες της κάθε γραμμής και αν πρόκειται για πληροφορίες των αισθητήρων, να καταχωρηθούν στη βάση δεδομένων
  • controller.py: Είναι το κεντρικό πρόγραμμα του server. Κάνει χρήση των άλλων δύο τμημάτων που προαναφέρθηκαν. Εδώ δημιουργείται ο εξυπηρετητής web και φιλτράρονται όλα τα ερωτήματα που αποστέλλονται μέσω δικτύου.

Τα αρχεία της ιστοσελίδας που μεταφέρονται στους πελάτες βρίσκονται στον κατάλογο web. Κι εκεί η δομή που χρησιμοποιείται είναι απλή:

  • index.html: Είναι το βασικό αρχείου που δίνει το οπτικό τμήμα της ιστοσελίδας. Το πρώτο αρχείο που διαβάζεται από ένα φυλλομετρητή
  • images: Ο κατάλογος περιέχει όλες τις εικόνες που συμπληρώνουν το οπτικό κομμάτι της ιστοσελίδας
  • styles: Περιέχει όλα τα αρχεία .css για την εφαρμογή οπτικών στυλ επάνω στα στοιχεία της ιστοσελίδας
  • scripts: Περιέχει τα αρχεία της JavaScript που χρησιμοποιούνται για τις λειτουργίες της σελίδας, αλλά και την υπόλοιπη επικοινωνία με τον εξυπηρετητή

Η εν λόγω δενδρική δομή βρίσκεται μέσα σε ένα κατάλογο coYaght που φτιάχνουμε μέσα στον κατάλογο του χρήστη. Για να τον δημιουργήσουμε, αρκεί να εκτελέσουμε την ακόλουθη εντολή:

pi@coyaght:~ $ mkdir coYaght

Όταν όλη η δενδρική δομή των αρχείων του server εγγραφεί μεσα στον κατάλογο που μόλις δημιουργήσαμε, τότε μπορούμε να τρέξουμε τον server με την εντολή:

pi@coyaght:~ $ cd coYaght
pi@coyaght:~ $ sudo python3 controller.py

Αν όλα έχουν πάει σωστά, τότε από τον υπολογιστή μας θα μπορούμε να μπούμε στο περιβάλλον του coYaght με τη χρήση του φυλλομετρητή μας (πχ. Firefox). Εκεί θα χρησιμοποιήσουμε τη διεύθυνση IP του coYaght, 192.168.111.10, όπως φαίνεται και στην ακόλουθη εικόνα:

Ο λόγος που πρέπει να μπει το sudo μπροστά, είναι πως ο εξυπηρετητής μας ακούει στην πόρτα 80 στην οποία έχει πρόσβαση μόνο ο χρήστης root του συστήματος.

Αυτόματη εκκίνηση του server με την εκκίνηση του Raspberry Pi

Το να έχουμε κατασευάσει τον server δεν αρκεί. Θα πρέπει κάθε φορά που ενεργοποιούμε το coYaght να μπαίνουμε με ssh και να τρέχουμε με τις προηγούμενες εντολές το πρόγραμμα. Αυτό δεν είναι καθόλου βολικό. Θα πρέπει ο εξυπηρετητής να ενεργοποιείται αυτόματα όταν εκκινεί το Raspberry Pi. Αυτό σημαίνει πως πρέπει να μετατραπεί σε υπηρεσία.

Το λειτουργικό Linux που τρέχει το Raspberry Pi χρησιμοποιεί τον systemd ώς κύριο τρόπο διαχείρισής του. Αυτός είναι υπεύθυνος, εκτός των άλλων, για τις υπηρεσίες που θα ενεργοποιηθούν. Θα πρέπει, λοιπόν να τον καθοδηγήσουμε να δει το controller.py ως υπηρεσία και να το "σηκωσει" όταν εκκινήσει το λειτουργικό. Το πρώτο πράγμα που κάνουμε είναι να δημιουργήσουμε το αρχείο .service:

pi@coyaght:~ $ sudo vi /lib/systemd/system/coYaght.service

Μέσα σε αυτό θα πρέπει να βάλουμε τις ακόλουθες πληροφορίες:

[Unit]
Description=coYaght control service. Serves HTTP at port 80
After=multi-user.target

[Service]
Type=simple
ExecStart=/usr/bin/python3 /home/pi/coYaght/controller.py
Restart=on-abort

[Install]
WantedBy=multi-user.target

Στη συνέχεια θα πρέπει να γίνει εκτελέσιμο:

pi@coyaght:~ $ sudo chmod 644 /lib/systemd/system/coYaght.service

Τέλος, θα πρέπει να πούμε στον systemd να ξαναδιαβάσει τις εγκαταστημένες υπηρεσίες και να ενεργοποιήσει την καινούργια:

pi@coyaght:~ $ sudo systemctl daemon-reload
pi@coyaght:~ $ sudo systemctl enable coYaght.service 
pi@coyaght:~ $ sudo systemctl status coYaght.service 

Η τελευταία εντολή μας δείχνει την κατάσταση της υπηρεσίας, πλέον, coYaght. Για να την εκκινήσουμε εμείς αρχεί η εντολή:

pi@coyaght:~ $ sudo systemctl start coYaght.service

Σε αυτό το σημείο αν κάνουμε μια επανεκκίνηση στο Raspberry Pi θα πρέπει να λειτουργήσει κανονικά ο server μας χωρίς άλλη παρέμβαση.

pi@coyaght:~ $ sudo shutdown -r now

Χρήση του coYaght

Για τη χρήση του coYaght, το πρώτο βασικό πράγμα είναι να συνδεθεί με ένα καλώδιο δικτύου σε έναν υπολογιστή. Αφού το ενεργοποιήσουμε, ο υπολογιστής θα πάρει μια διεύθυνση IP σύμφωνα με όσα προαναφέραμε. Από εκείνη τη στιγμή και μετά, με τη βοήθεια ενός φυλλομετρητή μπορούμε να μπούμε στην ιστοσελίδα του και να το χρησιμοποιήσουμε. Ένα βασικό σημείο είναι πως η αρχική ενεργοποίηση του coYaght πρέπει να γίνει στο επίπεδο της θάλασσας. Δεν εννοούμε πως θα πρέπει να βρίσκεται μέσα στη θάλασσα, αλλά στο επίπεδο 0. Αυτό είναι απαραίτητο γιατί το πρώτο πράγμα που κάνει το arduino είναι να μετρήσει την πίεση που δέχεται ο αντίστοιχος αισθητήρας και να κρατήσει την τιμή ως τιμή επιπέδου της θάλασσας.

Στην είσοδο της σελίδας του συστήματος, βλέπουμε το λογότυπο της DeepSeaRobotix, το οποίο καταλαμβάνει όλη την οθόνη. Στο κάτω μέρος βλέπουμε μια μπάρα κατάστασης που δείχνει πως ο server περιμένει να επικοινωνήσει με το arduino. Όταν αυτό ολοκληρωθεί και υπάρχει κανονική επικοινωνία μεταξύ Raspberry Pi και Arduino, τότε το λογότυπο φεύγει και τοποθετείται στο επάνω αριστερά μέρος, αφήνοντας όλη την υπόλοιπη οθόνη για το περιβάλλον χειρισμού.

Η οθόνη χωρίζεται σε τέσσερα μέρη:

  • Άνω δεξιά τμήμα: Live streaming της κάμερας
  • Άνω αριστερά τμήμα: Γραφήματα των αισθητήρων
  • Κάτω δεξιά τμήμα: Πλήκτρα πλοήγησης του coYaght στο οριζόντιο επίπεδο
  • Κάτω αριστερά τμήμα: Πλήκτρα πλοήγησης του coYaght στο κατακόρυφο επίπεδο

Το βίντεο που προέρχεται από την κάμερα του Raspberry Pi είναι ενεργοποιημένο. Κάτω από αυτό υπάρχει ένα πλήκτρο με το οποίο μπορούμε να κάνουμε παύση στο βίντεο ή αν είναι σε παύση να το εκκινήσουμε και πάλι.

Οι γραφικές παραστάσεις των αισθητήρων αρχικά είναι άδειες, ενώ δεν τοποθετούνται μετρήσεις μεσα σε αυτές. Αυτό συμβαίνει γιατί όσο το arduino στέλνει δεδομένα αισθητήρων, αυτά καταγράφονται και στη βάση δεδομένων. Ο ρυθμός των δεδομένων είναι ένα πακέτο ανά δευτερόλεπτο. Αν ξεχαστούμε μπορεί πολύ εύκολα η κάρτα μνήμης να γεμίσει με δεδομένα που στην πραγματικότητα δε χρειαζόμαστε. Έτσι, ο χρήστης θα πρέπει να ενεργοποιήσει τις μετρήσεις όταν χρειάζεται να τις κρατήσει. Για να γίνει αυτό, όπως και στην περιοχή της κάμερας, κάτω από τις γραφικές παραστάσεις των μετρήσεων υπάρχει ένα πλήκτρο που τις εκκινεί όταν είναι σταματημένες ή τις σταματάει όταν οι μετρήσεις καταγράφονται.

Κάτι ακόμα που πρέπει να αναφέρουμε για τις γραφικές παραστάσεις, είναι πως βλέπουμε δύο πίνακες. Ο επάνω περιέχει τα γραφήματα της Πίεσης και της Θερμοκρασίας, ενώ ο κάτω δείχνει τα γραφήματα Φωτεινότητας και Τάσης Τροφοδοσίας. Η μέτρηση της πίεσης ανάγεται και στο βάθος στο οποίο βρίσκεται το coYaght, σε μέτρα. Έχουμε την επιλογή στο επάνω γράφημα να μας δείχνει είτε την πίεση που μετράει ο αισθητήρας σε KPa είτε το βάθος σε μέτρα. Η επιλογή γίνεται με το να επιλέξουμε την κατάλληλη μονάδα μέτρησης κάτω από το γράφημα Πίεσης και Θερμοκρασίας.

Η κίνηση του coYaght γίνεται με τα πλήκτρα που εμφανίζονται στο κάτω μέρος της οθόνης. Επειδή δεν είναι δυνατόν να μπορέσουμε να το χειριστούμε απλά με το ποντίκι μας, παρότι υπάρχει η δυνατότητα, η ομάδα μας σκέφτηκε πως θα είναι ιδιαίτερα πιο χρήσιμο να μπορούμε να χρησιμοποιήσουμε το πληκτρολόγιο ώστε να μπορούμε να το κινούμε ταυτόχρονα τόσο στον κατακόρυφο, όσο και στον οριζόντιο άξονα. Τα πλάτρα που χρησιμοποιούμε είναι τα ακόλουθα:

  • Q: Κίνηση άνω, προς την επιφάνεια της θάλασας
  • A: Κίνηση κάτω, προς το βυθό
  • NumPad 8: Κίνηση εμπρός
  • NumPad 2: Κίνηση πίσω
  • NumPad 6: Δεξιόστροφη περιστροφή γύρω από τον κάθετο άξονα του coYaght
  • NumPad 4: Αριστερόστροφη περιστροφή γύρω από τον κάθετο άξονα του coYaght
  • NumPad 9: Στροφή δεξιά με κίνηση εμπρός
  • NumPad 3: Στροφή δεξιά με κίνηση πίσω
  • NumPad 7: Στροφή αριστερά με κίνηση εμπρός
  • NumPad 1: Στροφή αριστερά με κίνηση πίσω.

Συμπεράσματα

Σαν σχολικό project, το coYaght ήταν ένα δυνατό μάθημα. Με τη βοήθειά του η ομάδα τρίφτηκε αρκετά με τις νέες τεχνολογίες και ήρθαν σε επαφή με τον τρόπο που γίνοτναι οι μετρήσεις στο περιβάλλον. Βρέθηκαν αντιμέτωποι με τον τρόπο που λειτουργούν τα υπολογιστικά συστήματα, τον προγραμματισμό, τον τρόπο με τον οποίο λειτουργούν τα δίκτυα επικοινωνιών κλπ.

Ως κατασκευή, το coYaght είναι ένα drone που έχει κάποια μειονεκτήματα, πράγματα που μας δίνουν ιδέες να προχωρήσουμε ακόμα και στην κατασκευή μιας άλλης έκδοσής του, αρκετά καλύτερης από αυτή. Μέσα σε όλα όσα αναφέρθηκαν σε brainstorming με την ομάδα, είναι η λειτουργία με περισσότερους κινητήρες για βελτίωση της σταθερότητας, χρήση επικλινόμετρου για βελτίωση της πλοήγησης, σασί που να είναι 3D εκτυπωμένο, για να μπορεί να αποσυναρμολογείται, κ.α.

Όσον αφορά την εφαρμογή χειρισμού, θα μπορούσε να προστεθεί κώδικας που να συγχρονίζει το RTC με την ημερομηνία και την ώρα του υπολογιστή (μιας και το Raspberry δεν έχει πρόσβαση στο internet για να πάρει την ώρα από εκεί), δημιουργία sessions με ονομασία και στίγμα GPS για το σημείο στο οποίο πρόκειται να γίνουν οι μετρήσεις, ρύθμιση της ταχύτητας των κινητήρων ώστε να έχουμε απόλυτο έλεγχο και στην ταχύτητα με την οποία θα κινείται προς κάθε κατεύθυνση μέσα στο νερό, καταγραφή του βίντεο σε αρχείο στον υπολογιστή μας, επαναφορά μετρήσεων ενός session, ακόμα και την απενεργοποίηση του συστήματος.

Ο σκοπός που δημιουργήθηκε το project αυτό ήταν περισσότερο η τριβή των μαθητών με την τεχνολογία ώστε να γνωρίσουν μονοπάτια της, που με τη βοήθεια του "στεγνού" μαθήματος θα ήταν αδύνατο να συμβεί. Πραγματικά θέλω να ευχαριστήσω τον Διευθυντή του 1ου Γυμνασίου Γέρακα, κ. Κουρτέση Θεόδωρο, που με ένταξε στο πρόγραμμα του Junior Achievement, όσο και τα παιδιά της ομάδας που με έκαναν να αισθανθώ και να θαυμάσω τη δύναμη του μυαλού που έχουν αυτές οι ηλικίες:

  • Αδαμαντιάδης Παναγιώτης
  • Αμερκάνος Ευστράτιος
  • Δροσάκης Γιάννης
  • Ζωγράφου Ελένη
  • Καλαβρού Ελευθερία
  • Λέκκας Αντώνιος
  • Μπούκη Αντιγόνη

Παρασκευή 22 Μαΐου 2015

Παιδεία κι Ελληνική Πραγματικότητα

Το παρόν άρθρο δεν ανήκει ούτε στα ηλεκτρονικά, αλλά ούτε στους υπολογιστές. Ανήκει στο "... και άλλα!". Πιο συγκεκριμένα είναι ο προβληματισμός μου για το ποιόν της Ελλάδας, το τι κουβαλάμε οι Έλληνες μέσα στο κεφάλι μας αλλά και ο προβληματισμός μου σχετικά με το τι τελικά είναι αυτό που εμείς οι Έλληνες θέλουμε. Βαρύ ε;

Θα διηγηθώ μια ιστορία, προσωπική. Η ιστορία εξελίσσεται την ημέρα των πανελλαδικών εξετάσεων του παρόντος έτους (2015). Το νούμερο του έτους το θεωρώ σημαντικό διότι έχουμε ξεφύγει από την αρχαιότητα και τη στενομυαλιά και βαδίζουμε σε σύγχρονα μονοπάτια (πανάθεμά μας), με περισσότερη γνώση (πανάθεμά μας δεύτερη φορά!).

Είναι γνωστό πως εργάζομαι ως εκπαιδευτικός σε δημόσιο τεχνικό λύκειο (ΕΠΑ.Λ.) της χώρας. Αυτό σημαίνει πως κάθε χρόνο η συμμετοχή μου στις πανελλαδικές εξετάσεις ως επιτηρητής είναι δεδομένη. Φέτος βρέθηκα να είμαι επιτηρητής σε ένα γενικό λύκειο, κάπου στο νομό Χανίων.

Πρώτα απ' όλα θα πρέπει να αναφέρω λίγα "γνωστά" πράγματα σχετικά με τις εξετάσεις. Το σύστημα των εξετάσεων είναι πολύ ακριβές και πολύ ευαίσθητο με το θέμα της δολίευσης. Απαγορεύονται ρητά κινητά (τόσο στους μαθητές όσο και στους εκπαιδευτικούς) μέσα στην αίθουσα την ώρα της εξέτασης. Απαγορεύονται τα σκονάκια και οποιοσδήποτε τρόπος αντιγραφής γνώσεων και πληροφοριών. Απαγορεύεται να μιλήσεις σε κάποιον συμμαθητή σου, είτε για να σου πει, είτε για να του πεις. Απαγορεύεται να δημιουργείς φασαρία ενοχλώντας τους συμμαθητές σου. Απαγορεύεται να μεταφέρεις θέματα εκτός τάξης. Και πολλά άλλα. Γι αυτό οι επιτηρητές σε κάθε σχολείο προέρχονται από άλλα σχολεία και άλλες περιοχές, ώστε να μην υπάρχει κάποια περίπτωση γνωριμίας επιτηρητή με εξεταζόμενο. Ότι στραβό συμβεί έχει μόνο ένα αντίκτυπο: τον μηδενισμό του τετραδίου θεμάτων του μαθητή ή των μαθητών οι οποίοι δεν συμμορφώνονται με τους κανόνες.

Στις 20 Μαΐου, λοιπόν, επιτηρώ σε ένα σχολείο, κανονικά στη θέση μου, μαζί με κάποια άλλη συνάδελφο. Κάποια στιγμή μια μαθήτρια βάζει ένα σκονάκι στο χέρι της, προσπαθώντας, φυσικά, να το κρατήσει κρυφό. Έλα όμως που την είδαμε, τόσο η συνάδελφος όσο κι εγώ. Τελικά της παίρνω το σκονάκι, το παραδίδω στη Λυκειακή Επιτροπή, η οποία είναι υπεύθυνη για περαιτέρω διερεύνηση του θέματος και το λογικό αποτέλεσμα του μηδενισμού του τετραδίου της εξεταζομένης.

Μετά τη λήξη της εξέτασης, μίλησα με τη Λυκειακή Επιτροπή για τη μαθήτρια, η οποία, όπως ακριβώς μου είπαν, είναι μια μαθήτρια άριστη, η οποία δεν είναι τύπος που γενικά κάνει σκονάκια, φιλότιμη και γενικά τη στόλισαν με τα καλύτερα λόγια, κυριολεκτικά! Εδώ θα προσθέσω και το (όχι μόνο) δικό μου σχόλιο πως πίσω από ένα καλό μαθητή κρύβεται και μια οικογένεια επίσης καλή. Γιατί μια τέτοια μαθήτρια να έχει την ανάγκη να κάνει σκονάκι για να βοηθηθεί στις εξετάσεις; Στην πραγματικότητα δεν υπάρχει λόγος, πέρα από το άγχος της να γράψει καλά σε ένα μάθημα με αυξημένη για εκείνη βαρύτητα. Η κοπέλα είχε λύσει το θέμα και στη συνέχεια έβγαλε το σκονάκι για να σιγουρέψει πως λειτούργησε με το σωστό τρόπο στην απάντησή της. Παρόλα αυτά, το σύστημα είναι αυστηρό και αυτό της βγήκε... ξινό με το να χάσει παντελώς το μάθημα.

Ως εδώ, καλά (αν μπορεί πραγματικά να το πει κανείς έτσι). Το πρόβλημα "ξεκινάει" από εδώ και πέρα (και μιλάω για το πραγματικό πρόβλημα της νοοτροπίας των Ελλήνων).

Το απόγευμα κάποιος μου χτύπησε την πόρτα ΤΟΥ ΣΠΙΤΙΟΥ ΜΟΥ! Όταν άνοιξα, είδα έναν αγχωμένο-τσαντισμένο άντρα ο οποίος έβγαλε την πρώτη του κουβέντα: "Ο κύριος Χρυσοχέρης;". Φυσικά αποκρίθηκα θετικά. Και συνεχίζει "Δεν ήρθα εδώ για να δημιουργήσω κανένα πρόβλημα!". Εκεί, προφανώς η απορία στο πρόσωπό μου ήταν εμφανής. "Γιατί να δημιουργήσετε πρόβλημα;" του απάντησα. Και παίρνω το κεραμίδι στο κεφάλι: "Είμαι ο πατέρας της κοπελιάς από το πρωί". Εκεί, νομίζω πως η φάτσα μου θύμιζε λίγο τις φάτσες που ζωγραφίζει ο Αρκάς στα κόμικς του!

Ο κύριος, πατέρας της κοπελιάς που είχε γίνει το πρωινό επεισόδιο, ήρθε να με ρωτήσει, επικριτικά πάντα, γιατί έκανα σωστά τη δουλειά μου! Έπρεπε, σύμφωνα με τα δικά του λόγια, να πετάξω το σκονάκι και να αφήσω την κοπελιά να γράψει σα να μην συνέβαινε τίποτα. Το γεγονός βέβαια πως το σκονάκι το είδαν και όλοι οι υπόλοιποι εξεταζόμενοι δεν παίζει κανένα ρόλο, έτσι; Και φυσικά σαν ισχυρό συστατικό της στήριξης της γνώμης του ήταν το "έπρεπε να πάτε με το γράμμα του νόμου; Δηλαδή εσείς είστε καθόλα νόμιμος;". Δε νομίζω πως του άρεσε η απάντηση πως οι παρανομίες μου περιορίζονται στην μη τήρηση των ορίων ταχύτητας σε κάποιους δρόμους κι αυτό όταν είμαι μόνος, χωρίς άλλους οδηγούς! Μετά από λίγη, ας το πούμε συζήτηση (γιατί όπως είναι φυσικό ένας άνθρωπος σε μια τέτοια ψυχολογική κατάσταση δεν ακούει ποτέ τον αντίλογο και δεν κάθεται ποτέ να συζητήσει με ψυχραιμία) έλαβα και το ωραίο σχόλιο: "Νομίζω πάντως πως με αυτή τη στάση σας θα έχετε γενικότερα προβλήματα!". Για να είμαι ειλικρινής το εξέλαβα λίγο ως απειλή!

Πέρα από τα στενά όρια του συμβάντος και των απειλών και των δικαιολογιών κ.λ.π, κ.λ.π. εμένα τριγυρίζει στο μυαλό μου κάτι γενικότερο στον Έλληνα (καλά, δεν πιστεύω πως είναι μόνο στον Έλληνα, αλλά αυτή τη στιγμή αυτόν θα κοιτάξω). Το κομμάτι που κρατάω είναι το: Βρίσκω ποιος είναι αυτός που (θεωρώ πως) μου δημιούργησε πρόβλημα, μαθαίνω που μένει και πάω κατάμουτρα να τον "βρίσω"-απειλήσω γιατί έκανε τη δουλειά του όπως έπρεπε να την κάνει! Για μένα φυσικά αυτός δεν ανήκει στο οικογενειακό μου περιβάλλον (κοινώς δεν φταίει η κοπελιά που έβγαλε σκονάκι κατά τη διάρκεια της εξέτασης, αλλά ο επιτηρητής που την έπιασε!). Με την ίδια λογική, αν εμένα με σταματήσει ένας τροχονόμος και μου κόψει κλήση (θα έλεγα τι άλλο θα μου κόψει κανονικά, αλλά τέλος πάντων) για υπερβολική ταχύτητα, εγώ θα πάω ΣΠΙΤΙ ΤΟΥ να του ζητήσω τα ρέστα! Αντί να κοιτάξουμε πως η παιδεία (και πιστεύω στοχευμένα) έχει καταλήξει να είναι μια φαντασίωση στην Ελλάδα, κοιτάμε πάντα να πετύχουμε το στόχο μας με τον πλάγιο τρόπο. Αν κάποιος κάνει τη δουλειά του σωστά και με εμποδίσει να πετύχω το στόχο μου, τότε τον απειλώ. Αν ο ίδιος δεν κάνει τη δουλειά του σωστά αμέσως θα του κολλήσω τη ρετσινιά. Και για να το φέρω στο επάγγελμά μου, αν κάνω σωστά τη δουλειά μου και αποτρέψω τη δολιοφθορά των εξετάσεων, έχω πρόβλημα με τη στάση μου! Αν αφήσω τους μαθητές να αντιγράψουν και κάτσω απλά σε μια γωνία και σφυρίζω αδιάφορα για να μπορέσει να γίνει κάτι τέτοιο, είμαι αυτό το κάθαρμα που έριξα την Ελλάδα έξω με το να πληρώνομαι και να μην κάνω τίποτα! Το γεγονός όμως πως αν κάποιος αντιγράψει και βρεθεί στη σχολή που ήθελε να μπει η κόρη σου φίλε συμπατριώτη, πετώντας την έξω από τη σχολή, αυτό δε θα σε έκανε έξω φρενών; Γιατί αυτό πιθανόν θα είχε συμβεί αν δεν έκανα καλά τη δουλειά μου (εγώ ΚΑΙ οι συνάδελφοί μου)

Ο Έλληνας το μόνο που θέλει είναι να πετυχαίνει χωρίς να κοπιάζει. Είναι παρτάκιας και το μόνο που τον ενδιαφέρει είναι ο εαυτός του! Μήπως τελικά αυτό που έχει αδειάσει την Ελλάδα από τα δυνατά μυαλά και τους σοβαρούς επιστήμονες που διαπρέπουν στο εξωτερικό, είναι αυτή ακριβώς η νοοτροπία; Μήπως όλοι αυτοί που φεύγουν από αυτό τον "ευλογημένο" (να ξαναπώ το "πανάθεμά μας";) είναι αυτοί που δε μπορούν να συμβαδίσουν με τη νοοτροπία του πλάγιου δρόμου, αυτοί που πασχίζουν και πετυχαίνουν και τους αρέσει να αμείβονται γι' αυτό που καταφέρνουν; Μήπως τελικά τα καλά κεφάλια φεύγουν από την Ελλάδα γιατί δε γουστάρουν να τους καπελώνουν κάποιοι που σκαρφαλώνουν πάνω από αυτούς επειδή έχουν κάποιο γνωστό; Αυτό το αποτέλεσμα κρατάω, όπως επίσης και την καταγγελία του συμβάντος στην αστυνομία γιατί το να έρθει κάποιος στο σπίτι μου και να μου χτυπήσει την πόρτα για να μου κάνει με αυτό τον τρόπο την "παρατήρησή" του δε μου φαίνεται καθόλου... "φιλικό".

Όλα τα παραπάνω, νομίζω πως είναι πολύ καλή τροφή για σκέψη!

Ηλίας Χρυσοχέρης


Τετάρτη 4 Ιουνίου 2014

Σεμινάριο Δικτύων Υπολογιστών για Εκπαιδευτικούς

Στις 6 Μαρτίου 2014, στο Ηράκλειο Κρήτης, οργανώθηκε ένα σεμινάριο δικτύων υπολογιστών για εκπαιδευτικούς του Ηλεκτρονικού Τομέα. Η οργάνωση έγινε από το 1ο Εργαστηριακό Κέντρο Ηρακλείου Κρήτης και πιο συγκεκριμένα από τον κ. Μανατάκη Γεώργιο, Διευθυντή του 1ου ΕΚ Ηρακλείου και τον κ. Καζγκούτη Γεώργιο, Υπεύθυνο Τομέα Ηλεκτρονικών του Εργαστηριακού Κέντρου σε συνεργασία με τη Σχολικό Σύμβουλο κ. Σαλωνίδου Αθηνά και το Σχολικό Σύμβουλο Γενικής Παιδαγωγικής Ευθύνης, κ. Τζωρτζάκη Ιωάννη. Το σεμινάριο διεξήχθη στους χώρους του Εργαστηρίου Υπολογιστικών Συστημάτων και Δικτύων του Τομέα Ηλεκτρονικών στο Εργαστηριακό Κέντρο.

Στόχος του σεμιναρίου ήταν η επιμόρφωση των εκπαιδευτικών για την υποστήριξη των μαθημάτων του Τομέα Ηλεκτρονικής, αλλά και του μαθήματος της Ειδικής Θεματικής Δραστηριότητας, όσο και των Ερευνητικών Εργασιών και των υπολοίπων εκπαιδευτικών προγραμμάτων των σχολείων. Το σεμινάριο ξεκίνησε στις 16:00 και διήρκεσε περίπου 6:30 ώρες!...

Το περιεχόμενο κρατήθηκε στα πρώτα βήματα των δικτύων ώστε να μπορέσουν να καλυφθούν και όσοι δεν έχουν ασχοληθεί ποτέ με τη δικτύωση των υπολογιστών και τις δυνατότητές τους. Πιο συγκεκριμένα, η δομή του σεμιναρίου περιέχει:

  1. Εισαγωγή
    • Τι είναι δίκτυο
    • Βασικοί τρόποι λειτουργίας
    • Δυνατότητες δικτύων - Πλεονεκτήματα / Μειονεκτήματα
    • Επιπεδοποίηση της επικοινωνίας
    • Βασικά συστατικά δικτύου (Συσκευές δικτύωσης)
  2. TCP/IP - Το βασικό πρωτόκολλο δικτύωσης
    • Επίπεδα TCP/IP
    • Διευθυνσιοδότηση
      • IPv4
      • IPv6
    • Servers και Clients / Ports
  3. Δρομολόγηση
    • Routing
    • NAT
    • Port forwarding
    • DHCP
  4. Ασφάλεια
    • Γενικά περί ασφάλειας
    • Προστασία του υπολογιστή μας
    • Κρυπτογράφηση

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

Το εργαστηριακό κομμάτι αφορά στο στήσιμο ενός σχολικού εργαστηρίου με την κατάλληλη δομή, τους servers, δυναμικό DNS για απομακρυσμένη διαχείριση και επίδειξη εγκατάστασης ενός CMS προγράμματος όπως Joomla/Drupal/Wordpress.

Η βιντεοσκόπηση χρειάζεται ακόμα δουλειά για να μπορέσει να αναρτηθεί, αλλά οι διαφάνειες της παρουσίασης βρίσκονται εδώ:

Τα φυλλάδια παρουσίασης είναι οι συνολικές διαφάνειες της παρουσίασης, χωρίς τις μεταβάσεις των κειμένων. Όλα τα αρχεία είναι σε μορφή pdf.

Θα ήθελα να ευχαριστήσω θερμά τους κυρίου Τομαδάκη Ιωάννη και Καζγκούτη Γεώργιο που μου έδωσαν την ευκαιρία να βρεθώ εισηγητής του σεμιναρίου.


Ηλίας Χρυσοχέρης

Τρίτη 13 Μαΐου 2014

Ελληνικός Οδηγός Εγκατάστασης openSUSE 13.1

Για άλλη μια φορά ο οδηγός άργησε να βγει. Λίγο ο φόρτος εργασίας, λίγο κάποια προβληματάκια με το Virtual Box και λίγο το... τεμπέλιασμά μου (ας το πούμε κι έτσι...) έκαναν τον οδηγό να αργήσει. Η προσπάθεια ξεκίνησε τον Ιανουάριο, αλλά τελείωσε τώρα, το Μάιο. Αυτό γιατί ήθελα ταυτόχρονα να τελειώσω και το artwork για τα CD/DVD και τη θήκη τους. Τέλος πάντων, όλα καλά για άλλη μια φορά.

Ο οδηγός εγκατάστασης openSUSE 13.1 βρίσκεται στο wiki του ιστότοπου του Συλλόγου Φίλων Ανοικτού Λογισμικού Χανίων. Κάτω από το τμήμα "Τεκμηρίωση" έχει αναρτηθεί και ο εν λόγω οδηγός.

Ο οδηγός είναι γραμμένος και πάλι με τον τρόπο που να πηγαίνει τον αναγνώστη ένα βήμα παραπάνω από την απλή εγκατάσταση του λειτουργικού. Βοηθάει αρκετά στο να γνωρίσει κάποιος από λίγο κοντύτερα τη βασική παραμετροποίηση του συστήματος και τον τρόπο με τον οποίο μπορεί να το διαχειριστεί· απλά μια ιδέα επάνω σε αυτά χωρίς να γίνεται System Adminitrator...

Ελπίζω, όπως πάντα άλλωστε, να σας φανεί χρήσιμος


Ηλίας Χρυσοχέρης


Δευτέρα 3 Μαρτίου 2014

Σειρά Σεμιναρίων Για Εκπαιδευτικούς από το 1ο ΕΚ Ηρακλείου

Το 1ο ΕΚ Ηρακλείου είναι από το πιο ολοκληρωμένο Εργαστηριακό Κέντρο δευτεροβάθμιας εκπαίδευσης που έχω δεί. Κάθε χρόνο οργανώνουν επιμορφωτικά σεμινάρια για εκπαιδευτικούς. Φέτος η σειρά των σεμιναρίων ξεκινάει με διάλεξη και εργαστήριο δικτύων υπολογιστών:

Για περισσότερες πληροφορίες σχετικά με τα σεμινάρια που διεξάγωνται, καθώς και αίτηση αν επιθυμείτε να παρακολουθήσετε κάποια από αυτά, θα βρείτε στο http://semisek2014.weebly.com/.

Ελπίζω το παράδειγμά τους να εφαρμοστεί και σε άλλες περιοχές της Ελλάδας.

Ηλίας Χρυσοχέρης


Σάββατο 21 Σεπτεμβρίου 2013

Πολυγλωσσικές αναρτήσεις στο blogger.comMultilingual posts on blogger.com

Ξεκίνησα το blog μου στο blogger τον Αύγουστο του 2009. Όταν ξεκίνησα αγνοούσα τη δυνατότητα του να έχω πολυγλωσσικές αναρτήσεις. Πίστευα πως όταν χρειαζόταν να κάνω μια ανάρτηση σε άλλη γλώσσα από τη μητρική μου, απλά θα την έκανα. Η έννοια του να έχω μια ανάρτηση σε δύο γλώσσες δεν ήταν κάτι που με απασχολούσε. Λάθος μου!

I started my blog in blogger on August 2009. In the beginning I totally ignored the ability to make multilingual posts. I believed that when I needed to write something in a different language than my native one, I would just use that language. The thought of having a post written in two different languages was something that didn't even pass through my mind. I was wrong!

Όταν άρχισαν να διαβάζουν τις αναρτήσεις μου ακόμα και τα ανήψια μου, εκεί κατάλαβα πόσο σημαντικό είναι οι αναρτήσεις μου να είναι στα Ελληνικά. Ταυτόχρονα, οι αναρτήσεις θα έπρεπε να είναι και στα Αγγλικά (δυστυχώς δε γνωρίζω άλλη γλώσσα) διότι αφορούν τεχνολογικό περιεχόμενο. Συνεπώς, καλό είναι να μπορούν να το καταλάβουν και άλλοι αναγνώστες οι οποίοι ενδιαφέρονται για το αντικείμενο που περιγράφεται, εκτός Ελλάδας. Παράδειγμα υπήρξε ακόμα και στις λίστες του FreeBSD όπου έκανα αναφορά σε ένα how-to που έχω γράψει, το οποίο όμως είναι γραμμένο στα Ελληνικά. Ο ενδιαφερόμενος φυσικά και δυσκολεύτηκε να πετύχει αυτά που περιέγραφε το άρθρο γιατί ήταν χωμένος μέσα σε εντολές κονσόλας και σε... μεταφραστικό...

When even my siblings started to read my posts, I understood the importance of my posts to be written in Greek. At the same time some posts should be also in English (unfortunately I don't speak any other language than these two) because they are on technological aspects. So, it is a good thing for other readers, others than Greek, that are interested in the subject of the post, to be able to understand it. An example was on FreeBSD lists when I referenced an article of mine (a how-to) that it was, unfortunately, written in Greek. It was hard for the guy that was interested in the topic to achieve the goal of the post because he fell into terminal commands and... a translator...

Η απόφαση του να προσπαθήσω να κάνω το blog μου δίγλωσσο δεν άργησε (αντίθετα με την υλοποίησή του...).

The decision to convert my blog to multilingual was not that far (as opposed to its implementation...).

Τι θα δούμε σε αυτό το άρθρο

What's in this article

Σε αυτό το άρθρο θα παρουσιαστούν τα ακόλουθα κομμάτια:

In this article the following parts will be presented:

Πολυγλωσσική λειτουργία - βασικές ανάγκες

Multilingual Function - Basic Functionality

Για να μπορέσει να γίνει σωστά η λειτουργία της πολυγλωσσικής μορφής ενός άρθρου θα πρέπει το σύστημα τα ακολουθεί κάποιους κανόνες:

For the multilingual form of a post to be correct the system should follow some rules:

  • Όταν κάποιος επισκέπτεται τη σελίδα για πρώτη φορά, το σύστημα θα πρέπει να αποφασίζει σε ποια γλώσσα θα δείξει τα άρθρα.
  • When somebody visits the web page of the blog for the first time the system should decide what will be the presentation language.
  • Θα πρέπει ο αναγνώστης να μπορεί να αλλάξει γλώσσα εύκολα.
  • The reader must be able to change the language presented, easily.
  • Θα πρέπει να μπορεί το σύστημα να καταλάβει σε ποιες γλώσσες είναι γραμμένο το άρθρο, ώστε να δίνονται οι αντίστοιχες επιλογές στον αναγνώστη.
  • The system should be able to understand what are the available languages of the post, so only them should be presented to the reader as options.
  • Όταν ο αναγνώστης κάνει μια επιλογή μιας γλώσσας, το σύστημα θα πρέπει να τη θυμάται.
  • When the reader makes a language choice, the system should remember it.
  • Όταν ο αναγνώστης επιστρέψει μια άλλη μέρα στο blog θα πρέπει η πρώτη επιλεγμένη γλώσσα να είναι αυτή που χρησιμοποιήθηκε τελευταία φορά.
  • When the reader returns to the blog another day, the presentation language should be the one he last used.
  • Το σύστημα να μπορεί να διαχειριστεί άρθρα τα οποία είναι γραμμένα μόνο σε μια γλώσσα.
  • The system should be able to handle posts that are written in only one language.
  • Θα πρέπει να υπάρχει link parameter που να υποχρεώνει την εμφάνιση ενός άρθρου/άρθρων σε συγκεκριμμένη γλώσσα.
  • There must be a URL link parameter that should force the presentation of a post/article in a specific language.

Οι δύο βασικοί τρόποι για να συμβεί κάτι τέτοιο είναι:

The two basic ways of implementing such functionality are:

  1. Συγγραφή ξεχωριστού άρθρου για κάθε γλώσσα και χρήση links που να οδηγούν από τη μια γλώσσα στην άλλη
  2. Write of a new post for every language and usage of links to move from one language to the other
  3. Χρήση JavaScript η οποία να εμφανίζει τα στοιχεία HTML της επιλεγμένης γλώσσας και να εξαφανίζει αυτά που ανήκουν στις άλλες.
  4. JavaScript usage to display HTML elements that belong to the selected language and hide the others that belong to others.

Ο κάθε τρόπος έχει τα υπέρ και τα κατά του. Ο τρόπος που προτιμάει να χρησιμοποιήσει ο καθένας είναι καθαρά αντικειμενικός. Σε αυτό το blog χρησιμοποιείται ο δεύτερο· χρήση JavaScript.

Each way has its own pros and cons. The choise of the implementation way is just a matter of preference. In that blog we use and describe the latter; JavaScript usage.

Επιλογή Γλώσσας

Language Selection

Για να υλοποιηθεί η διαδικασία της πολυγλωσσικότητας πρώτα απ' όλα θα πρέπει να υπάρχει ο κατάλληλος τρόπος για την επιλογή μιας από τις διαθέσιμες γλώσσας από τον χρήστη. Η εμφάνιση μιας σημαίας για κάθε διαθέσιμη γλώσσα είναι κάτι βολικό για μια τέτοια λειτουργία. Το σημείο και ο τρόπος με τον οποίο θα εμφανίζεται η εν λόγω επιλογή είναι καθαρά θέμα του συγγραφέα του blog στο οποίο θα εφαρμοστεί η πολυγλωσσικότητα. Άλλη μια ιδέα για την επιλογή είναι η εμφάνιση μιας λίστας με τις διαθέσιμες γλώσσες μέσα από την οποία ο χρήστης θα επιλέγει αυτή που επιθυμεί.

For the multilanguage process to be implemented, first of all, there must be a propper way of reader selecting one of the available languages for the post. The presentation of a small flag for each available language option is very convenient for that purpose. The layout, the way of presentation and the part of the page that will host the language selection is only a matter of preference of the blog's writer. Another idea is to present a dropdown list of the available languages through which the user can apply his/her language choise.

Στο παρόν blog κρίθηκε κατάλληλο το να εμφανίζονται όλες οι διαθέσιμες επιλογές επάνω στον τίτλο του κάθε άρθρου, έτσι ώστε ο αναγνώστης να βλέπει αμέσως τις διαθέσιμες επιλογές. Κρίθηκε, επίσης, σκόπιμο η γλώσσα στην οποία εμφανίζεται το άρθρο να μην υπάρχει στις διαθέσιμες επιλογές (μιας και δεν υπάρχει νόημα στο να επιλέξει κανείς μια γλώσσα την οποία ήδη χρησιμοποιεί).

At the current blog the decision was to present all the available language options at the right of the post title, so every reader can see at once what are the options he/she has. Also, the flag of the currently presented language not to be presented (as there is no meaning to select a language that is already in use).

Και πως μπορεί να ελέγχεται ποια κομμάτια θα εμφανίζονται, ώστε κάθε φορά με την επιλογή μιας γλώσσας να εμφανίζονται μόνο τα επιθυμητά; Η λύση βρίσκεται στη δυνατότητα της HTML να μπορεί να περιέχει κρυφά και φανερά κομμάτια. Αν με κάποιο τρόπο σηματοδοτήσουμε ότι μια παράγραφος ανηκει στο Ελληνικό κείμενο και μια άλλη ανήκει σε κείμενο μιας άλλης γλώσσας, τότε σαρώνωντας τα δομικά στοιχεία της σελίδας θα μπορούν να αποκρύπτωνται τα στοιχεία που ανήκουν σε γλώσσα εκτός της επιλεγμένης και να εμφανίζονται μόνο αυτά που ανήκουν στην επιλεγμένη. Τα στοιχεία τα οποία δεν έχουν τέτοια σηματοδότηση θα εμφανίζονται πάντα. Ο τρόπος κατά τον οποίο γίνεται εύκολη αυτή η διεργασία της σηματοδότησης είναι, ποιος άλλος, η εφαρμογή μιας κλάσης με το όνομα της γλώσσας στην οποία ανήκει το δομικό στοιχείο. Έτσι, μια παράγραφος που ανήκει στην κλάση "el" ανήκει στο Ελληνικό κείμενο, ενώ μια άλλη που ανήκει στην κλάση "en" θα ανήκει στο Αγγλικό κείμενο.

And how is it possible to control which parts of the post will be visible, so each time a language selection is made, only the propper parts will be presented? The solution lies in the HTML ability of containing non visible elements in a page. If, somehow, there is a kind of note in a paragraph element that it belongs to the Greek text and another note in another pragraph that it belongs to some other language's text, then by scanning all the page's elements the ones that belong to some other language could be forced invisible, and leave visible only the ones of the reader's choice. Every other elements that do not contain such a note will be always visible. The way to apply such a note in every wanted element is, which else, the application of a class with the name of the valid language descriptor. So, if one paragraph belongs to the HTML class "el", it belongs to Greek text, while anothe that belongs to HTML class "en", belongs to English text.

Και πως γίνεται να προσθέσουμε τα δομικά στοιχεία και τον κώδικα που θα εκτελεί όλες τις λειτουργίες; Πρώτα θα πρέπει να δούμε τι εργαλεία υπάρχουν για εφαρμογή θέματος στη σελίδα του blog μας.

And how can we add the bulding code blocks that will perform such functionality? First, we have to see what kind of tools we have for applying a template to our blog.

Εφαρμογή Προτύπου

Apply Template

Το blogger.com μας δίνει τη δυνατότητα εφαρμογής προτύπων στη σελίδα μας. Δε θα μπορούσε να είναι σελίδα κατασκευής blogs αν δεν υπήρχε αυτή η δυνατότητα. Φυσικά, κάθε πρότυπο έχει και τη δική του δομή. Σε γενικές γραμμές, ο τρόπος που περιγράφεται εδώ είναι ίδιος με αυτόν που μπορείτε να ακολουθήσετε και σε blog με το δικό σας πρότυπο. Λίγο ο κώδικας του προτύπου, λίγο ο firebug, μπορούμε να βρούμε τα δομικά στοιχεία και τον τρόπο με τον οποίο θα κάνουμε τη παρέμβασή μας.

blogger.com offeres the ability to apply templates on our blog page. It would not be a blog spot if it didn't. Of course, every template has its own structure. In general the way described here is the same as the one you have to follow for your blog page with a different template. Well, some template code understanding, some firebug usage, we can hack around and find the bulding blocks of the template and the way to make our intervention in order to achieve our goal.

Ξεκινάμε από την εφαρμογή του προτύπου που μας ενδιαφέρει. Κάνουμε login στο blog μας και εκεί έχουμε τη δυνατότητα να επιλέξουμε πρότυπο εμφάνισης.

Lets start from the application of the template we are interested in. Lets log into our blog; there we have the option to select a template.

Εδώ μπορούμε να κάνουμε επιλογή του προτύπου που μας ενδιαφέρει. Το βασικό, όμως, είναι πως έχουμε τη δυνατότητα να επέμβουμε στον κώδικά του με τη χρήση του πλήκτρου "Επεξεργασία HTML". Με τη χρήση αυτού του πλήκτρου εμφανίζεται μπροστά μας όλος ο κώδικας που φτιάχνει την εμφάνιση της σελίδας μας.

Here is the place to choose the template we like. But, the most important thing is the access to the template's code, using the "Edit HTML" button. Using that we are able to alter the code that forms the visual part of our blog page at will.

Δομικά Στοιχεία

Structural Components

Κοιτάζοντας λίγο τον κώδικα του προτύπου μας, μπορούμε να δούμε όλα τα gadgets της σελίδας μας. Εκεί, μπορούμε να δούμε ότι η λίστα με τις αναρτήσεις αποτελείται από:

Looking around at our template's code we can find all the gadgets that are included in our page. Ther we can also find the structure of our posts. It is formed as described:

  • Στοιχείο HTML <div> που ανήκει στην κλάση blog-posts. Αυτό περιέχει όλες τις αναρτήσεις που εμφανίζονται στην ιστοσελίδα.
  • A <div> HTML element that belongs to blog-posts class. It contains all the posts that appear on the HTML page.
  • Μέσα σε αυτό περιέχειται ένα <div> που ανήκει στην κλάση date-outer. Αυτό φιλοξενεί τις αναρτήσεις μιας ημέρας.
  • In there, there is another <div> that belongs to date-outer class. It hosts all the posts of the same day.
  • Το τμήμα των αναρτήσεων μιας ημέρας αποτελείται από μια επικεφαλίδα (στη δικιά μας περίπτωση <h2> που ανήκει στην κλάση date-header) που δηλώνει την ημερομηνία που έγιναν οι ακόλουθες αναρτήσεις και ένα <div> που ανήκει στην κλάση date-posts. Εκεί μέσα είναι που θα φιλοξενηθούν οι αναρτήσεις της ίδιας ημέρας.
  • The part of a day's posts is formed by a heading element (in our case it is a <h2> tag tha belongs to date-header class) presenting the date of the posts and a <div> element that belongs to date-posts class. The latter hosts all the posts of that day.
  • Κάθε ανάρτηση είναι από μόνη της ένα <div> που ανήκει στην κλάση post-outer και περιέχει δύο <div> στοιχεία, ένα που περιέχει την ανάρτησή μας (ανήκει στην κλάση post) κι ένα που περιέχει τα σχόλια και τη φόρμα ανάρτησης σχολίων από τους αναγνώστες (ανήκει στην κλάση comments). Αυτό που μας ενδιαφέρει, φυσικα, είναι το πρώτο από τα δύο.
  • Each post is a single <div> that belongs to post-outer class and contains two other <div> elements, one for the post's text (it belongs to post class) and one containing the comments of the readers and a form for comments posting (it belongs to comments class). We are intrested on the first of these two, of course.
  • Κάθε ανάρτησή μας αποτελείται από τέσσερα βασικά τμήματα. Το πρώτο είναι ο τίτλος, το δεύτερο είναι κάποιου είδους επικεφαλίδα (στη δικιά μας περίπτωση είναι πάντα κενό), το τρίτο είναι το κείμενο της ανάρτησης και το τελευταίο είναι το τέλος της ανάρτησης που περιέχει κοινά στοιχεία σε όλες τις αναρτήσεις, όπως ονομα του συγγραφέα, εικονίδια για διαμοιρασμό της ανάρτησης σε facebook, google+, κ.λ.π.
  • Each post is formed by four parts. The first is the title, the second is the post's header (in our case it is always empty), the third part is the text of our post and the last one is the post's footer that contains common things to all the posts, like the author of the post, some post sharing buttons to social networks like facebook, google+, etc.
  • Ο τίτλος της ανάρτησης είναι κάτι που μας ενδιαφέρει. Είναι ένα HTML στοιχείο τύπου <h3> που ανήκει στην κλάση post-title. Μας ενδιαφέρει γιατί εκεί θα ενσωματωθούν οι ενδείξεις για τις διαθέσιμες γλώσσες. Επίσης, από τον τίτλο θα μπορεί να καταλάβει ο κώδικας JavaScript και ποιες είναι αυτές οι διαθέσιμες γλώσσες στις οποίες έχει γραφτεί η ανάρτηση.
  • The title of the post is something we are interested in very much. It is an HTML <h3> element that belongs to post-title class. In there will be inserted the necessary indications of the available languages. At the same time, the JavaScript code can understand what are the available languages of the post from the languages that are included in this title.
  • Το επόμενο κομμάτι της ανάρτησης που μας ενδιαφέρει είναι το HTML στοιχείο <div> που περιέχει το κυρίως κείμενο. Αυτό μας ενδιαφέρει, γιατί εκεί είναι που θα γίνεται η παρέμβαση της JavaScript για να εμφανίσει μόνο τα στοιχεία που ανήκουν στην επιλεγμένη γλώσσα. Το εν λόγω <div> ανήκει στην κλάση post-body.
  • The next part of the post that we are interested in, is the <div> HTML element that contains the main text. There is the most JavaScript code's intervention for showing only the elements that belong to the chosen language. The <div> in question belongs to post-body class.

Προσθήκη Κανόνων στο CSS

Adding CSS Rules

Η πρώτη προσθήκη που έχουμε να κάνουμε στον κώδικα είναι να προσθέσουμε κάποιους κανόνες στο CSS κομμάτι που δηλώνεται μέσα στο πρότυπο που χρησιμοποιούμε για την εμφάνιση της ιστοσελίδας μας. Όταν πατήσουμε το πλήκτρο "Επεξεργασία HTML" που φαίνεται και στο προηγούμενο στιγμιότυπο, κάτω από την προεπισκόπιση της σελίδας μας, μεταφερόμαστε στον κειμενογράφο όπου μπορούμε να "πειράξουμε" τον κώδικα του προτύπου.

The first addition we have to make to the template code is to add some rules in its CSS part. By pressing the "Edit HTML" button that we can see on the previous snapshot, under the template preview, we are transfered to an editor that we can alter the template's code.

Εκεί μπορούμε να βρούμε το σημείο στο οποίο βρίσκονται οι κανόνες CSS που στέλνονται για τη μορφοποίηση της σελίδας. Μια μικρή παρέμβαση που κάνουμε είναι η ακόλουθη:

We can find the part that there are a lot of CSS rules, already, formating our blog's page. A small addition we must make is the following:

...Some template code...
<b:skin>
...Some CSS code...

/*Added for multilingual support*/
.flag {
  height:24px;
  width:24px;
  margin-top:-3px;
  background-size:24px;
  float:right;
  cursor:pointer;
}

.flgen {
  background-image:url(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhevngcbkeTVwuM79NIvECzw-c8ZDzPx1ueBR_uMxZT79MzzsyOCfd_XnzsChqU2F0sGclwpb5NMTite-y16niyB37Py5plX-SDq7hwsFOWEHkhvds6pdLgrzoIQVKSgtYfXluB47JVymTb/s320/United-Kingdom-flag-icon.png);
}

.flgel {
  background-image:url(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMMfgCwXuktRQ6cQlLeCD76uvA_2aHdNmdTrHW-HnsspX4fccXA03KUanP8eI72HyzWk8gMrKp_Y9UntV45F2GGTiQSkfYUSeqSd-MeW_WTjU0xGMQEmH3nt0bJpQ0tkhyw315gEBFbFyZ/s1600/Greece-Flag2.png);
}

en {
  display:none;
}
//End of multilingual support edditions

...Some more CSS code...
</b:skin>
...Some more template code...

Εδώ χρειάζονται λίγες διευκρινήσεις σχετικά με το τμήμα του κώδικα που προσθέσαμε. Κάθε ένα σημαιάκι που θα εμφανίζεται για την επιλογή γλώσσας θα ανήκει στην κλάση flag η οποία ορίζει τα οπτικά χαρακτηριστικά, όπως το μέγεθος και το ότι θα εμφανίζεται στα δεξιά του τμήματος στο οποίο προστίθεται· κοινώς, στα δεξιά στον τίτλο του άρθρου. Για κάθε μια γλώσσα που χρησιμοποιούμε, δημιουργούμε από μια κλάση που έχει όνομα flg και το όνομα της γλώσσας. Για την Ελληνική γλώσσα, δηλαδή, η ονομασία της κλάσης είναι η flgel, ενώ για την Αγγλική (γενικά) θα είναι flgen. Αν υποστηρίζαμε και άλλη μια γλώσσα π.χ. την Ισπανική, τότε θα δημιουργούσαμε ακόμα μια κλάση με όνομα flges, μιας και το es είναι το χαρακτηριστικό της Iσπανικής γλώσσας. Κάθε μια από αυτές τις κλάσεις θα εφαρμόζεται στο αντίστοιχο ενδεικτικό σημαιάκι επιλογής γλώσσας, μαζί με την προηγούμενη κλάση που περιγράφηκε και ο μόνος κανόνας που περιλαμβάνεται είναι αυτός που θέτει ως υπόβαθρο την εικόνα της σημαίας που μας ενδιαφέρει να απεικονίζεται. Εδώ μπορείτε να αλλάξετε το URL της εικόνας που χρησιμοποιώ και να θέσετε το δικό σας. Τέλος, για κάθε άλλη γλώσσα, εκτός από αυτή που θέλουμε να είναι προεπιλεγμένη, δημιουργούμε μια κλάση με το όνομα της γλώσσας, όπου κάνουμε το συστατικό που ανήκει σε αυτή να μην εμφανίζεται στην οθόνη μας. Γι' αυτό το λόγο υπάρχει η κλάση en, μιας και η προεπιλεγμένη γλώσσα για το παρόν blog θεωρείται η Ελληνική· η Αγγλική αποκρύπτεται. Αν υποστηρίζαμε και την Ισπανική γλώσσα, μιας και δεν είναι η προεπιλεγμένη, θα έπρεπε να δημιουργήσουμε άλλη μια κλάση με το όνομα es που να περιέχει τον κανόνα απόκρυψης, δηλαδή το display:none.

Here we have to give some clarifications according to the part of the code we just added. Every little flag indicator for language selection will belong to flag class. This class sets the common optical characteristics of these flags, like the size, to be presented at the right side of the element that it is added to, meaning the right side of the title, cause that's were we are going to add it, etc. For each language we use, we create a class with name comprised of flg and the characteristic name of the language in question. Thus, for the Greek language the name of this class will be flgel, and for the English (general) will be flgen. If we support another language, lets say the Spanish, we should also create another class named flges, since es is the characteristic of this language. Each of these described classes will be applied to the corresponding indicator flag for this language selection, together with the previous one (flag class). The only rule they include is the one that sets the background image to the indication we like, meaning the flag image. Here you can set your URL instead of the one I use. Finally, for each other language we use except for the default one, we create a class with its characteristic name, were we make the elements belonging to that class, invisible. That is why there is a CSS rule for en class, since the default language in this blog is the Greek one; the English becomes invisible. If we also supported the Spanish language here, then we should create one more rule for es class making it invisible, also (having display:none).

Βασική Λειτουργία του Κώδικα JavaScript

Basic Functionality Of JavaScript Program

Ήρθε η ώρα να δούμε τι λειτουργίες και με ποια σειρά θα πρέπει να κάνει ο κώδικας της JavaScript. Εν συντομία έχουμε τα ακόλουθα βήματα:

Now it's time for the functionality of the JavaScript code we add, and in which order it must perform its functions. In short there are the following steps:

  • Ο κώδικας θα πρέπει να εκτελείται αμέσως μόλις φορτωθεί η σελίδα (HTML τμήμα· δε μας ενδιαφέρει να έχουν φορτωθεί και οι εικόνες, αλλά μόνο το DOM). Συνεπώς, ο κώδικας προστίθεται στο τέλος της σελίδας, πριν κλείσει το </body>.
  • The program must start its execution just after the page is loaded (HTML part· we don't care about extra files, like images etc., but only the DOM). That means that we have to add the code just before the closing </body> tag.
  • Το πρώτο πράγμα που πρέπει να γίνει στην εμφάνιση της σελίδας είναι η προσθήκη των διαθέσιμων γλωσσών στον τίτλο κάθε άρθρου. Για να μπορέσει να βρει ο κώδικας τις διαθέσιμες γλώσσες του ενός άρθρου, αρκεί να κοιτάξει τον τίτλο του και να δει σε ποιες γλώσσες είναι γραμμένος.
  • First thing the code must do is to add the language selection flags at the presentation of the page, just at the title of each post. For the code to be able to understand in which languages the post is available, it must look at the title and find out in which languages it is written.
  • Αν υπάρχει μόνο μια γλώσσα στον τίτλο του άρθρου, τότε ενεργοποιεί μόνο αυτή τη γλώσσα και στο κείμενό του. Χρήσιμο κυρίως για τα άρθρα που έχουν γραφτεί παλιότερα και γίνεται τώρα η μετάφρασή τους. Κατά τη διάρκεια της μετάφρασης, το μεταφρασμένο κείμενο δεν εμφανίζεται, αν δε προστεθεί και ο τίτλος στη δεύτερη γλώσσα.
  • If there is only one available language in the title, then, for this post only, it must make it active. That is useful for the older posts that are not translated and they are in a translation phase. During this phase we do not want the partial translated text to be presented. We add the second language only when the translation phase is complete.
  • Αν δε βρεθεί καμιά γλώσσα στον τίτλο του άρθρου, τότε δε γίνεται καμιά επεξεργασία στο κείμενο.
  • If there is no language specified in thte title of the post, then the text is presented as is; without any processing.
  • Θα πρέπει να μπορεί να διαβαστεί μια παράμετρος GET (δηλαδή από τη γραμμή διεύθυνσης) για την επιθυμητή γλώσσα. Με αυτό τον τρόπο, αν κάποιος θέλει να στείλει ένα link σε κάποιον άλλο γι διαμοιρασμό του άρθρου που διαβάζει, μπορεί να προσθέσει την εν λόγω παράμετρο έτσι ώστε ο αποδέκτης να ενεργοποιήσει τη προτοποθετημένη γλώσσα αυτόματα. Αυτό βοηθάει και στην προεπισκόπιση του άρθρου κατά τη διάρκεια της συγγραφής του. Με τη προσθήκη της παραμέτρου στη URL της προεπισκόπισης μπορούμε να δουμε την προεπισκόπιση του άρθρου σε μια άλλη γλώσσα.
  • There must be a GET parameter (in the URL address of the post) to force the presentation in a specific language. In that way, if someone wants to share a link of the post with a friend, he/she can add the parameter in question so the receiver will read the article in that language automatically. This is also helpful in the post preview during a post editing. By adding the parameter in the preview URL you can preview the post in the willing language.
  • Για να μπορεί να θυμάται το σύστημα την επιλογή γλώσσας του αναγνώστη θα πρέπει να γίνει χρήση Cookies.
  • For the system to be able to remember the language choice of the reader, it must use Cookies.
  • Θα πρέπει να μπορεί να διαβαστεί η επιλογή γλώσσας που έχει γίνει από τον φυλλομετρητή του αναγνώστη.
  • Also, there must be the ability to read the language settings of the reader's browser.
  • Αν από η γλώσσα που αποφασίστηκε να ακολουθηθεί δεν υπάρχει στο παρόν άρθρο τότε θα πρέπει να εμφανιστεί η προεπιλεγμένη. Το σύστημα θα πρέπει να λαμβάνει υπόψη του και την κοντινότερη γλώσσα επιλογής. Δηλαδή, αν η γλώσσα επιλογής είναι τα Αγγλικά Ηνωμένων Πολιτειών (με χαρακτηριστικό en_US), όταν αυτή δε βρεθεί, πρώτα θα πρέπει να ελέγχεται η ύπαρξη της κοντινότερης γλώσσας, δηλαδή η Αγγλική γενικότερα (με χαρακτηριστικό en).
  • If the reader's language decision ends to a language that is not used for the currently presented post, then the presented language must be the default one. But first, the system must take into account the existence of a closest language. To be more specific, if the user's choice is the United States English (with en_US literal characteristic), if this is not one of the post's languages, it must first check for the existence of the closest one, meaning the General English (with en literal characteristic).
  • Από τις σημαίες επιλογής γλώσσας πρέπει να αποκρύπτεται η γλώσσα στην οποία εμφανίζεται το άρθρο.
  • From the language selector indications, the post's currently presented one must become hidden.
  • Όταν ο χρήστης επιλέγει κάποια σημαία για αλλαγή γλώσσας εμφάνισης ενός άρθρου, θα πρέπει να ενημερώνεται το Cookie, να αποκρύπτεται η σημαία επιλογής, να εμφανίζεται η σημαία της προηγούμενης επιλογής, ενώ από το κείμενο να αποκρύπτονται όλα τα στοιχεία το οποία ανήκουν μόνο σε άλλες γλώσσες από την επιλεγμένη.
  • When the user makes a language choice, the cookie must be updated, the older hidden selector must become visible and the new one that becomes current must become hidden and, of cource, the post must become visible in the newlly selected language.

Κάτι που θα πρέπει να προσεχθεί είναι η χρήση της παραμέτρου display στα στοιχεία της ιστοσελίδας. Για κανονική εμφάνιση δεν αρκεί να πάρει την τιμή block. Κάποια στοιχεία για να εμφανιστούν σωστά πρέπει να έχουν άλλη τιμή, όπως τα στοιχεία <span> και τα στοιχεία <li>

Something that must be taken care of is the display CSS parameter of the page's elements. For normal appearance, not all of them must have the block value. Some, to be normally presented, must have a different value as happens for <span> and <li> elements.

Ο Κώδικας Βήμα Βήμα

The Code Step By Step

Ας δούμε τον κώδικα βήμα προς βήμα.

Lets walk through the code and examine it step by step.

Ορισμοί Γενικών Μεταβλητών
Global Variables

Ο κώδικας όπως προαναφέραμε προστίθεται ακριβώς πριν το κλείσιμο του tag </body>. Ας δούμε βήμα βήμα τον κώδικα. Ξεκινάμε απο τα "προκαταρκτικά"

As we mentioned earlier, the code we add lies just before the closing </body> tag of the page. Lets see this code step by step. We start from the "preliminary" part

...Previous Template Code...

<script type='text/javascript'>
  //Script for making the blog multilingual.
  var PREFEREDLANGS = &quot;el en&quot;;
  var LANGCOOKIENAME = &quot;echlang&quot;;
  var EXPIREDAYS = 7;
  var TITLES = {};
  TITLES[&quot;el&quot;] = &quot;Δείτε το άρθρο στα Ελληνικά&quot;;
  TITLES[&quot;en&quot;] = &quot;View the article in English&quot;;

...More code, will be presented later...

Πρώτα ορίζουμε μερικές μεταβλητές. Αυτές είναι που θα πειράξετε για να προσθέσετε γλώσσες και να παραμετροποιήσετε το πολυγλωσσικό σύστημα. Θα παρατηρήσατε, βέβαια, πως κάποιοι χαρακτήρες γράφονται με την HTML κωδικοποίηση, όπως π.χ. τα εισαγωγικά γράφονται με την έκφραση &quot;. Αυτό συμβαίνει γιατί στην ουσία πειράζουμε ένα αρχείο xml και αυτό θα πρέπει να μπορεί να το χειριστεί χωρίς προβλήματα ο xml parser του blogger.com. Για τα εισαγωγικά δεν τίθεται θέμα, μιας και από μόνο του το σύστημα τα μετατρέπει. Το πρόβλημα βρίσκεται σε άλλους χαρακτήρες, όπως π.χ. το '<' και το '>'. Αν αυτούς τους χαρακτήρες τους γράψουμε κανονικά και όχι με τη μορφή HTML, δηλαδή &lt; και &gt; αντίστοιχα, τότε το σύστημα θα παραπονεθεί.

First we define some variables. These are the ones you will have to alter to add some languages and use this multilingual system. I believe you noticed that some of the characters are written in their HTML notation, for example the quote characters are written as &quot;. This happens because what we alter here is the xml file of the template and the xml parser of blogger.com must be able to handle it without confusion. For the quotes there is no problem to write them without this notation, but for other characters as '<' and '>' this becomes a problem. If we use these characters not with their HTML notation (&lt; and &gt;, respectively) but straight then the system will thing it has a new tag and will complain.

Ας επανέλθουμε στο τμήμα του κώδικα που δώθηκε και ας δούμε μια προς μια τις μεταβλητές που ορίστηκαν:

Lets come back to the presented part of the code and see the global variables defined, one by one:

  • PREFEREDLANGS: Λίστα από τις υποστηριζόμενες γλώσσες. Η πρώτη είναι η βασική. Οι γλώσσες διαχωρίζονται από κενόSupported languages list. The first one is the default. The language literals are separated by a space character..
  • LANGCOOKIENAME: Το όνομα του Cookie που θα δημιουργείται. Αυτό θα περιέχει και τη προτίμιση της γλώσσας του χρήστηThe name of the Cookie to be created. It is going to store the reader's language choice.
  • EXPIREDAYS: Ο χρόνος διάρκειας του Cookie που δημιουργείται. Όταν ο αναγνώστης επισκέπτεται και πάλι τη σελίδα, το Cookie θα ανανεώνεται για άλλο τόσο χρονικό διάστημαThe duration time of the cookie. When the reader returnes to our blog some time after, its expiration time will be updated for as much time as it is defined here.
  • TITLES: Πρόκειται για ένα map. Ο λόγος ύπαρξής του είναι για το μικρό tooltip που θα εμφανίζεται όταν ο αναγνώστης αφήσει για λίγη ώρα τον κέρσορα του ποντικιού στο σημαιάκι επιλογής της αντίστοιχης γλώσσαςIt is a map type variable. The reason of its existence is for the text that appears in the small tooltip when the reader leaves his/her mouse pointer over the small indicator flag.
Προσθήκη Εικονιδίων Σημαίων Επιλογής Γλώσσας στον Τίτλο
Adding Small Selection Flags On Post Title

Ας δούμε το κομμάτι του κώδικα που προσθέτει τις σημαίες επιλογής γλώσσας:

The following is the part of the code that adds the small language selection flags:

...Previous JavaScript code...

  function setupFlags() {
    var availLangs = PREFEREDLANGS.split(&quot; &quot;);
    var headings = document.getElementsByClassName(&quot;post-title&quot;);
    var usedLangs = new Array();
    for(i=0; i&lt;headings.length; i++) {
      var tempHead = headings[i];
      usedLangs.length = 0;
      if(tempHead != undefined) {
        for(j=0; j&lt;availLangs.length; j++) {
          var tempElems = tempHead.getElementsByClassName(availLangs[j]);
          if(tempElems.length&gt;0) {
            usedLangs.push(availLangs[j]);
          }
        }
        if(usedLangs.length&gt;0) {
          for(j=0; j&lt;usedLangs.length; j++) {
            newDiv = document.createElement(&quot;div&quot;);
            newDiv.className = &quot;flag flg&quot; + usedLangs[j];
            newDiv.setAttribute(&quot;onclick&quot;, &quot;applyLang(&#39;&quot; +usedLangs[j]+ &quot;&#39;)&quot;);
            newDiv.title = TITLES[usedLangs[j]];
            tempHead.appendChild(newDiv);
          }
        }
      }
    }
  }

...More JavaScript code...

Στη γραμμή 4 φτιάχνεται ένας πίνακας με τις υποστηριζόμενες γλώσσες. Στη γραμμή 5 διαβάζονται όλοι οι διαθέσιμοι τίτλοι αναρτήσεων που υπάρχουν στη σελίδα που εμφανίζεται. Μια σελίδα μπορεί να προβάλει περισσότερες από μία αναρτήσεις. Αρκεί να θυμηθούμε ότι κάθε τίτλος ανάρτησης ανήκει στην κλάση post-title. Το επόμενο βήμα είναι να βρούμε σε πόσες και ποιες γλώσσες είναι διαθέσιμη κάθε ανάρτηση. Αυτό κάνει το for loop. Για κάθε τίτλο που έχει βρεθεί, μηδενίζει αρχικά τον πίνακα των χρησιμοποιούμενων γλωσσών (usedLangs - γραμμή 9) και αν πραγματικά έχει βρεθεί κάποιος τίτλος ανάρτησης, τότε μέσα σε αυτόν ελέγχει ποιες από τις διαθέσιμες γλώσσες χρησιμοποιούνται (εσωτερικό for loop - γραμμές 11 έως 16). Οι γλώσσες που βρίσκονται προστίθενται στη μεταβλητή usedLangs.

On line 4 an array is built containing all the supported languages. On line 5 the code reads all the available titles of the posts that appear on page. There can be more than one post. Just remember that every title belongs to post-title class. The next step is to find how many and which languages each post is available. This is the for loop's job. For each title found, it first clears the aray of used languages (usedLangs - line 9) and if there is a title found, it checks which of the available languages are used (nested for loop - lines 11 to 16). Each language found it is added to usedLangs.

Ας θυμηθούμε λίγο μια προΥπόθεση που έχουμε θέσει προτύτερα· αν κάποιο άρθρο δεν έχει καθόλου μετάφραση, τότε ο τίτλος δεν περιέχει καμιά κλάση γλώσσας ενώ αν ο τίτλος περιέχει μόνο μια γλώσσα, τότε βρισκόμαστε σε κατάσταση μεταγλώτισης η οποία δεν έχει τελειώσει κι έτσι ο κώδικας θα πρέπει να αποκρύπτει τα τμήματα των μη δηλωμένων γλωσσών. Η σημαία επιλογής της τρέχουσας γλώσσας πρέπει να μην εμφανίζεται. Για περισσότερες δηλωμένες γλώσσες στον τίτλο της ανάρτησης, δε νομίζω πως θα πρέπει να πούμε κάτι παραπάνω.

At this point we have to remember one condition we set earlier; If a post is not translated at all then there is no element with language class in the title; If there is only one language class defined then the post is in a translation phase so the code must hide the partial translated part, meaning the elements that belong to other than the specified in the title one, languages. The selection flag must also be hidden. I don't thing we have to say any more on that.

Αν λοιπόν βρέθηκαν δηλωμένες γλώσσες στον τίτλο, τότε θα πρέπει να δημιουργηθούν οι σημαίες επιλογής για κάθε μία. Αυτό κάνει και ο κώδικας των γραμμών 17 έως 25.

So, if there is any language defined in the title, then for each one there must be one selection flag. That is what lines 17 to 25 do.

Ανάγνωση Παραμέτρου από τη URL
Read URL Parameters

Το τμήμα που θα δούμε ακολούθως είναι αυτό που διαβάζει τις παραμέτρους τύπου GET από το URL του φυλλομετρητή μας. Πρόκειται για μια υπορουτίνα που δέχεται σαν παράμετρο εισόδου τη παράμετρο που αναζητάμε. Αν Αυτή βρεθεί, τότε επιστρέφει την τιμή της. Αν δε βρεθεί επιστρέφεται η τιμή null:

The part that follows is the one that reads GET type parameters from the URL of our browser. It is a funcition that takes the name of the wanted parameter as input. If it is found in URL then it returns the found value, else it returns null:

...Previous JavaScript code...

  function getParam(p_name) {
    pArray = location.search.substring(1).split(&quot;&amp;&quot;);
    retVal = null;
    pLength = pArray.length;
    for(i=0; i &lt; pLength; i++) {
      keys = pArray[i].split(&quot;=&quot;);
      if(decodeURIComponent(keys[0]) == p_name) {
        retVal = decodeURIComponent(keys[1]);
        break;
      }
    }
    return retVal
  }

...More JavaScript code...

Στη γραμμή 4 διαβάζεται το τμήμα της URL που περιέχει τις παραμέτρους. Ο πρώτος χαρακτήρας είναι ο "?" και γι' αυτό αποκόπτεται (substring(1)) ενώ το υπόλοιπο δημιουργεί ένα πίνακα που περιέχει τις παραμέτρους που δηλώνωνται. Η μια παράμετρος από την επόμενη χωρίζονται από τον χαρακτήρα "&". Αν βρεθούν παράμετροι, τότε εξετάζονται μια προς μία για να βρούμε αυτή που δηλώθηκε κατά την κλήση της υπορουτίνας. Προσέξτε ότι χρησιμοποιείται η decodeURIComponent για να αποκωδικοποιηθούν σωστά οι ειδικοί χαρακτήρες που μπορεί να περιέχονται στο URL. Αν η παράμετρος βρεθεί τότε σταματάει το ψάξιμο και επιστρέφεται η τιμή της, ενώ αν δε βρεθεί επιστρέφεται η προτοποθετημένη τιμή null.

In line 4 the parameters part of the URL is fetched. The first character is always "?" so it is omitted (substring(1)) and the rest forms an array containing the parameters read and their values. Each parameter is separated from the next by the "&" character. If there is any parameter found, they are checked one by one to match the one specified by the caller of the function. Mind that decodeURIComponent is used to decode the HTML characters used in URLs correctly. If the parameter needed is found in the list then the searching stops and its value is returned, else the returned value is the predefined null.

Θα μπορούσε κάποιος να παρατηρήσει πως η συγκεκριμμένη ρουτίνα δεν ξέρει να ασχοληθεί με παραμέτρους που μπορούν να πάρουν πολλές τιμές ταυτόχρονα (όπως επιλογές από checkboxes με το ίδιο όνομα). Αυτό δεν είναι κάτι που μας ενδιαφέρει γιατί η μόνη παράμετρος που διαχειριζόμαστε είναι η lang. Θα ήταν, λοιπόν, άσκοπο να προσθέσουμε κάτι παραπάνω σε αυτή τη ρουτίνα για κάτι που δε χρειαζόμαστε.

Someone could notice that this function does not know how to handle parameters that can take many values at the same time; a list of values (like from checkboxes with the same name). This is not of our concern because the only parameter we need to handle is lang and this takes only one value. So, it would be useless to try to handle something more complicated than that.

Διαχείριση Cookies
Cookies Manipulation

Ο κώδικας πρέπει να θυμάται την επιλογή της γλώσσας του αναγνώστη. Είναι αρκετά άβολο, κάθε φορά που ένας αναγνώστης επιλέγει να δει μια καινούργια ανάρτηση να πρέπει να ξαναεπιλέξει και τη γλώσσα που τον ενδιαφέρει να διαβάζει το άρθρο. Για να μπορεί να θυμάται το σύστημα την επιλογή της γλώσσας για τον κάθε ένα αναγνώστη ξεχωριστά, ο μόνος τρόπος είναι η χρήση ενός Cookie. Ας δούμε τις ρουτίνες που τα διαχειρίζονται.

The code must be able to remember reader's language choice. It is very inconvenient each time the reader visits our page, or changes post in our blog, to have to select again and again the same language. For the system to be able to remember each reader's choice, the only way is to use Cookies. Lets see the functions that manipulate them.

...Previous JavaScript code...

  function setCookie(c_name, c_inval, exdays) {
    if (exdays) {
      var exdate = new Date();
      exdate.setTime(exdate.getTime()+(exdays*24*60*60*1000));
      var expires = &quot;; expires=&quot; + exdate.toGMTString();
    } else {
      var expires = &quot;&quot;;
    }
    var c_value = escape(c_inval);
    document.cookie = c_name + &quot;=&quot; + c_value + expires + &quot;; path=/&quot;;
  }

  function getCookie(c_name) {
    var nameEQ = c_name + &quot;=&quot;;
    var ca = document.cookie.split(&quot;;&quot;);
    var caLength = ca.length;
    for(var i=0; i &lt; caLength; i++) {
      var c = ca[i];
      while (c.charAt(0)==&quot; &quot;) c = c.substring(1,c.length);
      if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
    }
    return null;
  }

  function updCookie(c_name, c_newval) {
    var c_val = c_newval || getCookie(c_name);
    if (c_val) {
      setCookie(c_name, c_val, EXPIREDAYS)
    }
  }

...More JavaScript code...

Σε αυτό το τμήμα του κώδικα βλέπουμε τρεις υπορουτίνες. Η πρώτη (setCookie) δημιουργεί ένα Cookie με όνομα που δηλώνεται στην παράμετρο c_name, η τιμή του καθορίζεται από τη παράμετρο c_inval ενώ ο χρόνος εγκυρότητάς του δηλώνεται από τη παράμετρο exdays.

In this part of the code we can see three functions. The first one, (setCookie), creates a Cookie with the name set at c_name calling parameter, its value is set according to c_inval and the time to live is set by exdays.

Η δεύτερη υπορουτίνα διαβάζει το Cookie με όνομα που δηλώνεται στη παράμετρο εισόδου c_name κι επιστρέφει την τιμή του. Αν δε το βρει επιστρέφει null.

The second function reads a Cookie named according to c_name input parameter and returns its value. If the cookie is not found then null is returned.

Η τρίτη κι τελευταία υπορουτίνα χρησιμοποιεί τη setCookie για να κάνει τη δουλειά της. Αν υπάρχει το Cookie που δηλώνεται στην παράμετρο c_name τότε το ενημερώνει με μια πιθανά καινούργια τιμή, αν αυτή έχει δηλωθεί στη παράμετρο c_newval και μια ημερομηνία που ορίζεται από τις αρχικές μεταβλητές που δηλώσαμε στην αρχή, την EXPIREDAYS.

The third and last function uses the previously mentioned setCookie to do its job. If there is already a Cookie named as the input parameter c_name specifies, it possibly updates its value to the new one specified by c_newval. If the parameter is omited then it does not change the cookie's value. Also, the expiration date is updated according to the global variable we saw in the beginning of the code, EXPIREDAYS.

Απόφαση Γλώσσας Αναγνώστη
Readers Language Decision

Ήρθε η ώρα να αποφασίσουμε τελικά σε ποια από τις διαθέσιμες γλώσσες θα εμφανίσουμε το άρθρο. Η απόφαση πρέπει να γίνει με βάση τα εξής κριτήρια:

Time to decide, finaly, which one of the available languages will be the one that the post will be displayed. The decision is made according to the following criteria:

  1. Αν υπάρχει παράμετρος με όνομα lang στη URL του φυλλομετρητή, τότε η απόφαση ορίζεται από αυτή την τιμήIf there is a parameter named lang in the URL of the browser, then the language to be used is the one specified there.
  2. Αν δεν υπάρχει η παράμετρος τότε εξετάζεται το ενδεχόμενο να έχει ξαναεπισκευτεί τη σελίδα ο αναγνώστης, δηλαδή το να υπάρχει αποθηκευμένο Cookie με το όνομα που δηλώνει η αρχική μεταβλητή LANGCOOKIENAME. Αν υπάρχει τότε η γλώσσα επιλέγεται από αυτόIf that parameter si not found then we have to check if the reader has visited our page before, by checking the existance of a Cookie with the name specified by global variable LANGCOOKIENAME. If it is true, then the language to be used is set by the Cookie's value.
  3. Αν ο αναγνώστης επισκέπτεται για πρώτη φορά τη σελίδα μας, ή έχει καιρό να την επισκευτεί έτσι ώστε να έχει λήξει η προθεσμία του Cookie, τότε η απόφαση θα παρθεί από τις ρυθμίσεις του φυλλομετρητήIf this is the first time the reader visits our page, or he/she has a long time to visit it so the Cookie in question has expired, then the decision must be made by the browser settings.
  4. Τέλος, αν όλες οι προηγούμενες προσπάθειες αποτύχουν, ορίζεται ως γλώσσα η πρώτη από τη λίστα που ορίζει η αρχική μεταβλητή PREFEREDLANGSFinally, when all the previous attempts fail, the default language is used and this is the first one in the global list in PREFEREDLANGS.

Όλα τα παραπάνω φαίνονται στο ακόλουθο κομμάτι κώδικα:

All the previously mentioned are performed by the following code:

...Previous JavaScript code...

  function getLang() {
    var langParam = getParam(&quot;lang&quot;);
    var availLangs = PREFEREDLANGS.split(&quot; &quot;);
    var browserLang = langParam || getCookie(LANGCOOKIENAME) || window.navigator.userLanguage || window.navigator.language || availLangs[0];
    var langCnt = availLangs.length;
    retVal = 0;
    for(i=0; i &lt; langCnt; i++) {
      if(browserLang == availLangs[i]) {
        retVal = i;
        break;
      } else if(browserLang.substring(0, browserLang.indexOf(&quot;_&quot;)) == availLangs[i]) {
        retVal = i;
 break;
      }
    }
    return availLangs[retVal];
  }

...More JavaScript code...

Στη γραμμή 6, εξετάζονται μια προς μια οι παράμετροι, με τη σειρά που εξηγήσαμε. Όποια βρεθεί πρώτη είναι και αυτή που θα δώσει την τιμή της στη μεταβλητή browserLang. Για να μπορέσουμε, όμως, να εξασφαλίσουμε ότι η γλώσσα που θα επιστραφεί είναι μια από τις αποδεκτές που ορίζονται στην αρχή του όλου κώδικα, με τη μεταβλητή PREFEREDLANGS, θα πρέπει να γίνει μια αντιπαράθεση με μια προς μια τις διαθέσιμες γλώσσες. Αυτό κάνει και το for loop στις γραμμές 9 έως 17. Μια μικρή λεπτομέρεια είναι πως η γλώσσα μπορεί να αποτελείται από το γενικό κομμάτι της (π.χ. "en" για την Αγγλική) αλλά μπορεί να περιέχει και το χαρακτηριστικό της περιοχής (όπως π.χ. "en_US" για την Αγγλική γλώσσα των Ηνωμένων Πολιτειών). Αυτό ο κώδικας το λαμβάνει υπόψη του.

In line 6, the parameters are checked ony by one in the described order. The first found one sets the value of browserLang. To be able to secure that the returned language value to be used is one of the available ones, set by PREFEREDLANGS global variable, we should compare their values. This is done by the for loop in lines 9 to 17. One small detail is that a language literal characteristic may contain only the general part of the language (ie. "en" for English) or may include the country literal (as in "en_US" for United States English). The code takes it into account, also.

Εφαρμογή Γλώσσας Στις Αναρτήσεις
Apply Language Selection On Posts

Γνωρίζωντας, πλέον, τη γλώσσα στην οποία θα πρέπει να εμφανιστεί το άρθρο, το μόνο που μένει είναι να εφαρμόσουμε αυτή την επιλογή. Η εφαρμογή γίνεται από την ίδια ρουτίνα που χρησιμοποιείται και από τις σημαίες επιλογής γλώσσας που εμφανίσαμε στον τίτλο της ανάρτησης. Αν γυρίσουμε, για μια στιγμή μόνο, πίσω στο κομμάτι του κώδικα που πρόσθεσε τα ενδεικτικά σημαιάκια στον τίτλο. Βλέπουμε στη γραμμή 21 εκείνου του κώδικα να ορίζεται το event onclick να καλεί μια υπορουτίνα με όνομα applyLang και παράμετρο τη γλώσσα που αντιπροσωπεύει το αντίστοιχο ενδεικτικό σημαιάκι. Ας δούμε τον κώδικα της υπορουτίνας:

Knowing the language that the post should be presented, the only thing left is to apply this decision. The same function that applies the language choice when selecting one of the title's flags, is the one that does the same job here, also. If we go back to the part of code that added the small language selection flags in the title, we can see in line 21 of that code part that it sets the onclick event to call a function named applyLang having as calling parameter the language that coresponds to the selected flag. Lets see now the code of this function:

...Previous JavaScript code...

  function applyLang(inLang) {
    var posts = document.getElementsByClassName(&quot;post&quot;);
    setCookie(LANGCOOKIENAME, inLang, EXPIREDAYS);
    if(posts[0] == undefined)
      return;
    for(k=0; k&lt;posts.length; k++) {
      var flags = posts[k].getElementsByClassName(&quot;flag&quot;);
      var langExist = (posts[k].getElementsByClassName(&quot;flag flg&quot; + inLang) != undefined);
      var flagsCnt = flags.length;
      if(flagsCnt==0) continue;
      var tempLang = inLang;
      if((flagsCnt==1) || !langExist) {
        tempLang = flags[0].className.indexOf(&quot;flg&quot;);
 tempLang = flags[0].className.substring(tempLang+3);
      }
      for(i=0; i&lt;flagsCnt; i++){
        curI = flags[i].className.indexOf(&quot;flg&quot;+tempLang);
        if(curI &gt;= 0) {
          flags[i].style.display = &quot;none&quot;;
        } else {
          flags[i].style.display = &quot;inline&quot;;
        }
      }
      var availLangs = PREFEREDLANGS.split(&quot; &quot;);
      for(i=0; i&lt;availLangs.length; i++){
        var currLang = availLangs[i];
        if(currLang == tempLang)
          continue;
        var divs = document.getElementsByClassName(currLang);
        var divsCnt = divs.length;
        for(j=0; j&lt;divsCnt; j++) {
          divs[j].style.display = &quot;none&quot;;
        }
      }
      var divs = document.getElementsByClassName(tempLang);
      var divsCnt = divs.length;
      for(j=0; j&lt;divsCnt; j++) {
        elemType = divs[j].tagName.toLowerCase();
        divDisplay = &quot;block&quot;;
        switch(elemType) {
          case &quot;a&quot;:
          case &quot;span&quot;:
            divDisplay = &quot;inline&quot;;
            break;
          case &quot;li&quot;:
            divDisplay = &quot;list-item&quot;;
            break;
        }
        divs[j].style.display = divDisplay;
      }
    }
  }

...More JavaScript code...

Πιθανόν κάποιος να αναρωτηθεί για τον τρόπο με τον οποίο είναι γραμμένη αυτή η υπορουτίνα. Ας δούμε λίγο τι κάνει.

Well, perhaps someone will ask for the way this function is written. Lets see how it operates.

Αρχικά ανανεώνει το Cookie για τη γλώσσα που πρόκειται να παρουσιαστεί και φυσικά το χρόνο λήξης της ισχύος του (γραμμή 5). Στη συνέχεια αν δεν υπάρχει κάποια διαθέσιμη ανάρτηση, τότε δεν υπάρχει κάτι να κάνει, οπότε και τερματίζεται (γραμμές 6 και 7).

In the beginning it updates the Cookie with the language value to be used and, of course, its expiration time (line 5). Next, if there is no post on screen it has nothing to do so it returns (lines 6 and 7).

Για κάθε ανάρτηση που βρίσκει αναγνωρίζει ποιες είναι οι διαθέσιμες γλώσσες και αν η ανάρτηση περιέχεται στη γλώσσα που επιλέχθηκε. Αν δε βρεθεί κάποια γλώσσα για την ανάρτηση την οποία ελέγχει τότε προχωράει στην επόμενη (γραμμή 12).

For every post it finds it checks its available languages and if the selected one appears in the list. If this is not true it continues to the next post (line 12).

Το τμήμα που αποτελείται από τις γραμμές 13 έως 17, αποφασίζει ποια γλώσσα από τις διαθέσιμες του άρθρου είναι αυτή στην οποία θα εμφανιστεί. Ο λόγος που γίνεται αυτό, είναι γιατί ένα άρθρο μπορεί να είναι ολοκληρωμένο μόνο σε μια γλώσσα, η οποία να είναι διαφορετική από την επιλεγμένη, οπότε και θα εμφανιστεί στη γλώσσα στην οποία είναι γραμμένο, ή να μην έχει γραφτεί καθόλου στην επιλεγμένη γλώσσα, συνεπώς εμφανίζεται στην προεπιλεγμένη. Μην ξεχνάμε πως ο λόγος να έχει δηλωθεί μόνο μια γλώσσα στον τίτλο ενός άρθρου, είναι κατά τη διάρκεια της μεταγλώτισής του ενώ αυτό έχει αναρτηθεί, έτσι ώστε να αποκρύπτεται η ημιτελής μετάφραση.

The part that is formed by lines 13 to 17, decides which of the post's available language will be used, finaly.The reason for this is that a post may be in a translation phase and the completed language be different from the one specified. Thus, the completed language is the one that should be used. The post may also be written only in a different language, so it is presented in the default one. Don't forget the reason of specifying only one language in the post's title. It means the article is in a translation phase and the non completed language should not be presented.

Από τη γραμμή 18 έως την 25 ενημερώνεται η εμφάνιση των σημαιών επιλογής γλώσσας. Εμφανίζονται, δηλαδή, οι σημαίες των γλωσσών που δεν είναι επιλεγμένες και αποκρύπτεται αυτή στην οποία εμφανίζεται η παρούσα ανάρτηση.

Form line 18 to line 25 the avalable selection flags are updated; the languages that are not used become visible and the one that represents the current selection becomes hidden.

Τα επόμενο βήμα είναι να εμφανιστούν τα HTML στοιχεία που ανήκουν στη γλώσσα που έχει αποφασιστεί να προβληθεί η ανάρτηση. Αυτό γίνεται σε δύο κομμάτια. Το πρώτο αποτελείται από τις γραμμές 27 έως 36, το οποίο αποκρύπτει όλες τις παραγράφους που έχουν επισήμανση γλώσσας. Το δεύτερο κομμάτι αποτελείται από τις γραμμές 37 έως και 52. Αυτό εμφανίζει τα στοιχεία τα οποία ανήκουν στη γλώσσα προβολής του άρθρου. Εδώ δίνεται και η δυνατότητα να μπορέσουν τα διαφορετικά στοιχεία να πάρουν διαφορετική τιμή στη παράμετρο display.

The next step is for the HTML elements that belong to the selected language to be displayed. It is done in two phases. The first is the code in lines 27 to 36, that hides all the elements that belong to another language. The second phase, code lines 37 to 52, displays the elements that belong to the currently selected language. Here every element can take a different display value for their correct appearance.

Ο λόγος για τον οποίο η εμφάνιση γίνεται με διπλό πέρασμα των στοιχείων της ανάρτησης είναι γιατί ένα στοιχείο μπορεί να ανήκει σε δύο γλώσσες. Παραδείγματος χάρην, αν το άρθρο έχει γραφτεί σε Ελληνικά, Αγγλικά και Κινέζικα, τότε ένα στοιχείο που εμφανίζεται και στα Ελληνικά, αλλά και στα Αγγλικά θα πρέπει να ανήκει και στις δύο κλάσεις γλώσσας (class="el en"). Αν δεν περνούσαμε την εμφάνιση σε δύο βήματα, τότε η λειτουργία της εμφάνισης δε θα γινόταν σωστά· ναι μεν στην επιλογή της εμφάνισης του άρθρου σε Κινέζικα δε θα εμφανιζόταν το εν λόγω στοιχείο, αλλά αναλόγως με τη θέση της γλώσσας των Ελληνικών και των Αγγλικών στη λίστα των διαθέσιμων γλωσσών δε θα είχαμε εμφάνιση και στις δύο γλώσσες...

The reason of the two phases insted of one, is that an element can belong to two or more languages. In example, if an article is written in Greek, English and Chinese, there is the posibility for an element to be presented for both Greek and English languages and be hidden in Chinese. For this to become true, the element must belong to both el and en classes (class="el en"). If there were not two phases the presentation of the article would be broken; in the Chinese post everything would be fine, but in the other two languages the correct representation would be only in the one that appears first in the global list of languages. We would not see the element in question in both specified ones...

Τελευταίες Πινελιές στον Κώδικα
Some Code's Finishing Touches

Τι δεν έχουμε δει ακόμα; Το κομμάτι του κώδικα που ξεκινάει την αυτόματη εκτέλεσή του. Μιας και δεν έχουμε τον πλήρη έλεγχο όλου του κώδικα που τρέχει στη σελίδα, παρά μόνο στο δικό μας κομμάτι, δε μπορούμε να χρησιμοποιήσουμε την onload. Μπορεί ήδη να τη χρησιμοποιεί κάποιο άλλο κομμάτι κώδικα από όλα αυτά που φορτώνονται για την επιβολή των στατιστικών κ.λ.π. που μας παρέχει το blogger.com. Κατα συνέπεια, ο μόνος διαθέσιμος τρόπος είναι οι αυτόματα εκτελέσιμες υπορουτίνες της JavaScript:

What we haven't seen yet? The part of the code that automatically starts its execution. Since we don't have the complete control of the whole code that runs in our page, but only in our part of code, we cannot use onload. It may be in use from another part of the code that the page loads for google statistics etc. and for the gadjets that blogger.com offeres. The only safe way is the autorun JavaScript functions:

...Previous JavaScript code...

  (function(){
    setupFlags();
    setupLang();
  })();

  function setupLang() {
    currLang = getLang();
    applyLang(currLang);
  }
</script>

</body>
</html>

Οι γραμμές 8 έως 11 δεν κάνουν τίποτα άλλο από το να διαβάσουν τη γλώσσα που θα πρέπει να χρησιμοποιηθεί, την πρώτη φορά που φορτώνεται η σελίδα, ενώ οι γραμμές 3 έως και 6 είναι αυτές που εκτελούνται αυτόματα με το που φορτώνεται η σελίδα μας. Αυτές είναι που ξεκινάνε την εμφάνιση των σημαιών επιλογής γλώσσας κι εμφανίζουν τα άρθρα που υπάρχουν στη σελίδα στη γλώσσα που είναι πιο κοντά στον χρήστη, όπως περιγράφτηκε στην παράγραφο "Απόφαση Γλώσσας Αναγνώστη". Σε αυτό το σημείο ολοκληρώνεται και ο κώδικας που περιέχεται σε αυτό εδώ το blog για την πολυγλωσσική εμφάνιση των αναρτήσεών του.

Lines from 8 to 11 do nothing more than finding the propper language the first time the page is loaded. Lines 3 to 6 are those that take advantage of the autorun feature of JavaScript. When the page is loaded they are automatically executed. These are the ones that start adding the language selection flags and present the posts on the page in the correct languages, the ones closer to the reader, just as described in "Readers Language Decision". And in that point the code we present is complete and is the code that this blog uses to offer nultilanguage capabilities in our posts.

Το Συνολικό Πρόγραμμα της JavaScript

The Whole JavaScript Program

Μιας και ο κώδικας περιγράφτηκε σε τμήματα, για να είναι πιο εύκολο για τον αναγνώστη να μπορέσει να τον αντιγράψει και να τον χρησιμοποιήσει/παραλλάξει σύμφωνα με τις ανάγκες του, ο κώδικας παρατίθεται ολόκληρος σε αυτό το σημείο. Μπορείτε να τον χρησιμοποιήσετε ελεύθερα.

Since the code was described part to part, for the reader to be easier to copy and use/alter it according to his/her needs, the whole code will be presented here. You can copy and use it freely.

<script type='text/javascript'>
  //Script for making the blog multilingual.
  //Written by Elias Chrysocheris
  /*THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES,
    INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS
    OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
    OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
    STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
  var PREFEREDLANGS = &quot;el en&quot;;
  var LANGCOOKIENAME = &quot;echlang&quot;;
  var EXPIREDAYS = 7;
  var TITLES = {};
  TITLES[&quot;el&quot;] = &quot;Δείτε το άρθρο στα Ελληνικά&quot;;
  TITLES[&quot;en&quot;] = &quot;View the article in English&quot;;

  (function(){
    setupFlags();
    setupLang();
  })();

  function setCookie(c_name, c_inval, exdays) {
    if (exdays) {
      var exdate = new Date();
      exdate.setTime(exdate.getTime()+(exdays*24*60*60*1000));
      var expires = &quot;; expires=&quot; + exdate.toGMTString();
    } else {
      var expires = &quot;&quot;;
    }
    var c_value = escape(c_inval);
    document.cookie = c_name + &quot;=&quot; + c_value + expires + &quot;; path=/&quot;;
  }

  function getCookie(c_name) {
    var nameEQ = c_name + &quot;=&quot;;
    var ca = document.cookie.split(&quot;;&quot;);
    var caLength = ca.length;
    for(var i=0; i &lt; caLength; i++) {
      var c = ca[i];
      while (c.charAt(0)==&quot; &quot;) c = c.substring(1,c.length);
      if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
    }
    return null;
  }

  function updCookie(c_name, c_newval) {
    var c_val = c_newval || getCookie(c_name);
    if (c_val) {
      setCookie(c_name, c_val, EXPIREDAYS)
    }
  }

  function getParam(p_name) {
    pArray = location.search.substring(1).split(&quot;&amp;&quot;);
    retVal = null;
    pLength = pArray.length;
    for(i=0; i &lt; pLength; i++) {
      keys = pArray[i].split(&quot;=&quot;);
      if(decodeURIComponent(keys[0]) == p_name) {
        retVal = decodeURIComponent(keys[1]);
        break;
      }
    }
    return retVal
  }

  function getLang() {
    var langParam = getParam(&quot;lang&quot;);
    var availLangs = PREFEREDLANGS.split(&quot; &quot;);
    var browserLang = langParam || getCookie(LANGCOOKIENAME) || window.navigator.userLanguage || window.navigator.language || availLangs[0];
    var langCnt = availLangs.length;
    retVal = 0;
    for(i=0; i &lt; langCnt; i++) {
      if(browserLang == availLangs[i]) {
        retVal = i;
        break;
      } else if(browserLang.substring(0, browserLang.indexOf(&quot;_&quot;)) == availLangs[i]) {
        retVal = i;
 break;
      }
    }
    return availLangs[retVal];
  }

  function setupLang() {
    currLang = getLang();
    applyLang(currLang);
  }

  function applyLang(inLang) {
    var posts = document.getElementsByClassName(&quot;post&quot;);
    setCookie(LANGCOOKIENAME, inLang, EXPIREDAYS);
    if(posts[0] == undefined)
      return;
    for(k=0; k&lt;posts.length; k++) {
      var flags = posts[k].getElementsByClassName(&quot;flag&quot;);
      var langExist = (posts[k].getElementsByClassName(&quot;flag flg&quot; + inLang) != undefined);
      var flagsCnt = flags.length;
      if(flagsCnt==0) continue;
      var tempLang = inLang;
      if((flagsCnt==1) || !langExist) {
        tempLang = flags[0].className.indexOf(&quot;flg&quot;);
 tempLang = flags[0].className.substring(tempLang+3);
      }
      for(i=0; i&lt;flagsCnt; i++){
        curI = flags[i].className.indexOf(&quot;flg&quot;+tempLang);
        if(curI &gt;= 0) {
          flags[i].style.display = &quot;none&quot;;
        } else {
          flags[i].style.display = &quot;inline&quot;;
        }
      }
      var availLangs = PREFEREDLANGS.split(&quot; &quot;);
      for(i=0; i&lt;availLangs.length; i++){
        var currLang = availLangs[i];
        if(currLang == tempLang)
          continue;
        var divs = document.getElementsByClassName(currLang);
        var divsCnt = divs.length;
        for(j=0; j&lt;divsCnt; j++) {
          divs[j].style.display = &quot;none&quot;;
        }
      }
      var divs = document.getElementsByClassName(tempLang);
      var divsCnt = divs.length;
      for(j=0; j&lt;divsCnt; j++) {
        elemType = divs[j].tagName.toLowerCase();
        divDisplay = &quot;block&quot;;
        switch(elemType) {
          case &quot;a&quot;:
          case &quot;span&quot;:
            divDisplay = &quot;inline&quot;;
            break;
          case &quot;li&quot;:
            divDisplay = &quot;list-item&quot;;
            break;
        }
        divs[j].style.display = divDisplay;
      }
    }
  }

  function setupFlags() {
    var availLangs = PREFEREDLANGS.split(&quot; &quot;);
    var headings = document.getElementsByClassName(&quot;post-title&quot;);
    var usedLangs = new Array();
    for(i=0; i&lt;headings.length; i++) {
      var tempHead = headings[i];
      usedLangs.length = 0;
      if(tempHead != undefined) {
        for(j=0; j&lt;availLangs.length; j++) {
          var tempElems = tempHead.getElementsByClassName(availLangs[j]);
          if(tempElems.length&gt;0) {
            usedLangs.push(availLangs[j]);
          }
        }
        if(usedLangs.length&gt;0) {
          for(j=0; j&lt;usedLangs.length; j++) {
            newDiv = document.createElement(&quot;div&quot;);
            newDiv.className = &quot;flag flg&quot; + usedLangs[j];
            newDiv.setAttribute(&quot;onclick&quot;, &quot;applyLang(&#39;&quot; +usedLangs[j]+ &quot;&#39;)&quot;);
            newDiv.title = TITLES[usedLangs[j]];
            tempHead.appendChild(newDiv);
          }
        }
      }
    }
  }

</script>
</body>
</html>

Απλά θυμηθείτε πως υπάρχει και το τμήμα του CSS καθώς επίσης θα πρέπει να παραλλάξετε τις global μεταβλητές σύμφωνα με τις δικές σας ανάγκες.

Just keep in mind that there is also the CSS part of the code and that you may have to alter the global variables for your needs.

Παράδειγμα Χρήσης

An Example Of Usage

Για να δούμε πώς μπορούμε να φτιάξουμε ένα πολυγλωσσικό κείμενο. Μιας και στο παρόν blog χρησιμοποιούμε Ελληνική και Αγγλική γλώσσα, το παράδειγμα που θα δοθεί είναι γι' αυτές. Ας δούμε ένα κομμάτι κειμένου που αναρτούμε σε ένα άρθρο μας. Να σημειωθεί ότι το κέιμενο είναι γραμμένο σε καθαρή HTML:

Lets see how we can create a multilingual text. Since in our blog we use only Greek and English languages, the example will be given for these two. Lets see a part of text that will be presented in our post. Notice that it is written in pure HTML:

<p class="el">Αυτό είναι το κείμενο της παραγράφου στα Ελληνικά. Εφόσον η κλάση που δηλώνεται
στο tag της παραγράφου είναι <tt>el</tt>, η παράγραφος αυτή θα εμφανίζεται όταν βλέπετε το
Ελληνικό κείμενο!</p>
<p class="en">This is the English text of the paragraph. Since the &lt;p&gt; tag belongs to
<tt>en</tt> class, this paragraph will be visible only when the English text is displayed!</p>

Το αποτέλεσμα είναι η ακόλουθη παράγραφος στο γκρι πλαίσιο. Η ενδεικτική σημαία δεν προστίθεται με αυτό τον HTML κώδικα, αλλά την έχουμε προσθέσει εμείς για την ευκολία της παρατήρησης του αναγνώστη. Δοκιμάστε να επιλέξετε άλλη γλώσσα από τον τίτλο του κειμένου (ή από τη σημαία στα δεξιά) και παρατηρείστε τι εμφανίζεται σε αυτή την παράγραφο:

The result is the following paragraph in the gray box. The selector flag at the right is not added by this HTML code, but we have added it for the reader's convenience to observe the results. Try to select another language from the post's tilte (or the indicator flag at the right) and observe the appeared paragraph:

Αυτό είναι το κείμενο της παραγράφου στα Ελληνικά. Εφόσον η κλάση που δηλώνεται στο tag της παραγράφου είναι el, η παράγραφος αυτή θα εμφανίζεται όταν βλέπετε το Ελληνικό κείμενο!

This is the English text of the paragraph. Since the <p> tag belongs to en class, this paragraph will be visible only when the English text is displayed!

Κάτι ακόμα που θα πρέπει να αναφερθεί, είναι πως κατά τη διάρκεια της προεπισκόπισης ενός άρθρου που ακόμα συντάσεται, χωρίς να έχει αναρτηθεί, επειδή το blogger κόβει κάποιες από τις λειτουργίες, ένας απλός τρόπος για να γίνει προεπισκόπιση σε άλλη γλώσσα, είναι η χρήση της παραμέτρου lang στο URL του παραθύρου της προεπισκόπισης. Δηλαδή, όταν πατήσουμε το πλήκτρο προεπισκόπιση κατά τη διάρκεια της συγγραφής ενός άρθρου, ανοίγει μια καινούργια καρτέλα (ή καινούργιο παράθυρο, ανάλογα με τις ρυθμίσεις του φυλλομετρητή) και μας δειχνει πως θα φαίνεται το άρθρο όταν αναρτηθεί. Αν στο URL προσθέσουμε το "&lang=en", τότε υποχρεώνουμε το σύστημα να μας εμφανίσει το άρθρο στην Αγγλική γλώσσα.

One more thing must be reported is that during the preview of a post that is still editted without being published, because blogger.com uses a "click trap", a simple way of previewing the post in a different language is to use the lang parameter in the URL of the preview page. Meaning, when we use the Preview button during the editing of a post, a new tab (o a new window, depending on your browser's settings) opens and it presents us how the post will appear when it is published. If we add "&lang=en" in the preview URL, then we force the system to present the article in English.

Συμπεράσματα

Conclusions

Το να μπορεί κάποιος να διαβάσει ένα κείμενο που τον ενδιαφέρει στη μητρική του γλώσσα, είναι κάτι πολύ σημαντικό. Σκεφτείτε πόσες φορές έχετε βρει ένα κείμενο σε μια γλώσσα που δεν καταλαβαίνετε· είτε δεν το προσπαθήσατε καθόλου, είτε χωθήκατε μέσα σε ένα μεταφραστικό και... ότι βγάλατε βγάλατε. Μην ξεχνάμε ότι παντού γίνονται προσπάθειες μετάφρασης. Από κλειστά λογισμικά μέχρι ανοικτά, ιστοσελίδες και ό,τι μπορεί να περιέχει κείμενο, κρύβουν μια ομάδα, μεγάλη ή μικρή που δουλειά της είναι να μεταφράζει τα κείμενα σε διάφορες γλώσσες. Όσοι ασχολείστε με το ανοικτό λογισμικό πιστεύω πως θα ασχοληθήκατε, ή έστω θα διαπιστώσατε τη μεγάλη προσπάθεια που γίνεται για τη μετάφραση των προγραμμάτων, τόσο του γραφικού περιβάλλοντός τους όσο και του κειμένου βοήθειας.

For somebody to be able to read a text in his/her native language is something very important. Just think of the times that you have found an interesting article in a language that you cannot understand. Either you didn't try to read it at all, or you fell into a translating site (or dictionary) and... whatever came out of this. Lets not forget that everywhere there are translation tries. From closed source programs to opensource ones, web pages and whatever may include text, everything hides a translating team behind the scenes, big or small to translate documents into different languages. Whoever of you uses open source programs and operating systems I believe that you have tried to do something like that, or at least you have seen the big effort made for translation of all programs, graphical environment and help files.

Το blogger.com δυστυχώς δε μας δίνει τη δυνατότητα να έχουμε μεταφράσεις του κειμένου μιας ανάρτησής μας. Αυτό το εμπόδιο, με λίγη προσπάθεια, το προσπερνάμε και έχουμε μεταφρασμένες αναρτήσεις. Με αυτό τον τρόπο η απήχηση του blog μας αυξάνει.

Unfortunately, blogger.com doesnot offer the ability to have multilingual posts. That barrier is oversteped with little effort, and now we can have what we need. In that way the audience of our blog grows.

Μια μικρή ματιά σε ιστότοπους, όπως αυτό της Transifex, νομίζω πως μπορεί να σας πείσει για την αναγκαιότητα της μετάφρασης.

Just a small search arround, to web pages and companies like Transifex, can show you the necessity of translation, I believe.

Ηλίας Χρυσοχέρης

Elias Chrysocheris