Τετάρτη 3 Ιουνίου 2015

Ενσωμάτωση delegate functions στην Μ2000

Πολύ καλή αναθεώρηση της Μ2000. προστέθηκαν ωραία πράγματα

Παρακάτω είναι η δική μου έκδοση ενός παραδείγματος που υπάρχει σε C# (δείτε εδώ). Κατάφερα να αυξήσω τις δυνατότητες των ομάδων της Μ2000, ώστε να μπορούν να δέχονται μια ομάδα από την οποία καλούν μια συγκεκριμένη συνάρτηση και περνούν μια αναφορά της ομάδας ώστε αυτή η συνάρτηση να κάνει κάποιες αλλαγές ή πράξεις γενικότερα. Μπορούμε να δίνουμε άλλες ομάδες με ίδια συνάρτηση μόνο στο όνομα...αλλά όχι στη λειτουργικότητα. Αυτές οι συναρτήσεις λέγονται delegates.

Το πρόγραμμα το έχω γράψει στα αγγλικά (η Μ2000 τρέχει στα ελληνικά και στα αγγλικά, έχει διπλό λεξιλόγιο). Χρησιμοποιεί τέσσερις ομάδες: PrintTitle, PriceTotaller, bookDB, SecondbookDB. Τα δυο τελευταία τα φτιάχνουμε με το booktype$, ένα αλφαριθμητικό, δηλαδή δίνουμε έμμεσα ορισμό.

Στη Μ2000 δεν υπάρχουν αντικείμενα, αλλά ομάδες Μια ομάδα μπορεί να περάσει με αναφορά (και ό,τι ορίζουμε τοπικό δεν θα είναι προσβάσιμο μέσω της αναφοράς). Αυτό γίνονταν και πριν, αλλά δεν γίνονταν μια μέθοδος ή μια συνάρτηση μιας ομάδας να περάσει τον εαυτό της με αναφορά. Επιπλέον έγιναν πολλές διορθώσεις και προστέθηκε η εντολή φόρμα$() ή format$() δείτε την παρακάτω, και η πολύ καλή "Για"με όνομα ομάδας μόνο. Την χρησιμοποιώ εδώ κατά κόρο. π.χ.
αντί να γράψω αυτό
      call SecondbookDB.ProcessPaperbackBooks &PriceTotaller
γράφω αυτό, και όπου υπάρχει μια τελεία προστίθεται το SecondbookDB
for SecondbookDB {
      call .ProcessPaperbackBooks &PriceTotaller
}
Μπορούμε να έχουμε φωλιασμένα Για και στο εσωτερικό, έστω δεύτερο θα έχουμε αναφορά με διπλή τελεία, στο τρίτο εσωτερικό με τρεις...
Δείτε εδώ η p(i) έχει δυο τελείες, και αναφέρεται στο Anybook, ενώ η total έχει μια και αναφέρεται στο τρέχον (το αυτό ή this στα αγγλικά).
   function processBook { read &AnyBook, i : for this {.items++ : for Anybook {.total+=..p(i)  } }}



\\ Παράδειγμα με delegate functions
booktype$={
      local countme=0
      dim t$(1), a$(1), p(1), pb(1)
      function AddBook {
            for this {
                  newdim =.countme+1
                  dim .t$(newdim), .a$(newdim), .p(newdim), .pb(newdim)      
                  read .t$(.countme), .a$(.countme), .p(.countme), .pb(.countme)
                  .countme++
            }
      }
      module ProcessPaperbackBooks {
            read &ProcessBookDelegate
                  for this {
                        if .countme<1 then exit
                        for i=0 to .countme-1 {
                              if .pb(i) then call ProcessBookDelegate.processBook(&this, i)
                        }
                  }
      }
}
group PrintTitle {
      function processBook { read &AnyBook, i : Report format$("    {0}", AnyBook.t$(i) )}
}
group PriceTotaller {
      local items, total
      function processBook { read &AnyBook, i : for this {.items++ : for Anybook {.total+=..p(i) } }}
      \\  look the <= operator, if we use = then we define local variables. Items and total are like global but for group only
      module zero { for this { .total<=0 : .items<=0 } }
      function AveragePrice { for this {if .items>0 then =.total/.items }}
}
group bookDB type booktype$
report "First Book DB"
for bookDB {
      call .AddBook("The C Programming Language", "Brian W. Kernighan and Dennis M. Ritchie", 19.95, true)
      call .AddBook("The Unicode Standard 2.0", "The Unicode Consortium", 39.95, true)
      call .AddBook("The MS-DOS Encyclopedia", "Ray Duncan", 129.95, false)
      call .AddBook("Dogbert's Clues for the Clueless", "Scott Adams", 12.00, true)
      call .ProcessPaperbackBooks &PriceTotaller
      report  "Average Paperback Book Price: $" + str$(PriceTotaller.AveragePrice(),"#.##")
      call .ProcessPaperbackBooks &PrintTitle
}
report "Second Book DB"    \\report prints text  proportionally with justification
PriceTotaller.zero
group SecondbookDB type booktype$
for SecondbookDB {
      call .AddBook("Any Big Big and Big Tilte", "Any Author", 3.45, true)
      call .ProcessPaperbackBooks &PriceTotaller
      report  "Average Paperback Book Price: $" + str$(PriceTotaller.AveragePrice(),"#.##")
      call .ProcessPaperbackBooks &PrintTitle
}

Αυτή είναι η έξοδος!



Το παραπάνω τρέχει ως έχει και στην Έκδοση 8, αλλά τρέχει και έτσι! (με την εντολή Class ή Κλάση)


class booktype {
      local countme=0
      dim t$(), a$(), p(), pb()
      module AddBook {
                  newdim =.countme+1
                  dim .t$(newdim), .a$(newdim), .p(newdim), .pb(newdim)
                  read .t$(.countme), .a$(.countme), .p(.countme), .pb(.countme)
                  .countme++
      }
      module ProcessPaperbackBooks {
            read &AnyFunction()
            if .countme<1 then exit
            for i=0 to .countme-1 {
                  if .pb(i) then call AnyFunction(&this, i)
            }
      }
}
function PrintTitle {
      read &AnyBook, i : Report format$("    {0}", AnyBook.t$(i) )
}
class PriceTotaller {
      local items, total
      function processBook { read &AnyBook, i : for this {.items++ : for Anybook {.total+=..p(i) } }}
      module zero { .total<=0 : .items<=0 }
      function AveragePrice { if .items>0 then =.total/.items }
}
bookDB=booktype()
PriceTotaller1=PriceTotaller()
report "First Book DB"
for bookDB {
      .AddBook"The C Programming Language",  "Brian W. Kernighan and Dennis M. Ritchie", 19.95, true
      .AddBook"The Unicode Standard 2.0",  "The Unicode Consortium", 39.95, true
      .AddBook"The MS-DOS Encyclopedia", "Ray Duncan", 129.95, false
      .AddBook"Dogbert's Clues for the Clueless", "Scott Adams", 12.00, true
      .ProcessPaperbackBooks &PriceTotaller1.processBook()
      report  "Average Paperback Book Price: $" + str$(PriceTotaller1.AveragePrice(),"#.##")
      .ProcessPaperbackBooks &PrintTitle()
}
report "Second Book DB"   
PriceTotaller2=PriceTotaller()
SecondbookDB=booktype()
for SecondbookDB {
      .AddBook "Any Big Big and Big Tilte",  "Any Author", 3.45, true
      .ProcessPaperbackBooks &PriceTotaller2.processBook()
      report  "Average Paperback Book Price: $" + str$(PriceTotaller2.AveragePrice(),"#.##")
      .ProcessPaperbackBooks &PrintTitle()
}

