Το HotXLS, το εγγενές component λογιστικών φύλλων Excel για Delphi και C++Builder, κυκλοφόρησε δύο συναφή fixes AGGREGATE τον Σεπτέμβριο του 2026. Η έκδοση 2.382.0 διόρθωσε το όρισμα επιλογών ώστε οι κωδικοί 1/3/5/7 να αγνοούν κρυφές σειρές, οι 2/3/6/7 να αγνοούν σφάλματα, και οι 0 έως 3 να αγνοούν εμφωλευμένα κελιά SUBTOTAL και AGGREGATE, ακριβώς όπως τεκμηριώνει η Microsoft. Η έκδοση 2.382.3 μετά σταμάτησε εκείνες τις σημαίες επιλογής από το να διαρρέουν στην αξιολόγηση των ακριβώς κελιών που αναφέρεται η συνάρτηση. Το πρώτο ελάττωμα είναι αμήχανο με τον τρόπο που είναι πάντα τα bugs αντιγραφής πινάκων: οι θέσεις bits ήταν αντεστραμμένες, οπότε κάθε τύπος που χρησιμοποιούσε μη μηδενικό κωδικό επιλογών έπαιρνε μια πολιτική που δεν ζήτησε ο συγγραφέας του. Το δεύτερο είναι πιο ενδιαφέρον, επειδή είναι σχήμα που θα συναντήσεις σε οποιονδήποτε evaluator που χρησιμοποιεί παροδικό πεδίο για να περάσει πλαίσιο σε αναδρομικό περπάτημα. Μια εξωτερική συσσωμάτωση οπλίζει μια σημαία, περπατάει ένα εύρος, και τραβάει ένα κελί του οποίου ο τύπος δεν έχει υπολογιστεί ακόμα. Εκείνος ο τύπος τρέχει πάνω στην ίδια αριθμομηχανή, βλέπει την ίδια οπλισμένη σημαία, και συσσωματώνει σιωπηλά τις λάθος σειρές, παράγοντας αριθμό που απέχει κατά ποσό που κανείς δεν μπορεί να εξηγήσει από το κείμενο του τύπου μόνο
Τι επιλέγουν πραγματικά οι επιλογές AGGREGATE 0 έως 7;
Το όρισμα επιλογών του AGGREGATE είναι matrix τριών bits, και τα τρία bits είναι ανεξάρτητα. Το bit 0 (τιμή 1) σημαίνει αγνόησε κρυφές σειρές, το bit 1 (τιμή 2) σημαίνει αγνόησε τιμές σφαλμάτων, και το bit 2 (τιμή 4) σημαίνει σταμάτα να αγνοείς εμφωλευμένα κελιά SUBTOTAL και AGGREGATE, επειδή το να τα παραλείπεις είναι η προεπιλογή για τους χαμηλούς κωδικούς. Δύο πράγματα εδώ είναι εύκολο να τα πάρεις ανάποδα. Το bit κρυφών σειρών είναι το χαμηλό bit, όχι το μεσαίο, οπότε το AGGREGATE(9,1,...) είναι η μορφή φιλτραρισμένου συνόλου και το AGGREGATE(9,2,...) είναι η ανεκτική στα σφάλματα. Και η πολιτική εμφωλευμένων aggregates είναι αντεστραμμένη σε σχέση με τις άλλες δύο: μόνο οι κωδικοί 4 έως 7 μεταχειρίζονται κελί του οποίου ο ίδιος τύπος είναι SUBTOTAL ή AGGREGATE ως συνηθισμένη τιμή. Το ECMA-376 Part 1 §18.17.7 ορίζει το SUBTOTAL με τον ίδιο διαχωρισμό συμπερίληψης-ή-εξαίρεσης κρυφών σειρών στους κωδικούς 1-11 και 101-111, και το AGGREGATE, αποθηκευμένο σε αρχεία OOXML υπό το πρόθεμα _xlfn., γενικεύει εκείνον τον διαχωρισμό στο όρισμα επιλογών, οπότε ο πίνακας που δημοσιεύει η Microsoft για τη συνάρτηση AGGREGATE είναι η σύμβαση που πρέπει να πληροί μια μηχανή και όχι ευκολία
| Επιλογή | Κρυφές σειρές | Τιμές σφάλματος | Εμφωλευμένα SUBTOTAL / AGGREGATE |
|---|---|---|---|
| 0 | περιλαμβάνονται | διαδίδονται | αγνοούνται |
| 1 | αγνοούνται | διαδίδονται | αγνοούνται |
| 2 | περιλαμβάνονται | αγνοούνται | αγνοούνται |
| 3 | αγνοούνται | αγνοούνται | αγνοούνται |
| 4 | περιλαμβάνονται | διαδίδονται | περιλαμβάνονται |
| 5 | αγνοούνται | διαδίδονται | περιλαμβάνονται |
| 6 | περιλαμβάνονται | αγνοούνται | περιλαμβάνονται |
| 7 | αγνοούνται | αγνοούνται | περιλαμβάνονται |
Γιατί το HotXLS είχε τις επιλογές AGGREGATE ανάποδα;
Επειδή το αρχικό TXLSCalculator.CalcAggregateFunc γράφτηκε από μια παράφραση του πίνακα και όχι από τον πίνακα. Υπολόγιζε ignoreErrors := (optCode >= 4) and (optCode <= 7) και οπλίζε την πύλη κρυφών σειρών για τους κωδικούς 2, 3, 6 και 7, ενώ η πολιτική εμφωλευμένων aggregates δεν ήταν καθόλου υλοποιημένη. Το προγενέστερο άρθρο για τις κρυφές σειρές SUBTOTAL και AGGREGATE απαριθμούσε εκείνο το κενό ως ανοιχτό όριο και περιέγραφε την παλιά αντιστοίχιση όπως κυκλοφορούσε τότε· η περιγραφή ήταν ακριβής για τον κώδικα και λάθος για το Excel, και κανείς δεν το πρόσεξε για πολύ καιρό επειδή οι δύο πολιτικές που συνδυάζουν οι περισσότεροι, κρυφές συν σφάλματα, προσγειώνονται στους κωδικούς 3 και 7 και στις δύο πίνακες. Μόνο ένας κωδικός ενός bit αποκάλυπτε την αντιστροφή: το AGGREGATE(9,1,A1:A4) επέστρεφε το άφιλτρο άθροισμα, και το AGGREGATE(9,2,...) παραλείπε κρυφές σειρές ενώ ακόμα διέδιδε #DIV/0!. Το ελάττωμα βγήκε στην επιφάνεια από μια στατική αναθεώρηση του lxCalc.pas, καταγεγραμμένο ως HXLS-008 στο μητρώο γνωστών θεμάτων του έργου, και όχι από αρχείο πελάτη, που λέει κάτι για το πόσο σπάνια εμφανίζονται οι κωδικοί ενός bit σε workbooks παραγωγής. Η έκδοση 2.382.0 ξαναέγραψε την αποκωδικοποίηση ως τρία tests συμμετοχής συνόλου και πρόσθεσε δεύτερη πύλη για την εμφωλευμένη πολιτική, συνδεδεμένη μέσω νέου callback TXLSIsSubtotalCell που παρέχει το workbook δίπλα στο TXLSIsRowHidden
// TXLSCalculator.CalcAggregateFunc, μορφή v2.382.3
if (optCode < 0) or (optCode > 7) then
begin
Result := lxErrorValue; // Το Excel απορρίπτει κωδικούς εκτός 0..7
Exit;
end;
ignoreErrors := optCode in [2, 3, 6, 7];
prevIgnoreHidden := FIgnoreHiddenRows;
prevIgnoreSubtotal := FIgnoreSubtotalCells;
FIgnoreHiddenRows := (optCode in [1, 3, 5, 7]) and Assigned(FIsRowHidden);
FIgnoreSubtotalCells := (optCode in [0, 1, 2, 3]) and Assigned(FIsSubtotalCell);
try
// ... αντιστοίχιση function_num στο εσωτερικό iftab, περπάτημα ref1..refN ...
finally
FIgnoreHiddenRows := prevIgnoreHidden;
FIgnoreSubtotalCells := prevIgnoreSubtotal;
end;
Πρόσεξε ότι οι δύο σημαίες ανατίθενται άνευ όρων και όχι μόνο θέτονται όταν το ζητά η επιλογή. Η έκδοση v2.382.0 ακόμα χρησιμοποιούσε if ... then FIgnoreHiddenRows := True, που σήμαινε ότι ένα AGGREGATE με κωδικό 4 εμφωλευμένο μέσα σε SUBTOTAL(109, ...) κληρονομούσε την εξωτερική πύλη κρυφών σειρών αντί να την καθαρίσει. Η ανάθεση της αποκωδικοποιημένης τιμής στην είσοδο και η επαναφορά της προηγούμενης τιμής στο block finally κάνει κάθε κλήση AGGREGATE να κατέχει τη δική της πολιτική για τη διάρκεια του περπατήματός της και τίποτα παραπάνω. Η έκδοση 2.382.0 έκανε επίσης την τυπική μορφή πίνακα ειλικρινή: όταν ένα όρισμα αξιολογείται σε Variant array ενός ή δύο διαστάσεων, το CalcAggregateFunc πλέον περπατάει κάθε στοιχείο και εφαρμόζει την πολιτική σφαλμάτων ανά στοιχείο, εκεί όπου ο παλιός κώδικας έλεγχε μόνο για NaN double και αλλιώς παρεδίδε όλο τον πίνακα στο ExcelSum
Γιατί ένα εξωτερικό AGGREGATE διαρρέει στους τύπους που αναφέρεται;
Επειδή τα FIgnoreHiddenRows και FIgnoreSubtotalCells είναι πεδία της αριθμομηχανής, και η αριθμομηχανή μοιράζεται από κάθε τύπο που αξιολογείται σε μία επανυπολογισμό. Οι πύλες σχεδιάστηκαν ως scratch πεδία ακριβώς ώστε έξι βρόχοι περπατήματος κελιών να τα συμβουλεύονται χωρίς να περνάει παράμετρος μέσα από κάθε υπογραφή, και εκείνος ο σχεδιασμός είναι υγιής όσο οτιδήποτε τρέχει όσο μια πύλη είναι οπλισμένη ανήκει στη συσσωμάτωση που την οπλίσε. Η υπόθεση σπάει σε ένα συγκεκριμένο σημείο: το FGetValue. Όταν ένας walker ζητά από το workbook τιμή κελιού και εκείνο το κελί κρατά τύπο χωρίς cached αποτέλεσμα, το workbook μεταγλωττίζει τον τύπο και τον αξιολογεί επιτόπου, πάνω στην ίδια TXLSCalculator, με τις εξωτερικές πύλες ακόμα ορισμένες. Το regression fixture στο HotXLS.WorkbookApiTests.pas δείχνει την αποτυχία με τέσσερα κελιά. Το A1 κρατά 10, το A2 κρατά 20 σε κρυφή σειρά, το A3 κρατά =1/0, και το A4 κρατά =SUBTOTAL(9,A1:A2), του οποίου η σωστή τιμή είναι 30. Τώρα αξιολόγησε =AGGREGATE(9,7,A1:A4): αγνόησε κρυφές σειρές, αγνόησε σφάλματα, μέτρησε το εμφωλευμένο subtotal ως τιμή. Το Excel επιστρέφει 10 + 30 = 40. Με το A4 χωρίς cache, η μηχανή προ-2.382.3 οπλίζε την πύλη κρυφών σειρών, περπατούσε μέχρι το A4, πυροδοτούσε την αξιολόγησή του, και το CalcSubtotalFunc για κωδικό 9 κληρονομούσε την οπλισμένη πύλη, επειδή θέτει μόνο τη σημαία για κωδικούς 101 έως 111 και δεν την καθαρίζει ποτέ. Το A4 αξιολογούνταν σε 10 αντί για 30, και το εξωτερικό σύνολο γύριζε 20. Τίποτα σε κάποιον από τους δύο τύπους δεν μνημονεύει κρυφές σειρές στη διαδρομή που παρήγε τον λάθος αριθμό
Η πύλη εμφωλευμένων aggregates διέρρεε με τον ίδιο τρόπο προς την άλλη κατεύθυνση. Με κωδικούς 0 έως 3, το FIgnoreSubtotalCells είναι οπλισμένο, και ο γενικός walker εύρους στο GetValueItemRange το τηρεί, οπότε προηγούμενος τύπος του οποίου ο τύπος είναι =SUM(B1:B3) θα πετούσε σιωπηλά το B2 αν το B2 τύχαινε να περιέχει SUBTOTAL. Χειρότερα, το CalcSubtotalFunc μηδένιζε το FIgnoreSubtotalCells σε False στην έξοδο αντί να επαναφέρει την προηγούμενη τιμή, οπότε ένας χωρίς cache πρόγονος SUBTOTAL που φτάνονταν στη μέση του περπατήματος αφοπλίζε την εξωτερική πύλη για κάθε κελί μετά από αυτόν. Το μητρώο γνωστών θεμάτων του έργου το καταχωρεί ως HXLS-008 ως διαρροή εμφωλευμένης κατάστασης επιλογής, και αυτό είναι το σωστό όνομα για την κατηγορία bug: μια καθολική παροδική σημαία που είναι σωστή για το πλαίσιο που την έθεσε και λάθος για κάθε πλαίσιο που την κληρονομεί
Πώς το AggregateGetCellValue και το AggregateGetItemValue μονώνουν το περπάτημα
Το fix στο v2.382.3 βάζει όριο γύρω από κάθε σημείο όπου το AGGREGATE διαβάζει τιμή που δεν υπολόγισε ο ίδιος. Το TXLSCalculator.AggregateGetCellValue τυλίγει την ακατέργαστη κλήση FGetValue: σώζει και τις δύο σημαίες, τις καθαρίζει, εκτελεί το τράβηγμα, και τις επαναφέρει σε block finally. Η εξωτερική συσσωμάτωση εξακολουθεί να εφαρμόζει τη δική της πολιτική στο κελί που μόλις τράβηξε, επειδή τα tests κρυφών σειρών και εμφωλευμένων κελιών γίνονται στον walker γύρω από το τράβηγμα, αλλά ο ίδιος ο πρόγονος τύπος τρέχει χωρίς καθόλου πολιτική, που είναι ακριβώς ό,τι κάνει το Excel
function TXLSCalculator.AggregateGetCellValue(SheetIndex, Row, Col: Integer;
var Value: Variant; var OutOfRange: Boolean): Integer;
var
Hidden, Nested: Boolean;
begin
Hidden := FIgnoreHiddenRows;
Nested := FIgnoreSubtotalCells;
FIgnoreHiddenRows := False; // ένας πρόγονος τύπος κατέχει τη δική του πολιτική
FIgnoreSubtotalCells := False;
try
Result := FGetValue(SheetIndex, Row, Col, Value, OutOfRange);
finally
FIgnoreHiddenRows := Hidden;
FIgnoreSubtotalCells := Nested;
end;
end;
Το AggregateGetItemValue κάνει το ίδιο για ορίσματα εκτός εύρους, και πρέπει να κάνει περισσότερα από το να καθαρίσει σημαίες, επειδή ένα όρισμα όπως A1:A4/(B1:B4-20) είναι υπολογιζόμενος πίνακας του οποίου το σχήμα στοιχείων πρέπει να επιβιώσει. Ο wrapper υλοποιεί σκέτο εύρος σε δισδιάστατο Variant array μέσω AggregateGetCellValue, αντιστοιχίζοντας κελί που επέστρεψε κωδικό σφάλματος σε VarAsError ώστε η πολιτική σφαλμάτων να εφαρμόζεται ακόμα ανά στοιχείο, και αναδύεται μέσα από τους κόμβους δυαδικών και μονάικών operators (SA_ADD, SA_DIV, SA_UNARMINUS, και τους υπόλοιπους) με ApplyArrayBinaryOp και ApplyArrayUnaryOp· οτιδήποτε άλλο πέφτει στο συνηθισμένο GetValueItem. Δύο guards κάθονται μπροστά από την υλοποίηση: εύρος μεγαλύτερο από EffectiveFormulaArrayMemoryLimit επιστρέφει lxErrorResourceLimit, και εύρος πολλαπλών φύλλων ή αντεστραμμένο επιστρέφει #VALUE!. Κωδικός ορίου πόρων σκόπιμα δεν μεταχειρίζεται ως αγνοήσιμο σφάλμα κελιού ούτε κάτω από επιλογές 2/3/6/7, αφού μια μηχανή που θα καταπίνε το δικό της σήμα out-of-memory επειδή ο χρήστης ζήτησε να παραλείπεται το #N/A θα έλεγε ψέματα. Και οι τρεις walkers AGGREGATE, το AggregateCollectRange για την οικογένεια SUM, το AggregateReduceVariance για STDEV, VAR και PRODUCT, και το AggregateReduceWithK για MEDIAN και τις μορφές ποσοστημορίων, άλλαξαν από FGetValue και GetValueItem στους δύο wrappers, και ο καθένας απέκτησε το test εμφωλευμένων κελιών μέσω FIsSubtotalCell
Ποιο σφάλμα επιστρέφει το AGGREGATE όταν δεν αγνοεί σφάλματα;
Το πρωτότυπο, από το v2.382.3. Η έκδοση 2.382.0 ανίχνευε σωστά κελιά σφαλμάτων αλλά κατέρρεε καθένα από αυτά σε lxErrorValue, οπότε το AGGREGATE(9,4,A1:A3) πάνω σε κελί #DIV/0! επέστρεφε #VALUE!, εκεί όπου το Excel διαδίδει το πρώτο σφάλμα που συναντά αμετάβλητο. Ο αντικαταστάτης helper AggregateErrorCode αντιστοιχίζει Variant στον ταιριάζοντα κωδικό lxError*, είτε το Variant είναι γνήσιο varError είτε ένα από τα επτά strings σφαλμάτων, και το AggregateValueIsError είναι πλέον απλώς test για μη μηδενικό αποτέλεσμα. Κάθε walker καταγράφει τον πρώτο κωδικό σφάλματος που βλέπει και επιστρέφει εκείνον τον κωδικό, που σημαίνει επίσης ότι κελί του οποίου ο τύπος δεν υπολογίστηκε ποτέ, και του οποίου το σφάλμα άρα φτάνει ως κωδικός επιστροφής από το FGetValue και όχι ως cached Variant, διαδίδεται με τον ίδιο τρόπο με ένα cached. Δύο συναρτήσεις μέτρησης παίρνουν ειδική μεταχείριση μέσα στο AggregateCollectRange, και η μεταχείριση ταιριάζει το SUBTOTAL και όχι το SUM. Για εσωτερική συνάρτηση 0, COUNT, κελί σφάλματος δεν μετράται ποτέ και δεν διαδίδεται ποτέ ανεξαρτήτως κωδικού επιλογών, επειδή το COUNT μετρά μόνο αριθμούς. Για εσωτερική συνάρτηση 169, COUNTA, κελί σφάλματος είναι μη κενή τιμή και μετρά ως 1 εκτός αν ο κωδικός επιλογών αγνοεί σφάλματα, οπότε παραλείπεται. Εκείνη η ασυμμετρία είναι πώς το Excel μεταχειρίζεται τα COUNT και COUNTA και εκτός AGGREGATE, και είναι το είδος λεπτομέρειας που ένας γενικός κανόνας «αν σφάλμα τότε διάδοση» παίρνει σιωπηλά λάθος
Τι επαληθεύει η matrix regression των οκτώ επιλογών
Το fixture που περιγράφηκε παραπάνω εξασκείται ως πλήρης matrix στο AggregateFunc_OptionMatrixCoversHiddenErrorsAndNestedAggregates: για κάθε κωδικό επιλογών από 0 έως 7 αξιολογεί και τη μορφή SUM και τη μορφή MEDIAN πάνω στο A1:A4 και ελέγχει το αποτέλεσμα απέναντι σε χειροκίνητα παραγόμενη προσδοκία. Οι κωδικοί 0, 1, 4 και 5 πρέπει να διαδώσουν το #DIV/0! από το A3, αφού κανένας δεν αγνοεί σφάλματα. Ο κωδικός 2 δίνει SUM 30 και MEDIAN 15, από 10 και 20 με το εμφωλευμένο A4 παραλειμμένο. Ο κωδικός 3 δίνει 10 και 10. Ο κωδικός 6 δίνει 60 και 20, επειδή το 30 στο A4 μετράει πλέον. Ο κωδικός 7 δίνει 40 και 20, που είναι η περίπτωση που επέστρεφε 20 πριν το fix της διαρροής. Το φαρδύτερο πέρασμα αποδοχής που καταγράφεται στο μητρώο γνωστών θεμάτων καλύπτει και τα δεκαεννιά function numbers απέναντι και στους οκτώ κωδικούς, με κάθε πρόγονο και cached και χωρίς cache, για 304 σενάρια σε Win32 και Win64
var
Book: TXLSXWorkbook;
Sheet: TXLSXWorksheet;
begin
Book := TXLSXWorkbook.Create;
try
Sheet := Book.Sheets.Add('Data');
Sheet.Cells[1, 1].Value := 10;
Sheet.Cells[2, 1].Value := 20;
Sheet.Cells[3, 1].Formula := '=1/0';
Sheet.Cells[4, 1].Formula := '=SUBTOTAL(9,A1:A2)'; // subtotal ομάδας = 30
Sheet.RowHidden[2] := True;
Sheet.Cells[6, 1].Formula := '=AGGREGATE(9,1,A1:A4)'; // #DIV/0! κρυφές παραλείπονται, το σφάλμα διαδίδεται
Sheet.Cells[7, 1].Formula := '=AGGREGATE(9,3,A1:A4)'; // 10 κρυφές + σφάλμα + εμφωλευμένα παραλείπονται
Sheet.Cells[8, 1].Formula := '=AGGREGATE(9,6,A1:A4)'; // 60 μόνο σφάλματα παραλείπονται
Sheet.Cells[9, 1].Formula := '=AGGREGATE(9,7,A1:A4)'; // 40 ήταν 20 πριν το v2.382.3
Book.Recalculate;
Book.SaveAs('aggregate-options.xlsx');
finally
Book.Free;
end;
end;
Πού βρίσκεται ακόμα το όριο
Τρία όρια αξίζει να ξέρεις πριν χτίσεις πάνω σε αυτό. Πρώτον, το κατηγόρημα εμφωλευμένων aggregates είναι κειμενικό. Τα TXLSXWorkbook.GetCalcIsSubtotalCell και το δίδυμό του classic-engine απαντούν True όταν ο τύπος κελιού ξεκινά SUBTOTAL(, AGGREGATE(, ή _xlfn.AGGREGATE(, με ή χωρίς το αρχικό equals sign, οπότε τύπος όπως =IF(C1,SUBTOTAL(9,B1:B9),0) ή =SUBTOTAL(9,B1:B9)*2 δεν αναγνωρίζεται ως εμφωλευμένος και θα μετρηθεί διπλά από τους κωδικούς 0 έως 3 εκεί όπου το Excel θα τον παρέλειπε· ένας generator που εκπέμπει υπολογιζόμενα subtotals πρέπει να κρατά την κλήση συσσωμάτωσης στην κεφαλή του τύπου. Δεύτερον, η μόνωση ζει στους τρεις walkers AGGREGATE. Το CalcSubtotalFunc εξακολουθεί να περπατάει μέσω GetValueItemRange, CollectRangeValues, και SubtotalReduceVariance, που καλούν FGetValue ευθέως, οπότε SUBTOTAL(109, ...) του οποίου το εύρος περιέχει χωρίς cache πρόγονο τύπο μπορεί ακόμα να περάσει την πύλη κρυφών σειρών του μέσα σε εκείνον τον πρόγονο. Ένα πλήρες Recalculate αξιολογεί προγόνους πριν από εξαρτήσεις, οπότε παίρνεται η cached διαδρομή και η πύλη δεν κληρονομείται ποτέ· η έκθεση περιορίζεται σε ad hoc αξιολόγηση μέσω Calculate και σε workbooks φορτωμένα χωρίς cached τιμές, και αν στηρίζεσαι στον incremental επανυπολογισμό πάνω στον γράφο εξαρτήσεων για να κρατάς μεγάλα μοντέλα ανταποκρίτικά, η ίδια εγγύηση σειράς είναι που κρατά αυτή τη διαρροή αδρανή. Τρίτον, και οι δύο πύλες εξαρτώνται από Assigned(FIsRowHidden) και Assigned(FIsSubtotalCell). Και τα δύο facades workbook συνδέουν τα callbacks στους constructors τους, αλλά κώδικας που χτίζει TXLSCalculator με το χέρι με μόνο τα δύο πρωτότυπα ορίσματα παίρνει τη legacy συμπεριφορά συμπερίληψης-όλων για κάθε κωδικό επιλογών, σιωπηλά. Όταν ένα σύνολο φαίνεται λάθος και το κείμενο του τύπου φαίνεται σωστό, το ιχνηλάτηση της αξιολόγησης βήμα προς βήμα είναι ο γρηγορότερος τρόπος να δεις αν ένας πρόγονος αξιολογήθηκε κάτω από κληρονομημένη πύλη ή αν ένα callback απλώς δεν συνδέθηκε ποτέ
Η μηχανή υπολογισμών που περιγράφεται εδώ, ο decoder επιλογών, τα μονωμένα wrappers τραβήγματος, και η matrix regression που τα καρφώνει όλα κυκλοφορούν ως πηγή με το HotXLS Delphi spreadsheet component, που διαβάζει, γράφει, και επανυπολογίζει workbooks XLS, XLSX και ODS σε Delphi και C++Builder χωρίς εγκατάσταση Excel