Κυριακή 24 Μαΐου 2015

Επιστροφή στο Blogging

Έχουν περάσει μήνες από το Νοέμβριο του 2014, από τότε που έγραψα στον ιστότοπο εδώ.

Στο διάστημα αυτό ασχολήθηκα με την γλώσσα Μ2000, όπου το Γενάρη του 2015 ανέβασα την έκδοση 7 αναθεώρηση 16. Μάλιστα βρήκα και μαθητές που ήθελαν να δουν τι είναι προγραμματισμός, να κάνουν κάτι. Θα ανεβάσω άλλη ανάρτηση για την εκπαίδευση.

Τους τελευταίους μήνες ψάχνω για γλώσσες προγραμματισμού να εντάξω στην εκπαιδευτική διαδικασία. Δεν είναι μόνο η γλώσσα το κριτήριο επιλογής αλλά και το περιβάλλον ανάπτυξης καθώς και οι δυνατότητες που προσφέρονται για ανάπτυξη εφαρμογών σε διάφορα λειτουργικά και με χρήση διεπαφής με διαλόγους-παράθυρα. Κατέληξα σε δυο γλώσσες στην python και την java. Ξεκίνησα από την java αλλά θέλησα να την διαβάσω κανονικά (να την ξαναδιαβάσω για την ακρίβεια), δηλαδή να την μάθω!

Η ανακάλυψη λοιπόν της περιόδου ήταν το πρόγραμμα της SoloLearn για τη java με βίντεο και ασκήσεις. Βλέπεις τα βίντεο και απαντάς στις ερωτήσεις είτε γράφεις κάτι είτε απλά επιλέγεις είτε αλλάζεις τη διάταξη των εντολών!
Δείτε εδώ το πρόγραμμα  (εγώ το κατέβασα σε android ταμπλε) Java Tutorial
Μετά την επιτυχή εκπαίδευση, "ζεστάθηκα" και άρχισα να φτιάχνω την Μ2000 στην αναθεώρηση 17. Δεν έχει τελειώσει ακόμα αλλά μπορώ να γράψω λίγα πράγματα γι΄αυτήν:

Μ2000 Έκδοση 7, Αναθεώρηση 17 (ακόμα δεν έχει τελειώσει..)

1. Διόρθωσα ένα Bug στην συνάρτηση ΡΩΤΑ() ASK() η οποία ανοίγει ένα παράθυρο διαλόγου για να δείξει κάτι ή να δείξει κάτι και να πάρει μια τιμή. Όταν κάνουμε αλλαγή μεγέθους τότε εμφανίζεται το πεδίο εισαγωγής ενώ δεν το θέλουμε (όταν δεν ρωτάμε κάτι δηλαδή), και τώρα διορθώθηκε.

2. Ξανακοίταξα το θέμα της βάσης δεδομένων. Πρόσθεσα τις εντολές DB.PROVIDER ή ΒΑΣΗ.ΠΑΡΟΧΟΣ και DB.USER ή ΒΑΣΗ.ΧΡΗΣΤΗΣ  και επιπλέον σε όλες τις εντολές μπορεί αντί για όνομα βάσης να δοθεί ένα συνθηματικό όνομα με παρενθέσεις ώστε να μην χρησιμοποιείται ως όνομα αρχείου αλλά ως όνομα σύνδεσης. Με αυτό το τρόπο μπόρεσα να αλλάξω το σύστημα και να κάνω τη Μ2000 να συνδέεται με βάσεις ODBC και άλλες που υποστηρίζει το σύστημα και απαιτούν όνομα χρήστη και κωδικό.

Μπορούμε για παράδειγμα να χρησιμοποιήσουμε αυτό: 

ΒΑΣΗ.ΠΑΡΟΧΟΣ  "Microsoft.ACE.OLEDB.12.0","Jet OLEDB"
 
 για όνομα βάσης θα βάλουμε κατάληξη .accdb  και έτσι έχουμε μια βάση δεδομένων σε Access 2007 και άνω (ανάλογα τι υπάρχει στον υπολογιστή).

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

db.provider "dsn=testme;Uid=toor;Pwd=alfa;", "ODBC","encryptionpass"  
basename$ ="(anyname)"  
Retrieve basename$,"UNI", 1, "key","Greek"

3. Ανάπτυξη εντολών και συναρτήσεων για τον Σωρό (Stack).
Η γλώσσα χρησιμοποιεί ένα σωρό τιμών (αλφαριθμητικών και αριθμών) για πολλούς λόγους, κύρια όμως για προσωρινή αποθήκευση και πέρασμα τιμών. Παλιά ο σωρός ήταν απλή κατασκευή, ήταν ένα αλφαριθμητικό, ενώ στις τελευταίες εκδόσεις (από την έξι) είναι συλλογή αντικειμένων. Έτσι κάθε στοιχείο στο σωρό είναι εσωτερικά ένα συνδεδεμένο αντικείμενο. Δεν θα αναπτύξω εδώ όλη τη λειτουργικότητα του σωρού - καθώς και πότε υπάρχουν άλλοι ξεχωριστοί σωροί. Αυτό που έχει σημασία είναι ότι έφτιαξα έναν τρόπο να έχω παραμέτρους σε ένα τμήμα (η διαδικασία στην Μ2000 λέγεται τμήμα), χωρίς όνομα. Αντί για όνομα οι παράμετροι έχουν θέσεις στο σωρό.
Από την αναθεώρηση 17 μπορούμε να διαβάσουμε την τιμή από οποιαδήποτε θέση στο σωρό χωρίς να την "σηκώσουμε". Μέχρι την αναθεώρηση 16 μπορούσαμε να κάνουμε αυτό:
ΒΑΛΕ 1,2,3,4,5 ' το 5 είναι στην κορυφή του σωρού
ΔΙΑΒΑΣΕ Α,Β
ΤΥΠΩΣΕ Α, Β
    5   4
ο σωρός έχει τώρα κορυφή το 3 και είναι έτσι 3 2 1

τώρα μπορούμε να παραλείψουμε τη ΔΙΑΒΑΣΕ
ΒΑΛΕ 1,2,3,4,5
ΤΥΠΩΣΕ ΣΩΡΟΥΤΙΜΗ(), ΣΩΡΟΥΤΙΜΗ(2)
    5    4
ο σωρός έχει κορυφή το 5 και είναι έτσι 5 4 3 2 1
Δηλαδή διαβάζουμε τιμές χωρίς να τις σηκώνουμε από το σωρό!

η συνάρτηση ΣΩΡΟΥΤΙΜΗ() ισοδυναμή με την ΣΩΡΟΥΤΙΜΗ(1)

Υπάρχει και η αντίστοιχη για αλφαριθμητικά (γράμματα λέγονται στην Μ2000)

ΒΑΛΕ 1, "γεια"
ΤΥΠΩΣΕ ΣΩΡΟΥΤΙΜΗ$(), ΣΩΡΟΥΤΙΜΗ(2)
Για να πετάξουμε τις τιμές (έστω και τις δυο από τις πέντε) χρησιμοποιούμε την ΠΕΤΑ (υπήρχε αλλά εμπλουτίστηκε με τον έλεγχο λαθών, δηλαδή να βγάζει λάθος όταν δώσουμε αρνητικό αριθμό ή μεγαλύτερο του αριθμού των στοιχείων του σωρού...)
ΠΕΤΑ 2

Επιπλέον μπήκαν τρεις ακόμα εντολές:
ΦΕΡΕ SHIFT, ΦΕΡΕΠΙΣΩ SHIFTBACK, ΠΑΝΩ OVER

ΒΑΛΕ 1,2,3,4,5
ΣΩΡΟΣ
 5 4 3 2 1
ΦΕΡΕ 4 ' φέρνει στη κορυφή το στοιχείο στην 4η θέση
ΣΩΡΟΣ 2 5 4 3 1
ΦΕΡΕΠΙΣΩ 4 ' πάει τη κορυφή στη 4η θέση
ΣΩΡΟΣ
5 4 3 2 1
ΠΑΝΩ 2 ' φέρνει στη κορυφή ένα αντίγραφο του στοιχείου της 2ης θέσης
ΣΩΡΟΣ
4 5 4 3 2 1

Για να αλλάξουμε τιμή, έστω στη θέση τρία θα κάνουμε:
ΦΕΡΕ 3
ΒΑΛΕ ΑΡΙΘΜΟΣ+100
ΦΕΡΕΠΙΣΩ 3
ΣΩΡΟΣ
 5 104 3 2 1

Μια ιδιαιτερότητα της ΠΑΝΩ που δεν φαίνεται άμεσα είναι ότι όταν φτιάχνει αντίγραφα...αντιγράφει μόνο αναφορές στο αντικείμενο.
Ο σωρός 15 18 21 έχει τέσσερα αντικείμενα:
το αντικείμενο του σωρού και από ένα για τις τιμές 15, 18 και 21
όταν κάνουμε ΠΑΝΩ 2 (OVER 2) τότε το  αντικείμενο με την τιμή 18 εμφανίζεται σε δυο θέσεις, στην 1 και στην 3 (η 2 έγινε με την προσθήκη νέας κορυφής 3). Όταν θέλουμε να αλλάξουμε τιμή στην ουσία το σύστημα δεν μας επιτρέπει να το κάνουμε άμεσα αλλά έμμεσα. Δηλαδή πρέπει να διαβάσουμε την κορυφή για να βγει η τιμή από το σωρό και μετά να φτιάξουμε μια νέα κορυφή με την νέα τιμή. Αυτό γίνεται σε μια γραμμή! ΒΑΛΕ ΑΡΙΘΜΟΣ+100. Η ΑΡΙΘΜΟΣ είναι εσωτερική μεταβλητή που διαβάζει την κορυφή και την πετάει ταυτόχρονα! Το αντίστοιχο για αλφαριθμητικά είναι η ΓΡΑΜΜΑ$, η οποία πετάει την κορυφή αμέσως αφού την διαβάσει. Ουσιαστικά και οι δύο πετάνε την αναφορά στο αντικείμενο. Αν δεν υπάρχει άλλη αναφορά στο αντικείμενο τότε το αντικείμενο διαγράφεται (είναι ο μηχανισμός αντικειμένων της VB6, σε αυτή τη γλώσσα έχει γραφτεί η Μ2000).

Θα μπορούσαμε δηλαδή να έχουμε έναν σωρό με 1000 θέσεις του αυτού αντικειμένου με τιμή "(άδειο)".  Η λέξη "(άδειο)" θα υπάρχει μια φορά ως αντικείμενο και 1000 φορές ως αναφορά στο αντικείμενο του σωρού!

Για να χειριστούμε το σωρό με την ΠΕΤΑ πρέπει να ξέρουμε πόσα αντικείμενα θα πετάξουμε (στην ουσία πόσες αναφορές σε αντικείμενα). Υπάρχει λοιπόν η ΜΕΓΕΘΟΣ.ΣΩΡΟΥ (STACK.SIZE) η οποία μπορεί να μπει σε μια μεταβλητή και μετά την επέκταση του σωρού να χρησιμοποιηθεί ως ΠΕΤΑ ΜΕΓΕΘΟΣ.ΣΩΡΟΥ-ΠΑΛΙΟ.ΜΕΓΕΘΟΣ και έτσι επιστρέφουμε στην προ της επέκτασης του σωρού (και υποτίθεται ότι τα στοιχεία τα διαβάσαμε με τις ΣΩΡΟΥΤΙΜΗ() και ΣΩΡΟΥΤΙΜΗ$().

Τέλος μπορούμε να γνωρίζουμε τι έχει ο σωρός σε τύπους με την ΦΑΚΕΛΟΣ$() ή ENVELOPE$() (αυτή υπήρχε) που δίνει ένα αλφαριθμητικό με N ή S (λατινικό N και S) στις θέσεις με κορυφή το πρώτο στο αλφαριθμητικό. Άλλος τρόπος είναι με τις ΕΙΝΑΡ (ISNUM) και ΕΙΝΓΡ (ISLET) (οι οποίες όμως φέρνουν λάθος αν είναι άδειος ο σωρός). Υπάρχει λοιπόν το ΑΔΕΙΟ (EMPTY), από την πρώτη έκδοση μάλιστα, για να ελέγχουμε αν είναι άδειος ο σωρός ή ελέγχουμε το ΜΕΓΕΘΟΣ.ΣΩΡΟΥ.

(Η M2000 έχει διπλό σετ εντολών, στα ελληνικά και στα αγγλικά).




Δευτέρα 17 Νοεμβρίου 2014

Η επέκταση της Quick Sort

Quick Sort extended
ή ελληνικά Μέθοδος ταξινόμησης Quick Sort με μια παραλλαγή δική μου!

Δημοσιεύτηκε εδώ: http://www.vbforums.com/showthread.php?781043-VB6-Dual-Pivot-QuickSort

Η ταξινόμηση τύπου Quick Sort είναι πολύ γρήγορη αλλά έχει μερικά μελανά σημεία. Μπορεί να γίνει πολύ χρονοβόρα αν υπάρχουν ορισμένες συνθήκες. Όπως αν έχουμε εναλλαγή 1 και 0 σε έναν πίνακα, ή αν έχουμε για μεγάλη έκταση μια αντιγραφή από το ίδιο στοιχείο (σταθερή τιμή).

Η πρότασή μου περιλαμβάνει μια προσθήκη στο κώδικα της ταξινόμησης Quick Sort, όπου κάποιες φορές την κάνει πιο γρήγορη. Σε κάθε περίπτωση το πρόβλημα των εναλλαγών 1 και 0 καθώς και των σταθερών τιμών το ξεπερνάει σε ελάχιστο χρόνο.

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

Μια ενδιάμεση περίπτωση είναι να βρει αρκετά στοιχεία όμοια στην αρχή μόνο. Τότε κοιτάει αν η θέση αυτού του μοναδικού (για την ώρα) στοιχείου πρέπει να αλλαχτεί με το πρώτο από τα όμοια και αν ναι την αλλάζει, και συνεχίζει τον κανονικό αλγόριθμο χωρίς το πρώτο κλάδο του, την εύρεση του πρώτου μεγαλύτερου, μετά τον πρώτο στη λίστα. Έτσι στην ουσία αντί να βρει το πρώτο μεγαλύτερο και να αφήσει μια σειρά όμοια μετά από αυτό...τα περνάει στα μικρότερα. Και αυτή είναι η περίπτωση που το κάνει ταχύτερο από την βασική Quick Sort.

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

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

αν παραστήσουμε τα όμοια με 1 και θεωρήσουμε αυτή την λίστα
11111101111001001
τότε  θα πάρει το σύστημα την μεσαία τιμή (εδώ 1) θα δει ότι είναι όμοια
και θα την παρατήσει! Θα ξεκινήσει από την αρχή+1 και θα κοιτάξει που σταματούν τα όμοια! θα βρει το 0 και θα το αλλάξει..
01111111111111001
οπότε το 0 είναι σε σωστή θέση και συνεχίζει την κανονική quick sort με μεσαία τιμή το 1 στη θέση 7.
Ας το δούμε αναλύτικά:
ελέχγει από το 17 (το τέλος) αν έχει τιμή μεγαλύτερη από το 1, δεν έχει και πάει για αλλαγή (τζούφια) και αλλάζει τους δείκτες 8 και 16.
τώρα ελέγχει αν στο 8 υπάρχει μικρότερη τιμή...δεν υπάρχει
πάμε για το 16 αν υπάρχει μεγαλύτερη τιμή...δεν υπάρχει...και αλλάζει τιμές
01111110111111011 και έχει δείκτες 9 και 15
στο 9 δεν βρίσκει μικρότερη τιμή...στο δεκαπέντε δεν βρίσκει μεγαλύτερη
κάνει αλλαγή
01111110011111111 και έχει δείκτες 10 και 14
τώρα κάνει τζούφιες αλλαγές ...και αλλάζει δείκτες 11 και 13, 12 και 12 και 13 και 11...
τώρα βγαίνουμε από την επανάληψη και πάμε σε δυο κλήσεις τις ίδιας ρουτίνας (αναδρομική διαδικασία), όπου οι λίστες είναι
1 εως 11 και 13 εως 17 (το 12 είναι στην θέση του...)
01111110011 και 111111
η δεύτερη λίστα με τη προσθήκη που έχω βάλει με μια εξέταση ότι δεν υπάρχει άλλη τιμή από 1 τερματίζει (δεν κάνει καθόλου αλλαγές).
Η πρώτη λίστα δίνει μεσαίο  1 στην θέση 6 είναι διαφορετικός από το στοιχείο στη θέση 0 οπότε πάμε σε κανονική εκτέλεση της quicksort με δείκτες 1 και 11
βρίσκει ότι στην 1 έχει μικρότερη τιμη και αυξάνει το δείκτη σε 2
τώρα κοιτάει στο 11 δεν βρίσκει μεγαλύτερη τιμή και πάει σε τζούφια αλλαγή...και δείκτες 3 και 10...ομοίως και πάμε σε 4 και 9..εδώ δεν έχουμ τζούφια αλλαγή:
01101110111  και δείκτες 5 και 8 πάλι αλλαγή
01100111111 και 6 και 7...τζούφια αλλαγή και 7 και 6 (7>6 βγαίνουμε από την επανάληψη).
πάμε πάλι σε δυο λίστες
την 1 εως 6 και την 7 εως 11
011001 και 11111 η δεύτερη με την προσθήκη κάνει απλά έναν έλεγχο και τερματίζει χωρίς καθόλους αλλαγές.
η δεύτερη  πέρνει μεσαίο το 3 δηλαδή το 1 και φτιάχνει δείκτες 1 και 6
στο 1 έχει μικρότερο και το αφήνει πάμε σε 2 και 6 και κάνουμε τζούφια αλλαγή...και πάμε σε 3 και 5...όπου
010011 και πάμε στα 4 και 4 το 4 γίνεται 5 (αφου το 0<1) και δεν γίνεται
καμία αλλαγή και βγαίνουμε σε δυο λίστες 1 - 4 και 5-6
0100 και 11 η δεύτερη λιστα είναι η περίπτωση που εξετάζει η επέκταση που έχω βάλει και βγαίνει αμέσως από την ρουτίνα.
τώρα βρίσκει το μεσαίο το 2 και παίρνει το 1 και φτιάχνει τους δείκτες 1 και 4
ο δείκτης 1 γίνεται 2 και κάνει την πρώτη αλλαγή μεταξύ 2 και 4
0001 και αλλάζει τους δείκτες σε 3 και 3...και κάνει μια ζούφια αλλαγή και 4 και 2 οι δείκτες
βγάζει μόνο μια λίστα την 00 (το τελευταίο 0 και το 1 τα θεωρεί στη θέση τους ο αλγόριθμος και είναι) και καλεί πάλι την ρουτίναι, η οποία βάση της προσθήκης την τερματίζει αμέσως..

(αν δεν υπήρχε η προσθήκη θα έβγαζε το μεσαίο, στα δυο στοιχεία είναι το πρώτο, το 0, και θα έβγαζε δυο δείκτες 1 και 2, θα έκανε μια τζούφια αλλαγή, θα πήγαινε τους δείκτες στο 2 και 1 και δεν θα καλούσε άλλη λίστα).

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

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


Public Sub NaiveQuickSortExtended(Arr() As Long, ByVal LB As Long, ByVal UB As Long)
Dim M1 As Long, M2 As Long
Dim Piv As Long, Tmp As Long '<- adjust types here, when switching to something different than Long
     If UB - LB = 1 Then
     M1 = LB
      If Arr(M1) > Arr(UB) Then Tmp = Arr(M1): Arr(M1) = Arr(UB): Arr(UB) = Tmp
      Exit Sub
     Else
       M1 = (LB + UB) \ 2
             If Arr(M1) = Arr(LB) Then
                M2 = UB - 1
                M1 = LB
                Do
                    M1 = M1 + 1
                    If M1 > M2 Then
                        If Arr(UB) < Arr(LB) Then Tmp = Arr(LB): Arr(LB) = Arr(UB): Arr(UB) = Tmp
                        Exit Sub
                    End If
                Loop Until Arr(M1) <> Arr(LB)
                Piv = Arr(M1)
                If M1 > LB Then If Arr(LB) > Piv Then Arr(M1) = Arr(LB): Arr(LB) = Piv: Piv = Arr(M1)
            Else
                Piv = Arr(M1)
                M1 = LB
                Do While (Arr(M1) < Piv): M1 = M1 + 1: Loop
            End If
    End If
    M2 = UB
    Do
      Do While (Arr(M2) > Piv): M2 = M2 - 1: Loop
      If M1 <= M2 Then
        Tmp = Arr(M1): Arr(M1) = Arr(M2): Arr(M2) = Tmp 'swap
        M1 = M1 + 1
        M2 = M2 - 1
      End If
      If M1 > M2 Then Exit Do
      Do While (Arr(M1) < Piv): M1 = M1 + 1: Loop
    Loop
    If LB < M2 Then NaiveQuickSortExtended Arr, LB, M2
    If M1 < UB Then NaiveQuickSortExtended Arr, M1, UB
End Sub








Σάββατο 18 Οκτωβρίου 2014

Nice TextBoxes

Επιτέλους μετά από προσπάθεια μερικών ημερών κατάφερα να φτιάξω μια συλλογή στοιχείων ελέγχου, τα οποία μπορούν να χρησιμοποιηθούν στην Visual Basic 6.

Δύο πράγματα τα κάνουν ξεχωριστά. Ένα είναι ότι δεν απαιτούν βιβλιοθήκες και δεν αλλάζουν ανάλογα με το λειτουργικό (όπως όταν χρησιμοποιούμε τα στάνταρ στοιχεία ελέγχου των Windows). Το δεύτερο είναι η αλλαγή σχεδίασης, όπου όλα τα στοιχεία είναι ένα βασικό  και μερικές κλάσεις που το τροποποιούν παρέχοντάς μας ιδιότητες και γεγονότα για να τα χειριστούμε.
Πέρα από αυτά επιπλέον σχεδιαστικά καλούδια είναι η δυνατότητα χρήσης Unicode γραμματοσειρών χωρίς όμως δυνατότητα γραφής από δεξιά προς αριστερά. Μπορούμε όμως να εμφανίσουμε κυριλλικό αλφάβητο με ευρωπαϊκό και ελληνικό. Επίσης το υπόστρωμα, το στοιχείο δηλαδή που πράγματι εμφανίζεται, το glist, έχει την δυνατότητα να χειρίζεται την απόσταση των στοιχείων του, ή αλλιώς το line spacing. Είναι βασικό αυτό για να φαίνονται περισσότερο όμορφα τα στοιχεία, και τα κάνει ξεχωριστά. Τα αντίστοιχα της Microsoft...δεν έχουν απόσταση γραμμής, αντί αυτού ορισμένα έχουν ύψος γραμμής αλλά αυτό δεν είναι το ίδιο, η απόσταση γραμμής εδώ είναι το άνω και κάτω περιθώριο κάθε γραμμής -  TextBlock Class .NET Framework 4.5

Αποκορύφωμα των κλάσεων είναι η TextViewer κλάση που διαχειρίζεται ένα στοιχείο glist (αυτό χωρίς χρήση κλάσης είναι ένα στοιχείο που μοιάζει με το listbox), και με την χρήση μια κλάσης MyDOC (αυτή κρατάει κείμενο με παραγράφους σε μια διπλή συνδεδεμένη λίστα), προβάλει και δίνει για επεξεργασία κείμενο. Παράλληλα λειτουργούν πλήκτρα όπως Ctl X, Ctrl C & Ctrl V για αποκοπή, αντιγραφή και επικόλληση, αλλά και τα Ctrl A, επιλογή όλων, shift Ctrl A, καμία επιλογή, Ctrl Z αναίρεση (Undo), και Ctrl Y αναίρεση αναίρεσης (Redo) - μάλιστα υποστηρίζει πολλαπλά undo/redo. Επίσης δουλεύει το drag and drop,  ή ελληνικά οι ενέργειες σύρε και άφησε.

Η συλλογή των στοιχείων περιλαμβάνει διαμορφώσεις του glist ως button όπου η ενεργοποίηση γίνεται με διπλό πάτημα ή με σύρσιμο δεξιά, το checkbox όπου μια κουκκίδα αριστερά δηλώνει την  θέση διακόπτη (ανοικτός - κλειστός), το infobox που δηλώνει απλά μια ένδειξη αλλά μπορεί να αλλάξει σε εισαγωγή κειμένου για κάποια ρύθμιση. Άλλες διαμορφώσεις είναι το spin box όπου δέχεται αριθμητική τιμή και η οποία αλλάζει η με τη μπάρα ολίσθησης και τα βελάκια του πληκτρολογίου, ή αν θέλουμε με απευθείας εγγραφή τιμής. Στο παράδειγμα φαίνεται μια λίστα που τροφοδοτεί τιμές το spin box. Τέλος ένα επίσης ωραίο στοιχείο είναι το combobox όπου δυο λίστες glist συνδέονται, η μία ως ένα textbox μιας γραμμής με την προσθήκη ενός χειριστή αριστερά ο οποίος ανοίγει μια δεύτερη λίστα, μια λίστα τιμών. Μπορούμε να γράψουμε στο πρώτο textbox και αυτόματα θα εμφανίζεται το υπόλοιπο της λέξης από όποια λέξη βρεθεί στη δεύτερη λίστα. Αυτό λέγεται αυτόματη συμπλήρωση.

Όλα τα στοιχεία ελέγχου μπορούμε να τα χειριστούμε μόνο με πληκτρολόγιο (εκτός του drag & drop που απαιτεί ποντίκι εξ ορισμού). Έχει δοκιμαστεί το παράδειγμα σε Linux και Wine. Αν και στην έκδοση που έχω το Wine ενώ δίνει ελληνικά δεν αφήνει να περάσουν γράμματα με τόνο απευθείας στις φόρμες (πιστεύω σε νεότερη έκδοση του Wine, θα το έχουν λύσει το θέμα).


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


Το στοιχεί ελέγχου change wrapping αλλάζει την αναδίπλωση γραμμής, και το Show Paragraph δείχνει ή κρύβει το σημάδι παραγράφου (φαίνεται στην εικόνα). Οι μπάρες ολίσθησης στις λίστες (και στο TextViewer) φαίνονται όταν πάμε στην άκρη το ποντίκι ή όταν κάνουμε ολίσθηση με σπρώξιμο - με πατημένο το αριστερό πλήκτρο κουνάμε το ποντίκι και μετακινούμε τη λίστα, με αυξανόμενη ταχύτητα ανάλογα με την κίνηση που κάνουμε - και αυτό δεν υπάρχει στα στάνταρ στοιχεία ελέγχου).



Εδώ υπάρχει ο κώδικας (δείτε στο τέλος την τελική έκδοση) Δημοσιευμένος Κώδικας


2022 Στο περιβάλλον της Μ2000, τα στοιχεία ελέγχου έχουν επεκταθεί σε δυνατότητες. Έχει μπει και η RTL (right to left) γραφή προσαρμοσμένη να λειτουργεί και τμηματικά, δηλαδή να έχουμε κώδικα της Μ2000 σε LTR με αλφαριθμητικά σε RTL, σε συνδυασμό με πληροφορίες χρώματος (το αλφαριθμητικό έχει διαφορετικό χρώμα, οπότε εκεί εφαρμόζεται χωριστά η RTL γραφή).
Υπάρχει μια παραλλαγή (παλαιότερη αυτή της Μ2000) όπου μπορούν να επαναπροσδιοριστούν οι χαρακτήρες για ασιατικές γλώσσες. Ίσως μπει και στη Μ2000.

Δευτέρα 13 Οκτωβρίου 2014

Βασικές γνώσεις για τα Ubuntu Studio #1

Βασικές γνώσεις για τα Ubuntu Studio

Τα δυο πράγματα που πρέπει να μην ξεχάσουμε και έχουμε εμείς ορίσει είναι  τα Όνομα χρήστη και κωδικός. Για να ανοίγει κανείς τον υπολογιστή δεν είναι απαραίτητα. Όμως όποτε υπάρχει λόγος να αλλάξει το σύστημα μας ζητείται το οκ για την πρόσβαση και αυτό δίνεται με την επίδοση του κωδικού χρήστη.

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

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

Η επιλογή έκδοσης είναι βασική, γιατί οι μονές εκδόσεις είναι ασταθείς άρα θέλουμε ή πρέπει να κάνουμε εγκατάσταση έκδοσης με ζυγό νούμερο. Αυτές οι εκδόσεις έχουν μακροχρόνια συντήρηση, δηλαδή αναβαθμίσεις και τροποποιήσεις. Όλη η διαδικασία αναβαθμίσεων γίνεται αυτόματα, και για όλο το λογισμικό που έχουμε, όχι μόνο για το λειτουργικό αλλά και για τα παρεχόμενα προγράμματα (κάτι για το οποίο δεν υπάρχει στα Windows).

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

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

Παρακάτω γράφω μια αναφορά για το τι μου συνέβη στα πρώτα βήματα στο Ubuntu (όπως ακριβώς το έγραψα):

Ευτυχώς θυμήθηκα ότι οι εφαρμογές έχουν pid (μάλλον program id) και πως υπάρχει εντολή που τις κλείνει από την κονσόλα.
Το πρόβλημα είχε ως εξής. Ξεκίνησα μια εφαρμογή με τρισδιάστατα γραφικά και ενώ άκουγα ήχο δεν έβλεπα τίποτα και επιπλέον...δεν μπορούσα να αλλάξω επιφάνεια εργασίας! Τελικά μπαίνω στην κονσόλα 1 με ctrl+alt+1 δίνω όνομα χρήστη και κωδικό και αρχίζω να ψάχνω...γράφω help...διαβάζω την man την εντολή που δίνει πληροφορίες για εντολές γράφω μια με την λέξη shutdown μου δίνει μερικές απαντήσεις κύρια όμως να χρησιμοποιήσω το -κ μετά το man για να ψάξει να βρει αλλού...Τελικά έβαλα με το pid και βρήκα την top ναι με τρια γράμματα top ξεκινάει μια εφαρμογή που δείχνει όλες τις εφαρμογές με όνομα και pid. Με h δίνει βοήθεια και με k κάνει kill δηλαδή στέλνει μήνυμα να τερματίσει μια εφαρμογή αφού όμως δώσουμε τον αριθμό της. Βλέπω ότι η εφαρμογή που είχα ανοίξει είχε δυο συνεχόμενα pid. Το παλιό, μικρό νούμερο, ήταν η φόρμα επιλογής που έτρεξε το άλλο, που μαύρισε την οθόνη. Με το που έφυγε κάνω έναν έλεγχο...πατάω alt-ctrl-7 και γυρνάω στο γραφικό περιβάλλον. Εντάξει είχε φύγει...
Κλείνω την “αδελφή” φόρμα, πάω στο κέντρο λογισμικού και καλώ την απεγκατάσταση του προγράμματος. Μετά γυρνάω με alt+ctrl+1 στην κονσόλα και πατάω το q για να τερματίσει το top και γράφω logout για να γυρίσει η κονσόλα στην αρχική της θέση, στην αναμονή ονόματος και κωδικού..για νέα συνεδρία. Γυρίζω στο γραφικό περιβάλλον. 

Με αυτόν τον τρόπο λοιπόν ξέφυγα από μια περίπτωση που σε windows απλά θα είχα πατήσει reset...με ότι ζημιά θα είχε προκαλέσει (λόγω ανοικτών αρχείων). Εδώ η όποια ζημιά περιορίστηκε στο πρόγραμμα που έκλεισε από την εφαρμογή top.

Η κοσνόλα υποστηρίζεται από ένα κέλυφος, το πρόγραμμα δηλαδή που τρέχει πίσω από το ορατό πράγμα που λέμε κοσνόλα (ή τερματικό). Το κέλυφος λέγεται bash. Με μια αναζήτηση στο διαδίκτυο μπορούμε να βρούμε περισσότερες πληροφορίες. Μέσα από το γραφικό περιβάλλον μπορούμε να ανοίξουμε έναν εξομοιωτή τερματικού. Όμως μπορούμε να πάμε απ΄ευθειας με τα alt+crl + νούμερο από 1 μέχρι 6. Το 7 μας βγάζει στο γραφικό περιβάλλον. Όλα τα νούμερα μπορούν να τρέχουν προγράμματα σε διαφορετικό χρήστη. Να γιατί λέγεται multiuser το σύστημα.
Εδώ παραθέτω ένα κείμενο που είχα γράψει για την δική μου βοήθεια:

Χρήσιμες οδηγίες από το τερματικό


Προσοχή μικρά ή κεφαλαία γράμματα έχουν διαφορά στο Linux (άρα και στο Ubuntu)
Όταν θέλουμε σε ένα όνομα να συμπεριλάβουμε το διάστημα βάζουμε την \ πίσω από ένα διάστημα, έτσι από το κατάλογο ~ πάμε με το cd Επιφάνεια\ εργασίας στην Επιφάνεια εργασίας
Οι κατάλογοι χωρίζονται με / και όχι με \ όπως στα Windows
Η τελεία στην αρχή ενός ονόματος δηλώνει ότι είναι κρυφό! Οπουδήποτε αλλού είναι απλά ένας ακόμα χαρακτήρας. Τα αρχεία δεν συσχετίζονται με εφαρμογές με την κατάληξη π.χ. txt. Μπορεί όμως να βάλει κανείς μια “κατάληξη” και ο Διαχειριστής αρχείων μπορεί να μάθει τις καταλήξεις...(όμως αυτή η εργασία δεν είναι του λειτουργικού)
Γιατί λέμε ότι τα παρακάτω είναι οδηγίες και όχι εντολές; Επειδή οι εντολές απαιτούν έναν μεταφραστή, δηλαδή είναι ενσωματωμένες σε ένα πρόγραμμα μετάφρασης μαζί με τις διαδικασίες στις οποίες αναφέρονται..οι μεταφράσεις. Ορισμένες οδηγίες είναι εντολές του bash, και άλλες είναι προγράμματα, δηλαδή υπάρχουν έξω από το bash.
lsb_release -a
Εμφανίζει την έκδοση του λειτουργικού
exit
Έξοδος από τη συνεδρία (σε εξομοιωτή κλείνει τον εξομοιωτή)
dmesg
Μας δείχνει τις τελευταίες εντολές που εκτέλεσε το κέλυφος. (δείτε με παράμετρο -h τις διαμορφώσεις που δέχεται)
cd
Αλλαγή καταλόγου (Change Directory)
Προσοχή επειδή είναι πρόγραμμα δεν δέχεται κολλητά όπως στα Windows παραμέτρους
έτσι το CD.. δεν θα τρέξει!
cd -
Εναλλαγή μεταξύ δυο τελευταίων καταλόγων.
ls
Δείχνει τα περιεχόμενα ενός κατάλογου
ls -lh
Δείχνει τα περιεχόμενα με περισσότερες πληροφορίες
ls -aD
Δείχνει ότι το ls αλλά και τα κρυφά αρχεία (ξεκινούν με τελεία).
mv
Μετακίνηση αρχείων αλλά και μετανομασία!




Συνεχίζεται...



 



Δευτέρα 29 Σεπτεμβρίου 2014

Bash Bug

Το Σεπτέμβριο του 2014 βρέθηκε ένα λάθος στο κέλυφος εντολών του Linux αλλά και του OS Χ (Mac), όπου μπορεί να εκτελεστεί κώδικας χωρίς την θέληση του χρήστη.

Το γιατί υπήρχε αυτό το "άγνωστο" λάθος τόσο καιρό είναι ένας προβληματισμός που δεν έχει βρει τη λύση του. Οπωσδήποτε ο κώδικας του BASH, του κελύφους δηλαδή επεξεργασίας εντολών, δεν είναι ένας κρυφός κώδικας. Υπάρχει όμως ένας κανόνας στο Linux και την γλώσσα C και κατ' επέκταση της C++ που λέει ότι ποτέ δεν γράφουμε για το ίδιο πράγμα νέο κώδικα. Έτσι όλα τα προγράμματα κτίζονται από κομμάτια που βρίσκονται σε μια βιβλιοθήκη έτοιμων λύσεων.

Η κοινή χρήση λύσεων στο Linux και στο OS X έχει ως αποτέλεσμα να περνάει τα τυχόν σφάλματα αυτών σε νέα σύνθετα προγράμματα.

Ευτυχώς που ένα σύστημα ελέγχου και αποφάσεων ενεργοποιείται κάθε φορά που κάποιος δηλώνει ένα ζήτημα και στην περίπτωση του Bash Bug έγινε χωρίς να δηλωθεί πριν ετοιμαστεί η διόρθωση. Επίσης λοιπόν με τον ίδιο τρόπο που παρέμεινε σε όλους το ίδιο λάθος (bug), η κοινή χρήση βιβλιοθήκης ρουτινών, έχουμε και την θεραπεία. Αρκεί δηλαδή να μπει το διορθωμένο πρόγραμμα στην θέση του στη βιβλιοθήκη και όλα τα προγράμματα που το χρησιμοποιούν θα έχουν αναβαθμιστεί.

Σήμερα συζητάμε το θέμα, ενώ είχε λυθεί όταν πια δημοσιεύτηκε.

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

Οπότε τώρα ήρθε η ώρα να κατανοήσουμε τι σημαίνει έκδοση λογισμικού. Στα μεν Windows με την φιλοσοφία "αγοράζεις λειτουργικότητα"...το σύστημα διατηρεί για τον ίδιο σκοπό διάφορες εκδόσεις ενός λογισμικού, ενώ στο Linux επειδή η φιλοσοφία είναι "διαθέτεις τη λειτουργικότητα που χρειάζεσαι επιλέγοντας ελεύθερο λογισμικό" απλά διατηρείς "φρέσκες" τις βιβλιοθήκες και έχεις όλα τα προγράμματα αναβαθμισμένα. Στα linux δεν θα "επέμενε" ένα πρόγραμμα να χρησιμοποιήσει την παλιά ρουτίνα (βιβλιοθήκης) επειδή δεν είχε ανανεώσει την άδεια χρήσης ο παραγωγός αυτού του λογισμικού. Απαιτείται φυσικά απόλυτη συμβατότητα..και αυτή μπορεί να επιτευχθεί όταν το λογισμικό είναι ανοικτό, ο κώδικάς του.

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

Το Linux παραμένει πάντα ως το λειτουργικό χωρίς ιούς, και θα παραμένει επειδή στη φιλοσοφία του είναι ο αποκλεισμός εκτελέσιμων αρχείων από την ελεύθερη πρόσβαση στους φακέλους του υπολογιστή, ενώ διατηρείται η ελεύθερη χρήση ρουτινών..(ελεύθερα χρησιμοποιείς την βιβλιοθήκη αλλά δεν την αλλάζεις). Οι αλλαγές γίνονται από προγράμματα με προχωρημένα δικαιώματα. Ένας ιός δεν μπορεί να πάρει αυτά τα προχωρημένα δικαιώματα...χωρίς την συγκατάθεση του χρήστη (του υπερ-χρήστη στην ουσία του Administrator).

O Bash είναι η εφαρμογή που τρέχει εφαρμογές τόσο για τον χρήστη όσο και για τον υπερ-χρήστη, οπότε εκεί υπήρχε θέμα "προσβολής" του συστήματος, αν εκτελεστεί με δικαιώματα υπερ-χρήστη κάτι παρά τη θέλησή μας. Όμως θα έπρεπε πιο πριν να είχαμε κατεβάσει μια αναβάθμιση βιβλιοθήκης που εσωτερικά θα είχε προγραμματιστεί να "διαβάλλει" το σύστημα. Με το συνήθη τρόπο ενημέρωσης του συστήματος αυτό είναι αδύνατο να συμβεί. Οι άλλοι δύο τρόποι είναι: η ενημέρωση με εκτελέσιμο κώδικα και η ενημέρωση με πηγαίο κώδικα (που απαιτεί μεταγλώττιση σε εκτελέσιμο κώδικα). Ο πρώτος είναι ο επικίνδυνος, ενώ ο δεύτερος αν και φαινομενικά είναι ακίνδυνος, αποδείχθηκε όπως στον Bash ότι μπορούν να υπάρξουν "τρύπες"...που ενώ είναι εκεί...και ο κώδικας είναι ανοικτός...δεν είναι κατανοητές.

Το Bash Bug λοιπόν είναι ένα από τα λάθη που υπήρχαν για χρόνια και ήταν μη παρατηρήσιμα....Υπάρχουν άλλα; Ποιος ξέρεις...σίγουρα; Αν είναι σπάνιο να βρεθεί ένα τέτοιο σφάλμα, είναι περισσότερο σπάνιο αυτός που θα το βρει να θέλει να επωφεληθεί δημιουργώντας το χάος..





Τετάρτη 24 Σεπτεμβρίου 2014

Νέα στοιχεία ελέγχου - για φόρμες της VB6



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

Στην εικόνα παραπάνω είναι ένα στοιχείο ελέγχου σε διάφορες μορφές. Η πιο κοπιαστική μορφή είναι αυτή του επεξεργαστή κειμένου. Εδώ έχουμε έναν επεξεργαστή κειμένου χωρίς μίξη γραμματοσειρών και μεγεθών/τύπου χαρακτήρων, αν και μπορούμε να αλλάξουμε οποτεδήποτε αυτά για όλα μαζί. Αυτό που προσφέρει είναι ότι χρησιμοποιεί εμφάνιση UNICODE χαρακτήρων, αλλάζει την απόσταση γραμμών, αλλάζει όποτε θέλουμε την αναδίπλωση λέξεων, μπορούμε να αποκόψουμε ή αντιγράψουμε προς το πρόχειρο ή να επικολλήσουμε από το πρόχειρο, μπορούμε να μεταφέρουμε σε άλλο ίδιο ή ακόμα και στο Word το κείμενο με "σύρε και απέθεσε" ενέργεια (Drag & Drop). Υπάρχει μπάρα οριζόντιας ολίσθησης που εμφανίζεται όταν πάμε στην δεξιά πλευρά και όταν μετακινήσουμε τις γραμμές πάνω ή κάτω με ώθηση κρατώντας πατημένο το αριστερό πλήκτρο του ποντικού. Μπορεί να χειριστεί τεράστιο κείμενο και σε μια φόρμα που αλλάζει μέγεθος μπορεί να αλλάξει την αναδίπλωση λέξεων άμεσα χωρίς καθυστέρηση. Υποστηρίζει απλή αναίρεση (αν μεταφέρουμε τον κέρσορα και δεν έχουμε πατήσει κάποιο πλήκτρο τότε ισχύει η αναίρεση της προηγούμενης ενέργειας με ctrl z). Δεν μπορούμε να αναιρέσουμε την προσθήκη πάνω από μια παράγραφο (αυτό θέλει περισσότερο προγραμματισμό). Αντί αυτού μπορούμε να μαρκάρουμε το κείμενο που θέλουμε να αφαιρέσουμε και να το κάνουμε και άμεσα μπορούμε να το επαναφέρουμε...

Επιπλέον υπάρχουν στοιχεία ελέγχου όπως, το Check Me, ή ελληνικά το Επίλεξέ Με όπου η επιλογή ή η μη επιλογή εμφανίζεται ως κουκκίδα τετράγωνη. Στην επιλογή του στοιχείου έχουμε αλλαγή χρωματισμού, στην εικόνα φαίνεται πράσινο. Με το πλήκτρο "διάστημα" μπορούμε να εναλλάσσουμε την τιμή του (την εμφάνιση ή απόκρυψη της κουκκίδας), και κάθε αλλαγή δίνει ένα "γεγονός" στο πρόγραμμα για να "εξυπηρετηθεί". (event service routine, event programming). 

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

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

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

Τέλος υπάρχει ένας συνδυασμός δυο στοιχείων ελέγχου που δίνει το Combobox, όπου μπορούμε να γράψουμε με αυτόματη συμπλήρωση από μια λίστα τιμών (εδώ  λέξεων πόλεων/μερών). Με τα άνω και κάτω βελάκια ανοίγουμε την λίστα, όπως και με πάτημα και τράβηγμα του πρώτου στοιχείου ελέγχου. Μπορούμε να επιλέξουμε από τη λίστα με Enter ή αν θέλουμε να τροποποιήσουμε την επιλογή στο κύριο στοιχείο χωρίς να κλείσουμε την λίστα. Η λίστα φεύγει αν πατήσουμε TAB για να κινηθούμε στο επόμενο στοιχείο ή SHIFT TAB στο προηγούμενο, ή απλά αν επιλέξουμε άλλο στοιχείο (ακόμα και με επιλογή από το ποντίκι του πρώτου στοιχείου πάλι κλείνει η λίστα, ουσιαστικά δεν κλείνει αν πληκτρολογούμε κάτι στο πρώτο στοιχείο ενώ είναι ανοικτή, με τα βελάκια άνω και κάτω πάμε στη λίστα και με τα δεξιά και αριστερά στην διόρθωση της επιλογής)

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

Τα παραπάνω καλούδια είναι γραμμένα με VB6, και το πρόγραμμα επίδειξης τρέχει σε XP, 7, Linoux με WINE. Ο κώδικας είναι ανοικτός και βρίσκεται εδώ:
http://www.vbforums.com/showthread.php?776741-Nice-Textboxes-version2